showcase/shell-docs/src/content/snippets/shared/backend/ag-ui.mdx
CopilotKit is built on the AG-UI protocol, a lightweight, event-based standard that defines how AI agents communicate with user-facing applications over Server-Sent Events (SSE).
Messages, state updates, tool calls, and agent lifecycle events all flow through AG-UI. Understanding this layer helps you debug and extend any CopilotKit integration.
<FrontendOnly frontend="react"> ## Accessing your agent with `useAgent`useAgent returns the AG-UI AbstractAgent behind your copilot:
import { useAgent } from "@copilotkit/react-core/v2";
function AgentStatus() {
const { agent } = useAgent({ agentId: "research-agent" });
// agent.messages — conversation history
// agent.state — current shared state
// agent.isRunning — whether the agent is running
}
injectAgentStore exposes the AG-UI agent and projects its messages, state,
and run status into Angular signals:
import { Component, computed } from "@angular/core";
import { injectAgentStore } from "@copilotkit/angular";
@Component({
selector: "app-agent-status",
template: `
<p>{{ messageCount() }} messages</p>
@if (store().isRunning()) {
<p>Agent is running…</p>
}
`,
})
export class AgentStatusComponent {
readonly store = injectAgentStore("research-agent");
readonly messageCount = computed(() => this.store().messages().length);
}
The resolved agent is a standard AG-UI AbstractAgent. You can read its
state, invoke protocol methods, and subscribe to its event stream.
import { useEffect } from "react";
import { useAgent } from "@copilotkit/react-core/v2";
function EventLog() {
const { agent } = useAgent({ agentId: "research-agent" });
useEffect(() => {
const subscription = agent.subscribe({
onTextMessageContentEvent({ textMessageBuffer }) {
console.log("Streaming text:", textMessageBuffer);
},
onToolCallEndEvent({ toolCallName, toolCallArgs }) {
console.log("Tool called:", toolCallName, toolCallArgs);
},
onStateChanged({ agent }) {
console.log("State changed:", agent.state);
},
});
return () => subscription.unsubscribe();
}, [agent]);
}
private readonly destroyRef = inject(DestroyRef);
readonly store = injectAgentStore("research-agent");
constructor() {
const subscription = this.store().agent.subscribe({
onTextMessageContentEvent({ textMessageBuffer }) {
console.log("Streaming text:", textMessageBuffer);
},
onToolCallEndEvent({ toolCallName, toolCallArgs }) {
console.log("Tool called:", toolCallName, toolCallArgs);
},
onStateChanged({ agent }) {
console.log("State changed:", agent.state);
},
});
this.destroyRef.onDestroy(() => subscription.unsubscribe());
}
The callback names map directly to the AG-UI event types:
| Event | Callback |
|---|---|
| Run lifecycle | onRunStartedEvent, onRunFinishedEvent, onRunErrorEvent |
| Steps | onStepStartedEvent, onStepFinishedEvent |
| Text messages | onTextMessageStartEvent, onTextMessageContentEvent, onTextMessageEndEvent |
| Tool calls | onToolCallStartEvent, onToolCallArgsEvent, onToolCallEndEvent, onToolCallResultEvent |
| State | onStateSnapshotEvent, onStateDeltaEvent |
| Messages | onMessagesSnapshotEvent |
| Custom | onCustomEvent, onRawEvent |
| High-level changes | onMessagesChanged, onStateChanged |
When you use CopilotKit with a runtime, your frontend does not talk directly
to the backend agent. CopilotKit discovers agents through the runtime's
/info endpoint and represents each one with a proxy that implements the
same AbstractAgent interface.
// useAgent() → registry checks /info → resolves a proxy agent
// agent.runAgent() → runtime POST → agent execution → SSE events
// injectAgentStore() → registry checks /info → resolves a proxy agent
// core.runAgent({ agent }) → runtime POST → agent execution → SSE events
This indirection lets the runtime provide authentication, middleware, agent routing, and CopilotKit Enterprise Intelligence without changing how the frontend interacts with agents.
On the server, CopilotRuntime accepts a map of AG-UI AbstractAgent
instances. A framework adapter, an HttpAgent pointing at a remote server,
and a custom implementation all use the same request path:
AgentRunner executes the agent and receives AG-UI events.The backend framework can change without forcing a corresponding change to the frontend AG-UI contract.