Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ public static IEnumerable<ThreadInitializationMessage> ToThreadInitializationMes
public static ResponseItem ToResponseItem(this ChatMessageContent message)
{
var items = message.Items;
IEnumerable<ResponseContentPart> contentParts = items.Select(item => item.ToResponseContentPart());
return message.Role.Label.ToUpperInvariant() switch
var roleLabel = message.Role.Label.ToUpperInvariant();

IEnumerable<ResponseContentPart> contentParts = items.Select(item => item.ToResponseContentPart(roleLabel == "ASSISTANT"));
return roleLabel switch
{
"SYSTEM" => ResponseItem.CreateSystemMessageItem(contentParts),
"USER" => ResponseItem.CreateUserMessageItem(contentParts),
Expand Down
10 changes: 6 additions & 4 deletions dotnet/src/Agents/OpenAI/Extensions/KernelContentExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,23 @@ namespace Microsoft.SemanticKernel.Agents.OpenAI;
/// </summary>
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(),
_ => throw new NotSupportedException($"Unsupported content type {content.GetType().Name}. Cannot convert to {nameof(ResponseContentPart)}.")
};
}

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)
Expand Down
45 changes: 45 additions & 0 deletions dotnet/src/IntegrationTests/Agents/OpenAIResponseAgentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,51 @@ public async Task OpenAIResponseAgentInvokeStreamingWithThreadAsync(bool isOpenA
Assert.Contains("Computer says no", responseText);
}


/// <summary>
/// Integration test for <see cref="OpenAIResponseAgent"/> with existing chat history.
/// </summary>
[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);
}

/// <summary>
/// Integration test for <see cref="OpenAIResponseAgent"/> adding override instructions to a thread on invocation via custom options.
/// </summary>
Expand Down