ag2-ag-ui
Skill12 starsChanged 10 days agoApache-2.0View on GitHub
Expose an AG2 `Agent` over the AG-UI 1.0 protocol (`ag-ui-protocol>=1.0`) so a web frontend (CopilotKit, `@ag-ui/client` HttpAgent, custom React/Next.js) or a CopilotKit Channel (Slack etc.) can stream text, render backend and frontend tool calls, sync shared state, see delegations, and answer human-in-the-loop interrupts. Covers `AGUIStream(agent)` with `stream.dispatch(...)` in FastAPI or `stream.build_asgi()` as a Starlette route, `read_run_input` (tolerant body parsing), `stream.capabilities()`, the `RunAgentInput` body (`threadId`/`runId`/`messages`/`state`/`context`/`tools`/`resume`), emitted events (`TEXT_MESSAGE_CHUNK`, `TEXT_MESSAGE_START/CONTENT/END`, `TOOL_CALL_*`, `STATE_SNAPSHOT`, `SUBAGENT_*`, `RUN_FINISHED` outcomes), interrupts/`resume`, `Retention`, `require_resume_proof`. For A2A interop see `ag2-a2a`; MCP `ag2-mcp`; IDE agents `ag2-acp`.
- Reads credentials
- Installs packages
- Sends data out
1 other project uses a version of this.
Adopted by
Most recently taken up by
- ag2ai/build-with-ag2their own version, first seen Oct 9, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- ag2ai/build-with-ag2★ 252same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository27 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- ag2-a2aSkill
- ag2-acpSkill
- ag2-add-custom-toolSkill
- ag2-eval-comparisonSkill
- ag2-evaluationSkill
- ag2-hitlSkill
- ag2-knowledge-and-memorySkill
- ag2-liveSkill
- ag2-mcpSkill
- ag2-middlewareSkill
- ag2-multimodal-inputSkill
- ag2-network-discussionSkill
- ag2-network-governanceSkill
- ag2-network-quickstartSkill
- ag2-network-tools-and-viewsSkill
- ag2-network-workflowSkill
- ag2-observers-and-alertsSkill
- ag2-overviewSkill
- ag2-quickstartSkill
- ag2-shell-toolSkill
- ag2-structured-outputSkill
- ag2-subagent-delegationSkill
- ag2-telemetrySkill
- ag2-testingSkill
- ag2-use-builtin-toolsSkill
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 60
Do not declare run_input: RunAgentInput as a FastAPI parameter — a newer client's unknown role/part gets a 422.
- Very specific: line 62
No custom logic? Add the generated endpoint as a route (not mount, which 307-redirects /chat → /chat/):
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
AG-UI integration (AG-UI 1.0)
ag2.ag_ui.AGUIStream turns an Agent into an AG-UI Server-Sent-Events endpoint. Use it when a browser UI (or a CopilotKit Channel) should talk to an AG2 agent with a standard contract; for a narrow app-specific API, a plain endpoint is simpler.
pip install "ag2[ag-ui,openai]" fastapi uvicornWhen to use
- A web UI (React / Next.js / anything HTTP + SSE) should talk to an AG2 agent.
- You want streamed text, reasoning, tool-call rendering, shared state or sub-task steps surfaced to the frontend through a standard protocol.
- You use or consider CopilotKit as the React client.
For a narrow app-specific API whose contract you own end to end, write a plain endpoint instead.
Server (FastAPI, manual dispatch — recommended)
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse, Response, StreamingResponse
from ag2 import Agent
from ag2.ag_ui import AGUIStream, read_run_input
from ag2.config import OpenAIResponsesConfig
agent = Agent(
name="support_bot",
prompt="You help users with billing questions.",
config=OpenAIResponsesConfig(model="gpt-4.1-mini"),
)
stream = AGUIStream(agent)
app = FastAPI()
@app.get("/chat")
@app.get("/chat/capabilities")
async def capabilities() -> JSONResponse:
return JSONResponse(stream.capabilities().model_dump(by_alias=True, exclude_none=True))
@app.post("/chat")
async def run_agent(request: Request) -> Response:
try:
run_input = read_run_input(await request.body()) # strips unknown roles/parts from newer clients
except ValueError:
return JSONResponse({"error": "invalid AG-UI RunAgentInput body"}, status_code=400)
return StreamingResponse(
stream.dispatch(run_input, accept=request.headers.get("accept")),
media_type="text/event-stream", # always SSE; don't echo Accept
)Do not declare run_input: RunAgentInput as a FastAPI parameter — a newer client's unknown role/part gets a 422; read_run_input serves it. dispatch(...) also takes variables=, dependencies= (server-only secrets, e.g. the verified user), prompt=, tools=, config=, middleware=, hitl_hook=, context_prompt=.
No custom logic? Add the generated endpoint as a route (not mount, which 307-redirects /chat → /chat/):
from starlette.routing import Route
endpoint = stream.build_asgi()
app.routes.append(Route("/chat", endpoint))
app.routes.append(Route("/chat/capabilities", endpoint))Request body (RunAgentInput, camelCase JSON)
curl -N -X POST http://127.0.0.1:8000/chat -H "Content-Type: application/json" -H "Accept: text/event-stream" -d '{
"threadId": "thread-1", "runId": "run-1", "protocolVersion": "1.0",
"messages": [{"id": "m1", "role": "user", "content": "Hello"}],
"state": {}, "context": [], "tools": [], "forwardedProps": {}
}'- New
runIdper POST; samethreadIdacross a turn (and for resumes). Send the full message history each run. state(JSON object) seedscontext.variables;context: [{"description", "value"}]is appended to the system prompt as prose (not variables).tools: [{"name", "description", "parameters": <JSON schema>}]are frontend tools.- Omit
protocolVersion→ treated as pre-1.0 (tool results downgraded to strings); major2.x→ loneRUN_ERRORUNSUPPORTED_PROTOCOL_VERSION.
Events actually emitted (verified, AG2 1.3.0)
Streaming is optional — AGUIStream works with either. For a chat UI, set streaming=True on the model config (e.g. OpenAIResponsesConfig(model=..., streaming=True)) so text renders token by token; without it the whole reply arrives as one chunk.
| Situation | Event sequence |
| Plain reply, non-streaming model | RUN_STARTED → TEXT_MESSAGE_CHUNK → RUN_FINISHED |
Model config streaming=True | RUN_STARTED → TEXT_MESSAGE_START → TEXT_MESSAGE_CONTENT×n → TEXT_MESSAGE_END → RUN_FINISHED |
| Backend tool | TOOL_CALL_START → TOOL_CALL_ARGS → TOOL_CALL_END → TOOL_CALL_RESULT then text |
Frontend tool (from tools) | RUN_STARTED → TOOL_CALL_CHUNK → RUN_FINISHED with outcome: {"type":"success","pendingToolCallIds":[...]}; client runs it and posts a new run with the assistant toolCalls + role:"tool" message |
| Reasoning | REASONING_START, REASONING_MESSAGE_START/CONTENT/END, REASONING_END |
| State changed | STATE_SNAPSHOT (client state + server variables) at start/end when different |
Delegation (agent.as_tool) | SUBAGENT_STARTED / SUBAGENT_FINISHED / SUBAGENT_ERROR (replaces old STEP_*) |
| Failure | RUN_ERROR (logged on ag2.ag_ui; dispatch does not raise) |
Text deltas are in event["delta"]. RUN_FINISHED/RUN_ERROR carry usage per provider/model.
Human-in-the-loop interrupts
A tool calling await context.input("Book LH441? (yes/no)") on an agent without hitl_hook ends the run with RUN_FINISHED + outcome: {"type": "interrupt", "interrupts": [{"id", "reason": "input_required", "message", "responseSchema", "expiresAt", "metadata"}]}; the coroutine stays suspended in-process. Answer with a new run on the same thread:
{"threadId": "thread-1", "runId": "run-2", "messages": [], "state": {}, "context": [], "tools": [],
"resume": [{"interruptId": "<id>", "status": "resolved", "payload": "yes", "metadata": <interrupt.metadata>}]}→ RUN_STARTED → TOOL_CALL_RESULT → TEXT_MESSAGE_CHUNK → RUN_FINISHED. "status": "cancelled" stops the turn. Tools wrapped in approval_required() interrupt with reason: "tool_call" + toolCallId; answer payload: true/false. With a hitl_hook (agent or dispatch) no interrupt is emitted.
Ops: held turns live in one process → route by threadId (sticky); restarts drop them. Tune AGUIStream(agent, retention=Retention(ttl=900.0, max_held=128), require_resume_proof=False). Call await stream.aclose() on shutdown (or async with stream:). Refusals: RUN_ERROR codes INTERRUPT_NOT_COVERED / INTERRUPT_NOT_PROVEN / INTERRUPT_PAYLOAD_REFUSED.
Frontends
- CopilotKit (React/Next.js):
npx copilotkit@latest create -f ag2or theag2ai/ag2-copilotkit-starter; bridge withnew HttpAgent({ url: "http://localhost:8000/chat" })from@ag-ui/client1.x in aCopilotRuntime. Seereferences/copilotkit.md. - Channels (Slack etc.): a Node 22 process with
@copilotkit/channelscalls the same/chatendpoint per message (website/docs/user-guide/ag-ui/channels.mdx). - Dojo for protocol testing: https://dojo.ag-ui.com/ag2/feature/agentic_chat
Pitfalls
- Expecting
TEXT_MESSAGE_START/CONTENT/ENDfrom a non-streaming model — you get oneTEXT_MESSAGE_CHUNK. Handle both. - Secrets in
variablesor the agent's variables are sent to the browser inSTATE_SNAPSHOT— usedispatch(dependencies=...). - A fresh run (no
resume) on a thread with a held interrupt is refused (INTERRUPT_NOT_COVERED). @ag-ui/client/ CopilotKituseInterruptdon't echo interruptmetadata; only matters withrequire_resume_proof=True.- Proxies must not buffer
text/event-stream; add CORS for the frontend origin; authenticate both GET and POST routes. - Frontend tool names in the UI must exactly match the names the model is given.
Reference
scripts/serve_and_probe.py— FastAPI + uvicorn in-process; prints real event sequences for plain run, backend tool, interrupt + resume (needsOPENAI_API_KEY).references/copilotkit.md— CopilotKit route/layout snippets, auth/production checklist.- Upstream:
website/docs/user-guide/ag-ui/{overview,backend-deepdive,copilotkit-quickstart,channels}.mdx;examples/ag_ui/human_input.py; sourceag2/ag_ui/.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

