Files
agent-framework/docs/specs/001-foundry-sdk-alignment.md
Ren Finlayson 539852f81c
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
dotnet-build-and-test / paths-filter (push) Waiting to run
dotnet-build-and-test / dotnet-build-and-test (Debug, windows-latest, net9.0) (push) Blocked by required conditions
dotnet-build-and-test / dotnet-build-and-test (Release, integration, true, ubuntu-latest, net10.0) (push) Blocked by required conditions
dotnet-build-and-test / dotnet-build-and-test (Release, integration, true, windows-latest, net472) (push) Blocked by required conditions
dotnet-build-and-test / dotnet-build-and-test (Release, ubuntu-latest, net8.0) (push) Blocked by required conditions
dotnet-build-and-test / dotnet-build-and-test-check (push) Blocked by required conditions
test
2026-01-24 03:05:12 +11:00

291 lines
13 KiB
Markdown

---
# 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);
```