| name | agent-framework |
| description | Use this skill when working with the Microsoft Agent Framework (Microsoft.Agents.AI, Microsoft.Extensions.AI) in .NET. Covers creating AIAgent, function calling, streaming, middleware, DI, provider setup (Anthropic/OpenAI/Google Gemini), and AgentSession. Also use when the user asks about agent-framework documentation, samples, or API reference. |
Microsoft Agent Framework — Usage Reference
Quick Reference Card
| Task | API |
|---|
| Create Anthropic agent | new AnthropicClient(opts).AsAIAgent(model, instructions, tools) |
| Create OpenAI agent | new OpenAIClient(cred, opts).GetChatClient(model).AsAIAgent(instructions, tools) |
| Create Google agent | new ChatClientAgent(new Client(…).AsIChatClient(model), instructions, tools) |
| Create agent with DI | builder.Services.AddSingleton<AIAgent>(sp => …) |
| Run (non-streaming) | AgentResponse response = await agent.RunAsync(message, session) |
| Run (streaming) | await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(message, session)) |
| Create tool from method | AIFunctionFactory.Create(staticMethod) or AIFunctionFactory.Create(methodInfo, targetInstance) |
| Create session | AgentSession session = await agent.CreateSessionAsync() |
| Add middleware | agent.AsBuilder().Use(funcCallMiddleware).Use(agentMiddleware, streamingMiddleware).Build() |
Documentation Sources
Official docs: https://learn.microsoft.com/agent-framework/
GitHub repo: https://github.com/microsoft/agent-framework
Samples: https://github.com/microsoft/agent-framework/tree/main/dotnet/samples
NuGet search: https://www.nuget.org/packages?q=Microsoft.Agents.AI
aka.ms shortcut: https://aka.ms/agent-framework
How to Look Up Framework Details
-
Find samples by topic:
01-get-started/01_hello_agent — simplest agent creation
01-get-started/02_add_tools — function tools
01-get-started/03_multi_turn — AgentSession multi-turn
02-agents/AgentWithAnthropic/ — Anthropic-specific (reasoning, tools, skills)
02-agents/AgentProviders/ — all providers (Anthropic, OpenAI, Google, Ollama, ONNX…)
02-agents/Agents/Agent_Step11_Middleware — middleware patterns
02-agents/Agents/Agent_Step06_DependencyInjection — DI registration
02-agents/Agents/Agent_Step20_DynamicFunctionTools — dynamic tool loading
04-hosting/ — hosting (Azure Functions, Foundry)
-
Fetch raw source: https://raw.githubusercontent.com/microsoft/agent-framework/main/dotnet/samples/{path}/Program.cs
-
Check installed packages locally:
dotnet list package # list packages in current project
ls ~/.nuget/packages/microsoft.agents.ai/ # find installed versions
grep "<member name" ~/.nuget/packages/microsoft.agents.ai/*/lib/net8.0/*.xml | grep -i "method_name"
NuGet Packages
| Package | Purpose | Current Stable |
|---|
Microsoft.Agents.AI | Core: AIAgent, ChatClientAgent, AgentSession, AgentResponseUpdate | 1.6.1 |
Microsoft.Agents.AI.Abstractions | Thin abstractions (transitive) | 1.6.1 |
Microsoft.Agents.AI.Anthropic | AnthropicClient → AsAIAgent() | 1.6.1-preview |
Microsoft.Agents.AI.OpenAI | OpenAIClient + Azure OpenAI → AsAIAgent() | 1.6.1 |
Microsoft.Agents.AI.Workflows | Workflow engine (sequential, concurrent, DAG) | 1.6.1 |
Microsoft.Extensions.AI | IChatClient, ChatMessage, AITool, AIFunctionFactory | 10.5.1 (transitive) |
Microsoft.Agents.AI depends on Microsoft.Extensions.AI 10.5.1 — it is automatically pulled in.
Agent Creation Patterns
Anthropic (Direct API Key)
using Anthropic;
using Anthropic.Core;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
var clientOpts = new ClientOptions
{
ApiKey = apiKey,
BaseUrl = baseUrl
};
AIAgent agent = new AnthropicClient(clientOpts)
.AsAIAgent(
model: "claude-sonnet-4-6",
instructions: "You are a helpful assistant.",
name: "MyAgent",
tools: tools);
AnthropicClient notes:
BaseUrl on AnthropicClient is init-only — must be set via ClientOptions, not after construction
new AnthropicClient { ApiKey = key } works for simple cases
- For custom endpoints, always use
new AnthropicClient(new ClientOptions { ApiKey = key, BaseUrl = url })
using Anthropic.Core; is required for ClientOptions
OpenAI / Azure OpenAI
using OpenAI;
using OpenAI.Chat;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using System.ClientModel;
var options = new OpenAIClientOptions();
if (!string.IsNullOrEmpty(customEndpoint))
options.Endpoint = new Uri(customEndpoint);
AIAgent agent = new OpenAIClient(new ApiKeyCredential(apiKey), options)
.GetChatClient(modelName)
.AsAIAgent(
instructions: "You are a helpful assistant.",
tools: tools);
AIAgent agent = new AzureOpenAIClient(
new Uri(endpoint),
new DefaultAzureCredential())
.GetChatClient(deploymentName)
.AsAIAgent(
instructions: "You are a helpful assistant.",
tools: tools);
OpenAI notes:
OpenAIClient constructor takes ApiKeyCredential, NOT a raw string
- Use
new ApiKeyCredential(key) (from System.ClientModel)
AzureOpenAIClient is the Azure variant (from the same OpenAI NuGet)
using OpenAI.Chat; is required for the AsAIAgent extension on ChatClient
Google Gemini
using Google.GenAI;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
AIAgent agent = new ChatClientAgent(
chatClient: new Google.GenAI.Client(
vertexAI: false,
apiKey: apiKey
).AsIChatClient(modelName),
instructions: "You are a helpful assistant.",
tools: tools);
Google notes:
Google.GenAI.Client.AsIChatClient(model) is an extension from Microsoft.Extensions.AI
- The extension method is defined in
Microsoft.Extensions.AI.GoogleGenAIExtensions
vertexAI: false for Gemini API; true for Vertex AI
- Must use
ChatClientAgent directly (no .AsAIAgent() extension on Google's client)
Function Calling (Tools)
Creating Tools from Static Methods
[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.";
AITool tool = AIFunctionFactory.Create(GetWeather);
Creating Tools from Instance Methods (Reflection)
List<AITool> tools = typeof(ISolidworksApi)
.GetMethods(BindingFlags.Public | BindingFlags.Instance)
.Where(m => m.ReturnType == typeof(Task<string>))
.Select(m => AIFunctionFactory.Create(m, targetInstance: swApiProxy))
.ToList<AITool>();
Important: AIFunctionFactory.Create(MethodInfo, object? target) creates a tool bound to an instance. The target's [Description] and parameter [Description] attributes are used for the tool schema.
Dynamic Tool Loading
The framework supports adding tools during a function-calling loop via FunctionInvokingChatClient.CurrentContext:
var context = FunctionInvokingChatClient.CurrentContext;
context?.Options?.Tools?.Add(newTool);
Running Agents
Non-Streaming
AgentSession session = await agent.CreateSessionAsync();
AgentResponse response = await agent.RunAsync("Hello!", session);
Console.WriteLine(response.Text);
AgentResponse<CityInfo> typedResponse = await agent.RunAsync<CityInfo>("Tell me about Paris.");
CityInfo city = typedResponse.Result;
Streaming
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(
"Hello!", session, null, cancellationToken))
{
foreach (var content in update.Contents)
{
switch (content)
{
case TextContent text when !string.IsNullOrWhiteSpace(text.Text):
Console.Write(text.Text);
break;
case FunctionCallContent functionCall:
Console.WriteLine($"[Tool Call] {functionCall.Name}({functionCall.Arguments})");
break;
case FunctionResultContent functionResult:
Console.WriteLine($"[Tool Result] {functionResult.Result}");
break;
}
}
}
RunAsync — Structured Output
AgentResponse<CityInfo> response = await agent.RunAsync<CityInfo>(
"Provide information about the capital of France.", session);
CityInfo cityInfo = response.Result;
Passing History
var history = new List<Microsoft.Extensions.AI.ChatMessage>
{
new(ChatRole.User, [new TextContent("Previous question")]),
new(ChatRole.Assistant, [new TextContent("Previous answer")])
};
history.Add(new ChatMessage(ChatRole.User, [new TextContent("Follow-up question")]));
await foreach (var update in agent.RunStreamingAsync(history, session, null, ct)) { ... }
AgentSession — Multi-Turn Conversations
Microsoft.Agents.AI.AgentSession maintains conversation context across turns:
AgentSession session = await agent.CreateSessionAsync();
string answer1 = await agent.RunAsync("What's 2+2?", session);
Console.WriteLine(answer1);
string answer2 = await agent.RunAsync("Multiply that by 3", session);
Console.WriteLine(answer2);
Key points:
- Created via
await agent.CreateSessionAsync()
- The session accumulates messages automatically (both user and assistant, including tool calls)
- For stateless servers: serialize the session or reconstruct history from stored messages
- For multi-turn with history: pass
IEnumerable<ChatMessage> to RunStreamingAsync AND a session — the session merges them
Middleware System
The framework provides a composable middleware pipeline at both Agent and ChatClient levels:
Agent-Level Middleware
AIAgent agent = originalAgent
.AsBuilder()
.Use(functionCallMiddleware)
.Use(agentMiddleware, streamingVersion)
.Build();
Agent middleware signature (non-streaming):
async Task<AgentResponse> MyMiddleware(
IEnumerable<ChatMessage> messages,
AgentSession? session,
AgentRunOptions? options,
AIAgent innerAgent, // next agent in pipeline
CancellationToken ct)
{
var response = await innerAgent.RunAsync(messages, session, options, ct);
return response;
}
Function invocation middleware signature:
async ValueTask<object?> FuncMiddleware(
AIAgent agent,
FunctionInvocationContext context,
Func<FunctionInvocationContext, CancellationToken, ValueTask<object?>> next,
CancellationToken ct)
{
var result = await next(context, ct);
return result;
}
ChatClient-Level Middleware
IChatClient client = baseClient
.AsBuilder()
.Use(getResponseFunc: ChatMiddleware, getStreamingResponseFunc: StreamingChatMiddleware)
.BuildAIAgent(instructions: "...", tools: [...]);
async Task<ChatResponse> ChatMiddleware(
IEnumerable<ChatMessage> messages,
ChatOptions? options,
IChatClient innerClient,
CancellationToken ct)
{
var response = await innerClient.GetResponseAsync(messages, options, ct);
return response;
}
AIContextProvider Middleware
Inject additional messages dynamically before each agent run:
internal sealed class DateTimeContextProvider : MessageAIContextProvider
{
protected override ValueTask<IEnumerable<ChatMessage>> ProvideMessagesAsync(
InvokingContext context, CancellationToken ct)
=> new([new ChatMessage(ChatRole.User, $"Current time: {DateTimeOffset.Now}")]);
}
agent.AsBuilder().UseAIContextProviders(new DateTimeContextProvider()).Build();
Dependency Injection
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddSingleton(new ChatClientAgentOptions()
{
Name = "MyAgent",
ChatOptions = new() { Instructions = "You are helpful." }
});
builder.Services.AddKeyedChatClient("MyProvider", sp =>
new AzureOpenAIClient(endpoint, credential)
.GetChatClient(deploymentName)
.AsIChatClient());
builder.Services.AddSingleton<AIAgent>(sp => new ChatClientAgent(
chatClient: sp.GetRequiredKeyedService<IChatClient>("MyProvider"),
options: sp.GetRequiredService<ChatClientAgentOptions>()));
builder.Services.AddHostedService<SampleAgentService>();
AgentResponseUpdate Structure
When streaming, each AgentResponseUpdate provides:
| Property | Type | Description |
|---|
Contents | IList<AIContent> | Content items in this update |
MessageId | string? | ID of the message this update belongs to |
Author | string? | Author/agent name |
ResponseType | AgentResponseType | Text, ToolCall, ToolResult etc. |
Content types within Contents:
TextContent — Text property contains a streaming delta
FunctionCallContent — CallId, Name, Arguments (Dictionary)
FunctionResultContent — CallId, Result
ToolApprovalRequestContent — HITL approval needed
DataContent, FileContent, etc. for multimodal
AgentResponseUpdate.ToString() returns the text delta for convenience (used in simple samples).
Agent vs ChatClientAgent
| Type | Use Case |
|---|
AIAgent (abstract) | General agent — the base type returned by .AsAIAgent() |
ChatClientAgent : AIAgent | Agent backed by an IChatClient — the most common concrete type |
ChatClientAgentOptions | Configuration: Name, ChatOptions (instructions, tools, temperature, etc.) |
ChatClientAgentRunOptions | Per-run overrides: additional tools, response format, etc. |
AIAgent agent = chatClient.AsAIAgent(instructions: "...", tools: [...]);
ChatClientAgent agent = new(chatClient, new ChatClientAgentOptions
{
Name = "MyAgent",
ChatOptions = new() { Instructions = "...", Temperature = 0.7f }
});
Common Pitfalls
- AnthropicClient.BaseUrl is init-only: Set it via
ClientOptions constructor/initializer, not after construction
- OpenAIClient takes ApiKeyCredential, not string: Use
new ApiKeyCredential(key) from System.ClientModel
- OpenAI
AsAIAgent() needs using OpenAI.Chat;: The extension is in OpenAI.Chat.OpenAIChatClientExtensions
- Google needs
ChatClientAgent wrapper: Google's Client doesn't have an AsAIAgent() extension; use new ChatClientAgent(googleClient.AsIChatClient(model), …)
- Anthropic
ClientOptions is in Anthropic.Core: Add using Anthropic.Core;
- Tools from instance methods: Use
AIFunctionFactory.Create(methodInfo, targetInstance) — the 2-argument overload binds to the instance
- Session is NOT thread-safe: One
AgentSession per conversation; don't share across concurrent requests
- AgentResponseUpdate.Contents can be empty: Sometimes an update fires with no content items — always check before processing
How to Verify Your Framework Usage
dotnet restore && dotnet build
dotnet list package | grep -i "agents\|anthropic\|openai"
grep -i "MethodName" ~/.nuget/packages/microsoft.agents.ai/1.6.1/lib/net8.0/Microsoft.Agents.AI.xml
grep "Extension" ~/.nuget/packages/microsoft.agents.ai.*/lib/net8.0/*.xml
Key Namespaces Summary
Anthropic — AnthropicClient, IAnthropicClient
Anthropic.Core — ClientOptions
OpenAI — OpenAIClient, OpenAIClientOptions
OpenAI.Chat — ChatClient, OpenAIChatClientExtensions.AsAIAgent
System.ClientModel — ApiKeyCredential
Google.GenAI — Client, AsIChatClient extension
Microsoft.Agents.AI — AIAgent, ChatClientAgent, AgentSession, AgentResponse, AgentResponseUpdate
Microsoft.Agents.AI.Hosting.* — Durable Agents hosting
Microsoft.Extensions.AI — IChatClient, ChatMessage, AITool, AIFunctionFactory, ChatRole, TextContent
Microsoft.Extensions.AI.Content — FunctionCallContent, FunctionResultContent