The final lesson: a recipe agent whose JSON replies are turned into trackable state snapshots by a middleware, so the client can render the recipe as it evolves.
The server side of AG-UI state management: middleware emits a DataContent state snapshot from the model's JSON so the client can adopt shared state across turns.
Seven patterns that turn a bare model call into production agent infrastructure — each written first as offline Go behind an interface, so the leap to Azure is a swap, not a rewrite.
Seven patterns that turn a bare model call into production agent infrastructure, each written first as offline Go behind an interface (the seam) so the leap to Azure is a swap, not a rewrite.
The server hosts an agent with one approval-gated tool — the model may propose calling it, but the framework refuses to run it until a human on the other end says yes.
The server side of AG-UI human-in-the-loop: gate a tool with tool.ApprovalRequiredFunc so the server suspends the run and resumes on the client's decision.
The mirror image of backend tools: the server hosts the agent but the tools live on the client, so the handler must forward tool calls instead of running them.
The server side of AG-UI frontend tools: set DisableFuncAutoCall so the server forwards tool calls to the client to execute and awaits the result.
Wrapping Go agents in A2A, MCP, and AG-UI transports, then a full client/server app that ties the whole series together.
Wrap Go agents in A2A, MCP, and AG-UI transports, then run the end-to-end client/server capstone where a host agent uses remote specialists as tools.
Same AG-UI transport as the getting-started server, but now the hosted agent carries a tool the model can call server-side while it answers.
The server side of AG-UI backend tools: attach server-owned function tools to the Foundry agent so the tool round-trip stays entirely server-side.
Durable workflows in Go: checkpoint and rehydrate, pause on a RequestPort for a human, nest sub-workflows, and coordinate through scoped shared state.
Durable MAF workflows in Go: checkpoint and rehydrate a fresh graph, pause on a RequestPort for a human, nest sub-workflows, and coordinate via scoped shared state.
The client half streams events over SSE; this is the process on the other end of the wire — a Foundry agent wrapped in an HTTP handler that speaks AG-UI.
The AG-UI server half: wrap a Foundry agent in aguiprovider.NewJSONHTTPHandler and serve it over HTTP/SSE for any AG-UI client to drive.
The prebuilt orchestration builders in agent-framework-go — Sequential, Concurrent, Group Chat — plus wrapping a whole workflow as one agent.
The Sequential, Concurrent, and Group Chat orchestration builders in agent-framework-go, plus wrapping a whole workflow as one nestable agent.
The final lesson ties the whole Go tutorial into one small product: an assistant that answers questions about your docs — grounded, cited, and refusing to guess.
The capstone: a grounded DocQA agent that answers only from embedded docs via a search_docs tool, cites sources, and refuses to guess — with an optional reviewer.
Agents as graph executors in Go: switch routing, fan-out/fan-in barriers, and mixing typed function nodes with agent nodes.
Agents as Go workflow executors: switch routing, fan-out and fan-in barriers, and mixing typed function nodes with agent nodes in one graph.
This lesson hosts one specialized Foundry agent over the A2A protocol, publishing an agent card the client can discover.
Host one Foundry agent over A2A: newMux pins the card interface URL, wraps the agent in an a2aprovider executor, and serves the card plus JSON-RPC routes.
The graph model underneath every multi-agent app: executors as nodes, edges as data flow, and typed events streaming out of `WatchStream` as it runs.
The MAF workflow model in Go: executors bound to IDs, AddEdge wiring, WithOutputFrom, and typed WatchStream events - plus an upstream route-builder fix.
This lesson builds a Foundry host agent that discovers remote A2A agents by their cards and calls each one as a tool.
A Foundry host agent resolves remote A2A agent cards and turns each remote agent into a callable tool with agenttool.New over the a2aprovider.
Wrap every run in an OpenTelemetry span, gate risky tool actions behind a permission handler, and swap model providers behind one agent.Agent.
Wrap every MAF run in an OpenTelemetry span, gate risky tool actions behind a permission handler, and swap Anthropic, OpenAI, Gemini, Copilot, and Azure behind one agent.
How a whole workflow binds as a single executor inside a larger workflow, so pipelines compose two levels deep.
inproc.BindSubworkflowAsExecutor binds a whole workflow as one node; an order pipeline nests Payment and FraudCheck two levels deep, and inner events still bubble up.
A guardrail that blocks a run before the model, chained ahead of a logger — and the upstream nil-update panic I fixed along the way.
A guardrail middleware that blocks an MAF Go run before the model, chained ahead of a logger — plus the tool-approval nil-update panic I fixed upstream in PR #472.
How one executor stores a value in scoped shared state and later executors read it back — instead of copying a whole payload down every edge.
One executor stores a document with QueueStateUpdate; fan-out counters read it back with ReadState, and an AddFanInBarrierEdge aggregates once both deliver. Offline.
Decoding typed structs from a run, draining a streamed response, and sending an image with `RunMessage`.
Decode typed structs from a run, drain a streamed response by ranging it, and send an image with RunMessage and DataContent.
How WithTelemetry instruments a whole workflow with OpenTelemetry spans, then agentworkflow.NewAgent wraps the graph so it behaves like one agent.
WithTelemetry instruments a French-to-English workflow with OpenTelemetry spans, then agentworkflow.NewAgent wraps the graph so RunText drives the whole pipeline.
A Session threads history into each run; a ContextProvider carries memory across sessions — and because a Session is JSON, both survive a process restart.
A Session threads history into each run and a ContextProvider carries memory across sessions. Because a Session is JSON, both survive a process restart.
How a workflow graph forms a cycle: two executors feed each other until one yields an output — the workflow analogue of a while-loop.
A workflow graph is not a DAG: two edges form a GuessNumber to Judge cycle that runs a binary search and exits only when Judge yields an output. The while-loop analogue.
Wrap a typed Go function as a tool, let the model call it, and compose whole agents as tools.
Wrap a typed Go function as a tool with functool.MustNew, let the model call it, and compose whole agents as tools with agenttool.New.
How a RequestPort pauses a workflow, emits a request to a human, and feeds their answer back into the graph.
A RequestPort emits a RequestInfoEvent and suspends the workflow; the driver answers with SendResponse. A guess-the-number cycle shows the pause/resume mechanism.
The minimal loop in Go: a Foundry provider, an Agent with instructions, run collected and streamed — and what RunText hands back.
The minimal MAF loop in Go: a foundryprovider agent, DefaultAzureCredential, and one RunText you either Collect or range over as a Go 1.23 iterator.
How an edge assigner delivers one message to a chosen subset of targets — a multi-way switch that may fall through to more than one case.
WithEdgeAssigner yields target indexes via an iter.Seq[int], so a single message reaches several branches at once — a long email goes to both assistant and summary, offline.
Why I learned the whole framework in Go by writing one runnable lesson per concept, against Azure AI Foundry, instead of reading the docs top to bottom.
I learned the whole Microsoft Agent Framework in Go by building one runnable lesson per concept against Azure AI Foundry. Here is the 12-track map.
How a switch builder fans one edge into three mutually-exclusive branches — the workflow analogue of switch/case/default.
AddSwitch/AddCase/WithDefault fans one edge into three mutually-exclusive branches with a guaranteed fallback — the workflow analogue of switch/case/default, fully offline.
Turning agents into a service you can run and expose, then a full DocQA app that ties the whole series together.
Host MAF agents with DevUI, A2A, MCP, and AG-UI, then build DocQA — a grounded, cited multi-agent app that ties the whole Python series together.
How a graph workflow forks: a predicate on each edge decides whether a message may pass, turning the graph into an if/else expressed as data flow.
The first 03-workflows lesson: AddDirectEdge attaches a func(any) bool to each edge so a spam-detection graph forks into send vs. handle-spam branches, offline.
Durable workflows in Python: checkpoint and resume, pause for a human with request_info, and package a workflow as an agent.
Durable MAF workflows in Python: checkpoint and resume every superstep, suspend on request_info for a human decision, and package a workflow as an agent.
How to express the classic MapReduce word-count as a five-stage workflow graph — fan-out to mappers, barrier to a shuffler, fan-out to reducers, barrier to completion.
MapReduce word-count as a five-stage workflow: fan-out to mappers, barrier to a shuffler, fan-out to reducers, barrier to completion, coordinated via shared state.
Five prebuilt multi-agent shapes — Sequential, Concurrent, Group Chat, Handoff, Magentic — and when each beats hand-wiring a graph.
Sequential, Concurrent, Group Chat, Handoff, Magentic — the five prebuilt MAF orchestrations in Python and when each beats hand-wiring a graph.
How to broadcast one input to several executors in parallel and join their answers with a barrier — the core workflow graph primitives, with no LLM in the way.
A start executor broadcasts a question to two experts via a fan-out edge; a fan-in barrier edge joins both answers before the aggregator yields output.
Agents as graph nodes: switch-case routing, fan-out/fan-in, and mixing plain functions with agent steps in one workflow.
Agents are just workflow executors: switch-case routing, fan-out/fan-in concurrency, and mixing plain function nodes with agent nodes in one graph.
How to pause a workflow to ask a human, checkpoint every super-step, then rewind the whole graph to a saved checkpoint and replay.
A RequestPort pauses to ask a human for a guess while every super-step is checkpointed, then RestoreCheckpoint rewinds the whole graph including tries state.
The graph model underneath every multi-agent app: executors as nodes, edges as data flow, and typed events streaming out as it runs.
The MAF workflow model in Python: executors as nodes, edges as data flow, switch-case routing, and typed streaming events - learned model-free.
How to snapshot a workflow after every super-step, then rewind the same live run to an earlier checkpoint and replay from it.
Same guess-the-number graph, but RestoreCheckpoint rewinds the live run to the 6th snapshot and replays forward — no fresh workflow instance needed.
Turn agent runs into OpenTelemetry spans, block prompt injection with information-flow control, and swap model providers behind one Agent API.
Turn MAF agent runs into OpenTelemetry spans, block prompt injection with information-flow control, and swap model providers behind one Agent API.
How to snapshot a running workflow at every super-step, then throw the instance away and rebuild a fresh workflow that resumes from a saved checkpoint.
A cyclic guess-the-number workflow snapshots state each super-step, then a brand-new workflow instance is rehydrated from a checkpoint via ResumeStreaming.
Wrapping an agent run with async seams that log, time, guard, and short-circuit — without touching the agent's logic.
Wrapping an MAF agent run in Python with async middleware seams — timing, logging, and a guardrail that short-circuits a tool call before it runs.
How to collapse a whole multi-agent workflow into a single agent so callers use it exactly like any leaf agent.
A concurrent French+English workflow is hosted as one agent via agentworkflow.NewAgent, with IncludeOutputsInResponse surfacing the merged output.
Typed results from `response_format`, consuming a stream event by event, and sending an image alongside text.
Three dials on one run() call: typed results via response_format, consuming a stream event by event, and sending an image alongside text.
How a multi-agent group chat pauses to ask a human for approval before one gated tool is allowed to run.
A QA and DevOps agent collaborate in a group chat where DeployToProduction is gated by tool.ApprovalRequiredFunc, pausing the workflow for human approval.
How a stateless agent remembers: sessions carry one conversation, context providers carry knowledge across all of them.
MAF agents are stateless. Sessions carry one conversation; context providers carry memory across all of them. Here is the mental model in real code.
How two Foundry agents cooperate inside a cyclic graph workflow where one of them owns the loop control.
Two Foundry agents cooperate in a cyclic workflow: a SloganWriter drafts, a FeedbackProvider critiques and owns loop control via YieldOutput vs SendMessage.
Turn a plain Python function into something the model can call, and watch the tool-call loop close itself.
Turn a plain Python function into a tool the model can call. The @tool decorator, the tool-call loop, multiple tools, and what the model actually sees.
This lesson teaches how to build a cyclic workflow where a Writer and Critic loop until approval, using `AddSwitch` to route on structured output.
A cyclic Writer-Critic-Summary workflow: the Critic emits a structured CriticDecision, AddSwitch routes on Approved, and Context state caps the revision loop at maxIterations.
The minimal loop: a Foundry chat client, an Agent with instructions, run non-streaming and streaming — and what actually comes back.
The minimal MAF loop in Python: a FoundryChatClient, an Agent whose instructions are its whole personality, run non-streaming and streaming.
This lesson teaches how deterministic function executors and agent-backed executors compose in one graph with the same `AddEdge` wiring.
One workflow that mixes deterministic executors with two Foundry agent nodes for jailbreak detection and response, joined by the same AddEdge wiring and TurnToken triggering.
Why I learned the whole framework by writing one runnable lesson per concept, against Azure AI Foundry, instead of reading the docs top to bottom.
I learned the whole Microsoft Agent Framework in Python by building one runnable lesson per concept against Azure AI Foundry. Here is the 12-track map.
This lesson teaches how to embed a whole built workflow as a single executor inside a larger one — workflows compose.
Embed an entire built workflow as one executor with inproc.BindSubworkflowAsExecutor, composing a Prefix to SubWorkflow to PostProcess parent graph that runs fully offline.
This lesson teaches how to chain three role-specialised agents — researcher → fact_checker → reporter — into one sequential workflow and stream each stage.
A sequential workflow of three role-specialised Foundry agents — researcher, fact_checker, reporter — built with NewSequentialWorkflowBuilder and streamed stage by stage.
This lesson teaches that orchestration is a property of the workflow, not the agents — the same three agents drop into three different built-in graph shapes.
The same three agents dropped into three built-in agentworkflow builders — sequential, concurrent, and round-robin group chat — showing orchestration is a property of the graph, not the agents.
This lesson teaches how to host real `agent.Agent`s as workflow executors and chain them into a sequential pipeline.
Host three translation agents as workflow executors and chain them French to Spanish to English, using DisableForwardIncomingMessages and a TurnToken to drive a strict pipeline.
This lesson teaches how to build a two-executor pipeline and watch it run as a live stream of typed events.
Your first Agent Framework Go workflow: two string executors wired by an edge, run with RunStreaming and watched as a stream of typed events, fully offline.
Compose three kinds of Agent Skill — code-defined, struct-based, and file-based — into a single agent through one skills context provider.
One skills ContextProvider blending three origins: in-memory volume and temperature skills plus a file-based unit-converter, unified behind one tool surface for the model.
An Agent Skill — on-demand instructions, resources, and scripts — defined entirely in Go, with no SKILL.md files on disk.
An Agent Skill built from Go closures: instructions, a static and a runtime-generated resource, and a convert script that runs in-process with no SKILL.md files.
Teach an agent a capability from a folder of files — a SKILL.md manifest, resources, and scripts — loaded on demand via progressive disclosure.
Teach an agent from a SKILL.md manifest, resources, and scripts on disk: fsskills scans the tree and a skills ContextProvider exposes load, read, and run tools.
The provider is the swappable back end: the same Joker agent, one-shot and streaming, now through the OpenAI API.
The same Joker agent, one-shot and streaming, through openaiprovider: openai.NewClient reads OPENAI_API_KEY and the model name lives in AgentConfig, not a Foundry deployment.
A provider whose "credential" is a local process, gated by a human-in-the-loop permission handler for every action the model wants to take.
A provider whose credential is a local copilot CLI process, with an OnPermissionRequest handler that approves or rejects each shell action the model wants to run.
How swapping in the Gemini provider changes the constructor and credential — and nothing else about your agent.
The Joker agent, unchanged, now backed by Google Gemini: geminiprovider.NewAgent takes a genai.Client and an API key instead of an Azure token credential.
Exposing an agent to any HTTP front-end over AG-UI, an SSE protocol, with one FastAPI helper.
AG-UI exposes an agent over HTTP + SSE: one add_agent_framework_fastapi_endpoint call registers a POST route that streams RUN_STARTED through RUN_FINISHED events.
This lesson teaches how to connect to a remote MCP server and decorate the tools it exposes with your own local behavior before an agent uses them.
List a remote MCP server's tools, then wrap each FuncTool with a logging decorator via embedding plus one Call override — MCP tools compose like any tool.FuncTool.
Rendering the OpenTelemetry spans an agent already emits as a timeline with serve(tracing_enabled=True).
DevUI tracing renders the OTel GenAI spans the framework already emits: pass tracing_enabled=True to serve() to see LLM and tool calls as a timeline.
This lesson teaches how to attach the hosted web-search tool and read the citation annotations the service returns with its answer.
Attach hostedtool.WebSearch so Foundry grounds its answer on live results, then pull CitationAnnotations off content headers with a pure, unit-testable extractor.
Serving a whole directory of agents at once by exporting a module-level agent variable.
DevUI directory discovery serves a folder of agents at once: each entity dir exports a module-level agent variable, then devui ./entities finds them all.
This lesson teaches the hosted tool: a marker that lets the Foundry service run code the model writes, instead of a Go function you implement.
Attach hostedtool.CodeInterpreter, a zero-value marker with no Run method, so Foundry executes model-written Python in a sandbox to solve sin(x) + x^2 = 42.
Packaging an agent as a container on Foundry Agent Service with ResponsesHostServer.
A Foundry hosted agent runs as a managed container: wrap the agent in ResponsesHostServer to serve POST /responses, and set store=False so the host owns history.
This lesson teaches how to bundle related function tools onto a Go type and attach the whole group to an agent as one slice.
Bundle GetWeather and GetCurrentTime onto one Go type, expose them as a tool.Tool slice, and let the model call both in a single turn — plugins as an organizing idea.
Speaking the OpenAI Chat Completions and Responses wire protocols on both sides of an agent.
Agent Framework speaks the OpenAI Chat Completions and stateful Responses protocols; the Python pivot consumes any base_url endpoint while a Foundry agent stays the backend brain.
This lesson teaches a middleware chain where a guardrail can block a run before the model is ever called, chained ahead of a logger.
Chain a guardrail middleware that yields its own refusal and skips the model ahead of a logger — short-circuiting a harmful request offline before Foundry is called.
Making agent threads and orchestrations crash-proof with AgentFunctionApp on Durable Task infrastructure.
The Durable Extension checkpoints agent threads on Durable Task infra: wrap agents in AgentFunctionApp and yield durable-wrapper calls inside orchestration triggers.
This lesson teaches the simplest form of multi-agent delegation: wrapping one agent as a tool another agent can call.
Wrap a specialist WeatherAgent with agenttool.New into a tool.Tool and hand it to a French TravelAgent — one model orchestrating another with no workflow engine.
Turning an agent into a network service other agents can call with the A2A protocol.
A2A turns an agent into a network service: consume a remote one with A2AAgent(url=...) or expose your local Foundry agent by wrapping it in A2AExecutor.
This lesson teaches how to send a question and an image together in one message to a vision-capable Foundry agent.
Put a TextContent and a base64 DataContent JPEG in one message and hand it to a vision agent — multimodal input with no upload step, embedded at compile time.
Giving any agent a local chat window plus a live call inspector with agent_framework.devui.serve.
DevUI wraps any Foundry agent in a local chat window plus a live inspector via serve(entities=[agent]) from the separate agent-framework-devui package.
This lesson teaches how a Foundry agent borrows tools from a remote MCP server and calls them as if they were local functions.
Connect a Foundry agent to Microsoft Learn's public MCP endpoint over streamable HTTP, list its tools, and hand the whole slice to the agent as proxied tools.
For open-ended tasks with no known solution path: a manager agent plans, keeps a shared ledger, and round-by-round picks which specialist acts next. Ordering is dynamic, not a fixed graph.
Magentic orchestration puts a manager agent in charge: it plans, keeps a shared ledger, and picks which specialist acts next round by round until it synthesizes an answer.
otelprovider.NewMiddleware wraps every run in an OpenTelemetry span tagged with gen_ai attributes — the same one-line middleware hook you use for logging.
A collaborative conversation among agents, coordinated by an orchestrator that decides who speaks next. Agents share full history and refine each other's work over rounds — a star topology.
Group chat coordinates several agents in a star topology: an orchestrator decides who speaks next while agents share full history and refine each other over rounds.
How to serialize an agent.Session to disk and resume it later, so a follow-up prompt still remembers earlier turns across a process restart.
An agent.Session serializes with encoding/json, so you can marshal it to disk or a database and resume it later with the model still remembering earlier turns.
A mesh of specialists where any agent can transfer the whole conversation to a better-suited peer — no central orchestrator. Control passes agent-to-agent via an auto-injected handoff tool call.
Handoff orchestration lets any agent transfer the whole conversation to a better-suited peer via an auto-injected tool call. Run unattended with autonomous mode.
How to make the model return a typed Go struct instead of prose — hand RunText a pointer, get back populated fields.
Pass RunText a pointer to a Go struct via WithStructuredOutput and the framework asks the model for matching JSON, then unmarshals it straight into your fields.
Run several agents on the same prompt in parallel, then fan their answers back in. `ConcurrentBuilder` wires the fan-out/fan-in graph — latency is max(agent), not sum.
Concurrent orchestration fans one prompt out to several agents in parallel, then fans their answers back in with a built-in aggregator. Latency is max(agent), not sum.
How to gate a sensitive tool behind human consent: the run pauses, hands you an approval request, and only calls the tool once you approve.
Wrap a tool with ApprovalRequiredFunc and the run pauses with a ToolApprovalRequestContent; approve it, feed the decision back on the same session, and the tool fires.
Wire agents into a pipeline where each runs in turn and feeds the next. Hand a list to `SequentialBuilder`, call `.build()`, run it once — draft then review, extract then summarize.
Sequential orchestration chains agents so each runs in turn and feeds the next. Hand a list to SequentialBuilder, build, and run once — draft then review.
How to wrap an ordinary Go function as a tool the model can call, with the schema derived automatically from its types.
Wrap a plain Go func with functool.MustNew and the framework derives its JSON schema and drives the tool call inside a single RunText — two model round-trips, one call.
A whole workflow run as a single executor inside a parent. Wrap the inner graph in `WorkflowExecutor`, drop it into the parent like any node, and compose big systems from small, testable pieces.
Run a whole workflow as one executor inside a parent: wrap the inner graph in WorkflowExecutor, line up its I/O types, and drop it into the parent like any node.
How to keep a conversation's history on the Foundry service instead of in local memory, so the client never resends the transcript.
Create a Foundry project conversation, bind its ID into a session with WithServiceID, and let the service keep the transcript across turns without resending it.
Executor state leaks when you reuse one workflow across independent runs. `.NET` has `IResettableExecutor`; Python's answer is simpler — never share state, build fresh instances from a factory.
Reusing one workflow across runs leaks executor state. .NET has IResettableExecutor; Python's answer is a factory that builds fresh workflow and executor instances per run.
How an agent.Session carries conversation history so a second prompt can refer back to the first.
A client-side agent.Session carries conversation history so a second prompt can refer back to the first. Create it with CreateSession, thread it with WithSession.
The same `workflow.run(...)` graph, consumed two ways — await it to completion, or stream its events live. The `.NET` OffThread/Lockstep modes don't apply to Python.
One workflow.run graph, two modes: await it to completion or iterate stream=True live events. The .NET OffThread/Lockstep modes do not apply to Python.
How the Foundry provider snaps a project endpoint, a credential, and a model deployment name into a runnable agent.
The Foundry provider is three inputs: a project endpoint, a credential, and a model deployment name. See how foundryprovider.NewAgent snaps them into an agent.
Wrapping agents as AgentExecutors explicitly — controlling the id, the context mode, and chaining a writer to a translator that sees only the previous agent's reply.
Wrap agents explicitly as AgentExecutors to set the id and context_mode. last_agent mode feeds a downstream agent only the previous reply, ideal for translate and refine.
Back the agent with Azure OpenAI's Responses API, and toggle whether conversation state lives on the server or locally.
Back an agent with Azure OpenAI Responses via NewResponsesAgent, and use DisableStoreOutput to keep chat history local instead of stored server-side.
WorkflowViz renders a built workflow's graph as a Mermaid diagram, a Graphviz DOT string, or an exported image — so you can eyeball fan-out/fan-in structure without running the agents.
Render a built workflow with WorkflowViz as Mermaid or Graphviz DOT, or export an image. Text formats need no deps; visualization reads graph shape without calling agents.
The same agent primitive, wired to Azure OpenAI's Chat Completions API where the model name is your deployment name.
Back an agent with Azure OpenAI Chat Completions via NewChatCompletionsAgent, where the Model field is your Azure deployment name, not a catalog model ID.
Turn a workflow run into a tree of OpenTelemetry spans — workflow.build, workflow.run, executor.process, edge_group.process, message.send — with one setup call.
Trace a workflow with configure_otel_providers and a root span. The framework emits workflow.build, workflow.run, executor.process, edge_group.process, message.send spans.
Reach a Foundry-hosted model through the OpenAI-compatible Responses API by configuring a plain openai.Client with three request options.
Reach a Foundry model through the OpenAI-compatible API by configuring an openai.Client with base URL, an Azure token credential, and the ai.azure.com scope.
Declare the orchestration in YAML instead of Python — ordered actions load at runtime via WorkflowFactory, with agents resolved by name and PowerFx expressions for logic.
Declare a workflow in YAML and load it with WorkflowFactory. Ordered actions call agents resolved by name, with PowerFx expressions for prompts and variables.
Point the same agent at an Azure AI Foundry project endpoint using the project Responses API mode.
Run an agent against an Azure AI Foundry project: foundryprovider.NewAgent plus ModelDeployment selects project Responses API mode from the project endpoint.
Shared workflow state: any executor writes a keyed value, any later executor reads it back — so big payloads never have to be threaded through every message on the edge.
Share workflow state with ctx.set_state and ctx.get_state so big payloads skip the edge. Writers see updates immediately; other nodes see them the next superstep.
The same agent primitive as the Foundry lessons, backed by the Anthropic (Claude) provider instead of Azure AI Foundry.
A provider swap onto Anthropic Claude: build an anthropic.Client, pass it to anthropicprovider.NewAgent, and run the identical agent surface.
An agent can be a graph node directly — no custom Executor subclass. Writer drafts, a direct edge hands its output to Reviewer, and streamed tokens group by author.
Use an agent as a workflow executor node directly, no subclass needed. Wire Writer to Reviewer with an edge and group streamed AgentResponseUpdate tokens by author.
This lesson swaps the LLM behind an agent for another agent, reached over the A2A protocol instead of a model API.
Back a Go agent with another agent over the A2A protocol: resolve the remote card, open a gRPC client, and wrap it with a2aprovider.NewAgent.
Wiring executors and edges into a graph with WorkflowBuilder — pick a start node, add edges, build, then run an input through the chain.
Build a graph workflow with WorkflowBuilder: set a start executor, add edges, build, and run. Handlers are async and type-annotated; output_from names the terminal node.
How to borrow tools from a remote Model Context Protocol server and hand them to a Foundry agent as ordinary tools.
Connect to Microsoft Learn's public MCP server with mcptool.Connect and ListTools, then hand the borrowed tools to a Foundry agent as ordinary agent.Config.Tools.
Streaming a workflow run so you can watch progress live — built-in lifecycle events plus your own custom ones — all discriminated by a single `.type` string.
Stream a Microsoft Agent Framework workflow with run(stream=True). Every event is one WorkflowEvent keyed by a .type string, plus custom events via ctx.add_event.
How a shared state snapshot rides along with every AG-UI turn, so client and server-hosted agent stay in sync on evolving structured data.
Share a JSON state snapshot across AG-UI turns — server middleware emits a DataContent snapshot from the model's JSON and the client adopts it via toStateContent and extractState.
A workflow and an agent both expose .run() — so package a whole workflow as an agent and drop it anywhere an agent is expected.
A workflow and an agent both expose run(); workflow.as_agent() packages a workflow as an agent whose start executor accepts a list of Message.
How an approval-required tool makes the server pause a run and wait for a human on the client to say yes or no.
Gate a tool behind tool.ApprovalRequiredFunc so the AG-UI server pauses the run, then answer the approval from the client with a message round-trip loop.
Some steps need a person — request_info suspends the workflow and hands control back to your code, then you resume by re-running with the human's answer keyed by request_id.
request_info suspends the workflow and returns a pending request; you resume by re-running with the human's answer keyed by the same request_id.
How the server-hosted agent can call a tool that actually runs on the client, and the one flag that makes it work.
Let a server-hosted agent call a client-side tool over AG-UI — the server sets DisableFuncAutoCall and forwards the call to the client, which runs the Go function locally.
Long or human-gated workflows can't live only in memory — hand the builder a CheckpointStorage and it snapshots state after each superstep, so you can restore and resume.
Hand the builder a CheckpointStorage and it snapshots state after each superstep, so you can list saved checkpoints and resume from an id.
How an AG-UI-hosted agent runs a server-side function tool while the thin client just streams the conversation.
Give an AG-UI-hosted agent a server-side search_restaurants tool via functool while the thin SSE client just streams the reply — the tool round-trip stays invisible.
The reason to reach for a graph over a chain: fan out work to run concurrently, then fan in to merge — wall-clock is the slowest worker, not the sum.
Fan-out broadcasts the same message to concurrent workers; fan-in gives a joiner a list of all outputs and fires once every source completes.
How to take the same Foundry agent from earlier lessons and serve it over the AG-UI protocol so a separate client can drive it over HTTP+SSE.
Serve an unchanged Foundry agent over the AG-UI protocol with one aguiprovider.NewJSONHTTPHandler call, then drive it from a credential-free SSE client.
A workflow isn't always a straight line — route the next executor by the data with a switch-case edge group, no model required.
A workflow isn't always a straight line: a switch-case edge group routes a message to the first Case whose predicate is true, else to the Default.
How a memory ContextProvider backed by an Azure AI Foundry store lets an agent recall you in a brand-new session.
Attach a Foundry-backed memory ContextProvider that retrieves before and stores after each run, so a fresh session still recalls facts keyed by a scope.
Point an agent at a remote MCP server and let Foundry do the calling — you describe the server once, the service discovers and invokes its tools for you.
A hosted MCP tool aims the agent at a remote MCP server and lets Foundry connect and call it; you describe the server once and set an approval mode.
How a real shell tool lets the model run commands, and an environment provider tells it which shell it is driving.
Pair a run_shell tool with an EnvironmentProvider that probes the shell once and injects OS-correct idioms, contrasting stateless and persistent shell modes.
Let an agent reach live search results for anything past its training cutoff — Foundry runs the search and grounding server-side, and returns URL citations.
The hosted web search tool lets an agent reach live results past its training cutoff; Foundry searches and grounds server-side and returns URL citations.
How to keep a long-running conversation inside the context window by chaining compaction strategies from gentle to aggressive.
Chain four compaction strategies from tool-result collapse to summarization to sliding window to truncation, each gated by a trigger and a preservation floor.
Ground an agent's answers in documents you upload — the provider indexes them into a vector store and searches server-side, no retrieval code of your own.
File search is a hosted tool: upload files, index them into a vector store, and bind the agent to the store id so Foundry runs retrieval server-side.
How a ContextProvider injects extra messages and tools into every run — a live todo list and calendar — with state that survives serialize and resume.
A ContextProvider injects a live todo list and calendar into each run and contributes session-mutating tools, with state that serializes to JSON and resumes.
A provider-hosted sandbox that writes and runs Python for exact answers.
The hosted code interpreter runs the model's Python server-side. Attach it via FoundryChatClient.get_code_interpreter_tool and read the code and output as content parts.
How wrapping one agent as a tool.Tool lets an orchestrator agent delegate to a specialist — composition all the way down, with no routing code.
Wrap a specialist agent with agenttool.New so an orchestrator calls it like any tool, cascading two levels deep from orchestrator to weather agent to leaf function.
Pausing the agent for a human yes/no before a sensitive tool runs.
Mark a tool approval_mode always_require and the run pauses with user_input_requests. Show the pending call, collect a decision, feed the approval back into a fresh run.
How one message can bundle a text prompt and an image, and why that forces RunMessage instead of the RunText shortcut.
Bundle a TextContent prompt and a base64 DataContent image into one message.Message and run it with RunMessage instead of the text-only RunText shortcut.
Growing and shrinking the tool set from inside a running turn.
From inside a tool you can call ctx.add_tools and ctx.remove_tools to reveal or hide tools on the next loop iteration, plus tool_choice to force a mandatory first call.
How to publish an agent as a discoverable tool on a Model Context Protocol server so any MCP client can invoke it.
Wrap an agent with agenttool.New then register it with mcptool.AddTool to serve it over MCP on stdio, so any MCP client can discover and invoke it.
How a plain Python function becomes a JSON schema the model can call.
The framework turns a function's signature and docstring into a schema. Annotated Field descriptions document each parameter, and @tool overrides the name and description.
How Go's constructor-over-an-interface idiom lets you inject a real Foundry agent into a service — and a fake into its test — through the same seam.
Inject a Foundry agent into a service through a two-method ChatAgent interface, so main injects the real agent and the test injects a fake through the same constructor.
Writing your own agent by subclassing BaseAgent — a drop-in for the built-in one.
Subclass BaseAgent and implement one run() method to satisfy SupportsAgentRun. A deterministic EchoAgent then behaves like any framework agent, no chat client required.
How to turn every agent run into an OpenTelemetry span with the SDK's otelprovider middleware.
Wire otelprovider.NewMiddleware into agent.Config.Middlewares to open a gen_ai span around every run, exported to whatever TracerProvider you register globally.
The two ways to reach a model in an Azure AI Foundry project.
Foundry offers two doors to a deployed model: FoundryChatClient where your app owns the loop, and FoundryAgent where the portal definition wins. This runs the direct path end to end.
How to teach an agent to load and persist conversation memory in your own store via a custom history provider.
Implement a custom agent.HistoryProvider with Provide and Store hooks so the agent loads and persists history in your store; DisableStoreOutput keeps it the single source of truth.
Passing per-request values to tools without leaking them into the model's schema.
Pass per-run values via function_invocation_kwargs and read them from FunctionInvocationContext inside tools and middleware, with session.state for state that persists across runs.
How to serialize an agent.Session to storage and resume the same conversation later, even from a new process.
Serialize an agent.Session with encoding/json, store the bytes, and reload them into a fresh Session in another process to resume the exact same conversation.
Passing data between middleware by putting them on one object.
Function middleware has no built-in shared bag, so put both middleware on one object and let them read and write instance attributes. That instance is the shared state.
How to make the agent return a typed Go struct instead of free-form prose, via a JSON schema derived from your type.
Two ways to get typed output from an agent: per-run agent.WithStructuredOutput, or agent.WithResponseFormat with jsonformat.MustFor baked into Config.RunOptions.
Catching tool failures in middleware and turning them into graceful replies.
Wrap call_next() in try/except inside FunctionInvocationContext middleware to catch tool exceptions like TimeoutError and set context.result to a friendly fallback.
How to pause a run for human approval before the framework is allowed to execute a tool.
Wrap a tool with tool.ApprovalRequiredFunc so the run pauses and returns a ToolApprovalRequestContent; approve or decline, then resume with RunMessage on the same session.
Rewriting a run's output after the model finishes, without touching instructions.
Result-override middleware rewrites context.result after call_next(); chat middleware overrides each ChatResponse and agent middleware wraps the whole AgentResponse.
How to wrap a plain typed Go function as a tool the model can call mid-run.
Wrap a plain typed Go function with functool.MustNew and attach it via agent.Config.Tools so the model can call it; the SDK infers the JSON schema from the signature.
Building guardrails by raising MiddlewareTermination to stop a run.
Raise MiddlewareTermination to stop a run: block disallowed input before the model, or cap responses using state carried on the middleware instance across runs.
How an agent.Session carries conversation history across RunText calls so the model remembers earlier turns.
Thread conversation history across RunText calls with an agent.Session and agent.WithSession, so a follow-up prompt builds on the previous turn; a new session starts fresh.
Where you attach middleware decides when it fires — every run, or just one.
Agent-scope middleware fires on every run for cross-cutting policy; run-scope fires only for its call. The same middleware= keyword nests both around the agent.
How to wrap every agent run with a middleware — the standard hook for logging, tracing, and guardrails.
Wrap every agent run with an agent.Middleware in the Foundry Go SDK: one pass-through function that observes messages and updates without altering the result.
Wrapping every model call to inspect, mutate, or short-circuit it.
Chat middleware wraps each model call via ChatContext and call_next; mutate context.messages in place, or set context.result and raise MiddlewareTermination to skip the model.
How to resume a long-running remote agent stream after it drops — using a continuation token to reconnect instead of re-sending the expensive query.
Capture the continuation token from a streamed remote run, then reconnect with WithContinuationToken and no messages to resume the same task to completion.
Keeping a growing transcript under a token budget with layered compaction strategies.
CompactionProvider rewrites in-memory history before each model call; a TokenBudgetComposedStrategy layers tool-result collapse, summarization and sliding window gentlest-first.
How to pin which transport a client uses when a remote A2A agent advertises several bindings at once.
Pin the transport an A2A client uses via PreferredTransports so binding negotiation is deterministic, while the wrapped remote agent stays a plain agent.Agent.
Where conversation history actually lives — local session state vs service-managed.
Local session state via InMemoryHistoryProvider re-sends the transcript each run; service-managed keeps only a remote id. Persist the whole AgentSession to survive restarts.
How to drive a slow remote agent that answers with a continuation token, then poll that token to completion instead of blocking on one long call.
Ask a remote A2A agent with AllowBackgroundResponses, get a continuation token, and poll with WithContinuationToken and no messages until the token clears.
Carrying conversation state across separate agent.run() calls with AgentSession.
AgentSession carries history across separate agent.run() calls; pass the same session every time and serialize it with to_dict()/from_dict() to resume.
How to discover a remote A2A agent's advertised skills and hand each one to a local host agent as an ordinary function tool.
Resolve a remote A2A agent card, turn each advertised skill into a function tool with derived names and descriptions, and hand them to a local Foundry host agent.
Letting the agent write and run one Python program instead of looping tool-by-tool.
CodeAct adds a single execute_code tool so the agent writes one sandboxed Python program calling tools via call_tool, wired through the Hyperlight provider with a fallback to direct tools.
The other primitive: a directed graph of executors wired by edges, running fully offline with no model, no credential, no Foundry.
Wire two executors into an uppercase to reverse pipeline with the fluent workflow builder and run it fully offline via inproc.Default, iterating ExecutorCompletedEvents.
The batteries-included autonomous agent pipeline from create_harness_agent.
Assemble a batteries-included autonomous agent with create_harness_agent: a function-calling loop, todo list, plan/execute modes, and compaction, each individually switchable via disable flags.
A custom ContextProvider gives the agent memory: it reads stored facts before a run and learns new ones after — all through the Session.
A custom ContextProvider wires Provide and Store hooks around every run so the agent reads remembered facts before the call and learns new ones after, all in the Session.
Packaging reusable agent capabilities that load lazily via progressive disclosure.
Package reusable agent capabilities as skills: define an InlineSkill with frontmatter, resources, and scripts, attach via SkillsProvider, and let the agent load them lazily on demand.
One Session threaded through every call turns two stateless one-shots into a single conversation that remembers.
Thread one agent.Session through every RunText call with agent.WithSession to turn stateless one-shots into a single conversation that remembers.
Scoring Microsoft Agent Framework agent outputs offline with a LocalEvaluator.
Score Microsoft Agent Framework agent outputs with evaluate_agent and a LocalEvaluator: run offline keyword, tool-call, and custom evaluator checks, then gate CI via raise_for_status.
Hand the agent a plain Go function it can decide to call mid-conversation — the model requests it, the framework runs it, the result flows back.
Register a plain Go function as a tool with functool.MustNew; the model decides when to call it, the framework runs it, and the result flows back into the answer.
Defining a Microsoft Agent Framework agent from a YAML spec instead of code.
Define a Microsoft Agent Framework agent from a YAML spec with AgentFactory create_agent_from_yaml, resolving connection values from env and building the Foundry client from the spec.
The smallest useful agent: give a model instructions and a name, hand it a message, get a response — collected or streamed.
Build the smallest useful agent from instructions and a model, then run the same RunText call two ways — collected all at once and streamed token-by-token.
Grounding a Microsoft Agent Framework agent in your own docs with a search tool.
Ground a Microsoft Agent Framework agent with RAG-as-a-tool: expose a search function over your docs, instruct the agent to retrieve then answer and cite, and decline when nothing matches.
The zero-network preflight that confirms your Foundry config and Azure credential chain exist before you run a single agent.
A zero-network preflight that confirms your Foundry endpoint, model deployment, and Azure credential chain exist before you run a single agent.
Starting long agent work in the background and polling with a continuation token.
Start long agent work with options background True, poll by re-running with the continuation_token until it returns None, and resume interrupted streams from the last token seen.
Making a Microsoft Agent Framework agent return typed data instead of prose.
Use response_format in agent.run options to make a Microsoft Agent Framework agent return a typed Pydantic model or parsed JSON on response.value, including streaming.
Building a Message of mixed content parts so an agent can reason about an image.
Sending images to a Microsoft Agent Framework agent by building a Message of Content parts with Content.from_uri and Content.from_data, targeting a vision-capable Foundry model.
An Agent is a layered pipeline — knowing the layers tells you exactly where to plug in.
The layered execution model of a Microsoft Agent Framework agent: agent middleware, RawAgent, context providers, and the separate swappable ChatClient pipeline.
The four ways you actually call run(): non-streaming, streaming, sessions, and per-run options.
The four ways to call run() in Microsoft Agent Framework: AgentResponse, stream=True with a ResponseStream, sessions for state, and per-run options merged over defaults.
Defending against prompt injection with information-flow control over trusted and untrusted content.
Defending a Microsoft Agent Framework agent from prompt injection with SecureAgentConfig, information-flow labeling of untrusted content, and block_on_violation enforcement.
Turning an agent run into OpenTelemetry spans you can read in the console or ship to a collector.
Wiring OpenTelemetry into a Microsoft Agent Framework agent with configure_otel_providers, console vs OTLP export, and the enable_sensitive_data content trade-off.
Context providers with two hooks — and file-backed history that survives restarts.
ContextProvider before_run/after_run hooks in Microsoft Agent Framework, plus FileHistoryProvider for on-disk transcripts and a per-session state dict for counters.
Borrowing tools from an external MCP server instead of writing them yourself.
Connecting a Microsoft Agent Framework agent to an external Model Context Protocol server via MCPStdioTool, entered with async with, so its remote tools merge into tools=[...].
Wrapping an agent run to observe, guard, or short-circuit it — without touching the agent's logic.
Agent, chat, and function middleware in Microsoft Agent Framework: one middleware=[...] list, call_next() with no args, and short-circuiting via MiddlewareTermination.
Everything so far ran once and exited. To use an agent like a product, put a server in front of it — DevUI stands up a local web chat around any agent with one call.
serve() from agent_framework.devui wraps any agent in a local web chat; it blocks with its own event loop and ships as a separate install.
The functional API hid the graph. Here it's explicit: executors are nodes, edges join them, and a message flows from the start executor along the edges.
Build a two-node graph with WorkflowBuilder: executors send_message or yield_output, and the type hint on WorkflowContext carries the routing intent.
A workflow is not an LLM thing — it's a way to compose steps with checkpointing and events. This one has no agent and no model call, so it runs with zero credentials.
A credential-free workflow of two @step functions composed by a @workflow, isolating checkpointing, steps and outputs from any model call.
Compose several agents into a pipeline with the gentlest workflow API: decorate an async function with @workflow and call agents inside it with plain await.
Decorate an async function with @workflow and call agents inside it with plain await: a writer drafts, an editor tightens, one line of glue each.
A session remembers within one conversation. A ContextProvider remembers across all of them — durable facts injected into every run.
A ContextProvider holds facts that outlive any session and injects them into every run via before_run and context.extend_instructions.
An Agent is stateless — two runs are strangers. What carries history from one turn to the next is an AgentSession.
An Agent is stateless; an AgentSession carries history between turns. Thread create_session() through each run so turn two can see turn one.
A tool is just a Python function the model may call: decorate it with @tool, annotate the arguments, and the framework wires the schema, the call, and the result back into the conversation.
Turn a Python function into a tool with the @tool decorator and Annotated Field descriptions, then let the model pick the right one from the question wording.
The smallest possible Python agent: a Foundry chat client plus instructions, run once collected and once streamed.
The smallest MAF Python agent: wire a FoundryChatClient plus instructions, then run it once collected and once streamed with stream=True.