
Microsoft Agent Framework
- 18 installs
- 466 repo stars
- Updated July 25, 2026
- managedcode/dotnet-skills
Helps with ai & agent building tasks.
About
microsoft-agent-framework is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- microsoft-agent-framework
- AI & Agent Building
- AI-coding skill
Microsoft Agent Framework by the numbers
- 18 all-time installs (skills.sh)
- +1 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #10,710 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/managedcode/dotnet-skills --skill microsoft-agent-frameworkAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 18 |
|---|---|
| repo stars | ★ 466 |
| Last updated | July 25, 2026 |
| Repository | managedcode/dotnet-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
{
"version": "1.8.1",
"category": "AI",
"package_prefix": "Microsoft.Agents"
}
DevUI
What DevUI Actually Is
DevUI is a sample app for development-time testing of agents and workflows.
It gives you:
- a local web UI
- an OpenAI-compatible local API surface
- trace viewing
- directory discovery for sample entities
- a quick way to exercise inputs without building your real frontend
It is not a production hosting surface.
.NET Caveat
The current docs are explicit that .NET DevUI documentation is still limited and mostly "coming soon", while Python has the richer published guidance.
So for .NET work:
- treat DevUI docs as conceptual guidance
- do not invent
.NETAPIs that the docs do not actually publish - do not anchor production architecture on DevUI behavior
Good Uses
- smoke-testing prompts and tools locally
- checking whether a workflow input shape is usable
- tracing runs during early development
- trying sample entities before you wire real hosting
Bad Uses
- production chat surfaces
- public internet endpoints
- security boundaries
- long-lived integration contracts
DevUI Versus Real Hosting
| Need | Use DevUI? | Real Answer |
|---|---|---|
| Local debugging | Yes | DevUI is good here |
| Human-facing production UI | No | AG-UI or your own app |
| OpenAI-compatible production endpoint | No | Hosting.OpenAI |
| Agent-to-agent interoperability | No | A2A |
| Secure public service boundary | No | ASP.NET Core hosting with your own auth and policies |
Safe Usage Rules
- Keep it on localhost by default.
- If you expose it to a network, add auth and still treat it as non-production.
- Be careful with side-effecting tools even in local demos.
- Do not mistake "it works in DevUI" for "the production contract is done".
Source Pages
references/official-docs/user-guide/devui/index.mdreferences/official-docs/user-guide/devui/security.mdreferences/official-docs/user-guide/devui/tracing.mdreferences/official-docs/user-guide/devui/directory-discovery.md
Quick-Start and Tutorial Recipes
Use this file when you need the smallest official proof that a pattern exists before you design the production version.
Foundation
| Need | Official Source Path | First Proof | Production Follow-Up |
|---|---|---|---|
| Understand the framework split | overview/agent-framework-overview.md | Agent versus workflow guidance | Route the architecture in patterns.md |
| Get a minimal install and first run | tutorials/quick-start.md | Smallest working setup | Convert the sample to your real provider and state model |
| See the tutorial families | tutorials/overview.md | Discover supported paths | Pick the smallest targeted walkthrough below |
Agent Recipes
| Need | Official Source Path | First Proof | Production Follow-Up |
|---|---|---|---|
| Basic single agent | tutorials/agents/run-agent.md | AsAIAgent, standard run flow | Decide thread model and middleware |
| Multi-turn conversation | tutorials/agents/multi-turn-conversation.md | AgentThread reuse | Persist the serialized thread |
| Persist and resume conversations | tutorials/agents/persisted-conversation.md | serialize and restore thread | Design storage and compatibility rules |
| Store history outside memory | tutorials/agents/third-party-chat-history-storage.md | custom ChatMessageStore | enforce keying and reduction strategy |
| Add memory augmentation | tutorials/agents/memory.md | AIContextProvider hooks | separate memory from raw chat history |
| Add function tools | tutorials/agents/function-tools.md | direct tool registration | narrow contracts, hide runtime-only values from the schema, and add approval rules |
| Add approval to tools | tutorials/agents/function-tools-approvals.md | tool approval flow | decide whether approval belongs in middleware or workflows |
| Structured output | tutorials/agents/structured-output.md | typed output shape | keep schema contracts explicit |
| Images or multimodal input | tutorials/agents/images.md | non-text content path | verify backend multimodal support |
| Add middleware | user-guide/agents/agent-middleware.md | run/function/client interception with the current AgentSession callback signatures | separate policy by layer |
| Use an agent as a tool | tutorials/agents/agent-as-function-tool.md | bounded delegation via the legacy alias page | escalate to workflows if control flow matters |
| Expose an agent as an MCP tool | tutorials/agents/agent-as-mcp-tool.md | MCP-facing tool wrapper | use A2A if the remote thing should stay an agent |
| Enable observability | tutorials/agents/enable-observability.md | tracing and instrumentation | add repo-specific correlation and policy spans |
| Durable hosted agent | tutorials/agents/create-and-run-durable-agent.md | Azure Functions durable path | only keep it if durability is genuinely required |
| Orchestrate durable agents | tutorials/agents/orchestrate-durable-agents.md | deterministic multi-agent orchestration | compare against ordinary workflows first |
Workflow Recipes
| Need | Official Source Path | First Proof | Production Follow-Up |
|---|---|---|---|
| Sequential workflow | tutorials/workflows/simple-sequential-workflow.md | ordered stage execution | verify stage boundaries and error handling |
| Concurrent workflow | tutorials/workflows/simple-concurrent-workflow.md | fan-out and aggregation | make aggregation deterministic |
| Agents inside workflows | tutorials/workflows/agents-in-workflows.md | specialist composition | keep agent versus executor responsibilities clear |
| Branching logic | tutorials/workflows/workflow-with-branching-logic.md | conditional routing | move branch policy out of prompts |
| Builder with factories | tutorials/workflows/workflow-builder-with-factories.md | construction patterns | watch state isolation and reuse |
| External requests and responses | tutorials/workflows/requests-and-responses.md | InputPort and RequestInfoEvent | use this for approval and async callbacks |
| Checkpointing and resuming | tutorials/workflows/checkpointing-and-resuming.md | save and restore flow state | explicitly checkpoint custom executor state |
Hosting And Integration Recipes
| Need | Official Source Path | First Proof | Production Follow-Up |
|---|---|---|---|
| Core ASP.NET Core hosting | user-guide/hosting/index.md | AddAIAgent, AddWorkflow, thread store wiring | keep runtime model protocol-agnostic |
| OpenAI-compatible endpoint | user-guide/hosting/openai-integration.md | map Chat Completions or Responses | prefer Responses for new clients |
| A2A endpoint | user-guide/hosting/agent-to-agent-integration.md | MapA2A and agent card | decide discovery and task semantics |
| AG-UI surface | integrations/ag-ui/index.md | SSE and UI protocol mapping | treat browser trust boundaries explicitly |
| Purview integration | tutorials/plugins/use-purview-with-agent-framework-sdk.md | policy/governance flow | use only when governance is a real requirement |
| Workflow as agent | user-guide/workflows/as-agents.md | wrap workflow behind AIAgent API | keep the workflow explicit in code and docs |
| DevUI smoke testing | user-guide/devui/index.md | local sample-driven testing | do not let it become production architecture |
Source Pages
references/official-docs/tutorials/overview.mdreferences/official-docs/tutorials/quick-start.mdreferences/official-docs/tutorials/agents/run-agent.mdreferences/official-docs/tutorials/workflows/simple-sequential-workflow.mdreferences/official-docs/user-guide/hosting/index.mdreferences/official-docs/integrations/ag-ui/index.md
Hosting and Integration Surfaces
Keep Hosting Separate From Core Logic
The core rule is simple:
- the agent or workflow is your core execution model
- hosting libraries are protocol adapters around it
Do not choose your architecture because a protocol package exists. Choose the runtime model first, then attach the hosting surface you actually need.
Core Hosting Library
Microsoft.Agents.AI.Hosting is the base ASP.NET Core hosting layer.
Use it to:
- register
AIAgentinstances in DI - register workflows
- attach tools and thread stores
- expose workflows as
AIAgentsurfaces when a protocol needs an agent
Representative shape:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton(chatClient);
var pirateAgent = builder.AddAIAgent(
"pirate",
instructions: "You are a pirate. Speak like a pirate.");
var workflow = builder.AddWorkflow("science-workflow", (sp, key) => { /* build workflow */ })
.AddAsAIAgent();Hosted Builder Extensions That Matter
The official docs repeatedly rely on these extensions:
.WithAITool(...).WithInMemoryThreadStore().AddAsAIAgent()for workflows
That means the hosting layer is not just for HTTP exposure. It is also the composition point for common infrastructure around the agent.
Protocol Adapter Matrix
| Surface | Package Family | Use It For | Key Rule |
|---|---|---|---|
| Core hosting | Microsoft.Agents.AI.Hosting | DI registration and local hosting composition | Start here |
| OpenAI-compatible HTTP | Microsoft.Agents.AI.Hosting.OpenAI | Chat Completions, Responses, Conversations endpoints | Prefer Responses for new work |
| A2A | Microsoft.Agents.AI.Hosting.A2A and .AspNetCore | agent-to-agent interoperability | Agent cards and task semantics matter |
| AG-UI | Microsoft.Agents.AI.Hosting.AGUI.AspNetCore | rich web/mobile UI protocols | Treat browser input as hostile unless mediated |
| Azure Functions durable | Microsoft.Agents.AI.Hosting.AzureFunctions | long-running durable hosting | Choose only for real durability needs |
OpenAI-Compatible Hosting
The docs expose three related protocol families:
- Chat Completions
- Responses
- Conversations
Key builder and mapping calls:
builder.AddOpenAIChatCompletions()app.MapOpenAIChatCompletions(agent)builder.AddOpenAIResponses()app.MapOpenAIResponses(agent)builder.AddOpenAIConversations()app.MapOpenAIConversations()
Choose Responses when:
- building new endpoints
- you want richer response semantics
- background responses or server-side conversation support matter
Choose Chat Completions when:
- integrating with existing clients that already speak that shape
- the endpoint is intentionally simple and stateless
A2A Hosting
A2A is the right surface when the caller is another agent platform rather than a generic HTTP app.
Representative mapping:
app.MapA2A(agent, "/a2a/my-agent", agentCard: new()
{
Name = "My Agent",
Description = "A helpful agent.",
Version = "1.0"
});A2A adds:
- agent discovery via agent cards
- message-based interoperability
- long-running task semantics
- cross-framework agent communication
If your real problem is tool exchange, use MCP instead. If your real problem is human UI, use AG-UI instead.
AG-UI Hosting
AG-UI is for rich human-facing agent interfaces over HTTP plus SSE.
Representative mapping:
app.MapAGUI("/", agent);What AG-UI adds beyond direct agent usage:
- remote service hosting
- SSE streaming for UI updates
- thread and state synchronization
- approval workflows
- backend and frontend tool rendering patterns
Important security rule from the docs:
- do not expose AG-UI directly to untrusted browser clients without a trusted frontend mediation layer
Durable Azure Functions Hosting
Use Microsoft.Agents.AI.Hosting.AzureFunctions only when durable execution is a real requirement.
Representative shape:
using IHost app = FunctionsApplication
.CreateBuilder(args)
.ConfigureFunctionsWebApplication()
.ConfigureDurableAgents(options => options.AddAIAgent(agent))
.Build();This is the right path for:
- replayable orchestration
- persistent threads
- failure recovery across long runs
- serverless Azure hosting
Purview Integration
The official docs also call out Microsoft.Agents.AI.Purview.
Use it when:
- prompts and responses need governance checks
- policy enforcement or audit requirements are enterprise-critical
- your rollout requires explicit compliance integration
This is not a universal default. It is a targeted enterprise control layer.
Production Rules
- Keep the in-process agent or workflow protocol-agnostic.
- Expose one clear protocol surface per endpoint.
- Use workflows-as-agents only when a protocol layer requires an
AIAgent. - Keep DevUI separate from production hosting.
- Document the trust boundary for AG-UI and MCP explicitly.
Source Pages
references/official-docs/user-guide/hosting/index.mdreferences/official-docs/user-guide/hosting/openai-integration.mdreferences/official-docs/user-guide/hosting/agent-to-agent-integration.mdreferences/official-docs/integrations/ag-ui/index.mdreferences/official-docs/integrations/ag-ui/security-considerations.mdreferences/official-docs/tutorials/agents/create-and-run-durable-agent.mdreferences/official-docs/tutorials/plugins/use-purview-with-agent-framework-sdk.md
Model Context Protocol and External Boundaries
Keep The Protocols Separate
| Need | Correct Protocol | Why |
|---|---|---|
| Expose tools or contextual data to models and agents | MCP | Tool and context transport |
| Let one remote agent talk to another remote agent | A2A | Agent-to-agent delegation and discovery |
| Drive a rich human-facing web or mobile UI | AG-UI | Interactive UI protocol with streaming and state |
The most common architectural mistake is to blur these:
- MCP is not a remote-agent protocol.
- A2A is not a tool protocol.
- AG-UI is not MCP over HTTP with a prettier client.
What MCP Means In Agent Framework
Agent Framework can attach remote MCP servers as tools for agents. In practice that means:
1. configure an MCP client or tool resource 2. add the resulting tool surface to the agent 3. run the agent normally
The agent sees MCP as tool capability, not as a separate execution runtime.
The Security Model Matters More Than The API
The official docs are very explicit here:
- review every third-party MCP server
- prefer servers run by trusted providers over random proxies
- review what prompt data is being sent
- log what the server receives and returns when possible
- inject headers and auth only at run time
The framework supports custom headers specifically so you can pass run-scoped auth, which is the safe default.
Header And Credential Rules
Custom headers should be:
- injected per run
- short-lived where possible
- excluded from durable thread state
- excluded from source code and static agent definitions
Common safe pattern:
- agent definition is stable
- MCP auth arrives via request-scoped tool resources
- the current run gets only the headers it needs
MCP Versus Hosted Tools
There are two distinct cases:
1. your agent uses an MCP server directly as an external tool source 2. your provider offers hosted MCP-like capabilities as managed service tools
Do not assume those behave the same way operationally. Hosted provider tools inherit provider behavior; remote MCP servers inherit the trust and failure modes of the remote server.
Agent As MCP Tool
You can expose an agent itself as an MCP tool so that MCP clients can call it.
using Microsoft.Agents.AI;
using Microsoft.Extensions.Hosting;
using ModelContextProtocol.Server;
McpServerTool tool = McpServerTool.Create(agent.AsAIFunction());
HostApplicationBuilder builder = Host.CreateEmptyApplicationBuilder(settings: null);
builder.Services
.AddMcpServer()
.WithStdioServerTransport()
.WithTools([tool]);
await builder.Build().RunAsync();Use this when:
- you want the agent to behave like a callable tool in the MCP ecosystem
- conversational agent semantics are not required by the caller
Use A2A instead when the remote thing should remain an agent with its own protocol semantics and discovery model.
Deployment Checklist
- Restrict MCP servers to the smallest trusted set.
- Keep auth request-scoped.
- Audit the prompt and tool data exchanged with remote servers.
- Treat MCP output as untrusted input before using it in downstream tools.
- Do not persist third-party secrets inside thread state.
When To Avoid MCP
Avoid MCP when:
- you really need remote-agent semantics rather than tool semantics
- your frontend protocol is the real problem and AG-UI is the right answer
- the external system is too sensitive to expose through a broad tool interface
Source Pages
references/official-docs/user-guide/model-context-protocol/index.mdreferences/official-docs/user-guide/model-context-protocol/using-mcp-tools.mdreferences/official-docs/user-guide/model-context-protocol/using-mcp-with-foundry-agents.mdreferences/official-docs/tutorials/agents/agent-as-mcp-tool.md
Middleware
Canonical Docs Shift
Current Microsoft Learn docs now route middleware content through a single canonical page under agents/middleware/.
- the old tutorial URL and the old user-guide URL now resolve to the same live page
- newer examples on that page use
AgentSession? sessionin run middleware callbacks even though broader persistence guidance still talks aboutAgentThread - function-calling middleware is currently supported only for agents that use
FunctionInvokingChatClient, such asChatClientAgent
Treat the old paths as aliases and verify callback signatures against the current canonical article when exact code matters.
Middleware Exists At Three Different Layers
| Layer | What It Intercepts | Use It For | Do Not Use It For |
|---|---|---|---|
| Agent run middleware | Whole agent runs and their outputs | audit, input normalization, cross-run policy, response shaping | core business flow that should live in workflows or tools |
| Function-calling middleware | Tool calls inside the agent loop | approvals, argument checks, result filtering, side-effect controls | generic model-call telemetry that belongs lower |
IChatClient middleware | Raw model requests for ChatClientAgent-style agents | logging, retries, tracing, transport policy, model-call stamping | hosted-agent paths that do not use IChatClient |
The important point is scope. Put the rule at the lowest layer that still sees the thing you need to govern.
Registration Patterns
Agent middleware is attached through the agent builder:
var guardedAgent = originalAgent
.AsBuilder()
.Use(runFunc: CustomRunMiddleware, runStreamingFunc: CustomRunStreamingMiddleware)
.Use(CustomFunctionCallingMiddleware)
.Build();IChatClient middleware is attached to the chat client:
var guardedChatClient = chatClient
.AsBuilder()
.Use(getResponseFunc: CustomChatClientMiddleware, getStreamingResponseFunc: CustomStreamingChatMiddleware)
.Build();Then the guarded client is wrapped in ChatClientAgent.
The latest official C# examples also switched these middleware samples to DefaultAzureCredential and now add an explicit production warning about credential fallback chains. Do not copy that credential choice blindly into production code.
Layer Selection Rules
Use agent run middleware when the policy cares about:
- inbound messages
- thread use
- high-level run options
- the final aggregated response
Use function middleware when the policy cares about:
- which tool is being invoked
- which arguments are being sent
- whether the tool call should be blocked or approved
- how the raw tool result is normalized
Tool-only runtime values such as tenant IDs, correlation hints, or request provenance belong here or in related runtime-context hooks, not in model-visible tool parameters.
Use IChatClient middleware when the policy cares about:
- model request and response telemetry
- transport, retries, and headers
- prompt stamping or correlation IDs
- low-level model call behavior
Streaming Caveats
The official docs call out an easy footgun:
- if you provide only non-streaming agent middleware, streaming runs can be forced through non-streaming execution
- that changes the runtime behavior and can hide streaming-specific issues
So the default rule is:
- provide both
runFuncandrunStreamingFunc - or use the shared overload only for pre-run inspection that does not need to rewrite output
- consider
Use(sharedFunc: ...)when you only need input inspection and want to preserve streaming semantics
Function Middleware Is The Right Place For Tool Governance
Function-calling middleware should own:
- approval checks
- argument validation
- allow/deny policy
- result filtering
- logging of side effects
This is where you stop dangerous calls before they execute, rather than trying to clean up the consequences after the agent already used the result.
Approval Pattern
If the backend does not provide first-class approval semantics, implement approval with:
1. function middleware that detects risky tools 2. workflow request and response if human approval is a real state transition 3. explicit denial or placeholder result when approval is absent
Use workflow request/response for approval when:
- the process must pause and wait
- the approval itself needs auditability
- the approval result affects future execution branches
Terminate Is Dangerous
The docs explicitly warn that terminating the function loop can leave the thread inconsistent.
Use FunctionInvocationContext.Terminate = true only when:
- you understand exactly how the current loop iteration will end
- you do not leave function-call content without matching result content
- you have tests proving the thread can still be reused safely
If the goal is human approval or escalation, request/response workflows are usually safer than hard loop termination.
Practical Middleware Compositions
Safe baseline for ChatClientAgent
1. IChatClient middleware for tracing, retries, and correlation IDs. 2. Agent run middleware for input normalization and high-level audit. 3. Function middleware for tool approval and result filtering.
Enterprise baseline
1. request-scoped correlation and telemetry 2. PII or sensitive-data checks before model calls 3. risky-tool approval middleware 4. response filtering before external emission 5. OpenTelemetry spans around the whole run
Anti-Patterns
- Putting domain business logic in middleware because it is "easy to inject".
- Mutating every message on the way through without documenting the contract.
- Assuming
IChatClientmiddleware covers hosted-agent services that bypassIChatClient. - Using middleware to fake workflow state transitions.
- Terminating function loops without understanding thread consistency.
Testing Checklist
- Non-streaming and streaming both execute through the intended middleware paths.
- Risky tools are blocked or paused exactly once.
- Middleware ordering is explicit and documented.
- Chat-client middleware does not leak transport-specific assumptions into provider-agnostic logic.
- Tool result filtering is deterministic and observable.
Source Pages
references/official-docs/user-guide/agents/agent-middleware.mdreferences/official-docs/tutorials/agents/middleware.mdreferences/official-docs/tutorials/agents/function-tools-approvals.md
Migration Notes
Migrate The Architecture, Not Just The API Names
The biggest migration mistake is to treat Agent Framework as a namespace rename from Semantic Kernel or AutoGen. It is not.
The framework changes:
- how threads are created
- how tools are registered
- how responses are represented
- how workflows are modeled
- how hosting is layered
Semantic Kernel To Agent Framework
Concept Mapping
| Semantic Kernel Pattern | Agent Framework Pattern | Important Difference |
|---|---|---|
Kernel-centric agent composition | AIAgent or ChatClientAgent over IChatClient | the agent is no longer a thin wrapper around a Kernel |
| caller-created provider thread types | await agent.GetNewThreadAsync() | thread creation moves behind the agent abstraction |
InvokeAsync / InvokeStreamingAsync | RunAsync / RunStreamingAsync | return models are different |
KernelFunction plugins | AIFunctionFactory.Create(...) | tool registration is direct and agent-first |
KernelArguments and prompt settings | ChatClientAgentRunOptions with ChatOptions | options become more localized to the agent type |
| plugin-heavy agent wiring | direct agent construction | less ceremony, but different extension points |
Mechanical Rewrite Points
1. Move namespaces to Microsoft.Agents.AI and Microsoft.Extensions.AI. 2. Replace provider-specific thread construction with GetNewThreadAsync(). 3. Replace plugin-style tool registration with direct AIFunctionFactory.Create(...). 4. Replace Invoke* calls with Run* calls. 5. Re-test response handling because the result model is not the same.
Behavioral Shifts
- non-streaming now returns one
AgentResponse, not a streaming-shaped sequence AgentResponsecan include tool calls, tool results, and metadata, not just final text- thread cleanup for hosted providers is provider-specific and may require the provider SDK
- Responses-based services are the forward-looking direction; Assistants-style hosted threads are no longer the main path
AutoGen To Agent Framework
The AutoGen migration guide is Python-oriented, but the architectural lessons still matter for .NET.
| AutoGen Concept | Agent Framework Concept | Main Shift |
|---|---|---|
| team orchestration loops | typed Workflow graphs | structure becomes explicit and typed |
| group chat coordination | group chat or Magentic orchestrations | still available, but modeled as workflow patterns |
| event-driven human loops | request and response via workflow boundaries | external interaction becomes a first-class workflow primitive |
| runtime recovery and resume | checkpoints | recovery is designed in, not bolted on |
The .NET takeaway is to translate concepts, not to fabricate .NET APIs from Python examples.
Migration Sequence That Usually Works
1. Re-evaluate whether the old design should stay a single agent. 2. Decide whether the new design should be:
- single
ChatClientAgent - typed
Workflow - durable orchestration
3. Replace thread creation and persistence first. 4. Replace tool registration next. 5. Re-test streaming and non-streaming behavior. 6. Revisit hosting last.
High-Risk Areas During Migration
- Assuming old thread IDs map cleanly to new thread models
- Blindly porting plugin catalogs into giant tool sets
- Treating Responses and Chat Completions as interchangeable
- Forgetting provider-specific cleanup for hosted threads
- Hiding old orchestration loops inside prompts instead of moving them to workflows
Migration Checklist
- Is the target architecture smaller or clearer than the source one?
- Are tool approvals and side-effect rules still explicit?
- Are serialized threads stored as full opaque objects?
- Have streaming and non-streaming response consumers been updated?
- Has the hosting surface been re-chosen deliberately instead of copied forward?
Source Pages
references/official-docs/migration-guide/from-semantic-kernel/index.mdreferences/official-docs/migration-guide/from-semantic-kernel/samples.mdreferences/official-docs/migration-guide/from-autogen/index.md
Official Docs Snapshot
Use this reference when the summarized guidance in the skill is not enough and you need the actual Microsoft Learn markdown pages that informed the skill.
The local snapshot lives under references/official-docs/.
Scope
- Mirrored authored docs:
100markdown pages across overview, tutorials, user guide, integrations, migration, and support - Live-only Learn pages added into the mirror:
support/faq.md,support/troubleshooting.md, andsupport/upgrade/index.md - Generated API references are not mirrored page-by-page; use the live
.NETAPI landing page when exact symbols matter - Intentional exclusions: media files, TOC scaffolding, breadcrumb files, DocFX support files, and Python-only upgrade pages are not mirrored into the skill
Section Map
| Section | Count | Start Here | Covers |
|---|---|---|---|
| Overview | 1 | official-docs/overview/agent-framework-overview.md | Top-level framing, preview state, and agent-vs-workflow guidance |
| Tutorials | 25 | official-docs/tutorials/overview.md | Quick start, agents, workflows, durable agents, middleware, memory, Purview |
| User Guide | 61 | official-docs/user-guide/overview.md | Agent types, threads, tools, MCP, workflows, hosting, DevUI, observability |
| Integrations | 8 | official-docs/integrations/ag-ui/index.md | AG-UI architecture, state sync, approvals, security, and testing |
| Migration | 3 | official-docs/migration-guide/from-semantic-kernel/index.md | Migration from Semantic Kernel and AutoGen |
| Support | 4 | official-docs/support/index.md | Support entry points, FAQ, troubleshooting, and the upgrade hub |
High-Value Entry Points
- Agent types:
official-docs/user-guide/agents/agent-types/index.md - Azure provider pages:
official-docs/user-guide/agents/agent-types/microsoft-foundry-agents.md,official-docs/user-guide/agents/agent-types/azure-openai-chat-completion-agent.md, andofficial-docs/user-guide/agents/agent-types/azure-openai-responses-agent.md - Running agents and conversations:
official-docs/user-guide/agents/running-agents.md - Tools:
official-docs/user-guide/agents/agent-tools.md - Middleware, memory, and RAG:
official-docs/user-guide/agents/agent-middleware.md,official-docs/user-guide/agents/agent-memory.md, andofficial-docs/user-guide/agents/agent-rag.md - MCP:
official-docs/user-guide/model-context-protocol/index.md - Workflow overview:
official-docs/user-guide/workflows/overview.md - Workflow core concepts:
official-docs/user-guide/workflows/core-concepts/overview.md - Workflow orchestrations:
official-docs/user-guide/workflows/orchestrations/overview.md - Declarative workflows:
official-docs/user-guide/workflows/declarative-workflows.md - Hosting and remote protocols:
official-docs/user-guide/hosting/index.md - A2A hosting:
official-docs/user-guide/hosting/agent-to-agent-integration.md - OpenAI-compatible hosting:
official-docs/user-guide/hosting/openai-integration.md - DevUI:
official-docs/user-guide/devui/index.md - AG-UI:
official-docs/integrations/ag-ui/index.md - Support FAQ:
official-docs/support/faq.md - Upgrade hub:
official-docs/support/upgrade/index.md
Complete Local File Map
Overview
- `official-docs/overview/agent-framework-overview.md`
Tutorials
- `official-docs/tutorials/overview.md`
- `official-docs/tutorials/quick-start.md`
Tutorials / Agents
- `official-docs/tutorials/agents/agent-as-function-tool.md` — Redirect alias retained locally because the live Learn URL now resolves into the broader Function Tools surface
- `official-docs/tutorials/agents/agent-as-mcp-tool.md`
- `official-docs/tutorials/agents/create-and-run-durable-agent.md`
- `official-docs/tutorials/agents/enable-observability.md`
- `official-docs/tutorials/agents/function-tools-approvals.md`
- `official-docs/tutorials/agents/function-tools.md`
- `official-docs/tutorials/agents/images.md`
- `official-docs/tutorials/agents/memory.md`
- `official-docs/tutorials/agents/middleware.md` — Redirect alias retained locally because the live Learn URL now resolves to the canonical middleware page
- `official-docs/tutorials/agents/multi-turn-conversation.md`
- `official-docs/tutorials/agents/orchestrate-durable-agents.md`
- `official-docs/tutorials/agents/persisted-conversation.md`
- `official-docs/tutorials/agents/run-agent.md`
- `official-docs/tutorials/agents/structured-output.md`
- `official-docs/tutorials/agents/third-party-chat-history-storage.md`
Tutorials / Workflows
- `official-docs/tutorials/workflows/agents-in-workflows.md`
- `official-docs/tutorials/workflows/checkpointing-and-resuming.md`
- `official-docs/tutorials/workflows/requests-and-responses.md`
- `official-docs/tutorials/workflows/simple-concurrent-workflow.md`
- `official-docs/tutorials/workflows/simple-sequential-workflow.md`
- `official-docs/tutorials/workflows/workflow-builder-with-factories.md`
- `official-docs/tutorials/workflows/workflow-with-branching-logic.md`
Tutorials / Plugins
- `official-docs/tutorials/plugins/use-purview-with-agent-framework-sdk.md`
User Guide
- `official-docs/user-guide/observability.md`
- `official-docs/user-guide/overview.md`
User Guide / Agents
- `official-docs/user-guide/agents/agent-background-responses.md`
- `official-docs/user-guide/agents/agent-memory.md`
- `official-docs/user-guide/agents/agent-middleware.md`
- `official-docs/user-guide/agents/agent-rag.md`
- `official-docs/user-guide/agents/agent-tools.md`
- `official-docs/user-guide/agents/multi-turn-conversation.md`
- `official-docs/user-guide/agents/running-agents.md`
User Guide / Agents / Agent Types
- `official-docs/user-guide/agents/agent-types/a2a-agent.md`
- `official-docs/user-guide/agents/agent-types/anthropic-agent.md`
- `official-docs/user-guide/agents/agent-types/microsoft-foundry-agents.md` — Consolidated "Microsoft Foundry Agents" page covering persistent Azure AI Foundry Agents, Foundry Models Chat Completions, and Foundry Models Responses (all three upstream URLs now resolve to this single page)
- `official-docs/user-guide/agents/agent-types/azure-openai-chat-completion-agent.md`
- `official-docs/user-guide/agents/agent-types/azure-openai-responses-agent.md`
- `official-docs/user-guide/agents/agent-types/chat-client-agent.md`
- `official-docs/user-guide/agents/agent-types/custom-agent.md`
- `official-docs/user-guide/agents/agent-types/index.md`
- `official-docs/user-guide/agents/agent-types/openai-assistants-agent.md`
- `official-docs/user-guide/agents/agent-types/openai-chat-completion-agent.md`
- `official-docs/user-guide/agents/agent-types/openai-responses-agent.md`
User Guide / Agents / Agent Types / Durable Agent
- `official-docs/user-guide/agents/agent-types/durable-agent/create-durable-agent.md`
- `official-docs/user-guide/agents/agent-types/durable-agent/features.md`
User Guide / Model Context Protocol
- `official-docs/user-guide/model-context-protocol/index.md`
- `official-docs/user-guide/model-context-protocol/using-mcp-tools.md`
- `official-docs/user-guide/model-context-protocol/using-mcp-with-foundry-agents.md`
User Guide / Workflows
- `official-docs/user-guide/workflows/as-agents.md`
- `official-docs/user-guide/workflows/checkpoints.md`
- `official-docs/user-guide/workflows/declarative-workflows.md`
- `official-docs/user-guide/workflows/observability.md`
- `official-docs/user-guide/workflows/overview.md`
- `official-docs/user-guide/workflows/requests-and-responses.md`
- `official-docs/user-guide/workflows/shared-states.md`
- `official-docs/user-guide/workflows/state-isolation.md`
- `official-docs/user-guide/workflows/using-agents.md`
- `official-docs/user-guide/workflows/visualization.md`
User Guide / Workflows / Core Concepts
- `official-docs/user-guide/workflows/core-concepts/edges.md`
- `official-docs/user-guide/workflows/core-concepts/events.md`
- `official-docs/user-guide/workflows/core-concepts/executors.md`
- `official-docs/user-guide/workflows/core-concepts/overview.md`
- `official-docs/user-guide/workflows/core-concepts/workflows.md`
User Guide / Workflows / Orchestrations
- `official-docs/user-guide/workflows/orchestrations/concurrent.md`
- `official-docs/user-guide/workflows/orchestrations/group-chat.md`
- `official-docs/user-guide/workflows/orchestrations/handoff.md`
- `official-docs/user-guide/workflows/orchestrations/human-in-the-loop.md`
- `official-docs/user-guide/workflows/orchestrations/magentic.md`
- `official-docs/user-guide/workflows/orchestrations/overview.md`
- `official-docs/user-guide/workflows/orchestrations/sequential.md`
User Guide / Workflows / Declarative Workflows
- `official-docs/user-guide/workflows/declarative-workflows/actions-reference.md`
- `official-docs/user-guide/workflows/declarative-workflows/advanced-patterns.md`
- `official-docs/user-guide/workflows/declarative-workflows/expressions.md`
User Guide / Hosting
- `official-docs/user-guide/hosting/agent-to-agent-integration.md`
- `official-docs/user-guide/hosting/index.md`
- `official-docs/user-guide/hosting/openai-integration.md`
User Guide / DevUI
- `official-docs/user-guide/devui/api-reference.md`
- `official-docs/user-guide/devui/directory-discovery.md`
- `official-docs/user-guide/devui/index.md`
- `official-docs/user-guide/devui/samples.md`
- `official-docs/user-guide/devui/security.md`
- `official-docs/user-guide/devui/tracing.md`
Integrations / AG-UI
- `official-docs/integrations/ag-ui/backend-tool-rendering.md`
- `official-docs/integrations/ag-ui/frontend-tools.md`
- `official-docs/integrations/ag-ui/getting-started.md`
- `official-docs/integrations/ag-ui/human-in-the-loop.md`
- `official-docs/integrations/ag-ui/index.md`
- `official-docs/integrations/ag-ui/security-considerations.md`
- `official-docs/integrations/ag-ui/state-management.md`
- `official-docs/integrations/ag-ui/testing-with-dojo.md`
Migration Guide / From AutoGen
- `official-docs/migration-guide/from-autogen/index.md`
Migration Guide / From Semantic Kernel
- `official-docs/migration-guide/from-semantic-kernel/index.md`
- `official-docs/migration-guide/from-semantic-kernel/samples.md`
Support
- `official-docs/support/faq.md`
- `official-docs/support/index.md`
- `official-docs/support/troubleshooting.md`
Support / Upgrade
- `official-docs/support/upgrade/index.md`
API Reference Pointer
.NETAPI landing page:https://learn.microsoft.com/dotnet/api/microsoft.agents.ai
Usage Guidance
- Start with the smallest relevant local page rather than loading the whole mirror.
- Use the local mirror for exact wording, edge-case features, migration notes, or to confirm preview limitations.
- Raw Learn
:::codeand:::imagesource-asset directives are stripped from the local snapshot to keep it prose-first and avoid broken local references. - Python-only upgrade guides are intentionally excluded from the local snapshot for this
.NETskill.
Backend Tool Rendering with AG-UI
::: zone pivot="programming-language-csharp"
This tutorial shows you how to add function tools to your AG-UI agents. Function tools are custom C# methods that the agent can call to perform specific tasks like retrieving data, performing calculations, or interacting with external systems. With AG-UI, these tools execute on the backend and their results are automatically streamed to the client.
Prerequisites
Before you begin, ensure you have completed the Getting Started tutorial and have:
- .NET 8.0 or later
Microsoft.Agents.AI.Hosting.AGUI.AspNetCorepackage installed- Azure OpenAI service configured
- Basic understanding of AG-UI server and client setup
What is Backend Tool Rendering?
Backend tool rendering means:
- Function tools are defined on the server
- The AI agent decides when to call these tools
- Tools execute on the backend (server-side)
- Tool call events and results are streamed to the client in real-time
- The client receives updates about tool execution progress
Creating an AG-UI Server with Function Tools
Here's a complete server implementation demonstrating how to register tools with complex parameter types:
// Copyright (c) Microsoft. All rights reserved.
using System.ComponentModel;
using System.Text.Json.Serialization;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Hosting.AGUI.AspNetCore;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Options;
using OpenAI.Chat;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient().AddLogging();
builder.Services.ConfigureHttpJsonOptions(options =>
options.SerializerOptions.TypeInfoResolverChain.Add(SampleJsonSerializerContext.Default));
builder.Services.AddAGUI();
WebApplication app = builder.Build();
string endpoint = builder.Configuration["AZURE_OPENAI_ENDPOINT"]
?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
string deploymentName = builder.Configuration["AZURE_OPENAI_DEPLOYMENT_NAME"]
?? throw new InvalidOperationException("AZURE_OPENAI_DEPLOYMENT_NAME is not set.");
// Define request/response types for the tool
internal sealed class RestaurantSearchRequest
{
public string Location { get; set; } = string.Empty;
public string Cuisine { get; set; } = "any";
}
internal sealed class RestaurantSearchResponse
{
public string Location { get; set; } = string.Empty;
public string Cuisine { get; set; } = string.Empty;
public RestaurantInfo[] Results { get; set; } = [];
}
internal sealed class RestaurantInfo
{
public string Name { get; set; } = string.Empty;
public string Cuisine { get; set; } = string.Empty;
public double Rating { get; set; }
public string Address { get; set; } = string.Empty;
}
// JSON serialization context for source generation
[JsonSerializable(typeof(RestaurantSearchRequest))]
[JsonSerializable(typeof(RestaurantSearchResponse))]
internal sealed partial class SampleJsonSerializerContext : JsonSerializerContext;
// Define the function tool
[Description("Search for restaurants in a location.")]
static RestaurantSearchResponse SearchRestaurants(
[Description("The restaurant search request")] RestaurantSearchRequest request)
{
// Simulated restaurant data
string cuisine = request.Cuisine == "any" ? "Italian" : request.Cuisine;
return new RestaurantSearchResponse
{
Location = request.Location,
Cuisine = request.Cuisine,
Results =
[
new RestaurantInfo
{
Name = "The Golden Fork",
Cuisine = cuisine,
Rating = 4.5,
Address = $"123 Main St, {request.Location}"
},
new RestaurantInfo
{
Name = "Spice Haven",
Cuisine = cuisine == "Italian" ? "Indian" : cuisine,
Rating = 4.7,
Address = $"456 Oak Ave, {request.Location}"
},
new RestaurantInfo
{
Name = "Green Leaf",
Cuisine = "Vegetarian",
Rating = 4.3,
Address = $"789 Elm Rd, {request.Location}"
}
]
};
}
// Get JsonSerializerOptions from the configured HTTP JSON options
Microsoft.AspNetCore.Http.Json.JsonOptions jsonOptions = app.Services.GetRequiredService<IOptions<Microsoft.AspNetCore.Http.Json.JsonOptions>>().Value;
// Create tool with serializer options
AITool[] tools =
[
AIFunctionFactory.Create(
SearchRestaurants,
serializerOptions: jsonOptions.SerializerOptions)
];
// Create the AI agent with tools
ChatClient chatClient = new AzureOpenAIClient(
new Uri(endpoint),
new DefaultAzureCredential())
.GetChatClient(deploymentName);
ChatClientAgent agent = chatClient.AsIChatClient().AsAIAgent(
name: "AGUIAssistant",
instructions: "You are a helpful assistant with access to restaurant information.",
tools: tools);
// Map the AG-UI agent endpoint
app.MapAGUI("/", agent);
await app.RunAsync();Key Concepts
- Server-side execution: Tools execute in the server process
- Automatic streaming: Tool calls and results are streamed to clients in real-time
[!IMPORTANT]
When creating tools with complex parameter types (objects, arrays, etc.), you must provide theserializerOptionsparameter toAIFunctionFactory.Create(). The serializer options should be obtained from the application's configuredJsonOptionsviaIOptions<Microsoft.AspNetCore.Http.Json.JsonOptions>to ensure consistency with the rest of the application's JSON serialization.
Running the Server
Set environment variables and run:
export AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/"
export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-mini"
dotnet run --urls http://localhost:8888Observing Tool Calls in the Client
The basic client from the Getting Started tutorial displays the agent's final text response. However, you can extend it to observe tool calls and results as they're streamed from the server.
Displaying Tool Execution Details
To see tool calls and results in real-time, extend the client's streaming loop to handle FunctionCallContent and FunctionResultContent:
// Inside the streaming loop from getting-started.md
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(messages, thread))
{
ChatResponseUpdate chatUpdate = update.AsChatResponseUpdate();
// ... existing run started code ...
// Display streaming content
foreach (AIContent content in update.Contents)
{
switch (content)
{
case TextContent textContent:
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write(textContent.Text);
Console.ResetColor();
break;
case FunctionCallContent functionCallContent:
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"\n[Function Call - Name: {functionCallContent.Name}]");
// Display individual parameters
if (functionCallContent.Arguments != null)
{
foreach (var kvp in functionCallContent.Arguments)
{
Console.WriteLine($" Parameter: {kvp.Key} = {kvp.Value}");
}
}
Console.ResetColor();
break;
case FunctionResultContent functionResultContent:
Console.ForegroundColor = ConsoleColor.Magenta;
Console.WriteLine($"\n[Function Result - CallId: {functionResultContent.CallId}]");
if (functionResultContent.Exception != null)
{
Console.WriteLine($" Exception: {functionResultContent.Exception}");
}
else
{
Console.WriteLine($" Result: {functionResultContent.Result}");
}
Console.ResetColor();
break;
case ErrorContent errorContent:
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"\n[Error: {errorContent.Message}]");
Console.ResetColor();
break;
}
}
}Expected Output with Tool Calls
When the agent calls backend tools, you'll see:
User (:q or quit to exit): What's the weather like in Amsterdam?
[Run Started - Thread: thread_abc123, Run: run_xyz789]
[Function Call - Name: SearchRestaurants]
Parameter: Location = Amsterdam
Parameter: Cuisine = any
[Function Result - CallId: call_def456]
Result: {"Location":"Amsterdam","Cuisine":"any","Results":[...]}
The weather in Amsterdam is sunny with a temperature of 22°C. Here are some
great restaurants in the area: The Golden Fork (Italian, 4.5 stars)...
[Run Finished - Thread: thread_abc123]Key Concepts
- `FunctionCallContent`: Represents a tool being called with its
NameandArguments(parameter key-value pairs) - `FunctionResultContent`: Contains the tool's
ResultorException, identified byCallId
Next Steps
Now that you can add function tools, you can:
- [Frontend tools](frontend-tools.md): Add frontend tools.
<!-- - [Implement Human-in-the-Loop](human-in-the-loop.md): Add approval workflows for sensitive operations --> <!-- - [Manage State](state-management.md): Implement shared state for generative UI applications -->
- [Test with Dojo](testing-with-dojo.md): Use AG-UI's Dojo app to test your agents
Additional Resources
- AG-UI Overview
- Getting Started Tutorial
- Agent Framework Documentation
::: zone-end
::: zone pivot="programming-language-python"
This tutorial shows you how to add function tools to your AG-UI agents. Function tools are custom Python functions that the agent can call to perform specific tasks like retrieving data, performing calculations, or interacting with external systems. With AG-UI, these tools execute on the backend and their results are automatically streamed to the client.
Prerequisites
Before you begin, ensure you have completed the Getting Started tutorial and have:
- Python 3.10 or later
agent-framework-ag-uiinstalled- Azure OpenAI service configured
- Basic understanding of AG-UI server and client setup
[!NOTE]
These samples useDefaultAzureCredentialfor authentication. Make sure you're authenticated with Azure (e.g., viaaz login). For more information, see the Azure Identity documentation.
What is Backend Tool Rendering?
Backend tool rendering means:
- Function tools are defined on the server
- The AI agent decides when to call these tools
- Tools execute on the backend (server-side)
- Tool call events and results are streamed to the client in real-time
- The client receives updates about tool execution progress
This approach provides:
- Security: Sensitive operations stay on the server
- Consistency: All clients use the same tool implementations
- Transparency: Clients can display tool execution progress
- Flexibility: Update tools without changing client code
Creating Function Tools
Basic Function Tool
You can turn any Python function into a tool using the @ai_function decorator:
from typing import Annotated
from pydantic import Field
from agent_framework import ai_function
@ai_function
def get_weather(
location: Annotated[str, Field(description="The city")],
) -> str:
"""Get the current weather for a location."""
# In a real application, you would call a weather API
return f"The weather in {location} is sunny with a temperature of 22°C."Key Concepts
- `@ai_function` decorator: Marks a function as available to the agent
- Type annotations: Provide type information for parameters
- `Annotated` and `Field`: Add descriptions to help the agent understand parameters
- Docstring: Describes what the function does (helps the agent decide when to use it)
- Return value: The result returned to the agent (and streamed to the client)
Multiple Function Tools
You can provide multiple tools to give the agent more capabilities:
from typing import Any
from agent_framework import ai_function
@ai_function
def get_weather(
location: Annotated[str, Field(description="The city.")],
) -> str:
"""Get the current weather for a location."""
return f"The weather in {location} is sunny with a temperature of 22°C."
@ai_function
def get_forecast(
location: Annotated[str, Field(description="The city.")],
days: Annotated[int, Field(description="Number of days to forecast")] = 3,
) -> dict[str, Any]:
"""Get the weather forecast for a location."""
return {
"location": location,
"days": days,
"forecast": [
{"day": 1, "weather": "Sunny", "high": 24, "low": 18},
{"day": 2, "weather": "Partly cloudy", "high": 22, "low": 17},
{"day": 3, "weather": "Rainy", "high": 19, "low": 15},
],
}Creating an AG-UI Server with Function Tools
Here's a complete server implementation with function tools:
"""AG-UI server with backend tool rendering."""
import os
from typing import Annotated, Any
from agent_framework import ChatAgent, ai_function
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework_ag_ui import add_agent_framework_fastapi_endpoint
from azure.identity import AzureCliCredential
from fastapi import FastAPI
from pydantic import Field
# Define function tools
@ai_function
def get_weather(
location: Annotated[str, Field(description="The city")],
) -> str:
"""Get the current weather for a location."""
# Simulated weather data
return f"The weather in {location} is sunny with a temperature of 22°C."
@ai_function
def search_restaurants(
location: Annotated[str, Field(description="The city to search in")],
cuisine: Annotated[str, Field(description="Type of cuisine")] = "any",
) -> dict[str, Any]:
"""Search for restaurants in a location."""
# Simulated restaurant data
return {
"location": location,
"cuisine": cuisine,
"results": [
{"name": "The Golden Fork", "rating": 4.5, "price": "$$"},
{"name": "Bella Italia", "rating": 4.2, "price": "$$$"},
{"name": "Spice Garden", "rating": 4.7, "price": "$$"},
],
}
# Read required configuration
endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT")
deployment_name = os.environ.get("AZURE_OPENAI_DEPLOYMENT_NAME")
if not endpoint:
raise ValueError("AZURE_OPENAI_ENDPOINT environment variable is required")
if not deployment_name:
raise ValueError("AZURE_OPENAI_DEPLOYMENT_NAME environment variable is required")
chat_client = AzureOpenAIChatClient(
credential=AzureCliCredential(),
endpoint=endpoint,
deployment_name=deployment_name,
)
# Create agent with tools
agent = ChatAgent(
name="TravelAssistant",
instructions="You are a helpful travel assistant. Use the available tools to help users plan their trips.",
chat_client=chat_client,
tools=[get_weather, search_restaurants],
)
# Create FastAPI app
app = FastAPI(title="AG-UI Travel Assistant")
add_agent_framework_fastapi_endpoint(app, agent, "/")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8888)Understanding Tool Events
When the agent calls a tool, the client receives several events:
Tool Call Events
# 1. TOOL_CALL_START - Tool execution begins
{
"type": "TOOL_CALL_START",
"toolCallId": "call_abc123",
"toolCallName": "get_weather"
}
# 2. TOOL_CALL_ARGS - Tool arguments (may stream in chunks)
{
"type": "TOOL_CALL_ARGS",
"toolCallId": "call_abc123",
"delta": "{\"location\": \"Paris, France\"}"
}
# 3. TOOL_CALL_END - Arguments complete
{
"type": "TOOL_CALL_END",
"toolCallId": "call_abc123"
}
# 4. TOOL_CALL_RESULT - Tool execution result
{
"type": "TOOL_CALL_RESULT",
"toolCallId": "call_abc123",
"content": "The weather in Paris, France is sunny with a temperature of 22°C."
}Enhanced Client for Tool Events
Here's an enhanced client using AGUIChatClient that displays tool execution:
"""AG-UI client with tool event handling."""
import asyncio
import os
from agent_framework import ChatAgent, ToolCallContent, ToolResultContent
from agent_framework_ag_ui import AGUIChatClient
async def main():
"""Main client loop with tool event display."""
server_url = os.environ.get("AGUI_SERVER_URL", "http://127.0.0.1:8888/")
print(f"Connecting to AG-UI server at: {server_url}\n")
# Create AG-UI chat client
chat_client = AGUIChatClient(server_url=server_url)
# Create agent with the chat client
agent = ChatAgent(
name="ClientAgent",
chat_client=chat_client,
instructions="You are a helpful assistant.",
)
# Get a thread for conversation continuity
thread = agent.get_new_thread()
try:
while True:
message = input("\nUser (:q or quit to exit): ")
if not message.strip():
continue
if message.lower() in (":q", "quit"):
break
print("\nAssistant: ", end="", flush=True)
async for update in agent.run_stream(message, thread=thread):
# Display text content
if update.text:
print(f"\033[96m{update.text}\033[0m", end="", flush=True)
# Display tool calls and results
for content in update.contents:
if isinstance(content, ToolCallContent):
print(f"\n\033[95m[Calling tool: {content.name}]\033[0m")
elif isinstance(content, ToolResultContent):
result_text = content.result if isinstance(content.result, str) else str(content.result)
print(f"\033[94m[Tool result: {result_text}]\033[0m")
print("\n")
except KeyboardInterrupt:
print("\n\nExiting...")
except Exception as e:
print(f"\n\033[91mError: {e}\033[0m")
if __name__ == "__main__":
asyncio.run(main())Example Interaction
With the enhanced server and client running:
User (:q or quit to exit): What's the weather like in Paris and suggest some Italian restaurants?
[Run Started]
[Tool Call: get_weather]
[Tool Result: The weather in Paris, France is sunny with a temperature of 22°C.]
[Tool Call: search_restaurants]
[Tool Result: {"location": "Paris", "cuisine": "Italian", "results": [...]}]
Based on the current weather in Paris (sunny, 22°C) and your interest in Italian cuisine,
I'd recommend visiting Bella Italia, which has a 4.2 rating. The weather is perfect for
outdoor dining!
[Run Finished]Tool Implementation Best Practices
Error Handling
Handle errors gracefully in your tools:
@ai_function
def get_weather(
location: Annotated[str, Field(description="The city.")],
) -> str:
"""Get the current weather for a location."""
try:
# Call weather API
result = call_weather_api(location)
return f"The weather in {location} is {result['condition']} with temperature {result['temp']}°C."
except Exception as e:
return f"Unable to retrieve weather for {location}. Error: {str(e)}"Rich Return Types
Return structured data when appropriate:
@ai_function
def analyze_sentiment(
text: Annotated[str, Field(description="The text to analyze")],
) -> dict[str, Any]:
"""Analyze the sentiment of text."""
# Perform sentiment analysis
return {
"text": text,
"sentiment": "positive",
"confidence": 0.87,
"scores": {
"positive": 0.87,
"neutral": 0.10,
"negative": 0.03,
},
}Descriptive Documentation
Provide clear descriptions to help the agent understand when to use tools:
@ai_function
def book_flight(
origin: Annotated[str, Field(description="Departure city and airport code, e.g., 'New York, JFK'")],
destination: Annotated[str, Field(description="Arrival city and airport code, e.g., 'London, LHR'")],
date: Annotated[str, Field(description="Departure date in YYYY-MM-DD format")],
passengers: Annotated[int, Field(description="Number of passengers")] = 1,
) -> dict[str, Any]:
"""
Book a flight for specified passengers from origin to destination.
This tool should be used when the user wants to book or reserve airline tickets.
Do not use this for searching flights - use search_flights instead.
"""
# Implementation
passTool Organization with Classes
For related tools, organize them in a class:
from agent_framework import ai_function
class WeatherTools:
"""Collection of weather-related tools."""
def __init__(self, api_key: str):
self.api_key = api_key
@ai_function
def get_current_weather(
self,
location: Annotated[str, Field(description="The city.")],
) -> str:
"""Get current weather for a location."""
# Use self.api_key to call API
return f"Current weather in {location}: Sunny, 22°C"
@ai_function
def get_forecast(
self,
location: Annotated[str, Field(description="The city.")],
days: Annotated[int, Field(description="Number of days")] = 3,
) -> dict[str, Any]:
"""Get weather forecast for a location."""
# Use self.api_key to call API
return {"location": location, "forecast": [...]}
# Create tools instance
weather_tools = WeatherTools(api_key="your-api-key")
# Create agent with class-based tools
agent = ChatAgent(
name="WeatherAgent",
instructions="You are a weather assistant.",
chat_client=AzureOpenAIChatClient(...),
tools=[
weather_tools.get_current_weather,
weather_tools.get_forecast,
],
)Next Steps
Now that you understand backend tool rendering, you can:
<!-- - [Add Human-in-the-Loop](human-in-the-loop.md): Require user approval before executing sensitive tools --> <!-- - [Manage State](state-management.md): Share state between client and server for richer interactions -->
- [Create Advanced Tools](../../tutorials/agents/function-tools.md): Learn more about creating function tools with Agent Framework
Additional Resources
- AG-UI Overview
- Getting Started with AG-UI
- Function Tools Tutorial
::: zone-end
Frontend Tool Rendering with AG-UI
::: zone pivot="programming-language-csharp"
This tutorial shows you how to add frontend function tools to your AG-UI clients. Frontend tools are functions that execute on the client side, allowing the AI agent to interact with the user's local environment, access client-specific data, or perform UI operations. The server orchestrates when to call these tools, but the execution happens entirely on the client.
Prerequisites
Before you begin, ensure you have completed the Getting Started tutorial and have:
- .NET 8.0 or later
Microsoft.Agents.AI.AGUIpackage installedMicrosoft.Agents.AIpackage installed- Basic understanding of AG-UI client setup
What are Frontend Tools?
Frontend tools are function tools that:
- Are defined and registered on the client
- Execute in the client's environment (not on the server)
- Allow the AI agent to interact with client-specific resources
- Provide results back to the server for the agent to incorporate into responses
- Enable personalized, context-aware experiences
Common use cases:
- Reading local sensor data (GPS, temperature, etc.)
- Accessing client-side storage or preferences
- Performing UI operations (changing themes, displaying notifications)
- Interacting with device-specific features (camera, microphone)
Registering Frontend Tools on the Client
The key difference from the Getting Started tutorial is registering tools with the client agent. Here's what changes:
// Define a frontend function tool
[Description("Get the user's current location from GPS.")]
static string GetUserLocation()
{
// Access client-side GPS
return "Amsterdam, Netherlands (52.37°N, 4.90°E)";
}
// Create frontend tools
AITool[] frontendTools = [AIFunctionFactory.Create(GetUserLocation)];
// Pass tools when creating the agent
AIAgent agent = chatClient.AsAIAgent(
name: "agui-client",
description: "AG-UI Client Agent",
tools: frontendTools);The rest of your client code remains the same as shown in the Getting Started tutorial.
How Tools Are Sent to the Server
When you register tools with AsAIAgent(), the AGUIChatClient automatically:
1. Captures the tool definitions (names, descriptions, parameter schemas) 3. Sends the tools with each request to the server agent which maps them to ChatAgentRunOptions.ChatOptions.Tools
The server receives the client tool declarations and the AI model can decide when to call them.
Inspecting and Modifying Tools with Middleware
You can use agent middleware to inspect or modify the agent run, including accessing the tools:
// Create agent with middleware that inspects tools
AIAgent inspectableAgent = baseAgent
.AsBuilder()
.Use(runFunc: null, runStreamingFunc: InspectToolsMiddleware)
.Build();
static async IAsyncEnumerable<AgentResponseUpdate> InspectToolsMiddleware(
IEnumerable<ChatMessage> messages,
AgentThread? thread,
AgentRunOptions? options,
AIAgent innerAgent,
CancellationToken cancellationToken)
{
// Access the tools from ChatClientAgentRunOptions
if (options is ChatClientAgentRunOptions chatOptions)
{
IList<AITool>? tools = chatOptions.ChatOptions?.Tools;
if (tools != null)
{
Console.WriteLine($"Tools available for this run: {tools.Count}");
foreach (AITool tool in tools)
{
if (tool is AIFunction function)
{
Console.WriteLine($" - {function.Metadata.Name}: {function.Metadata.Description}");
}
}
}
}
await foreach (AgentResponseUpdate update in innerAgent.RunStreamingAsync(messages, thread, options, cancellationToken))
{
yield return update;
}
}This middleware pattern allows you to:
- Validate tool definitions before execution
Key Concepts
The following are new concepts for frontend tools:
- Client-side registration: Tools are registered on the client using
AIFunctionFactory.Create()and passed toAsAIAgent() - Automatic capture: Tools are automatically captured and sent via
ChatAgentRunOptions.ChatOptions.Tools
How Frontend Tools Work
Server-Side Flow
The server doesn't know the implementation details of frontend tools. It only knows:
1. Tool names and descriptions (from client registration) 2. Parameter schemas 3. When to request tool execution
When the AI agent decides to call a frontend tool:
1. Server sends a tool call request to the client via SSE 2. Server waits for the client to execute the tool and return results 3. Server incorporates the results into the agent's context 4. Agent continues processing with the tool results
Client-Side Flow
The client handles frontend tool execution:
1. Receives FunctionCallContent from server indicating a tool call request 2. Matches the tool name to a locally registered function 3. Deserializes parameters from the request 4. Executes the function locally 5. Serializes the result 6. Sends FunctionResultContent back to the server 7. Continues receiving agent responses
Expected Output with Frontend Tools
When the agent calls frontend tools, you'll see the tool call and result in the streaming output:
User (:q or quit to exit): Where am I located?
[Client Tool Call - Name: GetUserLocation]
[Client Tool Result: Amsterdam, Netherlands (52.37°N, 4.90°E)]
You are currently in Amsterdam, Netherlands, at coordinates 52.37°N, 4.90°E.Server Setup for Frontend Tools
The server doesn't need special configuration to support frontend tools. Use the standard AG-UI server from the Getting Started tutorial - it automatically:
- Receives frontend tool declarations during client connection
- Requests tool execution when the AI agent needs them
- Waits for results from the client
- Incorporates results into the agent's decision-making
Next Steps
Now that you understand frontend tools, you can:
<!-- - [Implement Human-in-the-Loop](human-in-the-loop.md): Add approval workflows before tool execution --> <!-- - [Manage State](state-management.md): Share state between client and server -->
- [Combine with Backend Tools](backend-tool-rendering.md): Use both frontend and backend tools together
Additional Resources
- AG-UI Overview
- Getting Started Tutorial
- Backend Tool Rendering
- Agent Framework Documentation
::: zone-end
::: zone pivot="programming-language-python"
This tutorial shows you how to add frontend function tools to your AG-UI clients. Frontend tools are functions that execute on the client side, allowing the AI agent to interact with the user's local environment, access client-specific data, or perform UI operations.
Prerequisites
Before you begin, ensure you have completed the Getting Started tutorial and have:
- Python 3.10 or later
httpxinstalled for HTTP client functionality- Basic understanding of AG-UI client setup
- Azure OpenAI service configured
What are Frontend Tools?
Frontend tools are function tools that:
- Are defined and registered on the client
- Execute in the client's environment (not on the server)
- Allow the AI agent to interact with client-specific resources
- Provide results back to the server for the agent to incorporate into responses
Common use cases:
- Reading local sensor data
- Accessing client-side storage or preferences
- Performing UI operations
- Interacting with device-specific features
Creating Frontend Tools
Frontend tools in Python are defined similarly to backend tools but are registered with the client:
from typing import Annotated
from pydantic import BaseModel, Field
class SensorReading(BaseModel):
"""Sensor reading from client device."""
temperature: float
humidity: float
air_quality_index: int
def read_climate_sensors(
include_temperature: Annotated[bool, Field(description="Include temperature reading")] = True,
include_humidity: Annotated[bool, Field(description="Include humidity reading")] = True,
) -> SensorReading:
"""Read climate sensor data from the client device."""
# Simulate reading from local sensors
return SensorReading(
temperature=22.5 if include_temperature else 0.0,
humidity=45.0 if include_humidity else 0.0,
air_quality_index=75,
)
def change_background_color(color: Annotated[str, Field(description="Color name")] = "blue") -> str:
"""Change the console background color."""
# Simulate UI change
print(f"\n🎨 Background color changed to {color}")
return f"Background changed to {color}"Creating an AG-UI Client with Frontend Tools
Here's a complete client implementation with frontend tools:
"""AG-UI client with frontend tools."""
import asyncio
import json
import os
from typing import Annotated, AsyncIterator
import httpx
from pydantic import BaseModel, Field
class SensorReading(BaseModel):
"""Sensor reading from client device."""
temperature: float
humidity: float
air_quality_index: int
# Define frontend tools
def read_climate_sensors(
include_temperature: Annotated[bool, Field(description="Include temperature")] = True,
include_humidity: Annotated[bool, Field(description="Include humidity")] = True,
) -> SensorReading:
"""Read climate sensor data from the client device."""
return SensorReading(
temperature=22.5 if include_temperature else 0.0,
humidity=45.0 if include_humidity else 0.0,
air_quality_index=75,
)
def get_user_location() -> dict:
"""Get the user's current GPS location."""
# Simulate GPS reading
return {
"latitude": 52.3676,
"longitude": 4.9041,
"accuracy": 10.0,
"city": "Amsterdam",
}
# Tool registry maps tool names to functions
FRONTEND_TOOLS = {
"read_climate_sensors": read_climate_sensors,
"get_user_location": get_user_location,
}
class AGUIClientWithTools:
"""AG-UI client with frontend tool support."""
def __init__(self, server_url: str, tools: dict):
self.server_url = server_url
self.tools = tools
self.thread_id: str | None = None
async def send_message(self, message: str) -> AsyncIterator[dict]:
"""Send a message and handle streaming response with tool execution."""
# Prepare tool declarations for the server
tool_declarations = []
for name, func in self.tools.items():
tool_declarations.append({
"name": name,
"description": func.__doc__ or "",
# Add parameter schema from function signature
})
request_data = {
"messages": [
{"role": "system", "content": "You are a helpful assistant with access to client tools."},
{"role": "user", "content": message},
],
"tools": tool_declarations, # Send tool declarations to server
}
if self.thread_id:
request_data["thread_id"] = self.thread_id
async with httpx.AsyncClient(timeout=60.0) as client:
async with client.stream(
"POST",
self.server_url,
json=request_data,
headers={"Accept": "text/event-stream"},
) as response:
response.raise_for_status()
async for line in response.aiter_lines():
if line.startswith("data: "):
data = line[6:]
try:
event = json.loads(data)
# Handle tool call requests from server
if event.get("type") == "TOOL_CALL_REQUEST":
await self._handle_tool_call(event, client)
else:
yield event
# Capture thread_id
if event.get("type") == "RUN_STARTED" and not self.thread_id:
self.thread_id = event.get("threadId")
except json.JSONDecodeError:
continue
async def _handle_tool_call(self, event: dict, client: httpx.AsyncClient):
"""Execute frontend tool and send result back to server."""
tool_name = event.get("toolName")
tool_call_id = event.get("toolCallId")
arguments = event.get("arguments", {})
print(f"\n\033[95m[Client Tool Call: {tool_name}]\033[0m")
print(f" Arguments: {arguments}")
try:
# Execute the tool
tool_func = self.tools.get(tool_name)
if not tool_func:
raise ValueError(f"Unknown tool: {tool_name}")
result = tool_func(**arguments)
# Convert Pydantic models to dict
if hasattr(result, "model_dump"):
result = result.model_dump()
print(f"\033[94m[Client Tool Result: {result}]\033[0m")
# Send result back to server
await client.post(
f"{self.server_url}/tool_result",
json={
"tool_call_id": tool_call_id,
"result": result,
},
)
except Exception as e:
print(f"\033[91m[Tool Error: {e}]\033[0m")
# Send error back to server
await client.post(
f"{self.server_url}/tool_result",
json={
"tool_call_id": tool_call_id,
"error": str(e),
},
)
async def main():
"""Main client loop with frontend tools."""
server_url = os.environ.get("AGUI_SERVER_URL", "http://127.0.0.1:8888/")
print(f"Connecting to AG-UI server at: {server_url}\n")
client = AGUIClientWithTools(server_url, FRONTEND_TOOLS)
try:
while True:
message = input("\nUser (:q or quit to exit): ")
if not message.strip():
continue
if message.lower() in (":q", "quit"):
break
print()
async for event in client.send_message(message):
event_type = event.get("type", "")
if event_type == "RUN_STARTED":
print(f"\033[93m[Run Started]\033[0m")
elif event_type == "TEXT_MESSAGE_CONTENT":
print(f"\033[96m{event.get('delta', '')}\033[0m", end="", flush=True)
elif event_type == "RUN_FINISHED":
print(f"\n\033[92m[Run Finished]\033[0m")
elif event_type == "RUN_ERROR":
error_msg = event.get("message", "Unknown error")
print(f"\n\033[91m[Error: {error_msg}]\033[0m")
print()
except KeyboardInterrupt:
print("\n\nExiting...")
except Exception as e:
print(f"\n\033[91mError: {e}\033[0m")
if __name__ == "__main__":
asyncio.run(main())How Frontend Tools Work
Protocol Flow
1. Client Registration: Client sends tool declarations (names, descriptions, parameters) to server 2. Server Orchestration: AI agent decides when to call frontend tools based on user request 3. Tool Call Request: Server sends TOOL_CALL_REQUEST event to client via SSE 4. Client Execution: Client executes the tool locally 5. Result Submission: Client sends result back to server via POST request 6. Agent Processing: Server incorporates result and continues response
Key Events
- `TOOL_CALL_REQUEST`: Server requests frontend tool execution
- `TOOL_CALL_RESULT`: Client submits execution result (via HTTP POST)
Expected Output
User (:q or quit to exit): What's the temperature reading from my sensors?
[Run Started]
[Client Tool Call: read_climate_sensors]
Arguments: {'include_temperature': True, 'include_humidity': True}
[Client Tool Result: {'temperature': 22.5, 'humidity': 45.0, 'air_quality_index': 75}]
Based on your sensor readings, the current temperature is 22.5°C and the
humidity is at 45%. These are comfortable conditions!
[Run Finished]Server Setup
The standard AG-UI server from the Getting Started tutorial automatically supports frontend tools. No changes needed on the server side - it handles tool orchestration automatically.
Best Practices
Security
def access_sensitive_data() -> str:
"""Access user's sensitive data."""
# Always check permissions first
if not has_permission():
return "Error: Permission denied"
try:
# Access data
return "Data retrieved"
except Exception as e:
# Don't expose internal errors
return "Unable to access data"Error Handling
def read_file(path: str) -> str:
"""Read a local file."""
try:
with open(path, "r") as f:
return f.read()
except FileNotFoundError:
return f"Error: File not found: {path}"
except PermissionError:
return f"Error: Permission denied: {path}"
except Exception as e:
return f"Error reading file: {str(e)}"Async Operations
async def capture_photo() -> str:
"""Capture a photo from device camera."""
# Simulate camera access
await asyncio.sleep(1)
return "photo_12345.jpg"Troubleshooting
Tools Not Being Called
1. Ensure tool declarations are sent to server 2. Verify tool descriptions clearly indicate purpose 3. Check server logs for tool registration
Execution Errors
1. Add comprehensive error handling 2. Validate parameters before processing 3. Return user-friendly error messages 4. Log errors for debugging
Type Issues
1. Use Pydantic models for complex types 2. Convert models to dicts before serialization 3. Handle type conversions explicitly
Next Steps
- [Backend Tool Rendering](backend-tool-rendering.md): Combine with server-side tools
<!-- - [Human-in-the-Loop](human-in-the-loop.md): Add approval workflows --> <!-- - [State Management](state-management.md): Share state between client and server -->
Additional Resources
- AG-UI Overview
- Getting Started Tutorial
- Agent Framework Documentation
::: zone-end
Getting Started with AG-UI
This tutorial demonstrates how to build both server and client applications using the AG-UI protocol with .NET or Python and Agent Framework. You'll learn how to create an AG-UI server that hosts an AI agent and a client that connects to it for interactive conversations.
What You'll Build
By the end of this tutorial, you'll have:
- An AG-UI server hosting an AI agent accessible via HTTP
- A client application that connects to the server and streams responses
- Understanding of how the AG-UI protocol works with Agent Framework
::: zone pivot="programming-language-csharp"
Prerequisites
Before you begin, ensure you have the following:
- .NET 8.0 or later
- Azure OpenAI service endpoint and deployment configured
- Azure CLI installed and authenticated
- User has the
Cognitive Services OpenAI Contributorrole for the Azure OpenAI resource
[!NOTE]
These samples use Azure OpenAI models. For more information, see how to deploy Azure OpenAI models with Azure AI Foundry.
[!NOTE]
These samples useDefaultAzureCredentialfor authentication. Make sure you're authenticated with Azure (e.g., viaaz login). For more information, see the Azure Identity documentation.
[!WARNING]
The AG-UI protocol is still under development and subject to change. We will keep these samples updated as the protocol evolves.
Step 1: Creating an AG-UI Server
The AG-UI server hosts your AI agent and exposes it via HTTP endpoints using ASP.NET Core.
[!NOTE]
The server project requires theMicrosoft.NET.Sdk.WebSDK. If you're creating a new project from scratch, usedotnet new webor ensure your.csprojfile uses<Project Sdk="Microsoft.NET.Sdk.Web">instead ofMicrosoft.NET.Sdk.
Install Required Packages
Install the necessary packages for the server:
dotnet add package Microsoft.Agents.AI.Hosting.AGUI.AspNetCore --prerelease
dotnet add package Azure.AI.OpenAI --prerelease
dotnet add package Azure.Identity
dotnet add package Microsoft.Extensions.AI.OpenAI --prerelease[!NOTE]
TheMicrosoft.Extensions.AI.OpenAIpackage is required for theAsIChatClient()extension method that converts OpenAI'sChatClientto theIChatClientinterface expected by Agent Framework.
Server Code
Create a file named Program.cs:
// Copyright (c) Microsoft. All rights reserved.
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI.Hosting.AGUI.AspNetCore;
using Microsoft.Extensions.AI;
using OpenAI.Chat;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient().AddLogging();
builder.Services.AddAGUI();
WebApplication app = builder.Build();
string endpoint = builder.Configuration["AZURE_OPENAI_ENDPOINT"]
?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
string deploymentName = builder.Configuration["AZURE_OPENAI_DEPLOYMENT_NAME"]
?? throw new InvalidOperationException("AZURE_OPENAI_DEPLOYMENT_NAME is not set.");
// Create the AI agent
ChatClient chatClient = new AzureOpenAIClient(
new Uri(endpoint),
new DefaultAzureCredential())
.GetChatClient(deploymentName);
AIAgent agent = chatClient.AsIChatClient().AsAIAgent(
name: "AGUIAssistant",
instructions: "You are a helpful assistant.");
// Map the AG-UI agent endpoint
app.MapAGUI("/", agent);
await app.RunAsync();Key Concepts
- `AddAGUI`: Registers AG-UI services with the dependency injection container
- `MapAGUI`: Extension method that registers the AG-UI endpoint with automatic request/response handling and SSE streaming
- `ChatClient` and `AsIChatClient()`:
AzureOpenAIClient.GetChatClient()returns OpenAI'sChatClienttype. TheAsIChatClient()extension method (fromMicrosoft.Extensions.AI.OpenAI) converts it to theIChatClientinterface required by Agent Framework - `AsAIAgent`: Creates an Agent Framework agent from an
IChatClient - ASP.NET Core Integration: Uses ASP.NET Core's native async support for streaming responses
- Instructions: The agent is created with default instructions, which can be overridden by client messages
- Configuration:
AzureOpenAIClientwithDefaultAzureCredentialprovides secure authentication
Configure and Run the Server
Set the required environment variables:
export AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/"
export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-mini"Run the server:
dotnet run --urls http://localhost:8888The server will start listening on http://localhost:8888.
[!NOTE]
Keep this server running while you set up and run the client in Step 2. Both the server and client need to run simultaneously for the complete system to work.
Step 2: Creating an AG-UI Client
The AG-UI client connects to the remote server and displays streaming responses.
[!IMPORTANT]
Before running the client, ensure the AG-UI server from Step 1 is running at http://localhost:8888.Install Required Packages
Install the AG-UI client library:
dotnet add package Microsoft.Agents.AI.AGUI --prerelease
dotnet add package Microsoft.Agents.AI --prerelease[!NOTE]
TheMicrosoft.Agents.AIpackage provides theAsAIAgent()extension method.
Client Code
Create a file named Program.cs:
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.AGUI;
using Microsoft.Extensions.AI;
string serverUrl = Environment.GetEnvironmentVariable("AGUI_SERVER_URL") ?? "http://localhost:8888";
Console.WriteLine($"Connecting to AG-UI server at: {serverUrl}\n");
// Create the AG-UI client agent
using HttpClient httpClient = new()
{
Timeout = TimeSpan.FromSeconds(60)
};
AGUIChatClient chatClient = new(httpClient, serverUrl);
AIAgent agent = chatClient.AsAIAgent(
name: "agui-client",
description: "AG-UI Client Agent");
AgentThread thread = await agent.GetNewThreadAsync();
List<ChatMessage> messages =
[
new(ChatRole.System, "You are a helpful assistant.")
];
try
{
while (true)
{
// Get user input
Console.Write("\nUser (:q or quit to exit): ");
string? message = Console.ReadLine();
if (string.IsNullOrWhiteSpace(message))
{
Console.WriteLine("Request cannot be empty.");
continue;
}
if (message is ":q" or "quit")
{
break;
}
messages.Add(new ChatMessage(ChatRole.User, message));
// Stream the response
bool isFirstUpdate = true;
string? threadId = null;
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(messages, thread))
{
ChatResponseUpdate chatUpdate = update.AsChatResponseUpdate();
// First update indicates run started
if (isFirstUpdate)
{
threadId = chatUpdate.ConversationId;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"\n[Run Started - Thread: {chatUpdate.ConversationId}, Run: {chatUpdate.ResponseId}]");
Console.ResetColor();
isFirstUpdate = false;
}
// Display streaming text content
foreach (AIContent content in update.Contents)
{
if (content is TextContent textContent)
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write(textContent.Text);
Console.ResetColor();
}
else if (content is ErrorContent errorContent)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"\n[Error: {errorContent.Message}]");
Console.ResetColor();
}
}
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"\n[Run Finished - Thread: {threadId}]");
Console.ResetColor();
}
}
catch (Exception ex)
{
Console.WriteLine($"\nAn error occurred: {ex.Message}");
}Key Concepts
- Server-Sent Events (SSE): The protocol uses SSE for streaming responses
- AGUIChatClient: Client class that connects to AG-UI servers and implements
IChatClient - AsAIAgent: Extension method on
AGUIChatClientto create an agent from the client - RunStreamingAsync: Streams responses as
AgentResponseUpdateobjects - AsChatResponseUpdate: Extension method to access chat-specific properties like
ConversationIdandResponseId - Thread Management: The
AgentThreadmaintains conversation context across requests - Content Types: Responses include
TextContentfor messages andErrorContentfor errors
Configure and Run the Client
Optionally set a custom server URL:
export AGUI_SERVER_URL="http://localhost:8888"Run the client in a separate terminal (ensure the server from Step 1 is running):
dotnet runStep 3: Testing the Complete System
With both the server and client running, you can now test the complete system.
Expected Output
$ dotnet run
Connecting to AG-UI server at: http://localhost:8888
User (:q or quit to exit): What is 2 + 2?
[Run Started - Thread: thread_abc123, Run: run_xyz789]
2 + 2 equals 4.
[Run Finished - Thread: thread_abc123]
User (:q or quit to exit): Tell me a fun fact about space
[Run Started - Thread: thread_abc123, Run: run_def456]
Here's a fun fact: A day on Venus is longer than its year! Venus takes
about 243 Earth days to rotate once on its axis, but only about 225 Earth
days to orbit the Sun.
[Run Finished - Thread: thread_abc123]
User (:q or quit to exit): :qColor-Coded Output
The client displays different content types with distinct colors:
- Yellow: Run started notifications
- Cyan: Agent text responses (streamed in real-time)
- Green: Run completion notifications
- Red: Error messages
How It Works
Server-Side Flow
1. Client sends HTTP POST request with messages 2. ASP.NET Core endpoint receives the request via MapAGUI 3. Agent processes the messages using Agent Framework 4. Responses are converted to AG-UI events 5. Events are streamed back as Server-Sent Events (SSE) 6. Connection closes when the run completes
Client-Side Flow
1. AGUIChatClient sends HTTP POST request to server endpoint 2. Server responds with SSE stream 3. Client parses incoming events into AgentResponseUpdate objects 4. Each update is displayed based on its content type 5. ConversationId is captured for conversation continuity 6. Stream completes when run finishes
Protocol Details
The AG-UI protocol uses:
- HTTP POST for sending requests
- Server-Sent Events (SSE) for streaming responses
- JSON for event serialization
- Thread IDs (as
ConversationId) for maintaining conversation context - Run IDs (as
ResponseId) for tracking individual executions
Next Steps
Now that you understand the basics of AG-UI, you can:
- [Add Backend Tools](backend-tool-rendering.md): Create custom function tools for your domain
<!-- - [Implement Human-in-the-Loop](human-in-the-loop.md): Add approval workflows for sensitive operations --> <!-- - [Manage State](state-management.md): Implement shared state for generative UI applications -->
Additional Resources
- AG-UI Overview
- Agent Framework Documentation
- AG-UI Protocol Specification
::: zone-end
::: zone pivot="programming-language-python"
Prerequisites
Before you begin, ensure you have the following:
- Python 3.10 or later
- Azure OpenAI service endpoint and deployment configured
- Azure CLI installed and authenticated
- User has the
Cognitive Services OpenAI Contributorrole for the Azure OpenAI resource
[!NOTE]
These samples use Azure OpenAI models. For more information, see how to deploy Azure OpenAI models with Azure AI Foundry.
[!NOTE]
These samples useDefaultAzureCredentialfor authentication. Make sure you're authenticated with Azure (e.g., viaaz login). For more information, see the Azure Identity documentation.
[!WARNING]
The AG-UI protocol is still under development and subject to change. We will keep these samples updated as the protocol evolves.
Step 1: Creating an AG-UI Server
The AG-UI server hosts your AI agent and exposes it via HTTP endpoints using FastAPI.
Install Required Packages
Install the necessary packages for the server:
pip install agent-framework-ag-ui --preOr using uv:
uv pip install agent-framework-ag-ui --prerelease=allowThis will automatically install agent-framework-core, fastapi, and uvicorn as dependencies.
Server Code
Create a file named server.py:
"""AG-UI server example."""
import os
from agent_framework import ChatAgent
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework_ag_ui import add_agent_framework_fastapi_endpoint
from azure.identity import AzureCliCredential
from fastapi import FastAPI
# Read required configuration
endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT")
deployment_name = os.environ.get("AZURE_OPENAI_DEPLOYMENT_NAME")
if not endpoint:
raise ValueError("AZURE_OPENAI_ENDPOINT environment variable is required")
if not deployment_name:
raise ValueError("AZURE_OPENAI_DEPLOYMENT_NAME environment variable is required")
chat_client = AzureOpenAIChatClient(
credential=AzureCliCredential(),
endpoint=endpoint,
deployment_name=deployment_name,
)
# Create the AI agent
agent = ChatAgent(
name="AGUIAssistant",
instructions="You are a helpful assistant.",
chat_client=chat_client,
)
# Create FastAPI app
app = FastAPI(title="AG-UI Server")
# Register the AG-UI endpoint
add_agent_framework_fastapi_endpoint(app, agent, "/")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8888)Key Concepts
- `add_agent_framework_fastapi_endpoint`: Registers the AG-UI endpoint with automatic request/response handling and SSE streaming
- `ChatAgent`: The Agent Framework agent that will handle incoming requests
- FastAPI Integration: Uses FastAPI's native async support for streaming responses
- Instructions: The agent is created with default instructions, which can be overridden by client messages
- Configuration:
AzureOpenAIChatClientreads from environment variables or accepts parameters directly
Configure and Run the Server
Set the required environment variables:
export AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/"
export AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o-mini"Run the server:
python server.pyOr using uvicorn directly:
uvicorn server:app --host 127.0.0.1 --port 8888The server will start listening on http://127.0.0.1:8888.
Step 2: Creating an AG-UI Client
The AG-UI client connects to the remote server and displays streaming responses.
Install Required Packages
The AG-UI package is already installed, which includes the AGUIChatClient:
# Already installed with agent-framework-ag-ui
pip install agent-framework-ag-ui --preClient Code
Create a file named client.py:
"""AG-UI client example."""
import asyncio
import os
from agent_framework import ChatAgent
from agent_framework_ag_ui import AGUIChatClient
async def main():
"""Main client loop."""
# Get server URL from environment or use default
server_url = os.environ.get("AGUI_SERVER_URL", "http://127.0.0.1:8888/")
print(f"Connecting to AG-UI server at: {server_url}\n")
# Create AG-UI chat client
chat_client = AGUIChatClient(server_url=server_url)
# Create agent with the chat client
agent = ChatAgent(
name="ClientAgent",
chat_client=chat_client,
instructions="You are a helpful assistant.",
)
# Get a thread for conversation continuity
thread = agent.get_new_thread()
try:
while True:
# Get user input
message = input("\nUser (:q or quit to exit): ")
if not message.strip():
print("Request cannot be empty.")
continue
if message.lower() in (":q", "quit"):
break
# Stream the agent response
print("\nAssistant: ", end="", flush=True)
async for update in agent.run_stream(message, thread=thread):
# Print text content as it streams
if update.text:
print(f"\033[96m{update.text}\033[0m", end="", flush=True)
print("\n")
except KeyboardInterrupt:
print("\n\nExiting...")
except Exception as e:
print(f"\n\033[91mAn error occurred: {e}\033[0m")
if __name__ == "__main__":
asyncio.run(main())Key Concepts
- Server-Sent Events (SSE): The protocol uses SSE format (
data: {json}\n\n) - Event Types: Different events provide metadata and content (UPPERCASE with underscores):
RUN_STARTED: Agent has started processingTEXT_MESSAGE_START: Start of a text message from the agentTEXT_MESSAGE_CONTENT: Incremental text streamed from the agent (withdeltafield)TEXT_MESSAGE_END: End of a text messageRUN_FINISHED: Successful completionRUN_ERROR: Error information- Field Naming: Event fields use camelCase (e.g.,
threadId,runId,messageId) - Thread Management: The
threadIdmaintains conversation context across requests - Client-Side Instructions: System messages are sent from the client
Configure and Run the Client
Optionally set a custom server URL:
export AGUI_SERVER_URL="http://127.0.0.1:8888/"Run the client (in a separate terminal):
python client.pyStep 3: Testing the Complete System
With both the server and client running, you can now test the complete system.
Expected Output
$ python client.py
Connecting to AG-UI server at: http://127.0.0.1:8888/
User (:q or quit to exit): What is 2 + 2?
[Run Started - Thread: abc123, Run: xyz789]
2 + 2 equals 4.
[Run Finished - Thread: abc123, Run: xyz789]
User (:q or quit to exit): Tell me a fun fact about space
[Run Started - Thread: abc123, Run: def456]
Here's a fun fact: A day on Venus is longer than its year! Venus takes
about 243 Earth days to rotate once on its axis, but only about 225 Earth
days to orbit the Sun.
[Run Finished - Thread: abc123, Run: def456]
User (:q or quit to exit): :qColor-Coded Output
The client displays different content types with distinct colors:
- Yellow: Run started notifications
- Cyan: Agent text responses (streamed in real-time)
- Green: Run completion notifications
- Red: Error messages
Testing with curl (Optional)
Before running the client, you can test the server manually using curl:
curl -N http://127.0.0.1:8888/ \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"messages": [
{"role": "user", "content": "What is 2 + 2?"}
]
}'You should see Server-Sent Events streaming back:
data: {"type":"RUN_STARTED","threadId":"...","runId":"..."}
data: {"type":"TEXT_MESSAGE_START","messageId":"...","role":"assistant"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"...","delta":"The"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"...","delta":" answer"}
...
data: {"type":"TEXT_MESSAGE_END","messageId":"..."}
data: {"type":"RUN_FINISHED","threadId":"...","runId":"..."}How It Works
Server-Side Flow
1. Client sends HTTP POST request with messages 2. FastAPI endpoint receives the request 3. AgentFrameworkAgent wrapper orchestrates the execution 4. Agent processes the messages using Agent Framework 5. AgentFrameworkEventBridge converts agent updates to AG-UI events 6. Responses are streamed back as Server-Sent Events (SSE) 7. Connection closes when the run completes
Client-Side Flow
1. Client sends HTTP POST request to server endpoint 2. Server responds with SSE stream 3. Client parses incoming data: lines as JSON events 4. Each event is displayed based on its type 5. threadId is captured for conversation continuity 6. Stream completes when RUN_FINISHED event arrives
Protocol Details
The AG-UI protocol uses:
- HTTP POST for sending requests
- Server-Sent Events (SSE) for streaming responses
- JSON for event serialization
- Thread IDs for maintaining conversation context
- Run IDs for tracking individual executions
- Event type naming: UPPERCASE with underscores (e.g.,
RUN_STARTED,TEXT_MESSAGE_CONTENT) - Field naming: camelCase (e.g.,
threadId,runId,messageId)
Common Patterns
Custom Server Configuration
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# Add CORS for web clients
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
add_agent_framework_fastapi_endpoint(app, agent, "/agent")Multiple Agents
app = FastAPI()
weather_agent = ChatAgent(name="weather", ...)
finance_agent = ChatAgent(name="finance", ...)
add_agent_framework_fastapi_endpoint(app, weather_agent, "/weather")
add_agent_framework_fastapi_endpoint(app, finance_agent, "/finance")Error Handling
try:
async for event in client.send_message(message):
if event.get("type") == "RUN_ERROR":
error_msg = event.get("message", "Unknown error")
print(f"Error: {error_msg}")
# Handle error appropriately
except httpx.HTTPError as e:
print(f"HTTP error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")Troubleshooting
Connection Refused
Ensure the server is running before starting the client:
# Terminal 1
python server.py
# Terminal 2 (after server starts)
python client.pyAuthentication Errors
Make sure you're authenticated with Azure:
az loginVerify you have the correct role assignment on the Azure OpenAI resource.
Streaming Not Working
Check that your client timeout is sufficient:
httpx.AsyncClient(timeout=60.0) # 60 seconds should be enoughFor long-running agents, increase the timeout accordingly.
Thread Context Lost
The client automatically manages thread continuity. If context is lost:
1. Check that threadId is being captured from RUN_STARTED events 2. Ensure the same client instance is used across messages 3. Verify the server is receiving the thread_id in subsequent requests
Next Steps
Now that you understand the basics of AG-UI, you can:
- [Add Backend Tools](backend-tool-rendering.md): Create custom function tools for your domain
<!-- - [Implement Human-in-the-Loop](human-in-the-loop.md): Add approval workflows for sensitive operations --> <!-- - [Manage State](state-management.md): Implement shared state for generative UI applications -->
Additional Resources
- AG-UI Overview
- Agent Framework Documentation
- AG-UI Protocol Specification
::: zone-end
AG-UI Integration with Agent Framework
AG-UI is a protocol that enables you to build web-based AI agent applications with advanced features like real-time streaming, state management, and interactive UI components. The Agent Framework AG-UI integration provides seamless connectivity between your agents and web clients.
What is AG-UI?
AG-UI is a standardized protocol for building AI agent interfaces that provides:
- Remote Agent Hosting: Deploy AI agents as web services accessible by multiple clients
- Real-time Streaming: Stream agent responses using Server-Sent Events (SSE) for immediate feedback
- Standardized Communication: Consistent message format for reliable agent interactions
- Thread Management: Maintain conversation context across multiple requests
- Advanced Features: Human-in-the-loop approvals, state synchronization, and custom UI rendering
When to Use AG-UI
Consider using AG-UI when you need to:
- Build web or mobile applications that interact with AI agents
- Deploy agents as services accessible by multiple concurrent users
- Stream agent responses in real-time to provide immediate user feedback
- Implement approval workflows where users confirm actions before execution
- Synchronize state between client and server for interactive experiences
- Render custom UI components based on agent tool calls
Supported Features
The Agent Framework AG-UI integration supports all 7 AG-UI protocol features:
1. Agentic Chat: Basic streaming chat with automatic tool calling 2. Backend Tool Rendering: Tools executed on backend with results streamed to client 3. Human in the Loop: Function approval requests for user confirmation 4. Agentic Generative UI: Async tools for long-running operations with progress updates 5. Tool-based Generative UI: Custom UI components rendered based on tool calls 6. Shared State: Bidirectional state synchronization between client and server 7. Predictive State Updates: Stream tool arguments as optimistic state updates
Build agent UIs with CopilotKit
CopilotKit provides rich UI components for building agent user interfaces based on the standard AG-UI protocol. CopilotKit supports streaming chat interfaces, frontend & backend tool calling, human-in-the-loop interactions, generative UI, shared state, and much more. You can see a examples of the various agent UI scenarios that CopilotKit supports in the AG-UI Dojo sample application.
CopilotKit helps you focus on your agent’s capabilities while delivering a polished user experience without reinventing the wheel. To learn more about getting started with Microsoft Agent Framework and CopilotKit, see the Microsoft Agent Framework integration for CopilotKit documentation.
::: zone pivot="programming-language-csharp"
AG-UI vs. Direct Agent Usage
While you can run agents directly in your application using Agent Framework's Run and RunStreamingAsync methods, AG-UI provides additional capabilities:
| Feature | Direct Agent Usage | AG-UI Integration |
|---|---|---|
| Deployment | Embedded in application | Remote service via HTTP |
| Client Access | Single application | Multiple clients (web, mobile) |
| Streaming | In-process async iteration | Server-Sent Events (SSE) |
| State Management | Application-managed | Protocol-level state snapshots |
| Thread Context | Application-managed | Protocol-managed thread IDs |
| Approval Workflows | Custom implementation | Built-in middleware pattern |
Architecture Overview
The AG-UI integration uses ASP.NET Core and follows a clean middleware-based architecture:
┌─────────────────┐
│ Web Client │
│ (Browser/App) │
└────────┬────────┘
│ HTTP POST + SSE
▼
┌─────────────────────────┐
│ ASP.NET Core │
│ MapAGUI("/", agent) │
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ AIAgent │
│ (with Middleware) │
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ IChatClient │
│ (Azure OpenAI, etc.) │
└─────────────────────────┘Key Components
- ASP.NET Core Endpoint:
MapAGUIextension method handles HTTP requests and SSE streaming - AIAgent: Agent Framework agent created from
IChatClientor custom implementation - Middleware Pipeline: Optional middleware for approvals, state management, and custom logic
- Protocol Adapter: Converts between Agent Framework types and AG-UI protocol events
- Chat Client: Microsoft.Extensions.AI chat client (Azure OpenAI, OpenAI, Ollama, etc.)
How Agent Framework Translates to AG-UI
Understanding how Agent Framework concepts map to AG-UI helps you build effective integrations:
| Agent Framework Concept | AG-UI Equivalent | Description |
|---|---|---|
AIAgent | Agent Endpoint | Each agent becomes an HTTP endpoint |
agent.Run() | HTTP POST Request | Client sends messages via HTTP |
agent.RunStreamingAsync() | Server-Sent Events | Streaming responses via SSE |
AgentResponseUpdate | AG-UI Events | Converted to protocol events automatically |
AIFunctionFactory.Create() | Backend Tools | Executed on server, results streamed |
ApprovalRequiredAIFunction | Human-in-the-Loop | Middleware converts to approval protocol |
AgentThread | Thread Management | ConversationId maintains context |
ChatResponseFormat.ForJsonSchema<T>() | State Snapshots | Structured output becomes state events |
Installation
The AG-UI integration is included in the ASP.NET Core hosting package:
dotnet add package Microsoft.Agents.AI.Hosting.AGUI.AspNetCoreThis package includes all dependencies needed for AG-UI integration including Microsoft.Extensions.AI.
Next Steps
To get started with AG-UI integration:
1. [Getting Started](getting-started.md): Build your first AG-UI server and client 2. [Backend Tool Rendering](backend-tool-rendering.md): Add function tools to your agents <!-- 3. [Human-in-the-Loop](human-in-the-loop.md): Implement approval workflows --> <!-- 4. [State Management](state-management.md): Synchronize state between client and server -->
Additional Resources
- Agent Framework Documentation
- AG-UI Protocol Documentation
- Microsoft.Extensions.AI Documentation
- Agent Framework GitHub Repository
::: zone-end
::: zone pivot="programming-language-python"
AG-UI vs. Direct Agent Usage
While you can run agents directly in your application using Agent Framework's run and run_streaming methods, AG-UI provides additional capabilities:
| Feature | Direct Agent Usage | AG-UI Integration |
|---|---|---|
| Deployment | Embedded in application | Remote service via HTTP |
| Client Access | Single application | Multiple clients (web, mobile) |
| Streaming | In-process async iteration | Server-Sent Events (SSE) |
| State Management | Application-managed | Bidirectional protocol-level sync |
| Thread Context | Application-managed | Protocol-managed thread IDs |
| Approval Workflows | Custom implementation | Built-in protocol support |
Architecture Overview
The AG-UI integration uses a clean, modular architecture:
┌─────────────────┐
│ Web Client │
│ (Browser/App) │
└────────┬────────┘
│ HTTP POST + SSE
▼
┌─────────────────────────┐
│ FastAPI Endpoint │
│ (add_agent_framework_ │
│ fastapi_endpoint) │
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ AgentFrameworkAgent │
│ (Protocol Wrapper) │
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ Orchestrators │
│ (Execution Flow Logic) │
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ ChatAgent │
│ (Agent Framework) │
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ Chat Client │
│ (Azure OpenAI, etc.) │
└─────────────────────────┘Key Components
- FastAPI Endpoint: HTTP endpoint that handles SSE streaming and request routing
- AgentFrameworkAgent: Lightweight wrapper that adapts Agent Framework agents to AG-UI protocol
- Orchestrators: Handle different execution flows (default, human-in-the-loop, state management)
- Event Bridge: Converts Agent Framework events to AG-UI protocol events
- Message Adapters: Bidirectional conversion between AG-UI and Agent Framework message formats
- Confirmation Strategies: Extensible strategies for domain-specific confirmation messages
How Agent Framework Translates to AG-UI
Understanding how Agent Framework concepts map to AG-UI helps you build effective integrations:
| Agent Framework Concept | AG-UI Equivalent | Description |
|---|---|---|
ChatAgent | Agent Endpoint | Each agent becomes an HTTP endpoint |
agent.run() | HTTP POST Request | Client sends messages via HTTP |
agent.run_streaming() | Server-Sent Events | Streaming responses via SSE |
| Agent response updates | AG-UI Events | TEXT_MESSAGE_CONTENT, TOOL_CALL_START, etc. |
Function tools (@ai_function) | Backend Tools | Executed on server, results streamed to client |
| Tool approval mode | Human-in-the-Loop | Approval requests/responses via protocol |
| Conversation history | Thread Management | threadId maintains context across requests |
Installation
Install the AG-UI integration package:
pip install agent-framework-ag-ui --preThis installs both the core agent framework and AG-UI integration components.
Next Steps
To get started with AG-UI integration:
1. [Getting Started](getting-started.md): Build your first AG-UI server and client 2. [Backend Tool Rendering](backend-tool-rendering.md): Add function tools to your agents <!-- 3. [Human-in-the-Loop](human-in-the-loop.md): Implement approval workflows --> <!-- 4. [State Management](state-management.md): Synchronize state between client and server -->
Additional Resources
- Agent Framework Documentation
- AG-UI Protocol Documentation
- AG-UI Dojo App - Example application demonstrating Agent Framework integration
- Agent Framework GitHub Repository
::: zone-end
Semantic Kernel to Agent Framework Migration Samples
::: zone pivot="programming-language-csharp"
See the Semantic Kernel repository for detailed per agent type code samples showing the the Agent Framework equivalent code for Semantic Kernel features.
::: zone-end ::: zone pivot="programming-language-python"
See the Agent Framework repository for detailed per agent type code samples showing the the Agent Framework equivalent code for Semantic Kernel features.
::: zone-end
Frequently Asked Questions
General
What is Agent Framework?
Microsoft Agent Framework is an open-source SDK for building AI agents that can reason, use tools, and interact with users and other agents. It supports multiple AI providers and languages.
What languages are supported?
Agent Framework currently supports .NET (C#) and Python.
Is Agent Framework open source?
Yes, Agent Framework is open source and available on GitHub.
Getting Help
| Your preference | What's available |
|---|---|
| Read the docs | This learning site is the home of the latest information for developers |
| Visit the repo | Our open-source GitHub repository is available for perusal and suggestions |
| Connect with the Agent Framework Team | Visit our GitHub Discussions |
| Office Hours | We host regular office hours; details at Community.MD |
Support for Agent Framework
👋 Welcome! There are a variety of ways to get supported in the Agent Framework world.
| Your preference | What's available |
|---|---|
| Read the docs | This learning site is the home of the latest information for developers |
| Visit the repo | Our open-source GitHub repository is available for perusal and suggestions |
| Connect with the Agent Framework Team | Visit our GitHub Discussions to get supported quickly with our CoC actively enforced |
| Office Hours | We will be hosting regular office hours; the calendar invites and cadence are located here: Community.MD |
Troubleshooting
This page covers common issues and solutions when working with Agent Framework.
Note
>
This page is being restructured. Common troubleshooting scenarios will be added.
Common Issues
Authentication Errors
Ensure you have the correct credentials configured for your AI provider. For Azure OpenAI, verify:
- Azure CLI is installed and authenticated (
az login) - User has the
Cognitive Services OpenAI UserorCognitive Services OpenAI Contributorrole
Package Installation Issues
Ensure you're using .NET 8.0 SDK or later. Run dotnet --version to check your installed version.
Ensure you're using Python 3.10 or later. Run python --version to check your installed version.
Getting Help
If you can't find a solution here, visit our GitHub Discussions for community support.
Upgrade guides
This .NET skill does not mirror Python-only upgrade guides.
Use the live Microsoft Learn upgrade area if you need cross-language migration notes outside the C# and .NET scope covered by this skill.
Using an agent as a function tool
[!NOTE]
The live Learn URL for this old tutorial now redirects to the canonical Function Tools article.
Keep this local file only as a compatibility alias for existing references inside the skill catalog.
::: zone pivot="programming-language-csharp"
Use AIAgent.AsAIFunction() when one agent needs a bounded specialist capability without escalating to a full workflow.
Current guidance
- keep the delegated behavior narrow and easy to reason about
- keep the outer agent in control of retries, fallbacks, and policy
- escalate to explicit workflows when control flow, approvals, or fan-out logic become important
AIAgent coordinator = chatClient.AsAIAgent(
instructions: "Delegate weather questions when needed.",
tools: [weatherAgent.AsAIFunction()]);For current runnable examples, load:
references/official-docs/tutorials/agents/function-tools.mdreferences/official-docs/user-guide/agents/agent-tools.md
::: zone-end ::: zone pivot="programming-language-python"
The live alias now resolves to the broader Function Tools article. Use the canonical live docs for current Python examples.
::: zone-end
Next steps
- Use
references/official-docs/tutorials/agents/agent-as-mcp-tool.mdwhen the delegated capability should surface as an MCP tool instead of a normal function tool. - Escalate to
references/workflows.mdwhen delegation becomes explicit orchestration instead of bounded tool composition.
Agent Framework User Guide
Welcome to the Agent Framework User Guide. This guide provides comprehensive information for developers and solution architects working with Agent Framework. Here, you'll find detailed explanations of agent concepts, configuration options, advanced features, and best practices for building robust, scalable agent-based applications. Whether you're just getting started or looking to deepen your expertise, this guide will help you understand how to leverage the full capabilities of Agent Framework in your projects.