chore: import upstream snapshot with attribution
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,291 @@
|
||||
---
|
||||
# These are optional elements. Feel free to remove any of them.
|
||||
status: accepted
|
||||
contact: markwallace
|
||||
date: 2025-08-06
|
||||
deciders: markwallace-microsoft, westey-m, quibitron
|
||||
consulted: shawnhenry, elijahstraight
|
||||
informed:
|
||||
---
|
||||
|
||||
# Agent Framework / Foundry SDK Alignment
|
||||
|
||||
Agent Framework and Foundry SDK have overlapping functionality but serve different audiences & scenarios.
|
||||
This specification clarifies the positioning of these SDKs to customers, what goes in each and when to use what.
|
||||
|
||||
- **Foundry SDK** is a thin-client SDK for accessing everything available in the agent service and is autogenerated from REST APIs in multiple languages
|
||||
- **Agent Framework SDK** is general-purpose framework for agentic application development, where common agent abstractions enable creating and orchestrating heterogenous agent systems (across local & cloud)
|
||||
|
||||
## What is the goal of this feature?
|
||||
|
||||
Goals:
|
||||
- Developers can seamlessly combine Foundry and Agent Framework SDK's and there is no friction when using both SDKs at the same time
|
||||
- Developers can take advantage of the full capabilities supported by the Foundry SDK
|
||||
- Developers can create multi-agent orchestrations using Foundry and other agent types
|
||||
|
||||
Success Metrics:
|
||||
- Complexity of basic samples is comparable to other agent frameworks
|
||||
- Developers can easily discover how to use Foundry Agents in Agent Framework multi-agent orchestrations
|
||||
|
||||
## What is the problem being solved?
|
||||
|
||||
- In Semantic Kernel the Foundry Agent support isn't integrated into the Foundry SDK so there is a disjointed developer UX
|
||||
- Customers are confused as to when they should use Foundry SDK versus Semantic Kernel
|
||||
|
||||
|
||||
## API Changes
|
||||
|
||||
The proposed solution is to add helper methods which allow developers to either retrieve or create an `AIAgent` using a `PersistentAgentsClient`
|
||||
|
||||
- Retrieve an `AIAgent`
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// Retrieves an existing server side agent, wrapped as a <see cref="ChatClientAgent"/> using the provided <see cref="PersistentAgentsClient"/>.
|
||||
/// </summary>
|
||||
/// <param name="persistentAgentsClient">The <see cref="PersistentAgentsClient"/> to create the <see cref="ChatClientAgent"/> with.</param>
|
||||
/// <returns>A <see cref="ChatClientAgent"/> for the persistent agent.</returns>
|
||||
/// <param name="agentId"> The ID of the server side agent to create a <see cref="ChatClientAgent"/> for.</param>
|
||||
/// <param name="chatOptions">Options that should apply to all runs of the agent.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the persistent agent.</returns>
|
||||
public static async Task<ChatClientAgent> GetAIAgentAsync(
|
||||
this PersistentAgentsClient persistentAgentsClient,
|
||||
string agentId,
|
||||
ChatOptions? chatOptions = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
```
|
||||
- Create an `AIAgent`
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// Creates a new server side agent using the provided <see cref="PersistentAgentsClient"/>.
|
||||
/// </summary>
|
||||
/// <param name="persistentAgentsClient">The <see cref="PersistentAgentsClient"/> to create the agent with.</param>
|
||||
/// <param name="model">The model to be used by the agent.</param>
|
||||
/// <param name="name">The name of the agent.</param>
|
||||
/// <param name="description">The description of the agent.</param>
|
||||
/// <param name="instructions">The instructions for the agent.</param>
|
||||
/// <param name="tools">The tools to be used by the agent.</param>
|
||||
/// <param name="toolResources">The resources for the tools.</param>
|
||||
/// <param name="temperature">The temperature setting for the agent.</param>
|
||||
/// <param name="topP">The top-p setting for the agent.</param>
|
||||
/// <param name="responseFormat">The response format for the agent.</param>
|
||||
/// <param name="metadata">The metadata for the agent.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the newly created agent.</returns>
|
||||
public static async Task<ChatClientAgent> CreateAIAgentAsync(
|
||||
this PersistentAgentsClient persistentAgentsClient,
|
||||
string model,
|
||||
string? name = null,
|
||||
string? description = null,
|
||||
string? instructions = null,
|
||||
IEnumerable<ToolDefinition>? tools = null,
|
||||
ToolResources? toolResources = null,
|
||||
float? temperature = null,
|
||||
float? topP = null,
|
||||
BinaryData? responseFormat = null,
|
||||
IReadOnlyDictionary<string, string>? metadata = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
```
|
||||
- Additional overload using the M.E.AI types:
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// Creates a new server side agent using the provided <see cref="PersistentAgentsClient"/>.
|
||||
/// </summary>
|
||||
/// <param name="persistentAgentsClient">The <see cref="PersistentAgentsClient"/> to create the agent with.</param>
|
||||
/// <param name="model">The model to be used by the agent.</param>
|
||||
/// <param name="name">The name of the agent.</param>
|
||||
/// <param name="description">The description of the agent.</param>
|
||||
/// <param name="instructions">The instructions for the agent.</param>
|
||||
/// <param name="tools">The tools to be used by the agent.</param>
|
||||
/// <param name="temperature">The temperature setting for the agent.</param>
|
||||
/// <param name="topP">The top-p setting for the agent.</param>
|
||||
/// <param name="responseFormat">The response format for the agent.</param>
|
||||
/// <param name="metadata">The metadata for the agent.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the newly created agent.</returns>
|
||||
public static async Task<ChatClientAgent> CreateAIAgentAsync(
|
||||
this PersistentAgentsClient persistentAgentsClient,
|
||||
string model,
|
||||
string? name = null,
|
||||
string? description = null,
|
||||
string? instructions = null,
|
||||
IEnumerable<AITool>? tools = null,
|
||||
float? temperature = null,
|
||||
float? topP = null,
|
||||
BinaryData? responseFormat = null,
|
||||
IReadOnlyDictionary<string, string>? metadata = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
```
|
||||
|
||||
|
||||
## E2E Code Samples
|
||||
|
||||
### 1. Create and retrieve with Foundry SDK, run with Agent Framework
|
||||
|
||||
- [Foundry SDK] Create a `PersistentAgentsClient`
|
||||
- [Foundry SDK] Create a `PersistentAgent` using the `PersistentAgentsClient`
|
||||
- [Foundry SDK] Retrieve an `AIAgent` using the `PersistentAgentsClient`
|
||||
- [Agent Framework SDK] Invoke the `AIAgent` instance and access response from the `AgentResponse`
|
||||
- [Foundry SDK] Clean up the agent
|
||||
|
||||
|
||||
```csharp
|
||||
// Get a client to create server side agents with.
|
||||
var persistentAgentsClient = new PersistentAgentsClient(
|
||||
TestConfiguration.AzureAI.Endpoint, new AzureCliCredential());
|
||||
|
||||
// Create a persistent agent.
|
||||
var persistentAgentMetadata = await persistentAgentsClient.Administration.CreateAgentAsync(
|
||||
model: TestConfiguration.AzureAI.DeploymentName!,
|
||||
name: JokerName,
|
||||
instructions: JokerInstructions);
|
||||
|
||||
// Get the persistent agent we created in the previous step and expose it as an Agent Framework agent.
|
||||
AIAgent agent = await persistentAgentsClient.GetAIAgentAsync(persistentAgent.Value.Id);
|
||||
|
||||
// Respond to user input.
|
||||
var input = "Tell me a joke about a pirate.";
|
||||
Console.WriteLine(input);
|
||||
Console.WriteLine(await agent.RunAsync(input));
|
||||
|
||||
// Delete the persistent agent.
|
||||
await persistentAgentsClient.Administration.DeleteAgentAsync(agent.Id);
|
||||
```
|
||||
|
||||
### 2. Create directly with Foundry SDK, run with Agent Framework
|
||||
|
||||
- [Foundry SDK] Create a `PersistentAgentsClient`
|
||||
- [Foundry SDK] Create a `AIAgent` using the `PersistentAgentsClient`
|
||||
- [Agent Framework SDK] Invoke the `AIAgent` instance and access response from the `AgentResponse`
|
||||
- [Foundry SDK] Clean up the agent
|
||||
|
||||
```csharp
|
||||
// Get a client to create server side agents with.
|
||||
var persistentAgentsClient = new PersistentAgentsClient(
|
||||
TestConfiguration.AzureAI.Endpoint, new AzureCliCredential());
|
||||
|
||||
// Create a persistent agent and expose it as an Agent Framework agent.
|
||||
AIAgent agent = await persistentAgentsClient.CreateAIAgentAsync(
|
||||
model: TestConfiguration.AzureAI.DeploymentName!,
|
||||
name: JokerName,
|
||||
instructions: JokerInstructions);
|
||||
|
||||
// Respond to user input.
|
||||
var input = "Tell me a joke about a pirate.";
|
||||
Console.WriteLine(input);
|
||||
Console.WriteLine(await agent.RunAsync(input));
|
||||
|
||||
// Delete the persistent agent.
|
||||
await persistentAgentsClient.Administration.DeleteAgentAsync(agent.Id);
|
||||
```
|
||||
|
||||
### 3. Create directly with Foundry SDK, run with conversation state using Agent Framework
|
||||
|
||||
- [Foundry SDK] Create a `PersistentAgentsClient`
|
||||
- [Foundry SDK] Create a `AIAgent` using the `PersistentAgentsClient`
|
||||
- [Agent Framework SDK] Optionally create an `AgentThread` for the agent run
|
||||
- [Agent Framework SDK] Invoke the `AIAgent` instance and access response from the `AgentResponse`
|
||||
- [Foundry SDK] Clean up the agent and the agent thread
|
||||
|
||||
```csharp
|
||||
// Get a client to create server side agents with.
|
||||
var persistentAgentsClient = new PersistentAgentsClient(
|
||||
TestConfiguration.AzureAI.Endpoint, new AzureCliCredential());
|
||||
|
||||
// Create an Agent Framework agent.
|
||||
AIAgent agent = await persistentAgentsClient.CreateAIAgentAsync(
|
||||
model: TestConfiguration.AzureAI.DeploymentName!,
|
||||
name: JokerName,
|
||||
instructions: JokerInstructions);
|
||||
|
||||
// Start a new thread for the agent conversation.
|
||||
AgentThread thread = agent.GetNewThread();
|
||||
|
||||
// Respond to user input.
|
||||
await RunAgentAsync("Tell me a joke about a pirate.");
|
||||
await RunAgentAsync("Now add some emojis to the joke.");
|
||||
|
||||
// Local function to run agent and display the conversation messages for the thread.
|
||||
async Task RunAgentAsync(string input)
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"""
|
||||
User: {input}
|
||||
Assistant:
|
||||
{await agent.RunAsync(input, thread)}
|
||||
|
||||
""");
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
await persistentAgentsClient.Threads.DeleteThreadAsync(thread.ConversationId);
|
||||
await persistentAgentsClient.Administration.DeleteAgentAsync(agent.Id);
|
||||
```
|
||||
|
||||
### 4. Create directly with Foundry SDK, orchestrate with Agent Framework
|
||||
|
||||
- [Foundry SDK] Create a `PersistentAgentsClient`
|
||||
- [Foundry SDK] Create multiple `AIAgent` instances using the `PersistentAgentsClient`
|
||||
- [Agent Framework SDK] Create a `SequentialOrchestration` and add all of the agents to it
|
||||
- [Agent Framework SDK] Invoke the `SequentialOrchestration` instance and access response from the `AgentResponse`
|
||||
- [Foundry SDK] Clean up the agents
|
||||
|
||||
```csharp
|
||||
// Get a client to create server side agents with.
|
||||
var persistentAgentsClient = new PersistentAgentsClient(
|
||||
TestConfiguration.AzureAI.Endpoint, new AzureCliCredential());
|
||||
var model = TestConfiguration.OpenAI.ChatModelId;
|
||||
|
||||
// Define the agents
|
||||
AIAgent analystAgent =
|
||||
await persistentAgentsClient.CreateAIAgentAsync(
|
||||
model,
|
||||
name: "Analyst",
|
||||
instructions:
|
||||
"""
|
||||
You are a marketing analyst. Given a product description, identify:
|
||||
- Key features
|
||||
- Target audience
|
||||
- Unique selling points
|
||||
""",
|
||||
description: "An agent that extracts key concepts from a product description.");
|
||||
AIAgent writerAgent =
|
||||
await persistentAgentsClient.CreateAIAgentAsync(
|
||||
model,
|
||||
name: "copywriter",
|
||||
instructions:
|
||||
"""
|
||||
You are a marketing copywriter. Given a block of text describing features, audience, and USPs,
|
||||
compose a compelling marketing copy (like a newsletter section) that highlights these points.
|
||||
Output should be short (around 150 words), output just the copy as a single text block.
|
||||
""",
|
||||
description: "An agent that writes a marketing copy based on the extracted concepts.");
|
||||
AIAgent editorAgent =
|
||||
await persistentAgentsClient.CreateAIAgentAsync(
|
||||
model,
|
||||
name: "editor",
|
||||
instructions:
|
||||
"""
|
||||
You are an editor. Given the draft copy, correct grammar, improve clarity, ensure consistent tone,
|
||||
give format and make it polished. Output the final improved copy as a single text block.
|
||||
""",
|
||||
description: "An agent that formats and proofreads the marketing copy.");
|
||||
|
||||
// Define the orchestration
|
||||
SequentialOrchestration orchestration =
|
||||
new(analystAgent, writerAgent, editorAgent)
|
||||
{
|
||||
LoggerFactory = this.LoggerFactory,
|
||||
};
|
||||
|
||||
// Run the orchestration
|
||||
string input = "An eco-friendly stainless steel water bottle that keeps drinks cold for 24 hours";
|
||||
Console.WriteLine($"\n# INPUT: {input}\n");
|
||||
AgentResponse result = await orchestration.RunAsync(input);
|
||||
Console.WriteLine($"\n# RESULT: {result}");
|
||||
|
||||
// Cleanup
|
||||
await persistentAgentsClient.Administration.DeleteAgentAsync(analystAgent.Id);
|
||||
await persistentAgentsClient.Administration.DeleteAgentAsync(writerAgent.Id);
|
||||
await persistentAgentsClient.Administration.DeleteAgentAsync(editorAgent.Id);
|
||||
```
|
||||
Reference in New Issue
Block a user