Skip to content
Closed
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
3 changes: 2 additions & 1 deletion .github/_typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ extend-exclude = [
"SK-dotnet.sln.DotSettings",
"**/azure_ai_search_hotel_samples/README.md",
"**/Demos/ProcessFrameworkWithAspire/ProcessFramework.Aspire/ProcessFramework.Aspire.ProcessOrchestrator/Program.cs",
"**/Demos/ProcessFrameworkWithAspire/**/*.http"
"**/Demos/ProcessFrameworkWithAspire/**/*.http",
"openai_responses_what_is_the_semantic_kernel.json"
]

[default.extend-words]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.ChatCompletion;

namespace GettingStarted.OpenAIResponses;

/// <summary>
/// This example demonstrates using <see cref="OpenAIResponsesAgent"/>.
/// </summary>
public class Step01_ResponsesAgent(ITestOutputHelper output) : BaseResponsesAgentTest(output)
{
[Fact]
public async Task UseOpenAIResponsesAgentAsync()
{
// Define the agent
OpenAIResponsesAgent agent = new(this.Client)
{
Name = "ResponseAgent",
Instructions = "Answer all queries in English and French.",
};

// Invoke the agent and output the response
var responseItems = agent.InvokeAsync(new ChatMessageContent(AuthorRole.User, "What is the capital of France?"));
await foreach (ChatMessageContent responseItem in responseItems)
{
WriteAgentChatMessage(responseItem);
}
}

[Fact]
public async Task UseOpenAIResponsesAgentWithMessagesAsync()
{
// Define the agent
OpenAIResponsesAgent agent = new(this.Client)
{
Name = "ResponseAgent",
Instructions = "Answer all queries in English and French."
};

ICollection<ChatMessageContent> messages =
[
new ChatMessageContent(AuthorRole.User, "What is the capital of France?"),
new ChatMessageContent(AuthorRole.User, "What is the capital of Ireland?")
];

// Invoke the agent and output the response
var responseItems = agent.InvokeAsync(messages);
await foreach (ChatMessageContent responseItem in responseItems)
{
WriteAgentChatMessage(responseItem);
}
}

[Fact]
public async Task UseOpenAIResponsesAgentWithThreadedConversationAsync()
{
// Define the agent
OpenAIResponsesAgent agent = new(this.Client)
{
Name = "ResponseAgent",
Instructions = "Answer all queries in the users preferred language.",
};

string[] messages =
[
"My name is Bob and my preferred language is French.",
"What is the capital of France?",
"What is the capital of Spain?",
"What is the capital of Italy?"
];

// Initial thread can be null as it will be automatically created
AgentThread? agentThread = null;

// Invoke the agent and output the response
foreach (string message in messages)
{
var responseItems = agent.InvokeAsync(new ChatMessageContent(AuthorRole.User, message), agentThread);
await foreach (AgentResponseItem<ChatMessageContent> responseItem in responseItems)
{
// Update the thread so the previous response id is used
agentThread = responseItem.Thread;

WriteAgentChatMessage(responseItem.Message);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (c) Microsoft. All rights reserved.

using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.ChatCompletion;

namespace GettingStarted.OpenAIResponses;

/// <summary>
/// This example demonstrates how to manage conversation state during a model interaction using <see cref="OpenAIResponsesAgent"/>.
/// OpenAI provides a few ways to manage conversation state, which is important for preserving information across multiple messages or turns in a conversation.
/// </summary>
public class Step02_ConversationState(ITestOutputHelper output) : BaseResponsesAgentTest(output)
{
[Fact]
public async Task ManuallyConstructPastConversationAsync()
{
// Define the agent
OpenAIResponsesAgent agent = new(this.Client)
{
StoreEnabled = false,
};

ICollection<ChatMessageContent> messages =
[
new ChatMessageContent(AuthorRole.User, "knock knock."),
new ChatMessageContent(AuthorRole.Assistant, "Who's there?"),
new ChatMessageContent(AuthorRole.User, "Orange.")
];

// Invoke the agent and output the response
var responseItems = agent.InvokeAsync(messages);
await foreach (ChatMessageContent responseItem in responseItems)
{
WriteAgentChatMessage(responseItem);
}
}

[Fact]
public async Task ManuallyManageConversationStateWithResponsesApiAsync()
{
// Define the agent
OpenAIResponsesAgent agent = new(this.Client)
{
StoreEnabled = false,
};

string[] messages =
[
"Tell me a joke?",
"Tell me another?",
];

// Invoke the agent and output the response
AgentThread? agentThread = null;
foreach (string message in messages)
{
var responseItems = agent.InvokeAsync(new ChatMessageContent(AuthorRole.User, message), agentThread);
await foreach (AgentResponseItem<ChatMessageContent> responseItem in responseItems)
{
agentThread = responseItem.Thread;
WriteAgentChatMessage(responseItem.Message);
}
}
}

[Fact]
public async Task ManuallyManageConversationStateWithChatCompletionsApiAsync()
{
// Define the agent
OpenAIResponsesAgent agent = new(this.Client)
{
StoreEnabled = true,
};

string[] messages =
[
"Tell me a joke?",
"Explain why this is funny.",
];

// Invoke the agent and output the response
AgentThread? agentThread = null;
foreach (string message in messages)
{
var responseItems = agent.InvokeAsync(new ChatMessageContent(AuthorRole.User, message), agentThread);
await foreach (AgentResponseItem<ChatMessageContent> responseItem in responseItems)
{
agentThread = responseItem.Thread;
WriteAgentChatMessage(responseItem.Message);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.SemanticKernel.Agents.OpenAI.Internal;
using OpenAI.Assistants;
using OpenAI.Responses;

namespace Microsoft.SemanticKernel.Agents.OpenAI;

Expand Down Expand Up @@ -33,4 +35,21 @@ public static IEnumerable<ThreadInitializationMessage> ToThreadInitializationMes
{
return messages.Select(message => message.ToThreadInitializationMessage());
}

/// <summary>
/// Converts a <see cref="ChatMessageContent"/> instance to a <see cref="ResponseItem"/>.
/// </summary>
/// <param name="message">The chat message content to convert.</param>
/// <returns>A <see cref="ResponseItem"/> instance.</returns>
public static ResponseItem ToResponseItem(this ChatMessageContent message)
{
return message.Role.Label switch
{
"system" => ResponseItem.CreateSystemMessageItem(message.Content),
"user" => ResponseItem.CreateUserMessageItem(message.Content),
"developer" => ResponseItem.CreateDeveloperMessageItem(message.Content),
"assistant" => ResponseItem.CreateAssistantMessageItem(message.Content),
_ => throw new NotImplementedException(),
};
}
}
55 changes: 55 additions & 0 deletions dotnet/src/Agents/OpenAI/Extensions/ResponseItemExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) Microsoft. All rights reserved.

using System;
using System.Collections.Generic;
using Microsoft.SemanticKernel.ChatCompletion;
using OpenAI.Responses;

namespace Microsoft.SemanticKernel.Agents.OpenAI;

internal static class ResponseItemExtensions
{
/// <summary>
/// Converts a <see cref="ResponseItem"/> instance to a <see cref="ChatMessageContent"/>.
/// </summary>
/// <param name="item">The response item to convert.</param>
/// <returns>A <see cref="ChatMessageContent"/> instance.</returns>
public static ChatMessageContent ToChatMessageContent(this ResponseItem item)
{
if (item is MessageResponseItem messageResponseItem)
{
var role = messageResponseItem.Role.ToAuthorRole();
var collection = messageResponseItem.Content.ToChatMessageContentItemCollection();

return new ChatMessageContent(role, collection, innerContent: messageResponseItem);
}
throw new InvalidOperationException();
}

#region private
private static ChatMessageContentItemCollection ToChatMessageContentItemCollection(this IList<ResponseContentPart> content)
{
var collection = new ChatMessageContentItemCollection();
foreach (var part in content)
{
if (part.Kind == ResponseContentPartKind.OutputText)
{
collection.Add(new TextContent(part.Text));
}
}
return collection;
}

private static AuthorRole ToAuthorRole(this MessageRole messageRole)
{
return messageRole switch
{
MessageRole.Assistant => AuthorRole.Assistant,
MessageRole.Developer => AuthorRole.Developer,
MessageRole.System => AuthorRole.System,
MessageRole.User => AuthorRole.User,
_ => new AuthorRole("unknown"),
};
}
#endregion
}
Loading
Loading