.NET: Add SK-AF Migration Samples for Responses API. (#575)

* Responses wip

* Adding OpenAI Responses Migration samples

* Address all samples and code for Azure and OpenAI Responses Migration code

* Update dotnet/samples/SemanticKernelMigration/OpenAIResponses/Step02_ReasoningModel/Program.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Roger Barreto
2025-09-02 09:45:54 +01:00
committed by GitHub
Unverified
parent 98cdb51424
commit 9b61c72e18
19 changed files with 911 additions and 0 deletions
+12
View File
@@ -71,6 +71,18 @@
<Project Path="samples/HowToCreateAnAIAgentByProvider/AIAgent_With_OpenAIChatCompletion/AIAgent_With_OpenAIChatCompletion.csproj" />
<Project Path="samples/HowToCreateAnAIAgentByProvider/AIAgent_With_OpenAIResponses/AIAgent_With_OpenAIResponses.csproj" />
</Folder>
<Folder Name="/Samples/SemanticKernelMigration/OpenAIResponses/">
<Project Path="samples/SemanticKernelMigration/OpenAIResponses/Step01_Basics/OpenAIResponses_Step01_Basics.csproj" />
<Project Path="samples/SemanticKernelMigration/OpenAIResponses/Step02_ReasoningModel/OpenAIResponses_Step02_ReasoningModel.csproj" />
<Project Path="samples/SemanticKernelMigration/OpenAIResponses/Step03_ToolCall/OpenAIResponses_Step03_ToolCall.csproj" />
<Project Path="samples/SemanticKernelMigration/OpenAIResponses/Step04_DependencyInjection/OpenAIResponses_Step04_DependencyInjection.csproj" />
</Folder>
<Folder Name="/Samples/SemanticKernelMigration/AzureOpenAIResponses/">
<Project Path="samples/SemanticKernelMigration/AzureOpenAIResponses/Step01_Basics/AzureOpenAIResponses_Step01_Basics.csproj" />
<Project Path="samples/SemanticKernelMigration/AzureOpenAIResponses/Step02_ReasoningModel/AzureOpenAIResponses_Step02_ReasoningModel.csproj" />
<Project Path="samples/SemanticKernelMigration/AzureOpenAIResponses/Step03_ToolCall/AzureOpenAIResponses_Step03_ToolCall.csproj" />
<Project Path="samples/SemanticKernelMigration/AzureOpenAIResponses/Step04_DependencyInjection/AzureOpenAIResponses_Step04_DependencyInjection.csproj" />
</Folder>
<Folder Name="/Solution Items/">
<File Path=".editorconfig" />
<File Path=".gitignore" />
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1812;RCS1102;CA1707</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Linq.Async" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.SemanticKernel" VersionOverride="1.*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.OpenAI" VersionOverride="1.*-*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.Core" VersionOverride="1.*" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.Abstractions\Microsoft.Extensions.AI.Agents.Abstractions.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,68 @@
// Copyright (c) Microsoft. All rights reserved.
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Extensions.AI.Agents;
using Microsoft.SemanticKernel.Agents.OpenAI;
using OpenAI;
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var endpoint = Environment.GetEnvironmentVariable("AZUREOPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZUREOPENAI_ENDPOINT is not set.");
var deploymentName = System.Environment.GetEnvironmentVariable("AZUREOPENAI_DEPLOYMENT_NAME") ?? "gpt-4o";
var userInput = "Tell me a joke about a pirate.";
Console.WriteLine($"User Input: {userInput}");
await SKAgent();
await AFAgent();
async Task SKAgent()
{
Console.WriteLine("\n=== SK Agent ===\n");
OpenAIResponseAgent agent = new(new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential())
.GetOpenAIResponseClient(deploymentName))
{
Name = "Joker",
Instructions = "You are good at telling jokes.",
};
var agentOptions = new OpenAIResponseAgentInvokeOptions() { ResponseCreationOptions = new() { MaxOutputTokenCount = 1000 } };
Microsoft.SemanticKernel.Agents.AgentThread? thread = null;
await foreach (var item in agent.InvokeAsync(userInput, thread, agentOptions))
{
Console.WriteLine(item.Message);
}
Console.WriteLine("---");
await foreach (var item in agent.InvokeStreamingAsync(userInput, thread, agentOptions))
{
// Thread need to be updated for subsequent calls
thread = item.Thread;
Console.Write(item.Message);
}
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var agent = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential())
.GetOpenAIResponseClient(deploymentName)
.CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes.");
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 8000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update);
}
}
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1812;RCS1102;CA1707</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Linq.Async" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.SemanticKernel" VersionOverride="1.*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.OpenAI" VersionOverride="1.*-*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.Core" VersionOverride="1.*" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.Abstractions\Microsoft.Extensions.AI.Agents.Abstractions.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,166 @@
// Copyright (c) Microsoft. All rights reserved.
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.AI.Agents;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.ChatCompletion;
using OpenAI;
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var endpoint = Environment.GetEnvironmentVariable("AZUREOPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZUREOPENAI_ENDPOINT is not set.");
var deploymentName = System.Environment.GetEnvironmentVariable("AZUREOPENAI_DEPLOYMENT_NAME") ?? "o4-mini";
var userInput =
"""
Instructions:
- Given the React component below, think about it and change it so that nonfiction books have red
text.
- Return only the code in your reply
- Do not include any additional formatting, such as markdown code blocks
- For formatting, use four space tabs, and do not allow any lines of code to
exceed 80 columns
const books = [
{ title: 'Dune', category: 'fiction', id: 1 },
{ title: 'Frankenstein', category: 'fiction', id: 2 },
{ title: 'Moneyball', category: 'nonfiction', id: 3 },
];
export default function BookList() {
const listItems = books.map(book =>
<li>
{book.title}
</li>
);
return (
<ul>{listItems}</ul>
);
}
""";
Console.WriteLine($"User Input: {userInput}");
await SKAgent();
await AFAgent();
async Task SKAgent()
{
Console.WriteLine("\n=== SK Agent ===\n");
OpenAIResponseAgent agent = new(new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential())
.GetOpenAIResponseClient(deploymentName))
{
Name = "Joker",
Instructions = "You are good at telling jokes.",
};
var agentOptions = new OpenAIResponseAgentInvokeOptions()
{
ResponseCreationOptions = new()
{
MaxOutputTokenCount = 8000,
ReasoningOptions = new()
{
ReasoningEffortLevel = OpenAI.Responses.ResponseReasoningEffortLevel.High,
ReasoningSummaryVerbosity = OpenAI.Responses.ResponseReasoningSummaryVerbosity.Detailed
}
}
};
Microsoft.SemanticKernel.Agents.AgentThread? thread = null;
await foreach (var item in agent.InvokeAsync(userInput, thread, agentOptions))
{
foreach (var content in item.Message.Items)
{
// Currently SK Responses Agent doesn't distinguish thinking from non-thinking content in non-streaming mode.
// SK Bugfix WIP: https://github.com/microsoft/semantic-kernel/issues/13046
if (content is ReasoningContent thinking)
{
Console.Write($"Thinking: \n{thinking}\n---\n");
}
else if (content is Microsoft.SemanticKernel.TextContent text)
{
Console.Write($"Assistant: {text}");
}
}
Console.WriteLine(item.Message);
}
Console.WriteLine("---");
var userMessage = new ChatMessageContent(AuthorRole.User, userInput);
await foreach (var item in agent.InvokeStreamingAsync(userMessage, thread, agentOptions))
{
thread = item.Thread;
foreach (var content in item.Message.Items)
{
// Currently SK Agent doesn't output thinking in streaming mode.
// SK Bugfix WIP: https://github.com/microsoft/semantic-kernel/issues/13046
if (content is StreamingReasoningContent thinking)
{
Console.WriteLine($"Thinking: [{thinking}]");
continue;
}
if (content is StreamingTextContent text)
{
Console.WriteLine($"Response: [{text}]");
}
}
}
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var agent = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential())
.GetOpenAIResponseClient(deploymentName)
.CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes.");
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new()
{
MaxOutputTokens = 8000,
// Microsoft.Extensions.AI currently does not have an abstraction for reasoning-effort,
// we need to break glass using the RawRepresentationFactory.
RawRepresentationFactory = (_) => new OpenAI.Responses.ResponseCreationOptions()
{
ReasoningOptions = new()
{
ReasoningEffortLevel = OpenAI.Responses.ResponseReasoningEffortLevel.High,
ReasoningSummaryVerbosity = OpenAI.Responses.ResponseReasoningSummaryVerbosity.Detailed
}
}
});
var result = await agent.RunAsync(userInput, thread, agentOptions);
// Retrieve the thinking as a full text block requires flattening multiple TextReasoningContents from multiple messages content lists.
string assistantThinking = string.Join("\n", result.Messages
.SelectMany(m => m.Contents)
.OfType<TextReasoningContent>()
.Select(trc => trc.Text));
var assistantText = result.Text;
Console.WriteLine($"Thinking: \n{assistantThinking}\n---\n");
Console.WriteLine($"Assistant: \n{assistantText}\n---\n");
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
{
var thinkingContents = update.Contents
.OfType<TextReasoningContent>()
.Select(trc => trc.Text)
.ToList();
if (thinkingContents.Count != 0)
{
Console.WriteLine($"Thinking: [{string.Join("\n", thinkingContents)}]");
continue;
}
Console.WriteLine($"Response: [{update.Text}]");
}
}
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1812;RCS1102;CA1707;CA1050;CA1052</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Linq.Async" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.SemanticKernel" VersionOverride="1.*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.OpenAI" VersionOverride="1.*-*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.Core" VersionOverride="1.*" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.Abstractions\Microsoft.Extensions.AI.Agents.Abstractions.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,56 @@
// Copyright (c) Microsoft. All rights reserved.
using System.ComponentModel;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using OpenAI;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var endpoint = Environment.GetEnvironmentVariable("AZUREOPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZUREOPENAI_ENDPOINT is not set.");
var deploymentName = System.Environment.GetEnvironmentVariable("AZUREOPENAI_DEPLOYMENT_NAME") ?? "gpt-4o";
var userInput = "What is the weather like in Amsterdam?";
Console.WriteLine($"User Input: {userInput}");
[KernelFunction]
[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15°C.";
await SKAgent();
await AFAgent();
async Task SKAgent()
{
OpenAIResponseAgent agent = new(new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential())
.GetOpenAIResponseClient(deploymentName));
// Initialize plugin and add to the agent's Kernel (same as direct Kernel usage).
agent.Kernel.Plugins.Add(KernelPluginFactory.CreateFromFunctions("KernelPluginName", [KernelFunctionFactory.CreateFromMethod(GetWeather)]));
Console.WriteLine("\n=== SK Agent Response ===\n");
await foreach (ChatMessageContent responseItem in agent.InvokeAsync(userInput))
{
if (!string.IsNullOrWhiteSpace(responseItem.Content))
{
Console.WriteLine(responseItem);
}
}
}
async Task AFAgent()
{
var agent = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential())
.GetChatClient(deploymentName)
.CreateAIAgent(instructions: "You are a helpful assistant", tools: [AIFunctionFactory.Create(GetWeather)]);
Console.WriteLine("\n=== AF Agent Response ===\n");
var result = await agent.RunAsync(userInput);
Console.WriteLine(result);
}
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1812;RCS1102;CA1707</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Linq.Async" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.SemanticKernel" VersionOverride="1.*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.OpenAI" VersionOverride="1.*-*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.Core" VersionOverride="1.*" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.Abstractions\Microsoft.Extensions.AI.Agents.Abstractions.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,56 @@
// Copyright (c) Microsoft. All rights reserved.
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.AI.Agents;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel.Agents.OpenAI;
using OpenAI;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var endpoint = Environment.GetEnvironmentVariable("AZUREOPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZUREOPENAI_ENDPOINT is not set.");
var deploymentName = System.Environment.GetEnvironmentVariable("AZUREOPENAI_DEPLOYMENT_NAME") ?? "gpt-4o";
var userInput = "Tell me a joke about a pirate.";
Console.WriteLine($"User Input: {userInput}");
await SKAgent();
await AFAgent();
async Task SKAgent()
{
Console.WriteLine("\n=== SK Agent ===\n");
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<Microsoft.SemanticKernel.Agents.Agent>((sp)
=> new OpenAIResponseAgent(new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential())
.GetOpenAIResponseClient(deploymentName))
{
Name = "Joker",
Instructions = "You are good at telling jokes."
});
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<Microsoft.SemanticKernel.Agents.Agent>();
var result = await agent.InvokeAsync(userInput).FirstAsync();
Console.WriteLine(result.Message);
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient((sp) => new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential())
.GetChatClient(deploymentName)
.CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes."));
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<AIAgent>();
var result = await agent.RunAsync(userInput);
Console.WriteLine(result);
}
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1812;RCS1102;CA1707</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Linq.Async" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.SemanticKernel" VersionOverride="1.*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.OpenAI" VersionOverride="1.*-*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.Core" VersionOverride="1.*" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.Abstractions\Microsoft.Extensions.AI.Agents.Abstractions.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,64 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Extensions.AI.Agents;
using Microsoft.SemanticKernel.Agents.OpenAI;
using OpenAI;
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
var modelId = System.Environment.GetEnvironmentVariable("OPENAI_MODELID") ?? "gpt-4o";
var userInput = "Tell me a joke about a pirate.";
Console.WriteLine($"User Input: {userInput}");
await SKAgent();
await AFAgent();
async Task SKAgent()
{
Console.WriteLine("\n=== SK Agent ===\n");
OpenAIResponseAgent agent = new(new OpenAIClient(apiKey).GetOpenAIResponseClient(modelId))
{
Name = "Joker",
Instructions = "You are good at telling jokes.",
};
var agentOptions = new OpenAIResponseAgentInvokeOptions() { ResponseCreationOptions = new() { MaxOutputTokenCount = 1000 } };
Microsoft.SemanticKernel.Agents.AgentThread? thread = null;
await foreach (var item in agent.InvokeAsync(userInput, thread, agentOptions))
{
Console.WriteLine(item.Message);
}
Console.WriteLine("---");
await foreach (var item in agent.InvokeStreamingAsync(userInput, thread, agentOptions))
{
// Thread need to be updated for subsequent calls
thread = item.Thread;
Console.Write(item.Message);
}
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var agent = new OpenAIClient(apiKey).GetOpenAIResponseClient(modelId)
.CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes.");
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 8000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update);
}
}
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1812;RCS1102;CA1707</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Linq.Async" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.SemanticKernel" VersionOverride="1.*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.OpenAI" VersionOverride="1.*-*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.Core" VersionOverride="1.*" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.Abstractions\Microsoft.Extensions.AI.Agents.Abstractions.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,162 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Extensions.AI;
using Microsoft.Extensions.AI.Agents;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.ChatCompletion;
using OpenAI;
#pragma warning disable SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
var modelId = System.Environment.GetEnvironmentVariable("OPENAI_MODELID") ?? "o4-mini";
var userInput =
"""
Instructions:
- Given the React component below, think about it and change it so that nonfiction books have red
text.
- Return only the code in your reply
- Do not include any additional formatting, such as markdown code blocks
- For formatting, use four space tabs, and do not allow any lines of code to
exceed 80 columns
const books = [
{ title: 'Dune', category: 'fiction', id: 1 },
{ title: 'Frankenstein', category: 'fiction', id: 2 },
{ title: 'Moneyball', category: 'nonfiction', id: 3 },
];
export default function BookList() {
const listItems = books.map(book =>
<li>
{book.title}
</li>
);
return (
<ul>{listItems}</ul>
);
}
""";
Console.WriteLine($"User Input: {userInput}");
await SKAgent();
await AFAgent();
async Task SKAgent()
{
Console.WriteLine("\n=== SK Agent ===\n");
OpenAIResponseAgent agent = new(new OpenAIClient(apiKey).GetOpenAIResponseClient(modelId))
{
Name = "Joker",
Instructions = "You are good at telling jokes.",
};
var agentOptions = new OpenAIResponseAgentInvokeOptions()
{
ResponseCreationOptions = new()
{
MaxOutputTokenCount = 8000,
ReasoningOptions = new()
{
ReasoningEffortLevel = OpenAI.Responses.ResponseReasoningEffortLevel.High,
ReasoningSummaryVerbosity = OpenAI.Responses.ResponseReasoningSummaryVerbosity.Detailed
}
}
};
Microsoft.SemanticKernel.Agents.AgentThread? thread = null;
await foreach (var item in agent.InvokeAsync(userInput, thread, agentOptions))
{
foreach (var content in item.Message.Items)
{
// Currently SK Responses Agent doesn't distinguish thinking from non-thinking content in non-streaming mode.
// SK Bugfix WIP: https://github.com/microsoft/semantic-kernel/issues/13046
if (content is ReasoningContent thinking)
{
Console.Write($"Thinking: \n{thinking}\n---\n");
}
else if (content is Microsoft.SemanticKernel.TextContent text)
{
Console.Write($"Assistant: {text}");
}
}
Console.WriteLine(item.Message);
}
Console.WriteLine("---");
var userMessage = new ChatMessageContent(AuthorRole.User, userInput);
await foreach (var item in agent.InvokeStreamingAsync(userMessage, thread, agentOptions))
{
thread = item.Thread;
foreach (var content in item.Message.Items)
{
// Currently SK Agent doesn't output thinking in streaming mode.
// SK Bugfix WIP: https://github.com/microsoft/semantic-kernel/issues/13046
if (content is StreamingReasoningContent thinking)
{
Console.WriteLine($"Thinking: [{thinking}]");
continue;
}
if (content is StreamingTextContent text)
{
Console.WriteLine($"Response: [{text}]");
}
}
}
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var agent = new OpenAIClient(apiKey).GetOpenAIResponseClient(modelId)
.CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes.");
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new()
{
MaxOutputTokens = 8000,
// Microsoft.Extensions.AI currently does not have an abstraction for reasoning-effort,
// we need to break glass using the RawRepresentationFactory.
RawRepresentationFactory = (_) => new OpenAI.Responses.ResponseCreationOptions()
{
ReasoningOptions = new()
{
ReasoningEffortLevel = OpenAI.Responses.ResponseReasoningEffortLevel.High,
ReasoningSummaryVerbosity = OpenAI.Responses.ResponseReasoningSummaryVerbosity.Detailed
}
}
});
var result = await agent.RunAsync(userInput, thread, agentOptions);
// Retrieve the thinking as a full text block requires flattening multiple TextReasoningContents from multiple messages content lists.
string assistantThinking = string.Join("\n", result.Messages
.SelectMany(m => m.Contents)
.OfType<TextReasoningContent>()
.Select(trc => trc.Text));
var assistantText = result.Text;
Console.WriteLine($"Thinking: \n{assistantThinking}\n---\n");
Console.WriteLine($"Assistant: \n{assistantText}\n---\n");
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread, agentOptions))
{
var thinkingContents = update.Contents
.OfType<TextReasoningContent>()
.Select(trc => trc.Text)
.ToList();
if (thinkingContents.Count != 0)
{
Console.WriteLine($"Thinking: [{string.Join("\n", thinkingContents)}]");
continue;
}
Console.WriteLine($"Response: [{update.Text}]");
}
}
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1812;RCS1102;CA1707;CA1050;CA1052</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Linq.Async" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.SemanticKernel" VersionOverride="1.*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.OpenAI" VersionOverride="1.*-*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.Core" VersionOverride="1.*" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.Abstractions\Microsoft.Extensions.AI.Agents.Abstractions.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,55 @@
// Copyright (c) Microsoft. All rights reserved.
using System.ComponentModel;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using OpenAI;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
var modelId = System.Environment.GetEnvironmentVariable("OPENAI_MODELID") ?? "gpt-4o";
var userInput = "What is the weather like in Amsterdam?";
Console.WriteLine($"User Input: {userInput}");
[KernelFunction]
[Description("Get the weather for a given location.")]
static string GetWeather([Description("The location to get the weather for.")] string location)
=> $"The weather in {location} is cloudy with a high of 15°C.";
await SKAgent();
await AFAgent();
async Task SKAgent()
{
var builder = Kernel.CreateBuilder().AddOpenAIChatClient(modelId, apiKey);
OpenAIResponseAgent agent = new(new OpenAIClient(apiKey).GetOpenAIResponseClient(modelId));
// Initialize plugin and add to the agent's Kernel (same as direct Kernel usage).
agent.Kernel.Plugins.Add(KernelPluginFactory.CreateFromFunctions("KernelPluginName", [KernelFunctionFactory.CreateFromMethod(GetWeather)]));
Console.WriteLine("\n=== SK Agent Response ===\n");
await foreach (ChatMessageContent responseItem in agent.InvokeAsync(userInput))
{
if (!string.IsNullOrWhiteSpace(responseItem.Content))
{
Console.WriteLine(responseItem);
}
}
}
async Task AFAgent()
{
var agent = new OpenAIClient(apiKey).GetChatClient(modelId).CreateAIAgent(
instructions: "You are a helpful assistant",
tools: [AIFunctionFactory.Create(GetWeather)]);
Console.WriteLine("\n=== AF Agent Response ===\n");
var result = await agent.RunAsync(userInput);
Console.WriteLine(result);
}
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CA1812;RCS1102;CA1707</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Linq.Async" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.SemanticKernel" VersionOverride="1.*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.OpenAI" VersionOverride="1.*-*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.Core" VersionOverride="1.*" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.Abstractions\Microsoft.Extensions.AI.Agents.Abstractions.csproj" />
<ProjectReference Include="..\..\..\..\src\Microsoft.Extensions.AI.Agents.OpenAI\Microsoft.Extensions.AI.Agents.OpenAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,53 @@
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Extensions.AI;
using Microsoft.Extensions.AI.Agents;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel.Agents.OpenAI;
using OpenAI;
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
var modelId = System.Environment.GetEnvironmentVariable("OPENAI_MODELID") ?? "gpt-4o";
var userInput = "Tell me a joke about a pirate.";
Console.WriteLine($"User Input: {userInput}");
await SKAgent();
await AFAgent();
async Task SKAgent()
{
Console.WriteLine("\n=== SK Agent ===\n");
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<Microsoft.SemanticKernel.Agents.Agent>((sp)
=> new OpenAIResponseAgent(new OpenAIClient(apiKey).GetOpenAIResponseClient(modelId))
{
Name = "Joker",
Instructions = "You are good at telling jokes."
});
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<Microsoft.SemanticKernel.Agents.Agent>();
var result = await agent.InvokeAsync(userInput).FirstAsync();
Console.WriteLine(result.Message);
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient((sp) => new OpenAIClient(apiKey)
.GetChatClient(modelId)
.CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes."));
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<AIAgent>();
var result = await agent.RunAsync(userInput);
Console.WriteLine(result);
}
@@ -346,6 +346,10 @@ To run any migration sample, navigate to the desired sample directory:
cd "AzureAIFoundry\Step01_Basics"
dotnet run
# Azure OpenAI Examples
cd "AzureOpenAI\Step01_Basics"
dotnet run
# OpenAI Examples
cd "OpenAI\Step01_Basics"
dotnet run
@@ -354,6 +358,9 @@ dotnet run
cd "OpenAIAssistants\Step01_Basics"
dotnet run
# OpenAI Responses Examples
cd "OpenAIResponses\Step01_Basics"
# Azure OpenAI Examples
cd "AzureOpenAI\Step01_Basics"
dotnet run
@@ -11,6 +11,7 @@ using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using Microsoft.Shared.Diagnostics;
using OpenAI.Responses;
@@ -26,6 +27,9 @@ namespace Microsoft.Extensions.AI;
/// <summary>Represents an <see cref="IChatClient"/> for an <see cref="OpenAIResponseClient"/>.</summary>
internal sealed class NewOpenAIResponsesChatClient : IChatClient
{
/// <summary>Type info for serializing and deserializing arbitrary JSON objects.</summary>
private static readonly JsonTypeInfo s_jsonTypeInfo = AIJsonUtilities.DefaultOptions.GetTypeInfo(typeof(object));
/// <summary>Metadata about the client.</summary>
private readonly ChatClientMetadata _metadata;
@@ -324,8 +328,24 @@ internal sealed class NewOpenAIResponsesChatClient : IChatClient
break;
default:
{
// Capture streaming thinking contents
if (streamingUpdate.GetType().Name == "InternalResponseReasoningSummaryTextDeltaEvent")
{
var updateJson = JsonSerializer.Deserialize<JsonElement>(
JsonSerializer.Serialize(streamingUpdate, s_jsonTypeInfo),
OpenAIJsonContext2.Default.JsonElement);
if (updateJson.TryGetProperty("delta", out var deltaProperty))
{
yield return CreateUpdate(new TextReasoningContent(deltaProperty.GetString()));
break;
}
}
yield return CreateUpdate();
break;
}
}
}
}