mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
.NET: Add A2AAgentOptions and align A2AAgent constructors with ChatClientAgent pattern (#5954)
* .NET: Add A2AAgentOptions and align A2AAgent constructors with ChatClientAgent pattern Adds a new A2AAgentOptions class (Id, Name, Description, Clone) and an options-based constructor on A2AAgent, mirroring ChatClientAgent/ChatClientAgentOptions. The existing parameter-based constructor is preserved for backward compatibility and now delegates to the options-based one. Extension methods are extended with options-based overloads: - A2AClientExtensions.AsAIAgent(IA2AClient, A2AAgentOptions, ...) - A2AAgentCardExtensions.AsAIAgent(AgentCard, A2AAgentOptions, ...) - A2ACardResolverExtensions.GetAIAgentAsync(A2ACardResolver, A2AAgentOptions, ...) For card-based creation, user-supplied options override values from the agent card; Name and Description fall back to card values when not set. Options are cloned when stored on the agent to prevent post-construction mutation, matching the ChatClientAgent pattern. Resolves #5870. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review comments - Add Throw.IfNull(client) in A2AClientExtensions.AsAIAgent - Add Throw.IfNull(card) in A2AAgentCardExtensions.AsAIAgent - Clarify httpClient docs in A2ACardResolverExtensions.GetAIAgentAsync: it applies to the created A2A client, not to card discovery - Rename test methods from GetAIAgent_* to AsAIAgent_* to match the API under test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
f390595188
commit
dd1e615dad
@@ -28,9 +28,7 @@ public sealed class A2AAgent : AIAgent
|
||||
private static readonly AIAgentMetadata s_agentMetadata = new("a2a");
|
||||
|
||||
private readonly IA2AClient _a2aClient;
|
||||
private readonly string? _id;
|
||||
private readonly string? _name;
|
||||
private readonly string? _description;
|
||||
private readonly A2AAgentOptions _agentOptions;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
@@ -38,17 +36,37 @@ public sealed class A2AAgent : AIAgent
|
||||
/// </summary>
|
||||
/// <param name="a2aClient">The A2A client to use for interacting with A2A agents.</param>
|
||||
/// <param name="id">The unique identifier for the agent.</param>
|
||||
/// <param name="name">The the name of the agent.</param>
|
||||
/// <param name="name">The name of the agent.</param>
|
||||
/// <param name="description">The description of the agent.</param>
|
||||
/// <param name="loggerFactory">Optional logger factory to use for logging.</param>
|
||||
public A2AAgent(IA2AClient a2aClient, string? id = null, string? name = null, string? description = null, ILoggerFactory? loggerFactory = null)
|
||||
: this(
|
||||
a2aClient,
|
||||
new A2AAgentOptions
|
||||
{
|
||||
Id = id,
|
||||
Name = name,
|
||||
Description = description
|
||||
},
|
||||
loggerFactory)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="A2AAgent"/> class.
|
||||
/// </summary>
|
||||
/// <param name="a2aClient">The A2A client to use for interacting with A2A agents.</param>
|
||||
/// <param name="options">
|
||||
/// Configuration options that control the agent's identity, including its identifier, name, and description.
|
||||
/// </param>
|
||||
/// <param name="loggerFactory">Optional logger factory to use for logging.</param>
|
||||
public A2AAgent(IA2AClient a2aClient, A2AAgentOptions options, ILoggerFactory? loggerFactory = null)
|
||||
{
|
||||
_ = Throw.IfNull(a2aClient);
|
||||
_ = Throw.IfNull(options);
|
||||
|
||||
this._a2aClient = a2aClient;
|
||||
this._id = id;
|
||||
this._name = name;
|
||||
this._description = description;
|
||||
this._agentOptions = options.Clone();
|
||||
this._logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger<A2AAgent>();
|
||||
}
|
||||
|
||||
@@ -216,13 +234,13 @@ public sealed class A2AAgent : AIAgent
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string? IdCore => this._id;
|
||||
protected override string? IdCore => this._agentOptions.Id;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string? Name => this._name;
|
||||
public override string? Name => this._agentOptions.Name;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string? Description => this._description;
|
||||
public override string? Description => this._agentOptions.Description;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override object? GetService(Type serviceType, object? serviceKey = null)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
namespace Microsoft.Agents.AI.A2A;
|
||||
|
||||
/// <summary>
|
||||
/// Represents configuration options for an <see cref="A2AAgent"/>, including its identifier, name, and description.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is used to encapsulate information about an A2A agent, such as its unique
|
||||
/// identifier, display name, and a descriptive summary. It provides an alternative to passing
|
||||
/// these values as individual constructor parameters.
|
||||
/// </remarks>
|
||||
public sealed class A2AAgentOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the agent id.
|
||||
/// </summary>
|
||||
public string? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the agent name.
|
||||
/// </summary>
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the agent description.
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="A2AAgentOptions"/> with the same values as this instance.
|
||||
/// </summary>
|
||||
public A2AAgentOptions Clone()
|
||||
=> new()
|
||||
{
|
||||
Id = this.Id,
|
||||
Name = this.Name,
|
||||
Description = this.Description
|
||||
};
|
||||
}
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
using System.Net.Http;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.A2A;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace A2A;
|
||||
|
||||
@@ -36,4 +38,39 @@ public static class A2AAgentCardExtensions
|
||||
|
||||
return a2aClient.AsAIAgent(name: card.Name, description: card.Description, loggerFactory: loggerFactory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an instance of <see cref="AIAgent"/> for an existing A2A agent.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method can be used to access A2A agents that support the
|
||||
/// <see href="https://github.com/a2aproject/A2A/blob/main/docs/topics/agent-discovery.md#2-curated-registries-catalog-based-discovery">Curated Registries (Catalog-Based Discovery)</see>
|
||||
/// discovery mechanism. When <paramref name="agentOptions"/> is provided, any non-null values override
|
||||
/// the corresponding values from the <see cref="AgentCard"/>.
|
||||
/// </remarks>
|
||||
/// <param name="card">The <see cref="AgentCard" /> to use for the agent creation.</param>
|
||||
/// <param name="agentOptions">
|
||||
/// Configuration options that control the agent's identity. When provided, non-null values override the
|
||||
/// corresponding values from the agent card.
|
||||
/// </param>
|
||||
/// <param name="httpClient">The <see cref="HttpClient"/> to use for HTTP requests.</param>
|
||||
/// <param name="clientOptions">
|
||||
/// Optional <see cref="A2AClientOptions"/> controlling protocol binding preference.
|
||||
/// When not provided, defaults to preferring HTTP+JSON first, with JSON-RPC as fallback.
|
||||
/// </param>
|
||||
/// <param name="loggerFactory">The logger factory for enabling logging within the agent.</param>
|
||||
/// <returns>An <see cref="AIAgent"/> instance backed by the A2A agent.</returns>
|
||||
public static AIAgent AsAIAgent(this AgentCard card, A2AAgentOptions agentOptions, HttpClient? httpClient = null, A2AClientOptions? clientOptions = null, ILoggerFactory? loggerFactory = null)
|
||||
{
|
||||
_ = Throw.IfNull(card);
|
||||
_ = Throw.IfNull(agentOptions);
|
||||
|
||||
var a2aClient = A2AClientFactory.Create(card, httpClient, clientOptions);
|
||||
|
||||
var mergedOptions = agentOptions.Clone();
|
||||
mergedOptions.Name ??= card.Name;
|
||||
mergedOptions.Description ??= card.Description;
|
||||
|
||||
return a2aClient.AsAIAgent(mergedOptions, loggerFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.A2A;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace A2A;
|
||||
|
||||
@@ -48,4 +49,39 @@ public static class A2ACardResolverExtensions
|
||||
|
||||
return agentCard.AsAIAgent(httpClient, options, loggerFactory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an instance of <see cref="AIAgent"/> for an existing A2A agent.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method can be used to access A2A agents that support the
|
||||
/// <see href="https://github.com/a2aproject/A2A/blob/main/docs/topics/agent-discovery.md#1-well-known-uri">Well-Known URI</see>
|
||||
/// discovery mechanism. When <paramref name="agentOptions"/> is provided, any non-null values override
|
||||
/// the corresponding values from the resolved <see cref="AgentCard"/>.
|
||||
/// </remarks>
|
||||
/// <param name="resolver">The <see cref="A2ACardResolver" /> to use for the agent creation.</param>
|
||||
/// <param name="agentOptions">
|
||||
/// Configuration options that control the agent's identity. When provided, non-null values override the
|
||||
/// corresponding values from the resolved agent card.
|
||||
/// </param>
|
||||
/// <param name="httpClient">
|
||||
/// The <see cref="HttpClient"/> to use for HTTP requests made by the created A2A client.
|
||||
/// This is not used for fetching the agent card; the resolver uses its own configured client for that.
|
||||
/// </param>
|
||||
/// <param name="clientOptions">
|
||||
/// Optional <see cref="A2AClientOptions"/> controlling protocol binding preference.
|
||||
/// When not provided, defaults to preferring HTTP+JSON first, with JSON-RPC as fallback.
|
||||
/// </param>
|
||||
/// <param name="loggerFactory">The logger factory for enabling logging within the agent.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>An <see cref="AIAgent"/> instance backed by the A2A agent.</returns>
|
||||
public static async Task<AIAgent> GetAIAgentAsync(this A2ACardResolver resolver, A2AAgentOptions agentOptions, HttpClient? httpClient = null, A2AClientOptions? clientOptions = null, ILoggerFactory? loggerFactory = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_ = Throw.IfNull(agentOptions);
|
||||
|
||||
// Obtain the agent card from the resolver.
|
||||
var agentCard = await resolver.GetAgentCardAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return agentCard.AsAIAgent(agentOptions, httpClient, clientOptions, loggerFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.A2A;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace A2A;
|
||||
|
||||
@@ -31,10 +32,32 @@ public static class A2AClientExtensions
|
||||
/// </remarks>
|
||||
/// <param name="client">The <see cref="IA2AClient" /> to use for the agent.</param>
|
||||
/// <param name="id">The unique identifier for the agent.</param>
|
||||
/// <param name="name">The the name of the agent.</param>
|
||||
/// <param name="name">The name of the agent.</param>
|
||||
/// <param name="description">The description of the agent.</param>
|
||||
/// <param name="loggerFactory">Optional logger factory for enabling logging within the agent.</param>
|
||||
/// <returns>An <see cref="AIAgent"/> instance backed by the A2A agent.</returns>
|
||||
public static AIAgent AsAIAgent(this IA2AClient client, string? id = null, string? name = null, string? description = null, ILoggerFactory? loggerFactory = null) =>
|
||||
new A2AAgent(client, id, name, description, loggerFactory);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an instance of <see cref="AIAgent"/> for an existing A2A agent.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method can be used to access A2A agents that support the
|
||||
/// <see href="https://github.com/a2aproject/A2A/blob/main/docs/topics/agent-discovery.md#3-direct-configuration--private-discovery">Direct Configuration / Private Discovery</see>
|
||||
/// discovery mechanism.
|
||||
/// </remarks>
|
||||
/// <param name="client">The <see cref="IA2AClient" /> to use for the agent.</param>
|
||||
/// <param name="options">
|
||||
/// Configuration options that control the agent's identity, including its identifier, name, and description.
|
||||
/// </param>
|
||||
/// <param name="loggerFactory">Optional logger factory for enabling logging within the agent.</param>
|
||||
/// <returns>An <see cref="AIAgent"/> instance backed by the A2A agent.</returns>
|
||||
public static AIAgent AsAIAgent(this IA2AClient client, A2AAgentOptions options, ILoggerFactory? loggerFactory = null)
|
||||
{
|
||||
_ = Throw.IfNull(client);
|
||||
_ = Throw.IfNull(options);
|
||||
|
||||
return new A2AAgent(client, options, loggerFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,72 @@ public sealed class A2AAgentTests : IDisposable
|
||||
Assert.Null(agent.Description);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithOptions_InitializesPropertiesCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var options = new A2AAgentOptions
|
||||
{
|
||||
Id = "options-id",
|
||||
Name = "options-name",
|
||||
Description = "options-description"
|
||||
};
|
||||
|
||||
// Act
|
||||
var agent = new A2AAgent(this._a2aClient, options);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("options-id", agent.Id);
|
||||
Assert.Equal("options-name", agent.Name);
|
||||
Assert.Equal("options-description", agent.Description);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithOptions_IsolatesAgentFromOptionsMutation()
|
||||
{
|
||||
// Arrange
|
||||
var options = new A2AAgentOptions
|
||||
{
|
||||
Id = "original-id",
|
||||
Name = "Original Name",
|
||||
Description = "Original Description"
|
||||
};
|
||||
var agent = new A2AAgent(this._a2aClient, options);
|
||||
|
||||
// Act - mutate options after agent construction
|
||||
options.Id = "mutated-id";
|
||||
options.Name = "Mutated Name";
|
||||
options.Description = "Mutated Description";
|
||||
|
||||
// Assert - agent should retain original values
|
||||
Assert.Equal("original-id", agent.Id);
|
||||
Assert.Equal("Original Name", agent.Name);
|
||||
Assert.Equal("Original Description", agent.Description);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithNullOptions_ThrowsArgumentNullException() =>
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentNullException>(() => new A2AAgent(this._a2aClient, options: null!));
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithEmptyOptions_UsesBaseProperties()
|
||||
{
|
||||
// Act
|
||||
var agent = new A2AAgent(this._a2aClient, new A2AAgentOptions());
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(agent.Id);
|
||||
Assert.NotEmpty(agent.Id);
|
||||
Assert.Null(agent.Name);
|
||||
Assert.Null(agent.Description);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithOptions_NullA2AClient_ThrowsArgumentNullException() =>
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentNullException>(() => new A2AAgent(null!, new A2AAgentOptions()));
|
||||
|
||||
[Fact]
|
||||
public async Task RunAsync_AllowsNonUserRoleMessagesAsync()
|
||||
{
|
||||
|
||||
+76
-1
@@ -31,7 +31,7 @@ public sealed class A2AAgentCardExtensionsTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAIAgent_ReturnsAIAgent()
|
||||
public void AsAIAgent_ReturnsAIAgent()
|
||||
{
|
||||
// Act
|
||||
var agent = this._agentCard.AsAIAgent();
|
||||
@@ -165,6 +165,81 @@ public sealed class A2AAgentCardExtensionsTests
|
||||
Assert.ThrowsAny<Exception>(() => card.AsAIAgent());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentOptions_OverridesCardValues()
|
||||
{
|
||||
// Arrange
|
||||
var card = new AgentCard
|
||||
{
|
||||
Name = "Card Agent",
|
||||
Description = "Card description",
|
||||
SupportedInterfaces = [new AgentInterface { Url = "http://test-endpoint/agent" }]
|
||||
};
|
||||
|
||||
var agentOptions = new A2AAgentOptions
|
||||
{
|
||||
Id = "custom-id",
|
||||
Name = "Custom Agent",
|
||||
Description = "Custom description"
|
||||
};
|
||||
|
||||
// Act
|
||||
var agent = card.AsAIAgent(agentOptions);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(agent);
|
||||
Assert.IsType<A2AAgent>(agent);
|
||||
Assert.Equal("custom-id", agent.Id);
|
||||
Assert.Equal("Custom Agent", agent.Name);
|
||||
Assert.Equal("Custom description", agent.Description);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AsAIAgent_WithAgentOptions_FallsBackToCardValues()
|
||||
{
|
||||
// Arrange
|
||||
var card = new AgentCard
|
||||
{
|
||||
Name = "Card Agent",
|
||||
Description = "Card description",
|
||||
SupportedInterfaces = [new AgentInterface { Url = "http://test-endpoint/agent" }]
|
||||
};
|
||||
|
||||
var agentOptions = new A2AAgentOptions
|
||||
{
|
||||
Id = "custom-id"
|
||||
};
|
||||
|
||||
// Act
|
||||
var agent = card.AsAIAgent(agentOptions);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(agent);
|
||||
Assert.Equal("custom-id", agent.Id);
|
||||
Assert.Equal("Card Agent", agent.Name);
|
||||
Assert.Equal("Card description", agent.Description);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AsAIAgent_WithEmptyAgentOptions_UsesCardValues()
|
||||
{
|
||||
// Arrange
|
||||
var card = new AgentCard
|
||||
{
|
||||
Name = "Card Agent",
|
||||
Description = "Card description",
|
||||
SupportedInterfaces = [new AgentInterface { Url = "http://test-endpoint/agent" }]
|
||||
};
|
||||
|
||||
// Act
|
||||
var agent = card.AsAIAgent(new A2AAgentOptions());
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(agent);
|
||||
Assert.Equal("Card Agent", agent.Name);
|
||||
Assert.Equal("Card description", agent.Description);
|
||||
}
|
||||
|
||||
internal sealed class HttpMessageHandlerStub : HttpMessageHandler
|
||||
{
|
||||
public Queue ResponsesToReturn { get; } = new();
|
||||
|
||||
+55
@@ -113,6 +113,61 @@ public sealed class A2ACardResolverExtensionsTests : IDisposable
|
||||
Assert.Equal(new Uri("http://jsonrpc/agent"), this._handler.CapturedUris[1]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAIAgentAsync_WithAgentOptions_OverridesCardValuesAsync()
|
||||
{
|
||||
// Arrange
|
||||
this._handler.ResponsesToReturn.Enqueue(new AgentCard
|
||||
{
|
||||
Name = "Card Agent",
|
||||
Description = "Card description",
|
||||
SupportedInterfaces = [new AgentInterface { Url = "http://test-endpoint/agent" }]
|
||||
});
|
||||
|
||||
var agentOptions = new A2AAgentOptions
|
||||
{
|
||||
Id = "custom-id",
|
||||
Name = "Custom Agent",
|
||||
Description = "Custom description"
|
||||
};
|
||||
|
||||
// Act
|
||||
var agent = await this._resolver.GetAIAgentAsync(agentOptions, httpClient: this._httpClient);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(agent);
|
||||
Assert.IsType<A2AAgent>(agent);
|
||||
Assert.Equal("custom-id", agent.Id);
|
||||
Assert.Equal("Custom Agent", agent.Name);
|
||||
Assert.Equal("Custom description", agent.Description);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAIAgentAsync_WithAgentOptions_FallsBackToCardValuesAsync()
|
||||
{
|
||||
// Arrange
|
||||
this._handler.ResponsesToReturn.Enqueue(new AgentCard
|
||||
{
|
||||
Name = "Card Agent",
|
||||
Description = "Card description",
|
||||
SupportedInterfaces = [new AgentInterface { Url = "http://test-endpoint/agent" }]
|
||||
});
|
||||
|
||||
var agentOptions = new A2AAgentOptions
|
||||
{
|
||||
Id = "custom-id"
|
||||
};
|
||||
|
||||
// Act
|
||||
var agent = await this._resolver.GetAIAgentAsync(agentOptions, httpClient: this._httpClient);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(agent);
|
||||
Assert.Equal("custom-id", agent.Id);
|
||||
Assert.Equal("Card Agent", agent.Name);
|
||||
Assert.Equal("Card description", agent.Description);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this._handler.Dispose();
|
||||
|
||||
+44
-3
@@ -11,7 +11,7 @@ namespace Microsoft.Agents.AI.A2A.UnitTests;
|
||||
public sealed class A2AClientExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetAIAgent_WithAllParameters_ReturnsA2AAgentWithSpecifiedProperties()
|
||||
public void AsAIAgent_WithAllParameters_ReturnsA2AAgentWithSpecifiedProperties()
|
||||
{
|
||||
// Arrange
|
||||
var a2aClient = new A2AClient(new Uri("http://test-endpoint"));
|
||||
@@ -32,7 +32,7 @@ public sealed class A2AClientExtensionsTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAIAgent_WithIA2AClient_ReturnsA2AAgentWithSpecifiedProperties()
|
||||
public void AsAIAgent_WithIA2AClient_ReturnsA2AAgentWithSpecifiedProperties()
|
||||
{
|
||||
// Arrange - use IA2AClient reference type to verify the extension method works with the interface
|
||||
IA2AClient a2aClient = new A2AClient(new Uri("http://test-endpoint"));
|
||||
@@ -53,7 +53,7 @@ public sealed class A2AClientExtensionsTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAIAgent_WithIA2AClient_ExposesClientViaGetService()
|
||||
public void AsAIAgent_WithIA2AClient_ExposesClientViaGetService()
|
||||
{
|
||||
// Arrange
|
||||
IA2AClient a2aClient = new A2AClient(new Uri("http://test-endpoint"));
|
||||
@@ -66,4 +66,45 @@ public sealed class A2AClientExtensionsTests
|
||||
Assert.NotNull(service);
|
||||
Assert.Same(a2aClient, service);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AsAIAgent_WithOptions_ReturnsA2AAgentWithSpecifiedProperties()
|
||||
{
|
||||
// Arrange
|
||||
var a2aClient = new A2AClient(new Uri("http://test-endpoint"));
|
||||
var options = new A2AAgentOptions
|
||||
{
|
||||
Id = "options-agent-id",
|
||||
Name = "Options Agent",
|
||||
Description = "Agent created with options"
|
||||
};
|
||||
|
||||
// Act
|
||||
var agent = a2aClient.AsAIAgent(options);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(agent);
|
||||
Assert.IsType<A2AAgent>(agent);
|
||||
Assert.Equal("options-agent-id", agent.Id);
|
||||
Assert.Equal("Options Agent", agent.Name);
|
||||
Assert.Equal("Agent created with options", agent.Description);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AsAIAgent_WithEmptyOptions_ReturnsA2AAgentWithDefaultProperties()
|
||||
{
|
||||
// Arrange
|
||||
var a2aClient = new A2AClient(new Uri("http://test-endpoint"));
|
||||
|
||||
// Act
|
||||
var agent = a2aClient.AsAIAgent(new A2AAgentOptions());
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(agent);
|
||||
Assert.IsType<A2AAgent>(agent);
|
||||
Assert.NotNull(agent.Id);
|
||||
Assert.NotEmpty(agent.Id);
|
||||
Assert.Null(agent.Name);
|
||||
Assert.Null(agent.Description);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user