Update A2A library to 0.3.1-preview (#1141)

Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>
This commit is contained in:
Stephen Toub
2025-10-03 05:31:31 -04:00
committed by GitHub
Unverified
parent 4daeeb0f07
commit cf831b0348
14 changed files with 72 additions and 72 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<LangVersion>13</LangVersion>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);NU5128;CS8002</NoWarn>
<NoWarn>$(NoWarn);NU5128</NoWarn>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<ProjectsCoreTargetFrameworks>net9.0</ProjectsCoreTargetFrameworks>
<ProjectsTargetFrameworks>net9.0;net8.0;netstandard2.0;net472</ProjectsTargetFrameworks>
+2 -2
View File
@@ -83,8 +83,8 @@
<!-- Agent SDKs -->
<PackageVersion Include="Microsoft.Agents.CopilotStudio.Client" Version="1.2.41" />
<!-- A2A -->
<PackageVersion Include="A2A" Version="0.1.0-preview.2" />
<PackageVersion Include="A2A.AspNetCore" Version="0.1.0-preview.2" />
<PackageVersion Include="A2A" Version="0.3.1-preview" />
<PackageVersion Include="A2A.AspNetCore" Version="0.3.1-preview" />
<!-- MCP -->
<PackageVersion Include="ModelContextProtocol" Version="0.4.0-preview.1" />
<!-- Inference SDKs -->
@@ -43,7 +43,7 @@ internal sealed class A2AAgentClient : IAgentClient
{
// Convert all messages to A2A parts and create a single message
var parts = messages.ToParts();
var a2aMessage = new Message
var a2aMessage = new AgentMessage
{
MessageId = Guid.NewGuid().ToString("N"),
ContextId = contextId,
@@ -55,9 +55,9 @@ internal sealed class A2AAgentClient : IAgentClient
var a2aResponse = await a2aClient.SendMessageAsync(messageSendParams, cancellationToken);
// Handle different response types
if (a2aResponse is Message message)
if (a2aResponse is AgentMessage message)
{
var responseMessage = MessageConverter.ToChatMessage(message);
var responseMessage = message.ToChatMessage();
if (responseMessage is not null)
{
results.Add(new AgentRunResponseUpdate(responseMessage.Role, responseMessage.Contents)
@@ -188,17 +188,17 @@ internal sealed class A2AAgentClient : IAgentClient
// Extension method to convert multiple chat messages to A2A messages
internal static class ChatMessageExtensions
{
public static List<Message> ToA2AMessages(this IList<ChatMessage> chatMessages)
public static List<AgentMessage> ToA2AMessages(this IList<ChatMessage> chatMessages)
{
if (chatMessages is null || chatMessages.Count == 0)
{
return [];
}
var result = new List<Message>();
var result = new List<AgentMessage>();
foreach (var chatMessage in chatMessages)
{
result.Add(MessageConverter.ToA2AMessage(chatMessage));
result.Add(chatMessage.ToA2AMessage());
}
return result;
}
@@ -91,7 +91,7 @@ internal sealed class A2AAgent : AIAgent
this._logger.LogAgentChatClientInvokedAgent(nameof(RunAsync), this.Id, this.Name);
if (a2aResponse is Message message)
if (a2aResponse is AgentMessage message)
{
UpdateThreadConversationId(typedThread, message.ContextId);
@@ -139,13 +139,13 @@ internal sealed class A2AAgent : AIAgent
this._logger.LogA2AAgentInvokingAgent(nameof(RunStreamingAsync), this.Id, this.Name);
var a2aSseEvents = this._a2aClient.SendMessageStreamAsync(new MessageSendParams { Message = a2aMessage }, cancellationToken).ConfigureAwait(false);
var a2aSseEvents = this._a2aClient.SendMessageStreamingAsync(new MessageSendParams { Message = a2aMessage }, cancellationToken).ConfigureAwait(false);
this._logger.LogAgentChatClientInvokedAgent(nameof(RunStreamingAsync), this.Id, this.Name);
await foreach (var sseEvent in a2aSseEvents)
{
if (sseEvent.Data is not Message message)
if (sseEvent.Data is not AgentMessage message)
{
throw new NotSupportedException($"Only message responses are supported from A2A agents. Received: {sseEvent.Data?.GetType().FullName ?? "null"}");
}
@@ -66,7 +66,7 @@ public sealed class A2AHostAgent
/// </summary>
/// <param name="messageSend">The <see cref="MessageSendParams"/> to handle.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
public async Task<Message> OnMessageReceivedAsync(MessageSendParams messageSend, CancellationToken cancellationToken = default)
public async Task<A2AResponse> OnMessageReceivedAsync(MessageSendParams messageSend, CancellationToken cancellationToken = default)
{
Throw.IfNull(messageSend);
Throw.IfNull(this.Agent);
@@ -80,7 +80,7 @@ public sealed class A2AHostAgent
var userMessage = messageSend.Message.ToChatMessage();
// Get the response from the agent
var message = new Message();
var message = new AgentMessage();
var agentResponse = await this.Agent.RunAsync(userMessage, cancellationToken: cancellationToken).ConfigureAwait(false);
foreach (var chatMessage in agentResponse.Messages)
{
@@ -6,11 +6,11 @@ using Microsoft.Extensions.AI;
namespace A2A;
/// <summary>
/// Extension methods for the <see cref="Message"/> class.
/// Extension methods for the <see cref="AgentMessage"/> class.
/// </summary>
internal static class A2AMessageExtensions
{
internal static ChatMessage ToChatMessage(this Message message)
internal static ChatMessage ToChatMessage(this AgentMessage message)
{
List<AIContent>? aiContents = null;
@@ -11,7 +11,7 @@ namespace Microsoft.Extensions.AI;
/// </summary>
internal static class ChatMessageExtensions
{
internal static Message ToA2AMessage(this IEnumerable<ChatMessage> messages)
internal static AgentMessage ToA2AMessage(this IEnumerable<ChatMessage> messages)
{
List<Part> allParts = [];
@@ -23,7 +23,7 @@ internal static class ChatMessageExtensions
}
}
return new Message
return new AgentMessage
{
MessageId = Guid.NewGuid().ToString("N"),
Role = MessageRole.User,
@@ -35,7 +35,7 @@ public static class AIAgentExtensions
return taskManager;
async Task<Message> OnMessageReceivedAsync(MessageSendParams messageSendParams, CancellationToken cancellationToken)
async Task<A2AResponse> OnMessageReceivedAsync(MessageSendParams messageSendParams, CancellationToken cancellationToken)
{
var response = await agent.RunAsync(
messageSendParams.ToChatMessages(),
@@ -43,7 +43,7 @@ public static class AIAgentExtensions
var contextId = messageSendParams.Message.ContextId ?? Guid.NewGuid().ToString("N");
var parts = response.Messages.ToParts();
return new Message
return new AgentMessage
{
MessageId = response.ResponseId ?? Guid.NewGuid().ToString("N"),
ContextId = contextId,
@@ -65,10 +65,10 @@ internal static class MessageConverter
}
/// <summary>
/// Converts collection of A2A <see cref="Message"/> to a collection of <see cref="ChatMessage"/> objects.
/// Converts collection of A2A <see cref="AgentMessage"/> to a collection of <see cref="ChatMessage"/> objects.
/// </summary>
/// <returns>A read-only collection of ChatMessage objects.</returns>
public static IReadOnlyCollection<ChatMessage> ToChatMessages(this ICollection<Message> messages)
public static IReadOnlyCollection<ChatMessage> ToChatMessages(this ICollection<AgentMessage> messages)
{
if (messages is null || messages.Count == 0)
{
@@ -89,11 +89,11 @@ internal static class MessageConverter
}
/// <summary>
/// Converts a single <see cref="Message"/> to a <see cref="ChatMessage"/>.
/// Converts a single <see cref="AgentMessage"/> to a <see cref="ChatMessage"/>.
/// </summary>
/// <param name="message">The A2A message to convert.</param>
/// <returns>A ChatMessage object, or null if conversion is not possible.</returns>
public static ChatMessage? ToChatMessage(this Message message)
public static ChatMessage? ToChatMessage(this AgentMessage message)
{
if (message?.Parts is not { Count: > 0 })
{
@@ -169,14 +169,14 @@ internal static class MessageConverter
/// </summary>
/// <param name="chatMessage">The ChatMessage to convert.</param>
/// <returns>An A2A Message object.</returns>
public static Message ToA2AMessage(this ChatMessage chatMessage)
public static AgentMessage ToA2AMessage(this ChatMessage chatMessage)
{
if (chatMessage is null)
{
throw new ArgumentNullException(nameof(chatMessage));
}
var message = new Message
var message = new AgentMessage
{
MessageId = chatMessage.MessageId ?? Guid.NewGuid().ToString("N"),
Role = ConvertChatRoleToMessageRole(chatMessage.Role),
@@ -91,7 +91,7 @@ public sealed class A2AAgentTests : IDisposable
public async Task RunAsync_WithValidUserMessage_RunsSuccessfullyAsync()
{
// Arrange
this._handler.ResponseToReturn = new Message
this._handler.ResponseToReturn = new AgentMessage
{
MessageId = "response-123",
Role = MessageRole.Agent,
@@ -122,8 +122,8 @@ public sealed class A2AAgentTests : IDisposable
Assert.Equal("response-123", result.ResponseId);
Assert.NotNull(result.RawRepresentation);
Assert.IsType<Message>(result.RawRepresentation);
Assert.Equal("response-123", ((Message)result.RawRepresentation).MessageId);
Assert.IsType<AgentMessage>(result.RawRepresentation);
Assert.Equal("response-123", ((AgentMessage)result.RawRepresentation).MessageId);
Assert.Single(result.Messages);
Assert.Equal(ChatRole.Assistant, result.Messages[0].Role);
@@ -134,7 +134,7 @@ public sealed class A2AAgentTests : IDisposable
public async Task RunAsync_WithNewThread_UpdatesThreadConversationIdAsync()
{
// Arrange
this._handler.ResponseToReturn = new Message
this._handler.ResponseToReturn = new AgentMessage
{
MessageId = "response-123",
Role = MessageRole.Agent,
@@ -192,7 +192,7 @@ public sealed class A2AAgentTests : IDisposable
new(ChatRole.User, "Test message")
};
this._handler.ResponseToReturn = new Message
this._handler.ResponseToReturn = new AgentMessage
{
MessageId = "response-123",
Role = MessageRole.Agent,
@@ -220,7 +220,7 @@ public sealed class A2AAgentTests : IDisposable
new(ChatRole.User, "Hello, streaming!")
};
this._handler.StreamingResponseToReturn = new Message()
this._handler.StreamingResponseToReturn = new AgentMessage()
{
MessageId = "stream-1",
Role = MessageRole.Agent,
@@ -253,8 +253,8 @@ public sealed class A2AAgentTests : IDisposable
Assert.Equal("stream-1", updates[0].ResponseId);
Assert.NotNull(updates[0].RawRepresentation);
Assert.IsType<Message>(updates[0].RawRepresentation);
Assert.Equal("stream-1", ((Message)updates[0].RawRepresentation!).MessageId);
Assert.IsType<AgentMessage>(updates[0].RawRepresentation);
Assert.Equal("stream-1", ((AgentMessage)updates[0].RawRepresentation!).MessageId);
}
[Fact]
@@ -266,7 +266,7 @@ public sealed class A2AAgentTests : IDisposable
new(ChatRole.User, "Test streaming")
};
this._handler.StreamingResponseToReturn = new Message()
this._handler.StreamingResponseToReturn = new AgentMessage()
{
MessageId = "stream-1",
Role = MessageRole.Agent,
@@ -296,7 +296,7 @@ public sealed class A2AAgentTests : IDisposable
new(ChatRole.User, "Test streaming")
};
this._handler.StreamingResponseToReturn = new Message();
this._handler.StreamingResponseToReturn = new AgentMessage();
var thread = this._agent.GetNewThread();
var a2aThread = (A2AAgentThread)thread;
@@ -327,7 +327,7 @@ public sealed class A2AAgentTests : IDisposable
new(ChatRole.User, "Test streaming")
};
this._handler.StreamingResponseToReturn = new Message()
this._handler.StreamingResponseToReturn = new AgentMessage()
{
MessageId = "stream-1",
Role = MessageRole.Agent,
@@ -453,7 +453,7 @@ public sealed class A2AAgentTests : IDisposable
}
else
{
var jsonRpcResponse = JsonRpcResponse.CreateJsonRpcResponse<A2AEvent>("response-id", new Message());
var jsonRpcResponse = JsonRpcResponse.CreateJsonRpcResponse<A2AEvent>("response-id", new AgentMessage());
return new HttpResponseMessage(HttpStatusCode.OK)
{
@@ -62,7 +62,7 @@ public sealed class A2ACardResolverExtensionsTests : IDisposable
{
Url = "http://test-endpoint/agent"
});
this._handler.ResponsesToReturn.Enqueue(new Message
this._handler.ResponsesToReturn.Enqueue(new AgentMessage
{
Role = MessageRole.Agent,
Parts = [new TextPart { Text = "Response" }],
@@ -104,7 +104,7 @@ public sealed class A2ACardResolverExtensionsTests : IDisposable
Content = new StringContent(json, Encoding.UTF8, "application/json")
};
}
else if (response is Message message)
else if (response is AgentMessage message)
{
var jsonRpcResponse = JsonRpcResponse.CreateJsonRpcResponse<A2AEvent>("response-id", message);
@@ -6,7 +6,7 @@ using A2A;
namespace Microsoft.Agents.AI.A2A.UnitTests;
/// <summary>
/// Unit tests for the <see cref="A2AClientExtensions"/> class.
/// Unit tests for the A2AClientExtensions class.
/// </summary>
public sealed class A2AClientExtensionsTests
{
@@ -23,7 +23,7 @@ public sealed class A2AMessageExtensionsTests
["isUrgent"] = JsonDocument.Parse("true").RootElement
};
var message = new Message
var message = new AgentMessage
{
MessageId = "mixed-parts-id",
Role = MessageRole.Agent,
@@ -42,7 +42,7 @@ public class MessageConverterTests
{
var messageSendParams = new MessageSendParams
{
Message = new Message
Message = new AgentMessage
{
MessageId = "test-id",
Role = MessageRole.User,
@@ -61,7 +61,7 @@ public class MessageConverterTests
{
var messageSendParams = new MessageSendParams
{
Message = new Message
Message = new AgentMessage
{
MessageId = "test-id",
Role = MessageRole.User,
@@ -89,7 +89,7 @@ public class MessageConverterTests
[Fact]
public void ToChatMessages_MessageCollection_Null_ReturnsEmptyCollection()
{
ICollection<Message>? messages = null;
ICollection<AgentMessage>? messages = null;
var result = messages!.ToChatMessages();
@@ -100,7 +100,7 @@ public class MessageConverterTests
[Fact]
public void ToChatMessages_MessageCollection_Empty_ReturnsEmptyCollection()
{
var messages = new List<Message>();
var messages = new List<AgentMessage>();
var result = messages.ToChatMessages();
@@ -111,7 +111,7 @@ public class MessageConverterTests
[Fact]
public void ToChatMessages_MessageCollection_WithValidMessages_ReturnsCorrectChatMessages()
{
var messages = new List<Message>
var messages = new List<AgentMessage>
{
new()
{
@@ -146,7 +146,7 @@ public class MessageConverterTests
[Fact]
public void ToChatMessages_MessageCollection_SkipsInvalidMessages_ReturnsValidChatMessages()
{
var messages = new List<Message>
var messages = new List<AgentMessage>
{
new()
{
@@ -254,14 +254,14 @@ public class MessageConverterTests
[Fact]
public void ConvertMessageRoleToChatRole_UserRole_ReturnsUserChatRole()
{
var message = new Message
var message = new AgentMessage
{
MessageId = "test",
Role = MessageRole.User,
Parts = [new TextPart { Text = "Test" }]
};
var result = new List<Message> { message }.ToChatMessages();
var result = new List<AgentMessage> { message }.ToChatMessages();
var chatMessage = result.First();
Assert.Equal(ChatRole.User, chatMessage.Role);
@@ -270,14 +270,14 @@ public class MessageConverterTests
[Fact]
public void ConvertMessageRoleToChatRole_AgentRole_ReturnsAssistantChatRole()
{
var message = new Message
var message = new AgentMessage
{
MessageId = "test",
Role = MessageRole.Agent,
Parts = [new TextPart { Text = "Test" }]
};
var result = new List<Message> { message }.ToChatMessages();
var result = new List<AgentMessage> { message }.ToChatMessages();
var chatMessage = result.First();
Assert.Equal(ChatRole.Assistant, chatMessage.Role);
@@ -286,14 +286,14 @@ public class MessageConverterTests
[Fact]
public void ConvertMessageRoleToChatRole_UnknownRole_ReturnsUserChatRole()
{
var message = new Message
var message = new AgentMessage
{
MessageId = "test",
Role = (MessageRole)999, // Unknown role
Parts = [new TextPart { Text = "Test" }]
};
var result = new List<Message> { message }.ToChatMessages();
var result = new List<AgentMessage> { message }.ToChatMessages();
var chatMessage = result.First();
Assert.Equal(ChatRole.User, chatMessage.Role);
@@ -343,14 +343,14 @@ public class MessageConverterTests
public void ConvertPartToAIContent_TextPart_ReturnsTextContent()
{
var textPart = new TextPart { Text = "Sample text" };
var message = new Message
var message = new AgentMessage
{
MessageId = "test",
Role = MessageRole.User,
Parts = [textPart]
};
var result = new List<Message> { message }.ToChatMessages();
var result = new List<AgentMessage> { message }.ToChatMessages();
var chatMessage = result.First();
var textContent = Assert.IsType<TextContent>(chatMessage.Contents.First());
@@ -371,14 +371,14 @@ public class MessageConverterTests
Text = "Text with metadata",
Metadata = metadata
};
var message = new Message
var message = new AgentMessage
{
MessageId = "test",
Role = MessageRole.User,
Parts = [textPart]
};
var result = new List<Message> { message }.ToChatMessages();
var result = new List<AgentMessage> { message }.ToChatMessages();
var chatMessage = result.First();
var textContent = Assert.IsType<TextContent>(chatMessage.Contents.First());
@@ -392,14 +392,14 @@ public class MessageConverterTests
public void ConvertPartToAIContent_FilePart_ThrowsNotSupportedException()
{
var filePart = new FilePart();
var message = new Message
var message = new AgentMessage
{
MessageId = "test",
Role = MessageRole.User,
Parts = [filePart]
};
var exception = Assert.Throws<NotSupportedException>(() => new List<Message> { message }.ToChatMessages());
var exception = Assert.Throws<NotSupportedException>(() => new List<AgentMessage> { message }.ToChatMessages());
Assert.Contains("Part type 'FilePart' is not supported", exception.Message);
}
@@ -407,14 +407,14 @@ public class MessageConverterTests
public void ConvertPartToAIContent_DataPart_ThrowsNotSupportedException()
{
var dataPart = new DataPart();
var message = new Message
var message = new AgentMessage
{
MessageId = "test",
Role = MessageRole.User,
Parts = [dataPart]
};
var exception = Assert.Throws<NotSupportedException>(() => new List<Message> { message }.ToChatMessages());
var exception = Assert.Throws<NotSupportedException>(() => new List<AgentMessage> { message }.ToChatMessages());
Assert.Contains("Part type 'DataPart' is not supported", exception.Message);
}
@@ -426,7 +426,7 @@ public class MessageConverterTests
["timestamp"] = JsonDocument.Parse("\"2024-01-01T00:00:00Z\"").RootElement,
["priority"] = JsonDocument.Parse("1").RootElement
};
var message = new Message
var message = new AgentMessage
{
MessageId = "test-id",
Role = MessageRole.User,
@@ -434,7 +434,7 @@ public class MessageConverterTests
Metadata = metadata
};
var result = new List<Message> { message }.ToChatMessages();
var result = new List<AgentMessage> { message }.ToChatMessages();
var chatMessage = result.First();
Assert.NotNull(chatMessage.AdditionalProperties);
@@ -446,14 +446,14 @@ public class MessageConverterTests
[Fact]
public void ConvertMessageToChatMessage_WithRawRepresentation_PreservesOriginalMessage()
{
var message = new Message
var message = new AgentMessage
{
MessageId = "test-id",
Role = MessageRole.Agent,
Parts = [new TextPart { Text = "Test response" }]
};
var result = new List<Message> { message }.ToChatMessages();
var result = new List<AgentMessage> { message }.ToChatMessages();
var chatMessage = result.First();
Assert.Equal(message, chatMessage.RawRepresentation);
@@ -462,14 +462,14 @@ public class MessageConverterTests
[Fact]
public void ToChatMessages_MessageWithEmptyParts_ReturnsEmptyCollection()
{
var message = new Message
var message = new AgentMessage
{
MessageId = "test-id",
Role = MessageRole.User,
Parts = [] // Empty list
};
var result = new List<Message> { message }.ToChatMessages();
var result = new List<AgentMessage> { message }.ToChatMessages();
Assert.NotNull(result);
Assert.Empty(result);
@@ -499,7 +499,7 @@ public class MessageConverterTests
[Fact]
public void ToAdditionalPropertiesDictionary_NullMetadata_ReturnsNull()
{
var message = new Message
var message = new AgentMessage
{
MessageId = "test-id",
Role = MessageRole.User,
@@ -507,7 +507,7 @@ public class MessageConverterTests
Metadata = null
};
var result = new List<Message> { message }.ToChatMessages();
var result = new List<AgentMessage> { message }.ToChatMessages();
var chatMessage = result.First();
Assert.Null(chatMessage.AdditionalProperties);
@@ -516,7 +516,7 @@ public class MessageConverterTests
[Fact]
public void ToAdditionalPropertiesDictionary_EmptyMetadata_ReturnsNull()
{
var message = new Message
var message = new AgentMessage
{
MessageId = "test-id",
Role = MessageRole.User,
@@ -524,7 +524,7 @@ public class MessageConverterTests
Metadata = []
};
var result = new List<Message> { message }.ToChatMessages();
var result = new List<AgentMessage> { message }.ToChatMessages();
var chatMessage = result.First();
Assert.Null(chatMessage.AdditionalProperties);