mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
.NET: Fix role assignment in ChatMessage construction (#4290)
* Use actual message role when creating ChatMessage Replace hard-coded ChatRole.User with a ChatRole constructed from the message's Role. The change ensures ToChatMessage and FunctionMessage use the original role (new ChatRole(this.Role)) for both text and contents branches, fixing incorrect role assignment when constructing ChatMessage instances. * Update changes * Fix formatting in ToChatMessage tests --------- Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
d2977d63da
commit
9691c9c271
+7
-3
@@ -39,14 +39,16 @@ internal abstract record ChatCompletionRequestMessage
|
||||
/// <exception cref="InvalidOperationException">Thrown when the content is neither text nor AI contents.</exception>
|
||||
public virtual ChatMessage ToChatMessage()
|
||||
{
|
||||
var role = new ChatRole(this.Role);
|
||||
|
||||
if (this.Content.IsText)
|
||||
{
|
||||
return new(ChatRole.User, this.Content.Text);
|
||||
return new(role, this.Content.Text);
|
||||
}
|
||||
else if (this.Content.IsContents)
|
||||
{
|
||||
var aiContents = this.Content.Contents.Select(MessageContentPartConverter.ToAIContent).Where(c => c is not null).ToList();
|
||||
return new ChatMessage(ChatRole.User, aiContents!);
|
||||
return new ChatMessage(role, aiContents!);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("MessageContent has no value");
|
||||
@@ -165,9 +167,11 @@ internal sealed record FunctionMessage : ChatCompletionRequestMessage
|
||||
/// <exception cref="InvalidOperationException">Thrown when the content is not text.</exception>
|
||||
public override ChatMessage ToChatMessage()
|
||||
{
|
||||
var role = new ChatRole(this.Role);
|
||||
|
||||
if (this.Content.IsText)
|
||||
{
|
||||
return new(ChatRole.User, this.Content.Text);
|
||||
return new(role, this.Content.Text);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("FunctionMessage Content must be text");
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Agents.AI.Hosting.OpenAI.ChatCompletions.Models;
|
||||
using Microsoft.Extensions.AI;
|
||||
|
||||
namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for ChatCompletionRequestMessage.ToChatMessage() role preservation.
|
||||
/// Verifies that each message type correctly maps its role to the corresponding ChatRole.
|
||||
/// </summary>
|
||||
public sealed class ChatCompletionRequestMessageToChatMessageTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("system", """{"role":"system","content":"You are a helpful assistant."}""")]
|
||||
[InlineData("developer", """{"role":"developer","content":"Follow these rules."}""")]
|
||||
[InlineData("user", """{"role":"user","content":"Hello!"}""")]
|
||||
[InlineData("assistant", """{"role":"assistant","content":"Hi there!"}""")]
|
||||
[InlineData("tool", """{"role":"tool","content":"result","tool_call_id":"call_123"}""")]
|
||||
public void ToChatMessage_PreservesRole_ForTextContent(string expectedRole, string json)
|
||||
{
|
||||
// Arrange
|
||||
ChatCompletionRequestMessage message = JsonSerializer.Deserialize(
|
||||
json, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletionRequestMessage)!;
|
||||
|
||||
// Act
|
||||
ChatMessage chatMessage = message.ToChatMessage();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedRole, message.Role);
|
||||
Assert.Equal(new ChatRole(expectedRole), chatMessage.Role);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessage_FunctionMessage_PreservesRole()
|
||||
{
|
||||
// Arrange
|
||||
const string Json = """{"role":"function","name":"get_weather","content":"sunny"}""";
|
||||
ChatCompletionRequestMessage message = JsonSerializer.Deserialize(
|
||||
Json, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletionRequestMessage)!;
|
||||
|
||||
// Act
|
||||
ChatMessage chatMessage = message.ToChatMessage();
|
||||
|
||||
// Assert
|
||||
Assert.Equal("function", message.Role);
|
||||
Assert.Equal(new ChatRole("function"), chatMessage.Role);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("system")]
|
||||
[InlineData("developer")]
|
||||
[InlineData("user")]
|
||||
[InlineData("assistant")]
|
||||
public void ToChatMessage_PreservesRole_ForMultiPartContent(string expectedRole)
|
||||
{
|
||||
// Arrange
|
||||
string json = $$"""{"role":"{{expectedRole}}","content":[{"type":"text","text":"Hello!"}]}""";
|
||||
ChatCompletionRequestMessage message = JsonSerializer.Deserialize(
|
||||
json, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletionRequestMessage)!;
|
||||
|
||||
// Act
|
||||
ChatMessage chatMessage = message.ToChatMessage();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedRole, message.Role);
|
||||
Assert.Equal(new ChatRole(expectedRole), chatMessage.Role);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessage_MultiTurnConversation_PreservesAllRoles()
|
||||
{
|
||||
// Arrange - simulate a multi-turn conversation
|
||||
string[] jsons =
|
||||
[
|
||||
"""{"role":"system","content":"You are a helpful assistant."}""",
|
||||
"""{"role":"user","content":"Hello!"}""",
|
||||
"""{"role":"assistant","content":"Hi there! How can I help?"}""",
|
||||
"""{"role":"user","content":"What did I just say?"}"""
|
||||
];
|
||||
|
||||
string[] expectedRoles = ["system", "user", "assistant", "user"];
|
||||
|
||||
// Act
|
||||
ChatMessage[] chatMessages = jsons
|
||||
.Select(j => JsonSerializer.Deserialize(
|
||||
j, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletionRequestMessage)!)
|
||||
.Select(m => m.ToChatMessage())
|
||||
.ToArray();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedRoles.Length, chatMessages.Length);
|
||||
for (int i = 0; i < expectedRoles.Length; i++)
|
||||
{
|
||||
Assert.Equal(new ChatRole(expectedRoles[i]), chatMessages[i].Role);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToChatMessage_PreservesTextContent()
|
||||
{
|
||||
// Arrange
|
||||
const string Json = """{"role":"system","content":"You are a helpful assistant."}""";
|
||||
ChatCompletionRequestMessage message = JsonSerializer.Deserialize(
|
||||
Json, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletionRequestMessage)!;
|
||||
|
||||
// Act
|
||||
ChatMessage chatMessage = message.ToChatMessage();
|
||||
|
||||
// Assert
|
||||
Assert.Contains(chatMessage.Contents, c => c is TextContent tc && tc.Text == "You are a helpful assistant.");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user