diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props
index 5f1f297c92..df6a36cc41 100644
--- a/dotnet/Directory.Packages.props
+++ b/dotnet/Directory.Packages.props
@@ -17,7 +17,7 @@
-
+
@@ -67,7 +67,11 @@
-
+
+
+
+
+
diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index 1722d656c4..d14fe62675 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -8,6 +8,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/demos/Directory.Build.props b/dotnet/demos/Directory.Build.props
index d69fd22796..cfcc22dab6 100644
--- a/dotnet/demos/Directory.Build.props
+++ b/dotnet/demos/Directory.Build.props
@@ -14,7 +14,7 @@
-
+
diff --git a/dotnet/samples/.gitignore b/dotnet/samples/.gitignore
new file mode 100644
index 0000000000..8392c905c6
--- /dev/null
+++ b/dotnet/samples/.gitignore
@@ -0,0 +1 @@
+launchSettings.json
\ No newline at end of file
diff --git a/dotnet/samples/GettingStarted/AgentSample.cs b/dotnet/samples/GettingStarted/AgentSample.cs
index 5c23370b85..004f1bf2e0 100644
--- a/dotnet/samples/GettingStarted/AgentSample.cs
+++ b/dotnet/samples/GettingStarted/AgentSample.cs
@@ -113,11 +113,11 @@ public class AgentSample(ITestOutputHelper output) : BaseSample(output)
=> new OpenAIResponseClient(TestConfiguration.OpenAI.ChatModelId, TestConfiguration.OpenAI.ApiKey)
.AsNewIChatClient();
- private NewPersistentAgentsChatClient GetAzureAIAgentPersistentClient(ChatClientAgentOptions options)
- => new(new PersistentAgentsClient(TestConfiguration.AzureAI.Endpoint, new AzureCliCredential()), options.Id!);
+ private IChatClient GetAzureAIAgentPersistentClient(ChatClientAgentOptions options)
+ => new PersistentAgentsClient(TestConfiguration.AzureAI.Endpoint, new AzureCliCredential()).AsNewIChatClient(options.Id!);
- private NewOpenAIAssistantChatClient GetOpenAIAssistantChatClient(ChatClientAgentOptions options)
- => new(new AssistantClient(TestConfiguration.OpenAI.ApiKey), options.Id!);
+ private IChatClient GetOpenAIAssistantChatClient(ChatClientAgentOptions options)
+ => new AssistantClient(TestConfiguration.OpenAI.ApiKey).AsNewIChatClient(options.Id!);
#endregion
diff --git a/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step01_Basics/AzureAIFoundry_Step01_Basics.csproj b/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step01_Basics/AzureAIFoundry_Step01_Basics.csproj
new file mode 100644
index 0000000000..f0655e396b
--- /dev/null
+++ b/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step01_Basics/AzureAIFoundry_Step01_Basics.csproj
@@ -0,0 +1,25 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+ $(NoWarn);CA1812;RCS1102;CA1707
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step01_Basics/Program.cs b/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step01_Basics/Program.cs
new file mode 100644
index 0000000000..3d0dac58ba
--- /dev/null
+++ b/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step01_Basics/Program.cs
@@ -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);
+}
diff --git a/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step02_ToolCall/AzureAIFoundry_Step02_ToolCall.csproj b/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step02_ToolCall/AzureAIFoundry_Step02_ToolCall.csproj
new file mode 100644
index 0000000000..5fb1669c6d
--- /dev/null
+++ b/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step02_ToolCall/AzureAIFoundry_Step02_ToolCall.csproj
@@ -0,0 +1,24 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+ $(NoWarn);CA1812;RCS1102;CA1707;CA1050;CA1052
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step02_ToolCall/Program.cs b/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step02_ToolCall/Program.cs
new file mode 100644
index 0000000000..9caaa2dd2b
--- /dev/null
+++ b/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step02_ToolCall/Program.cs
@@ -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);
+}
diff --git a/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step03_DependencyInjection/AzureAIFoundry_Step03_DependencyInjection.csproj b/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step03_DependencyInjection/AzureAIFoundry_Step03_DependencyInjection.csproj
new file mode 100644
index 0000000000..3e22c21d32
--- /dev/null
+++ b/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step03_DependencyInjection/AzureAIFoundry_Step03_DependencyInjection.csproj
@@ -0,0 +1,24 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+ $(NoWarn);CA1812;RCS1102;CA1707
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step03_DependencyInjection/Program.cs b/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step03_DependencyInjection/Program.cs
new file mode 100644
index 0000000000..e944c02091
--- /dev/null
+++ b/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step03_DependencyInjection/Program.cs
@@ -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((sp) =>
+ {
+ var azureAgentClient = sp.GetRequiredService();
+
+ 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();
+
+ 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((sp) =>
+ {
+ var azureAgentClient = sp.GetRequiredService();
+
+ 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();
+
+ 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();
+ await azureAgentClient.Threads.DeleteThreadAsync(thread.ConversationId);
+ await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
+}
diff --git a/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step04_CodeInterpreter/AzureAIFoundry_Step04_CodeInterpreter.csproj b/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step04_CodeInterpreter/AzureAIFoundry_Step04_CodeInterpreter.csproj
new file mode 100644
index 0000000000..a71ffa2f51
--- /dev/null
+++ b/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step04_CodeInterpreter/AzureAIFoundry_Step04_CodeInterpreter.csproj
@@ -0,0 +1,24 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+ $(NoWarn);CA1812;RCS1102;CA1707
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step04_CodeInterpreter/Program.cs b/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step04_CodeInterpreter/Program.cs
new file mode 100644
index 0000000000..436f6d2d46
--- /dev/null
+++ b/dotnet/samples/SemanticKernelMigration/AzureAIFoundry/Step04_CodeInterpreter/Program.cs
@@ -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