.NET: Adding Semantic Kernel - Migration Samples (#499)

* Guidance

* Guidance

* WIP Migration Preps

* Move to single file projects

* Update guidance code and final adjustments to ensure all feature compatibility

* Move from demos to samples

* Address format

* Address chat client pipeline order

* Update project naming

* Revisition on README

* Remove unused ctor

* Address feedback

* Address feedback

* Address merge conflict fix

* Address SK versioning

* Address folder naming

* Address feedback
This commit is contained in:
Roger Barreto
2025-08-29 14:29:03 +00:00
committed by GitHub
parent ecb2989382
commit dac17a8f48
37 changed files with 1973 additions and 138 deletions
@@ -0,0 +1,25 @@
<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>
<InjectSharedThrow>true</InjectSharedThrow>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Linq.Async" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<PackageReference Include="Microsoft.SemanticKernel" VersionOverride="1.*" />
<PackageReference Include="Microsoft.SemanticKernel.Agents.AzureAI" 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.AzureAI\Microsoft.Extensions.AI.Agents.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,76 @@
// Copyright (c) Microsoft. All rights reserved.
using Azure.AI.Agents.Persistent;
using Azure.Identity;
using Microsoft.Extensions.AI.Agents;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.AzureAI;
#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.
var azureEndpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
var deploymentName = System.Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_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 azureAgentClient = AzureAIAgent.CreateAgentsClient(azureEndpoint, new AzureCliCredential());
PersistentAgent definition = await azureAgentClient.Administration.CreateAgentAsync(
deploymentName,
name: "GenerateStory",
instructions: "You are good at telling jokes.");
AzureAIAgent agent = new(definition, azureAgentClient);
var thread = new AzureAIAgentThread(azureAgentClient);
AzureAIAgentInvokeOptions options = new() { MaxPromptTokens = 1000 };
var result = await agent.InvokeAsync(userInput, thread, options).FirstAsync();
Console.WriteLine(result.Message);
Console.WriteLine("---");
await foreach (StreamingChatMessageContent update in agent.InvokeStreamingAsync(userInput, thread))
{
Console.Write(update);
}
// Clean up
await thread.DeleteAsync();
await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var azureAgentClient = new PersistentAgentsClient(azureEndpoint, new AzureCliCredential());
var agent = await azureAgentClient.CreateAIAgentAsync(
deploymentName,
name: "GenerateStory",
instructions: "You are good at telling jokes.");
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
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);
}
// Clean up
await azureAgentClient.Threads.DeleteThreadAsync(thread.ConversationId);
await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
}
@@ -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.AzureAI" 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.AzureAI\Microsoft.Extensions.AI.Agents.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,85 @@
// Copyright (c) Microsoft. All rights reserved.
using System.ComponentModel;
using Azure.AI.Agents.Persistent;
using Azure.Identity;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.AI.Agents;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.AzureAI;
#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.
var azureEndpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
var deploymentName = System.Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_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()
{
Console.WriteLine("\n=== SK Agent ===\n");
var azureAgentClient = AzureAIAgent.CreateAgentsClient(azureEndpoint, new AzureCliCredential());
PersistentAgent definition = await azureAgentClient.Administration.CreateAgentAsync(deploymentName, instructions: "You are a helpful assistant");
AzureAIAgent agent = new(definition, azureAgentClient)
{
Kernel = Kernel.CreateBuilder().Build(),
Name = "Host",
Instructions = "You are a helpful assistant",
Arguments = new KernelArguments(new PromptExecutionSettings() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() }),
};
var thread = new AzureAIAgentThread(azureAgentClient);
// Initialize plugin and add to the agent's Kernel (same as direct Kernel usage).
agent.Kernel.Plugins.Add(KernelPluginFactory.CreateFromFunctions("KernelPluginName", [KernelFunctionFactory.CreateFromMethod(GetWeather)]));
var result = await agent.InvokeAsync(userInput).FirstAsync();
Console.WriteLine(result.Message);
Console.WriteLine("---");
await foreach (ChatMessageContent update in agent.InvokeAsync(userInput, thread))
{
Console.Write(update);
}
// Clean up
await thread.DeleteAsync();
await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var azureAgentClient = new PersistentAgentsClient(azureEndpoint, new AzureCliCredential());
var agent = await azureAgentClient.CreateAIAgentAsync(deploymentName, instructions: "Answer questions about the menu");
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { Tools = [AIFunctionFactory.Create(GetWeather)] });
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);
}
// Clean up
await azureAgentClient.Threads.DeleteThreadAsync(thread.ConversationId);
await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
}
@@ -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.AzureAI" 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.AzureAI\Microsoft.Extensions.AI.Agents.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,100 @@
// Copyright (c) Microsoft. All rights reserved.
using Azure.AI.Agents.Persistent;
using Azure.Identity;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.AI.Agents;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.AzureAI;
#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.
var azureEndpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
var deploymentName = System.Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_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.AddSingleton((sp) => AzureAIAgent.CreateAgentsClient(azureEndpoint, new AzureCliCredential()));
serviceCollection.AddTransient<AzureAIAgent>((sp) =>
{
var azureAgentClient = sp.GetRequiredService<PersistentAgentsClient>();
Console.Write("Creating agent in the cloud...");
PersistentAgent definition = azureAgentClient.Administration
.CreateAgent(deploymentName,
name: "GenerateStory",
instructions: "You are good at telling jokes.");
Console.Write("Done\n");
return new(definition, azureAgentClient);
});
serviceCollection.AddKernel();
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<AzureAIAgent>();
var thread = new AzureAIAgentThread(agent.Client);
var result = await agent.InvokeAsync(userInput).FirstAsync();
Console.WriteLine(result.Message);
Console.WriteLine("---");
await foreach (ChatMessageContent update in agent.InvokeAsync(userInput, thread))
{
Console.Write(update);
}
// Clean up
await thread.DeleteAsync();
await agent.Client.Administration.DeleteAgentAsync(agent.Id);
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton((sp) => AzureAIAgent.CreateAgentsClient(azureEndpoint, new AzureCliCredential()));
serviceCollection.AddTransient<AIAgent>((sp) =>
{
var azureAgentClient = sp.GetRequiredService<PersistentAgentsClient>();
var aiAgent = azureAgentClient.CreateAIAgent(
deploymentName,
name: "GenerateStory",
instructions: "You are good at telling jokes.");
return aiAgent;
});
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<AIAgent>();
var thread = agent.GetNewThread();
var result = await agent.RunAsync(userInput, thread);
Console.WriteLine(result);
Console.WriteLine("---");
await foreach (var update in agent.RunStreamingAsync(userInput, thread))
{
Console.Write(update);
}
// Clean up
var azureAgentClient = serviceProvider.GetRequiredService<PersistentAgentsClient>();
await azureAgentClient.Threads.DeleteThreadAsync(thread.ConversationId);
await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
}
@@ -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.AzureAI" 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.AzureAI\Microsoft.Extensions.AI.Agents.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,121 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text;
using Azure.AI.Agents.Persistent;
using Azure.Identity;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.AzureAI;
#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 CS8321 // Local function is declared but never used
var azureEndpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
var deploymentName = System.Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o";
var userInput = "Create a python code file using the code interpreter tool with a code ready to determine the values in the Fibonacci sequence that are less then the value of 101";
Console.WriteLine($"User Input: {userInput}");
await SKAgent();
await AFAgent();
async Task SKAgent()
{
Console.WriteLine("\n=== SK Agent ===\n");
var azureAgentClient = AzureAIAgent.CreateAgentsClient(azureEndpoint, new AzureCliCredential());
PersistentAgent definition = await azureAgentClient.Administration.CreateAgentAsync(deploymentName, tools: [new CodeInterpreterToolDefinition()]);
AzureAIAgent agent = new(definition, azureAgentClient);
var thread = new AzureAIAgentThread(azureAgentClient);
// SK Azure AI Agent provides the code interpreter content and the assistant message as different contents in the call iteration.
await foreach (var content in agent.InvokeAsync(userInput, thread))
{
if (!string.IsNullOrWhiteSpace(content.Message.Content))
{
bool isCode = content.Message.Metadata?.ContainsKey(AzureAIAgent.CodeInterpreterMetadataKey) ?? false;
Console.WriteLine($"\n# {content.Message.Role}{(isCode ? "\n# Generated Code:\n" : ":")}{content.Message.Content}");
}
// Check for the citations
foreach (var item in content.Message.Items)
{
// Process each item in the message
#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.
if (item is AnnotationContent annotation)
{
if (annotation.Kind != AnnotationKind.UrlCitation)
{
Console.WriteLine($" [{item.GetType().Name}] {annotation.Label}: File #{annotation.ReferenceId}");
}
}
else if (item is FileReferenceContent fileReference)
{
Console.WriteLine($" [{item.GetType().Name}] File #{fileReference.FileId}");
}
}
}
#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
// Clean up
await thread.DeleteAsync();
await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var azureAgentClient = new PersistentAgentsClient(azureEndpoint, new AzureCliCredential());
var agent = await azureAgentClient.CreateAIAgentAsync(deploymentName, tools: [new CodeInterpreterToolDefinition()]);
var thread = agent.GetNewThread();
var result = await agent.RunAsync(userInput, thread);
Console.WriteLine(result);
// Extracts via breaking glass the code generated by code interpreter tool
var chatResponse = result.RawRepresentation as ChatResponse;
StringBuilder generatedCode = new();
foreach (object? updateRawRepresentation in chatResponse?.RawRepresentation as IEnumerable<object?> ?? [])
{
if (updateRawRepresentation is RunStepDetailsUpdate update && update.CodeInterpreterInput is not null)
{
generatedCode.Append(update.CodeInterpreterInput);
}
}
if (!string.IsNullOrEmpty(generatedCode.ToString()))
{
Console.WriteLine($"\n# {chatResponse?.Messages[0].Role}:Generated Code:\n{generatedCode}");
}
// Update the citations
foreach (var textContent in result.Messages[0].Contents.OfType<Microsoft.Extensions.AI.TextContent>())
{
foreach (var annotation in textContent.Annotations ?? [])
{
if (annotation is CitationAnnotation citation)
{
if (citation.Url is null)
{
Console.WriteLine($" [{citation.GetType().Name}] {citation.Snippet}: File #{citation.FileId}");
}
foreach (var region in citation.AnnotatedRegions ?? [])
{
if (region is TextSpanAnnotatedRegion textSpanRegion)
{
Console.WriteLine($"\n[TextSpan Region] {textSpanRegion.StartIndex}-{textSpanRegion.EndIndex}");
}
}
}
}
}
// Clean up
await azureAgentClient.Threads.DeleteThreadAsync(thread.ConversationId);
await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
}
@@ -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;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using OpenAI;
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 builder = Kernel.CreateBuilder().AddOpenAIChatClient(modelId, apiKey);
var agent = new ChatCompletionAgent()
{
Kernel = builder.Build(),
Name = "Joker",
Instructions = "You are good at telling jokes.",
};
var thread = new ChatHistoryAgentThread();
var settings = new OpenAIPromptExecutionSettings() { MaxTokens = 1000 };
var agentOptions = new AgentInvokeOptions() { KernelArguments = new(settings) };
await foreach (var result in agent.InvokeAsync(userInput, thread, agentOptions))
{
Console.WriteLine(result.Message);
}
Console.WriteLine("---");
await foreach (var update in agent.InvokeStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update.Message);
}
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var agent = new OpenAIClient(apiKey).GetChatClient(modelId)
.CreateAIAgent(name: "Joker", instructions: "You are good at telling jokes.");
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
var result = await agent.RunAsync(userInput, thread, agentOptions);
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;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,53 @@
// Copyright (c) Microsoft. All rights reserved.
using System.ComponentModel;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using OpenAI;
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);
ChatCompletionAgent agent = new()
{
Instructions = "You are a helpful assistant",
Kernel = builder.Build(),
Arguments = new KernelArguments(new PromptExecutionSettings() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() }),
};
// 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");
var result = await agent.InvokeAsync(userInput).FirstAsync();
Console.WriteLine(result.Message);
}
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;
using Microsoft.SemanticKernel.Agents;
using OpenAI;
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.AddKernel().AddOpenAIChatClient(modelId, apiKey);
serviceCollection.AddTransient((sp) => new ChatCompletionAgent()
{
Kernel = sp.GetRequiredService<Kernel>(),
Name = "Joker",
Instructions = "You are good at telling jokes."
});
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<ChatCompletionAgent>();
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);
}
@@ -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,80 @@
// Copyright (c) Microsoft. All rights reserved.
#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.
using Microsoft.Extensions.AI.Agents;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using OpenAI;
using OpenAI.Assistants;
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 builder = Kernel.CreateBuilder().AddOpenAIChatClient(modelId, apiKey);
var assistantsClient = new AssistantClient(apiKey);
// Define the assistant
Assistant assistant = await assistantsClient.CreateAssistantAsync(modelId, name: "Joker", instructions: "You are good at telling jokes.");
// Create the agent
OpenAIAssistantAgent agent = new(assistant, assistantsClient);
// Create a thread for the agent conversation.
var thread = new OpenAIAssistantAgentThread(assistantsClient);
var settings = new OpenAIPromptExecutionSettings() { MaxTokens = 1000 };
var agentOptions = new OpenAIAssistantAgentInvokeOptions() { KernelArguments = new(settings) };
await foreach (var result in agent.InvokeAsync(userInput, thread, agentOptions))
{
Console.WriteLine(result.Message);
}
Console.WriteLine("---");
await foreach (var update in agent.InvokeStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update.Message);
}
// Clean up
await thread.DeleteAsync();
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var assistantClient = new AssistantClient(apiKey);
var agent = await assistantClient.CreateAIAgentAsync(modelId, name: "Joker", instructions: "You are good at telling jokes.");
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
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);
}
var yes = agent.GetService<AssistantClient>() is not null;
// Clean up
await assistantClient.DeleteThreadAsync(thread.ConversationId);
await assistantClient.DeleteAssistantAsync(agent.Id);
}
@@ -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,95 @@
// Copyright (c) Microsoft. All rights reserved.
#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.
using System.ComponentModel;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.AI.Agents;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using OpenAI;
using OpenAI.Assistants;
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?";
[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.";
Console.WriteLine($"User Input: {userInput}");
await SKAgent();
await AFAgent();
async Task SKAgent()
{
Console.WriteLine("\n=== SK Agent ===\n");
var builder = Kernel.CreateBuilder();
var assistantsClient = new AssistantClient(apiKey);
Assistant assistant = await assistantsClient.CreateAssistantAsync(modelId,
instructions: "You are a helpful assistant");
OpenAIAssistantAgent agent = new(assistant, assistantsClient)
{
Kernel = builder.Build(),
Arguments = new KernelArguments(new OpenAIPromptExecutionSettings()
{
MaxTokens = 1000,
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
}),
};
// Initialize plugin and add to the agent's Kernel (same as direct Kernel usage).
agent.Kernel.Plugins.Add(KernelPluginFactory.CreateFromFunctions("KernelPluginName", [KernelFunctionFactory.CreateFromMethod(GetWeather)]));
// Create a thread for the agent conversation.
var thread = new OpenAIAssistantAgentThread(assistantsClient);
await foreach (var result in agent.InvokeAsync(userInput, thread))
{
Console.WriteLine(result.Message);
}
Console.WriteLine("---");
await foreach (var update in agent.InvokeStreamingAsync(userInput, thread))
{
Console.Write(update.Message);
}
// Clean up
await thread.DeleteAsync();
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var assistantClient = new AssistantClient(apiKey);
var agent = await assistantClient.CreateAIAgentAsync(modelId,
instructions: "You are a helpful assistant",
tools: [AIFunctionFactory.Create(GetWeather)]);
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
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);
}
// Clean up
await assistantClient.DeleteThreadAsync(thread.ConversationId);
await assistantClient.DeleteAssistantAsync(agent.Id);
}
@@ -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,97 @@
// Copyright (c) Microsoft. All rights reserved.
#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.
using Microsoft.Extensions.AI.Agents;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents.OpenAI;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using OpenAI;
using OpenAI.Assistants;
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.AddSingleton((sp) => new AssistantClient(apiKey));
serviceCollection.AddKernel().AddOpenAIChatClient(modelId, apiKey);
serviceCollection.AddTransient((sp) =>
{
var assistantsClient = sp.GetRequiredService<AssistantClient>();
Assistant assistant = assistantsClient.CreateAssistant(modelId, new() { Name = "Joker", Instructions = "You are good at telling jokes." });
return new OpenAIAssistantAgent(assistant, assistantsClient);
});
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<OpenAIAssistantAgent>();
// Create a thread for the agent conversation.
var assistantsClient = serviceProvider.GetRequiredService<AssistantClient>();
var thread = new OpenAIAssistantAgentThread(assistantsClient);
var settings = new OpenAIPromptExecutionSettings() { MaxTokens = 1000 };
var agentOptions = new OpenAIAssistantAgentInvokeOptions() { KernelArguments = new(settings) };
await foreach (var result in agent.InvokeAsync(userInput, thread, agentOptions))
{
Console.WriteLine(result.Message);
}
Console.WriteLine("---");
await foreach (var update in agent.InvokeStreamingAsync(userInput, thread, agentOptions))
{
Console.Write(update.Message);
}
// Clean up
await thread.DeleteAsync();
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton((sp) => new AssistantClient(apiKey));
serviceCollection.AddTransient((sp) =>
{
var assistantClient = sp.GetRequiredService<AssistantClient>();
var agent = assistantClient.CreateAIAgent(modelId, name: "Joker", instructions: "You are good at telling jokes.");
return agent;
});
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
var agent = serviceProvider.GetRequiredService<AIAgent>();
var thread = agent.GetNewThread();
var agentOptions = new ChatClientAgentRunOptions(new() { MaxOutputTokens = 1000 });
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);
}
// Clean up
var assistantClient = serviceProvider.GetRequiredService<AssistantClient>();
await assistantClient.DeleteThreadAsync(thread.ConversationId);
await assistantClient.DeleteAssistantAsync(agent.Id);
}
@@ -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,127 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.OpenAI;
using OpenAI;
using OpenAI.Assistants;
#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.
#pragma warning disable CS8321 // Local function is declared but never used
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 = "Create a python code file using the code interpreter tool with a code ready to determine the values in the Fibonacci sequence that are less then the value of 101";
var assistantsClient = new AssistantClient(apiKey);
Console.WriteLine($"User Input: {userInput}");
await SKAgent();
await AFAgent();
async Task SKAgent()
{
Console.WriteLine("\n=== SK Agent ===\n");
var builder = Kernel.CreateBuilder().AddOpenAIChatClient(modelId, apiKey);
// Define the assistant
Assistant assistant = await assistantsClient.CreateAssistantAsync(modelId, enableCodeInterpreter: true);
// Create the agent
OpenAIAssistantAgent agent = new(assistant, assistantsClient);
// Create a thread for the agent conversation.
var thread = new OpenAIAssistantAgentThread(assistantsClient);
// Respond to user input
await foreach (var content in agent.InvokeAsync(userInput, thread))
{
if (!string.IsNullOrWhiteSpace(content.Message.Content))
{
bool isCode = content.Message.Metadata?.ContainsKey(OpenAIAssistantAgent.CodeInterpreterMetadataKey) ?? false;
Console.WriteLine($"\n# {content.Message.Role}{(isCode ? "\n# Generated Code:\n" : ":")}{content.Message.Content}");
}
// Check for the citations
foreach (var item in content.Message.Items)
{
// Process each item in the message
#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.
if (item is AnnotationContent annotation)
{
if (annotation.Kind != AnnotationKind.UrlCitation)
{
Console.WriteLine($" [{item.GetType().Name}] {annotation.Label}: File #{annotation.ReferenceId}");
}
}
else if (item is FileReferenceContent fileReference)
{
Console.WriteLine($" [{item.GetType().Name}] File #{fileReference.FileId}");
}
}
}
#pragma warning restore SKEXP0110 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
// Clean up
await thread.DeleteAsync();
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
async Task AFAgent()
{
Console.WriteLine("\n=== AF Agent ===\n");
var agent = await assistantsClient.CreateAIAgentAsync(modelId, tools: [new HostedCodeInterpreterTool()]);
var thread = agent.GetNewThread();
var result = await agent.RunAsync(userInput, thread);
Console.WriteLine(result);
// Extracts via breaking glass the code generated by code interpreter tool
var chatResponse = result.RawRepresentation as ChatResponse;
StringBuilder generatedCode = new();
foreach (object? updateRawRepresentation in chatResponse?.RawRepresentation as IEnumerable<object?> ?? [])
{
if (updateRawRepresentation is RunStepDetailsUpdate update && update.CodeInterpreterInput is not null)
{
generatedCode.Append(update.CodeInterpreterInput);
}
}
if (!string.IsNullOrEmpty(generatedCode.ToString()))
{
Console.WriteLine($"\n# {chatResponse?.Messages[0].Role}:Generated Code:\n{generatedCode}");
}
// Check for the citations
foreach (var textContent in result.Messages[0].Contents.OfType<Microsoft.Extensions.AI.TextContent>())
{
foreach (var annotation in textContent.Annotations ?? [])
{
if (annotation is CitationAnnotation citation)
{
if (citation.Url is null)
{
Console.WriteLine($" [{citation.GetType().Name}] {citation.Snippet}: File #{citation.FileId}");
}
foreach (var region in citation.AnnotatedRegions ?? [])
{
if (region is TextSpanAnnotatedRegion textSpanRegion)
{
Console.WriteLine($"\n[TextSpan Region] {textSpanRegion.StartIndex}-{textSpanRegion.EndIndex}");
}
}
}
}
}
// Clean up
await assistantsClient.DeleteThreadAsync(thread.ConversationId);
await assistantsClient.DeleteAssistantAsync(agent.Id);
}
@@ -0,0 +1,357 @@
# Semantic Kernel to Agent Framework Migration Guide
## What's Changed?
- **Namespace Updates**: From `Microsoft.SemanticKernel.Agents` to `Microsoft.Extensions.AI.Agents`
- **Agent Creation**: Single fluent API calls vs multi-step builder patterns
- **Thread Management**: Built-in thread management vs manual thread creation
- **Tool Registration**: Direct function registration vs plugin wrapper systems
- **Dependency Injection**: Simplified service registration patterns
- **Invocation Patterns**: Streamlined options and result handling
## Benefits of Migration
- **Simplified API**: Reduced complexity and boilerplate code
- **Better Performance**: Optimized object creation and memory usage
- **Unified Interface**: Consistent patterns across different AI providers
- **Enhanced Developer Experience**: More intuitive and discoverable APIs
## Key Changes
### 1. Namespace Updates
#### Semantic Kernel
```csharp
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
```
#### Agent Framework
Agent Framework namespaces are now under `Microsoft.Extensions.AI`.
- `Microsoft.Extensions.AI` for core AI types
- `Microsoft.Extensions.AI.Agents` for core agent types
OR just
- `Microsoft.Extensions.AI.Agents.Abstractions` if your
```csharp
using Microsoft.Extensions.AI;
using Microsoft.Extensions.AI.Agents;
```
### 2. Agent Creation Simplification
#### Semantic Kernel
Every agent in Semantic Kernel depends on a `Kernel` instance and will have
an empty `Kernel` if not provided.
```csharp
Kernel kernel = Kernel
.AddOpenAIChatClient(modelId, apiKey)
.Build();
ChatCompletionAgent agent = new() { Instructions = ParrotInstructions, Kernel = kernel };
```
Azure AI Foundry requires a strong setup before creating an agent
```csharp
PersistentAgentsClient azureAgentClient = AzureAIAgent.CreateAgentsClient(azureEndpoint, new AzureCliCredential());
PersistentAgent definition = await azureAgentClient.Administration.CreateAgentAsync(
deploymentName,
instructions: ParrotInstructions);
AzureAIAgent agent = new(definition, azureAgentClient);
```
#### Agent Framework
Agent creation in Agent Framework is made simpler with extensions provided by all main providers.
```csharp
AIAgent openAIAgent = chatClient.CreateAIAgent(instructions: ParrotInstructions);
AIAgent azureFoundryAgent = persistentAgentsClient.CreateAIAgent(instructions: ParrotInstructions);
AIAgent openAIAssistantAgent = assistantClient.CreateAIAgent(instructions: ParrotInstructions);
```
Additionally for hosted agent providers you can also use the `GetAIAgent` to retrieve an agent from an existing hosted agent.
```csharp
AIAgent azureFoundryAgent = await persistentAgentsClient.GetAIAgentAsync(agentId);
```
### Agent Thread Creation
#### Semantic Kernel
The caller has to know the thread type and create it manually.
```csharp
// Create a thread for the agent conversation.
AgentThread thread = new OpenAIAssistantAgentThread(this.AssistantClient);
AgentThread thread = new AzureAIAgentThread(this.Client);
AgentThread thread = new OpenAIResponseAgentThread(this.Client);
```
#### Agent Framework
The agent is responsible for creating the thread.
```csharp
// New
AgentThread thread = agent.GetNewThread();
```
### Hosted Agent Thread Cleanup
This case applies exclusively to a few AI providers that still provide hosted threads.
#### Semantic Kernel
Threads have a `self` deletion method
i.e: OpenAI Assistants Provider
```csharp
await thread.DeleteAsync();
```
#### Agent Framework
> [!NOTE]
> OpenAI Responses introduced a new conversation model that simplifies completely how conversations are handled avoiding any previous hosted thread management complexities that were initially introduced by the now deprecated OpenAI Assistants model well documented in https://platform.openai.com/docs/assistants/migration
Agent Framework doesn't have thread deletion API in the `AgentThread` type as not all providers require hosted thread cleanup and this will become more common as more providers shift to conversation based architectures.
**When the provider allow thread deletion** the caller **should** keep track of the created threads and delete them later when necessary.
i.e: OpenAI Assistants Provider
```csharp
await assistantClient.DeleteThreadAsync(thread.ConversationId);
```
### Tool Registration
#### Semantic Kernel
In semantic kernel to expose a function as a tool you must:
1. Decorate the function with `[KernelFunction]` attribute.
2. Have a `Plugin` class or use the `KernelPluginFactory` to wrap the function.
3. Have a `Kernel` to use add your plugin.
4. Pass the `Kernel` to the agent.
```csharp
KernelFunction function = KernelFunctionFactory.CreateFromMethod(GetWeather);
KernelPlugin plugin = KernelPluginFactory.CreateFromFunctions("KernelPluginName", [function]);
Kernel kernel = ... // Create kernel
kernel.Plugins.Add(plugin);
ChatCompletionAgent agent = new() { Kernel = kernel, ... };
```
#### Agent Framework
In agent framework in a single call you can register tools directly in the agent creation process.
```csharp
AIAgent agent = chatClient.CreateAIAgent(tools: [AIFunctionFactory.Create(GetWeather)]);
```
### Agent Non-Streaming Invocation
Key differences can be seen in the method names from `Invoke` to `Run`, return types and parameters `AgentRunOptions`.
#### Semantic Kernel
The Non-Streaming uses a streaming pattern `IAsyncEnumerable<AgentResponseItem<ChatMessageContent>>` for returning multiple agent messages.
```csharp
await foreach (AgentResponseItem<ChatMessageContent> result in agent.InvokeAsync(userInput, thread, agentOptions))
{
Console.WriteLine(result.Message);
}
```
#### Agent Framework
The Non-Streaming returns a single `AgentRunResponse` with the agent response that can contain multiple messages.
The text result of the run is available in `AgentRunResponse.Text` or `AgentRunResponse.ToString()`.
All intermediate messages that lead up to creating the result is returned in the `AgentRunResponse.Messages` list.
```csharp
AgentRunResponse agentResponse = await agent.RunAsync(userInput, thread);
```
### Agent Streaming Invocation
Key differences in the method names from `Invoke` to `Run`, return types and parameters `AgentRunOptions`.
#### Semantic Kernel
```csharp
await foreach (StreamingChatMessageContent update in agent.InvokeStreamingAsync(userInput, thread))
{
Console.Write(update);
}
```
#### Agent Framework
Similar streaming API pattern with the key difference being that it `AgentRunResponseUpdate` including more agent related information per update.
All updates produced by any service underlying the AIAgent is returned. The textual result of the agent is available by concatenating the `AgentRunResponse.Text` values.
```csharp
await foreach (AgentRunResponseUpdate update in agent.RunStreamingAsync(userInput, thread))
{
Console.Write(update); // Update is ToString() friendly
}
``
### Tool Function Signatures
**Problem**: SK plugin methods need `[KernelFunction]` attributes
```csharp
public class MenuPlugin
{
[KernelFunction] // Required for SK
public static MenuItem[] GetMenu() => ...;
}
```
**Solution**: AF can use methods directly without attributes
```csharp
public class MenuTools
{
[Description("Get menu items")] // Only Description needed
public static MenuItem[] GetMenu() => ...;
}
```
### Options Configuration
**Problem**: Complex options setup in SK
```csharp
OpenAIPromptExecutionSettings settings = new() { MaxTokens = 1000 };
AgentInvokeOptions options = new() { KernelArguments = new(settings) };
```
**Solution**: Simplified options in AF
```csharp
ChatClientAgentRunOptions options = new(new() { MaxOutputTokens = 1000 });
```
### Dependency Injection
#### Semantic Kernel
A `Kernel` registration is required in the service container to be able to create an agent
as every agent abstractions needs to be initialized with a `Kernel` property.
Semantic Kernel uses `Agent` type as the lower level abstraction for agents.
```csharp
services.AddKernel().AddProvider(...);
serviceContainer.AddKeyedSingleton<SemanticKernel.Agents.Agent>(
TutorName,
(sp, key) =>
new ChatCompletionAgent()
{
// Passing the kernel is required
Kernel = sp.GetRequiredService<Kernel>(),
});
```
#### Agent Framework
Agent framework lower level agents abstraction are defined as `AIAgent` type to avoid potential type clashes with other `Agent` types
not necessarily related to AI Agents.
```csharp
services.AddKeyedSingleton<AIAgent>(() => client.CreateAIAgent(...));
```
# Migration Samples
This folder contains **separate console application projects** demonstrating how to transition from **Semantic Kernel (SK)** to the new **Agent Framework (AF)**.
Each project shows side-by-side comparisons of equivalent functionality in both frameworks and can be run independently.
Each sample code contains the following:
1. **SK Agent** (Semantic Kernel before)
2. **AF Agent** (Agent Framework after)
## Running the samples from Visual Studio
Open the solution in Visual Studio and set the desired sample project as the startup project. Then, run the project using the built-in debugger or by pressing `F5`.
You will be prompted for any required environment variables if they are not already set.
## Prerequisites
Before you begin, ensure you have the following:
- [.NET 8.0 SDK or later](https://dotnet.microsoft.com/download)
- For Azure AI Foundry samples: Azure OpenAI service endpoint and deployment configured
- For OpenAI samples: OpenAI API key
- For OpenAI Assistants samples: OpenAI API key with Assistant API access
## Environment Variables
Set the appropriate environment variables based on the sample type you want to run:
**For Azure AI Foundry projects:**
```powershell
$env:AZURE_FOUNDRY_PROJECT_ENDPOINT = "https://<your-project>-resource.services.ai.azure.com/api/projects/<your-project>"
```
**For OpenAI and OpenAI Assistants projects:**
```powershell
$env:OPENAI_API_KEY = "sk-..."
```
**Optional debug mode:**
```powershell
$env:AF_SHOW_ALL_DEMO_SETTING_VALUES = "Y"
```
If environment variables are not set, the demos will prompt you to enter values interactively.
## Samples
The migration samples are organized into three categories, each demonstrating different AI service integrations:
|Category|Description|
|---|---|
|[AzureAIFoundry](./AzureAIFoundry/)|Azure OpenAI service integration samples|
|[OpenAI](./OpenAI/)|Direct OpenAI API integration samples|
|[OpenAIAssistants](./OpenAIAssistants/)|OpenAI Assistant API integration samples|
## Running the samples from the console
To run any migration sample, navigate to the desired sample directory:
```powershell
# Azure AI Foundry Examples
cd "AzureAIFoundry\Step01_Basics"
dotnet run
cd "AzureAIFoundry\Step03_ToolCall"
dotnet run
# OpenAI Examples
cd "OpenAI\Step01_Basics"
dotnet run
cd "OpenAI\Step02_DependencyInjection"
dotnet run
# OpenAI Assistants Examples
cd "OpenAIAssistants\Step01_Basics"
dotnet run
cd "OpenAIAssistants\Step04_CodeInterpreter"
dotnet run
```