AG-UI Human-in-the-Loop: The Server

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.

Part 90 of 91 Microsoft Agent Framework Go — Every Lesson

What this lesson demonstrates

Human-in-the-loop is a pause enforced by the server. The Foundry agent hosts a single tool, approve_expense_report, that is marked approval-required. When the model wants to call it, the agent does not run it — it emits an approval request over AG-UI instead. A separate client program collects the human’s decision and sends it back, and only then does the call proceed.

The server’s job is to enforce the pause. Everything hinges on one wrapper.

The real code

newHandler builds the agent and wraps the plain tool with tool.ApprovalRequiredFunc:

a := foundryprovider.NewAgent(
    endpoint,
    cred,
    foundryprovider.ModelDeployment(model),
    foundryprovider.AgentConfig{
        Instructions: "You are a helpful assistant in charge of approving expenses.",
        Config: agent.Config{
            Name:  "AGUIAssistant",
            Tools: []tool.Tool{tool.ApprovalRequiredFunc(newExpenseTool())}, // gate this tool behind human approval
        },
    },
)

newExpenseTool is an ordinary functool.MustNew tool around approveExpenseReport. On its own it would auto-run. tool.ApprovalRequiredFunc(...) wraps it so the framework marks it “needs approval” — that is the load-bearing line. The rest is the familiar aguiprovider.NewJSONHTTPHandler mounted at /.

What to notice

How it maps to the Microsoft Agent Framework Go SDK

tool.ApprovalRequiredFunc decorates any tool.FuncTool so the runtime emits an approval request rather than executing it. Over AG-UI, that request becomes an event the client answers, and the answer flows back as the approval the framework was waiting on. It is the SDK’s built-in way to put a human in the middle of an autonomous run.

Run it

go run ./tutorial/02-agents/agui/step04_human_in_loop/server, then point the matching AG-UI client at it. Needs az login + FOUNDRY_PROJECT_ENDPOINT (+ FOUNDRY_MODEL). Offline tests run with go test ./...; the live bind skips without AF_LIVE=1.


Next: AG-UI State Management — The Server

Sources & References

The Go SDK this lesson exercises
Serving an agent over the AG-UI protocol