Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.Net: Use empty string instead of null content in assistant message in Azure/OpenAI connectors #9150

Merged
merged 2 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1373,6 +1373,51 @@ public async Task ItDoesNotChangeDefaultsForToolsAndChoiceIfNeitherOfFunctionCal
Assert.False(optionsJson.TryGetProperty("tool_choice", out var _));
}

[Fact]
public async Task ItSendsEmptyStringWhenAssistantMessageContentIsNull()
{
// Arrange
var sut = new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id", this._httpClient);

using var responseMessage = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(AzureOpenAITestHelper.GetTestResponse("chat_completion_test_response.json"))
};
this._messageHandlerStub.ResponsesToReturn.Add(responseMessage);

List<ChatToolCall> assistantToolCalls = [ChatToolCall.CreateFunctionToolCall("id", "name", BinaryData.FromString("args"))];

var chatHistory = new ChatHistory()
{
new ChatMessageContent(role: AuthorRole.User, content: "User content", modelId: "any"),
new ChatMessageContent(role: AuthorRole.Assistant, content: null, modelId: "any", metadata: new Dictionary<string, object?>
{
["ChatResponseMessage.FunctionToolCalls"] = assistantToolCalls
}),
new ChatMessageContent(role: AuthorRole.Tool, content: null, modelId: "any")
{
Items = [new FunctionResultContent("FunctionName", "PluginName", "CallId", "Function result")]
},
};

var executionSettings = new AzureOpenAIPromptExecutionSettings();

// Act
await sut.GetChatMessageContentsAsync(chatHistory, executionSettings);

// Assert
var actualRequestContent = Encoding.UTF8.GetString(this._messageHandlerStub.RequestContents[0]!);
Assert.NotNull(actualRequestContent);

var requestContent = JsonSerializer.Deserialize<JsonElement>(actualRequestContent);
var messages = requestContent.GetProperty("messages").EnumerateArray().ToList();

var assistantMessage = messages.First(message => message.GetProperty("role").GetString() == "assistant");
var assistantMessageContent = assistantMessage.GetProperty("content").GetString();

Assert.Equal(string.Empty, assistantMessageContent);
}

public void Dispose()
{
this._httpClient.Dispose();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1359,6 +1359,47 @@ public async Task ItDoesNotChangeDefaultsForToolsAndChoiceIfNeitherOfFunctionCal
Assert.False(optionsJson.TryGetProperty("tool_choice", out var _));
}

[Fact]
public async Task ItSendsEmptyStringWhenAssistantMessageContentIsNull()
{
// Arrange
var chatCompletion = new OpenAIChatCompletionService(modelId: "any", apiKey: "NOKEY", httpClient: this._httpClient);
this._messageHandlerStub.ResponseToReturn = new HttpResponseMessage(System.Net.HttpStatusCode.OK)
{
Content = new StringContent(ChatCompletionResponse)
};

List<ChatToolCall> assistantToolCalls = [ChatToolCall.CreateFunctionToolCall("id", "name", BinaryData.FromString("args"))];

var chatHistory = new ChatHistory()
{
new ChatMessageContent(role: AuthorRole.User, content: "User content", modelId: "any"),
new ChatMessageContent(role: AuthorRole.Assistant, content: null, modelId: "any", metadata: new Dictionary<string, object?>
{
["ChatResponseMessage.FunctionToolCalls"] = assistantToolCalls
}),
new ChatMessageContent(role: AuthorRole.Tool, content: null, modelId: "any")
{
Items = [new FunctionResultContent("FunctionName", "PluginName", "CallId", "Function result")]
},
};

// Act
await chatCompletion.GetChatMessageContentsAsync(chatHistory, this._executionSettings);

// Assert
var actualRequestContent = Encoding.UTF8.GetString(this._messageHandlerStub.RequestContent!);
Assert.NotNull(actualRequestContent);

var requestContent = JsonSerializer.Deserialize<JsonElement>(actualRequestContent);
var messages = requestContent.GetProperty("messages").EnumerateArray().ToList();

var assistantMessage = messages.First(message => message.GetProperty("role").GetString() == "assistant");
var assistantMessageContent = assistantMessage.GetProperty("content").GetString();

Assert.Equal(string.Empty, assistantMessageContent);
}

public void Dispose()
{
this._httpClient.Dispose();
Expand Down
RogerBarreto marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -758,10 +758,10 @@ private static List<ChatMessage> CreateRequestMessages(ChatMessageContent messag
}

var assistantMessage = new AssistantChatMessage(toolCalls) { ParticipantName = message.AuthorName };
if (message.Content is { } content)
{
assistantMessage.Content.Add(content);
}

// If message content is null, adding it as empty string,
// because chat message content must be string.
assistantMessage.Content.Add(message.Content ?? string.Empty);

return [assistantMessage];
}
Expand Down
Loading