diff --git a/dotnet/src/Agents/OpenAI/Extensions/ChatContentMessageExtensions.cs b/dotnet/src/Agents/OpenAI/Extensions/ChatContentMessageExtensions.cs index c627d9517c81..86ed4085a91b 100644 --- a/dotnet/src/Agents/OpenAI/Extensions/ChatContentMessageExtensions.cs +++ b/dotnet/src/Agents/OpenAI/Extensions/ChatContentMessageExtensions.cs @@ -44,8 +44,10 @@ public static IEnumerable ToThreadInitializationMes public static ResponseItem ToResponseItem(this ChatMessageContent message) { var items = message.Items; - IEnumerable contentParts = items.Select(item => item.ToResponseContentPart()); - return message.Role.Label.ToUpperInvariant() switch + var roleLabel = message.Role.Label.ToUpperInvariant(); + + IEnumerable contentParts = items.Select(item => item.ToResponseContentPart(roleLabel == "ASSISTANT")); + return roleLabel switch { "SYSTEM" => ResponseItem.CreateSystemMessageItem(contentParts), "USER" => ResponseItem.CreateUserMessageItem(contentParts), diff --git a/dotnet/src/Agents/OpenAI/Extensions/KernelContentExtensions.cs b/dotnet/src/Agents/OpenAI/Extensions/KernelContentExtensions.cs index 59f11f0f68cd..010a7b64976b 100644 --- a/dotnet/src/Agents/OpenAI/Extensions/KernelContentExtensions.cs +++ b/dotnet/src/Agents/OpenAI/Extensions/KernelContentExtensions.cs @@ -10,11 +10,11 @@ namespace Microsoft.SemanticKernel.Agents.OpenAI; /// internal static class KernelContentExtensions { - internal static ResponseContentPart ToResponseContentPart(this KernelContent content) + internal static ResponseContentPart ToResponseContentPart(this KernelContent content, bool isOutput = false) { return content switch { - TextContent textContent => textContent.ToResponseContentPart(), + TextContent textContent => textContent.ToResponseContentPart(isOutput), ImageContent imageContent => imageContent.ToResponseContentPart(), BinaryContent binaryContent => binaryContent.ToResponseContentPart(), FileReferenceContent fileReferenceContent => fileReferenceContent.ToResponseContentPart(), @@ -22,9 +22,11 @@ internal static ResponseContentPart ToResponseContentPart(this KernelContent con }; } - internal static ResponseContentPart ToResponseContentPart(this TextContent content) + internal static ResponseContentPart ToResponseContentPart(this TextContent content, bool isOutput) { - return ResponseContentPart.CreateInputTextPart(content.Text); + return isOutput ? + ResponseContentPart.CreateOutputTextPart(content.Text, []) : + ResponseContentPart.CreateInputTextPart(content.Text); } internal static ResponseContentPart ToResponseContentPart(this ImageContent content) diff --git a/dotnet/src/IntegrationTests/Agents/OpenAIResponseAgentTests.cs b/dotnet/src/IntegrationTests/Agents/OpenAIResponseAgentTests.cs index fcb77d4a7fad..ca20aff1cea3 100644 --- a/dotnet/src/IntegrationTests/Agents/OpenAIResponseAgentTests.cs +++ b/dotnet/src/IntegrationTests/Agents/OpenAIResponseAgentTests.cs @@ -218,6 +218,51 @@ public async Task OpenAIResponseAgentInvokeStreamingWithThreadAsync(bool isOpenA Assert.Contains("Computer says no", responseText); } + + /// + /// Integration test for with existing chat history. + /// + [RetryTheory(typeof(HttpOperationException))] + [InlineData(false, false)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(true, true)] + public async Task OpenAIResponseAgentInvokeStreamingWithChatHistoryAsync(bool isOpenAI, bool storeEnabled) + { + // Arrange + OpenAIResponseClient client = this.CreateClient(isOpenAI); + OpenAIResponseAgent agent = new(client) + { + StoreEnabled = storeEnabled, + Instructions = "Answer all queries in English and French." + }; + + var chatHistory = new ChatHistory(); + chatHistory.AddUserMessage("Hello my name is John"); + chatHistory.AddAssistantMessage("Hello John, how can I help you today?"); + chatHistory.AddUserMessage("What is my Name?"); + + AgentThread agentThread = storeEnabled ? new OpenAIResponseAgentThread(client) : new ChatHistoryAgentThread(); + + // Act + string? responseText = null; + try + { + var responseMessages = await agent.InvokeStreamingAsync(chatHistory, agentThread).ToArrayAsync(); + responseText = string.Join(string.Empty, responseMessages.Select(ri => ri.Message.Content)); + } + finally + { + if (agentThread.Id is not null) + { + await agentThread.DeleteAsync(); + } + } + + // Assert + Assert.NotNull(responseText); + } + /// /// Integration test for adding override instructions to a thread on invocation via custom options. ///