mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
## Description Updates the SK → Agent Framework migration document, samples, and bridge code from AF preview (`1.0.0-preview.251009.1`) to GA (`1.0.0`). ### Breaking changes addressed | Preview API | AF 1.0 GA | Scope | |---|---|---| | `AgentThread` | `AgentSession` | Core type rename | | `GetNewThread()` | `CreateSessionAsync()` | Now async | | `AgentRunResponse` | `AgentResponse` | Return type rename | | `AgentRunResponseUpdate` | `AgentResponseUpdate` | Streaming type rename | | `CreateAIAgent()` | `AsAIAgent()` | Extension method rename | | `AssistantClient.CreateAIAgentAsync()` | **Removed** | Redirect to Responses API | | `PersistentAgentsClient` | **Obsolete** | Use `AIProjectClient` via `Microsoft.Agents.AI.Foundry` | | `Microsoft.Agents.AI.AzureAI` | `Microsoft.Agents.AI.Foundry` | Package rename | | `InProcessExecution.StreamAsync` | `RunStreamingAsync` | Workflow API | | `AgentRunUpdateEvent` | `AgentResponseUpdateEvent` | Workflow event | | `AIAgent.Id` (virtual) | `IdCore` (protected virtual) | Override pattern | ### Additional discoveries - `using OpenAI.Chat;` required for `ChatClient.AsAIAgent()` extension to resolve - `using OpenAI.Responses;` required for `ResponsesClient.AsAIAgent()` extension to resolve ### What changed **Package versions** (`dotnet/Directory.Packages.props`) - AF packages updated to `1.0.0` - `Microsoft.Agents.AI.AzureAI` → `Microsoft.Agents.AI.Foundry` **Bridge code** (`dotnet/src/Agents/Abstractions/AIAgent/`) - `SemanticKernelAIAgent.cs`: New `Core` method overrides (`CreateSessionCoreAsync`, `RunCoreAsync`, etc.) - `SemanticKernelAIAgentThread` → `SemanticKernelAIAgentSession` (extends `AgentSession`) **31 migration samples** (all compile ✅) - OpenAI/AzureOpenAI: `AsAIAgent`, `CreateSessionAsync`, `using OpenAI.Chat;` - Assistants (8): AF sections rewritten to Responses API - Responses (8): Direct `ResponsesClient.AsAIAgent()` - Foundry (4): `AIProjectClient.AsAIAgent()` via `Microsoft.Agents.AI.Foundry` - Orchestrations (3): `RunStreamingAsync`, `AgentResponseUpdateEvent` **Migration document** (`.github/upgrades/prompts/SemanticKernelToAgentFramework.md`) - All AF preview API references updated to 1.0 GA patterns **Unit/integration tests** (~15 files) - Mechanical renames for `AgentSession`, `AgentResponse`, `CreateSessionAsync` ### Validation 8 standalone console programs were created and executed against AF 1.0.0 NuGet packages with real API keys, validating all migration patterns end-to-end: 1. OpenAI Basics (ChatClient → AsAIAgent, CreateSessionAsync, Run/RunStreaming) 2. OpenAI ToolCall (AIFunctionFactory.Create, tool invocation) 3. OpenAI DI (ServiceProvider registration) 4. OpenAI Responses (ResponsesClient.AsAIAgent) 5. Azure AI Foundry (AIProjectClient.AsAIAgent) 6. Workflows Handoff (HandoffWorkflowBuilder, InProcessExecution.RunStreamingAsync) 7. Session Lifecycle (Create, Serialize, Deserialize, multi-turn) 8. Assistants Migration Path (Responses API as replacement) --------- Co-authored-by: Copilot <[email protected]>
145 lines
5.0 KiB
C#
145 lines
5.0 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
using Azure.AI.Agents.Persistent;
|
|
using Azure.AI.Projects;
|
|
using Azure.Identity;
|
|
using Microsoft.Agents.AI;
|
|
using Microsoft.Extensions.AI;
|
|
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 SKAgentAsync();
|
|
await SKAgent_As_AFAgentAsync();
|
|
await AFAgentAsync();
|
|
|
|
async Task SKAgentAsync()
|
|
{
|
|
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 SKAgent_As_AFAgentAsync()
|
|
{
|
|
Console.WriteLine("\n=== SK Agent Converted as an AF 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 skAgent = serviceProvider.GetRequiredService<AzureAIAgent>();
|
|
|
|
var agent = skAgent.AsAIAgent();
|
|
|
|
var thread = await agent.CreateSessionAsync();
|
|
|
|
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>();
|
|
if (thread is ChatClientAgentSession chatSession)
|
|
{
|
|
await azureAgentClient.Threads.DeleteThreadAsync(chatSession.ConversationId);
|
|
}
|
|
await azureAgentClient.Administration.DeleteAgentAsync(agent.Id);
|
|
}
|
|
|
|
async Task AFAgentAsync()
|
|
{
|
|
Console.WriteLine("\n=== AF Agent ===\n");
|
|
|
|
var serviceCollection = new ServiceCollection();
|
|
serviceCollection.AddSingleton((sp) => new AIProjectClient(new Uri(azureEndpoint), new AzureCliCredential()));
|
|
serviceCollection.AddTransient<AIAgent>((sp) =>
|
|
{
|
|
var client = sp.GetRequiredService<AIProjectClient>();
|
|
return client.AsAIAgent(
|
|
deploymentName,
|
|
instructions: "You are good at telling jokes.",
|
|
name: "GenerateStory");
|
|
});
|
|
|
|
await using ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
|
|
var agent = serviceProvider.GetRequiredService<AIAgent>();
|
|
|
|
var session = await agent.CreateSessionAsync();
|
|
|
|
var result = await agent.RunAsync(userInput, session);
|
|
Console.WriteLine(result);
|
|
|
|
Console.WriteLine("---");
|
|
await foreach (var update in agent.RunStreamingAsync(userInput, session))
|
|
{
|
|
Console.Write(update);
|
|
}
|
|
|
|
// No cleanup needed - non-hosted path doesn't create server-side resources.
|
|
}
|