TL;DR:
- AG-UI is an open, event-based protocol for streaming AI agent state to web frontends — tool calls, reasoning steps, messages, and custom events
- It sits between your agent backend and your React/Vue/web frontend, replacing ad-hoc WebSocket implementations with a standardised event stream
- Compatible with any agent framework (LangGraph, CrewAI, Mastra, custom) and any frontend — with official React hooks from CopilotKit
If you’ve built a production AI agent with a web interface, you’ve encountered the same problem: the agent is running on your backend, and your frontend needs to know what’s happening in real time. Is the agent thinking? Which tool did it call? What did it return? Is there a partial message being streamed?
The usual answer is a custom WebSocket implementation, a hand-rolled SSE endpoint, or a polling loop. It works, but it’s boilerplate that every team rebuilds from scratch, with subtle differences that make it hard to reuse UI components across agent projects.
AG-UI is an open protocol designed to solve this specific problem. It defines a standard event stream format that any agent backend can emit and any frontend can consume — without coupling agent logic to UI implementation details.
What AG-UI Defines
At its core, AG-UI is a specification for a unidirectional event stream from agent to frontend. The protocol defines a set of typed events covering the full lifecycle of an agent run:
Run lifecycle events:
RUN_STARTED/RUN_FINISHED/RUN_ERROR— top-level run stateSTEP_STARTED/STEP_FINISHED— discrete reasoning or execution steps
Message streaming events:
TEXT_MESSAGE_START/TEXT_MESSAGE_CONTENT/TEXT_MESSAGE_END— streaming LLM output, token by tokenTOOL_CALL_START/TOOL_CALL_ARGS/TOOL_CALL_END— streaming tool invocations
State events:
STATE_SNAPSHOT— full agent state at a point in timeSTATE_DELTA— incremental JSON Patch update to agent stateMESSAGES_SNAPSHOT— full conversation history sync
Custom events:
CUSTOM— arbitrary events for application-specific metadata
The transport layer is intentionally simple: HTTP with Server-Sent Events (SSE) is the reference implementation. WebSocket and other transports are supported but SSE is the default — it’s unidirectional, stateless, and works through proxies and load balancers without configuration.
Why a Protocol Instead of a Library
The pragmatic answer is that your agent backend and your frontend may be in completely different languages and frameworks. Your agent might be LangGraph in Python; your frontend might be Next.js. A protocol-level specification means:
- Your Python agent emits SSE events in the AG-UI format
- Your React frontend consumes them with a library that speaks AG-UI
- Neither side needs to know how the other is implemented
Contrast this with embedding a specific agent framework’s streaming format into your UI components. Switch from LangGraph to Mastra, or add a second agent framework to handle a different workflow, and your frontend needs rework.
AG-UI puts the contract at the wire protocol level. The agent backend just needs to emit the right events; the frontend just needs to consume them.
The CopilotKit React Integration
AG-UI was developed by the CopilotKit team and is used as the foundation of their copilot infrastructure. For React applications, the @ag-ui/client and CopilotKit packages provide hooks that consume an AG-UI stream directly:
import { useCoAgent } from "@copilotkit/react-core";
function AgentPanel() {
const { state, run, running } = useCoAgent({
name: "research-agent",
initialState: { query: "", results: [] },
});
return (
<div>
{running && <ProgressIndicator />}
<ResultsList results={state.results} />
</div>
);
}
The state object is kept in sync with the agent’s state via STATE_DELTA events — you get real-time updates to your React component as the agent processes, without managing WebSocket connections or polling.
Connecting Your Agent Backend
On the backend, any agent framework can emit AG-UI events. For Python agents, the agui package provides emitter utilities:
from agui import EventEmitter, RunStarted, TextMessageStart, TextMessageContent, TextMessageEnd, RunFinished
async def run_agent_with_agui(query: str):
emitter = EventEmitter()
async with emitter.stream() as stream:
await stream.emit(RunStarted(thread_id="run-1"))
msg_id = "msg-1"
await stream.emit(TextMessageStart(message_id=msg_id, role="assistant"))
async for token in llm.stream(query):
await stream.emit(TextMessageContent(message_id=msg_id, delta=token))
await stream.emit(TextMessageEnd(message_id=msg_id))
await stream.emit(RunFinished(thread_id="run-1"))
return stream.response() # FastAPI/Starlette StreamingResponse
For LangGraph specifically, AG-UI provides a LangGraph adapter that wraps graph execution and automatically translates LangGraph’s event stream to AG-UI events — you connect your existing graph without rewriting it.
State Streaming: The Most Underrated Feature
Most teams focus on message streaming when evaluating agent UI protocols — watching tokens appear in real time. The state streaming capability is actually more powerful for building useful interfaces.
AG-UI’s STATE_SNAPSHOT and STATE_DELTA events mean your agent can maintain arbitrary structured state and have it reflected in your UI in real time. A research agent can stream its list of sources as they’re found. A coding agent can stream its plan of changes before executing them. A customer support agent can stream the customer record it’s retrieved and the actions it’s considering.
This enables genuinely reactive agent UIs — not just a chat interface that shows streaming text, but a dashboard that reflects the agent’s working state as it updates.
The STATE_DELTA format uses JSON Patch (RFC 6902), which means diffs are minimal even for large state objects. Only the changed paths are transmitted.
Comparing to Alternatives
Raw SSE / WebSocket: More control, more code. You own the event schema, the reconnection logic, the type definitions. AG-UI gives you a standard schema and client libraries at the cost of conforming to the protocol.
LangChain/LangGraph streaming: Framework-specific streaming that ties your frontend to LangGraph’s event format. AG-UI adds a translation layer that decouples the two.
OpenAI Responses API streaming: API-specific format (JSONL events). Useful if you’re only ever using OpenAI, but non-portable.
CopilotKit without AG-UI: CopilotKit previously required their own backend SDK. AG-UI makes the protocol public and framework-agnostic, which means you can connect any agent backend to CopilotKit’s frontend components.
When to Use AG-UI
AG-UI is worth adopting when:
- You’re building a UI where users need real-time visibility into agent progress (not just final output)
- You want to reuse frontend components across multiple agent projects
- Your team is split between backend (agent logic) and frontend, and you want a clear interface contract
- You’re considering adding a second agent framework alongside your existing one
It adds meaningful overhead if your agent is purely backend and the frontend only consumes final results — in that case, a simple REST API is sufficient.
For teams building genuine agentic UIs with streaming, AG-UI is the closest thing the ecosystem has to a standard — and given its open licensing and growing adoption across frameworks, it’s worth building to.
Resources
- AG-UI specification and GitHub: github.com/ag-ui-protocol/ag-ui
- CopilotKit documentation: docs.copilotkit.ai
- LangGraph AG-UI adapter: available via the
agui-langgraphpackage