7acadae
CopilotKitDocs
  • Docs
  • Integrations
  • Reference
Get Started
QuickstartCoding Agents
Concepts
ArchitectureGenerative UI OverviewOSS vs Enterprise
Agentic Protocols
OverviewAG-UIAG-UI MiddlewareMCPA2A
Build Chat UIs
Prebuilt Components
CopilotChatCopilotSidebarCopilotPopup
Custom Look and Feel
CSS CustomizationSlots (Subcomponents)Fully Headless UIReasoning Messages
Multimodal AttachmentsVoice
Build Generative UI
Controlled
Tool-based Generative UITool RenderingState RenderingReasoning
Your Components
Display ComponentsInteractive Components
Declarative
A2UIDynamic Schema A2UIFixed Schema A2UI
Open-Ended
MCP Apps
Adding Agent Powers
Frontend ToolsShared State
Human-in-the-Loop
HITL OverviewPausing the Agent for InputHeadless Interrupts
Sub-AgentsAgent ConfigProgrammatic Control
Agents & Backends
Built-in Agent
Backend
Copilot RuntimeFactory ModeAG-UI
Runtime Server AdapterAuthentication
Built-in Agent (TanStack AI)
Advanced ConfigurationMCP ServersModel SelectionServer Tools
Observe & Operate
InspectorVS Code Extension
Troubleshooting
Common Copilot IssuesError Debugging & ObservabilityDebug ModeAG-UI Event InspectorHook ExplorerError Observability Connectors
Enterprise
CopilotKit PremiumHow the Enterprise Intelligence Platform WorksHow Threads & Persistence WorkObservabilitySelf-Hosting IntelligenceThreads
Deploy
AWS AgentCore
What's New
Full MCP Apps SupportLangGraph Deep Agents in CopilotKitA2UI Launches with full AG-UI SupportCopilotKit v1.50Generative UI Spec SupportA2A and MCP Handshake
Migrate
Migrate to V2Migrate to 1.8.2
Other
Contributing
Code ContributionsDocumentation Contributions
Anonymous Telemetry
Built-in Agent (TanStack AI)BackendAG-UI

AG-UI

How CopilotKit uses the AG-UI protocol to connect your frontend to your Built-in Agent.

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).

Everything in CopilotKit — messages, state updates, tool calls, and more — flows through AG-UI events. Understanding this layer helps you debug, extend, and build on top of CopilotKit more effectively.

Accessing your agent with useAgent#

The useAgent hook is your primary interface to the AG-UI agent powering your copilot. It returns an AbstractAgent from the AG-UI client library — the same base type that all AG-UI agents implement.

import { useAgent } from "@copilotkit/react-core/v2";

function MyComponent() {
  const { agent } = useAgent();

  // agent.messages   — conversation history
  // agent.state      — current agent state
  // agent.isRunning  — whether the agent is currently running
}

If you have multiple agents, pass the agentId to select one:

const { agent } = useAgent({ agentId: "research-agent" });

The returned agent is a standard AG-UI AbstractAgent. You can subscribe to its events, read its state, and interact with it using the same interface defined by the AG-UI specification.

Subscribing to AG-UI events#

Every agent exposes a subscribe method that lets you listen for specific AG-UI events as they stream in. Each callback receives the event and the current agent state:

import { useAgent } from "@copilotkit/react-core/v2";
import { useEffect } from "react";

function MyComponent() {
  const { agent } = useAgent();

  useEffect(() => {
    const subscription = agent.subscribe({
      // Called on every event
      onEvent({ event }) {
        console.log("Event:", event.type, event);
      },

      // Text message streaming
      onTextMessageContentEvent({ textMessageBuffer }) {
        console.log("Streaming text:", textMessageBuffer);
      },

      // Tool calls
      onToolCallEndEvent({ toolCallName, toolCallArgs }) {
        console.log("Tool called:", toolCallName, toolCallArgs);
      },

      // State updates
      onStateSnapshotEvent({ agent }) {
        console.log("State snapshot:", agent.state);
      },

      // High-level lifecycle
      onMessagesChanged({ agent }) {
        console.log("Messages updated:", agent.messages);
      },
      onStateChanged({ agent }) {
        console.log("State changed:", agent.state);
      },
    });

    return () => subscription.unsubscribe();
  }, [agent]);
}

The full list of subscribable events maps directly to the AG-UI event types:

EventCallbackDescription
Run lifecycleonRunStartedEvent, onRunFinishedEvent, onRunErrorEventAgent run start, completion, and errors
StepsonStepStartedEvent, onStepFinishedEventIndividual step boundaries within a run
Text messagesonTextMessageStartEvent, onTextMessageContentEvent, onTextMessageEndEventStreaming text content from the agent
Tool callsonToolCallStartEvent, onToolCallArgsEvent, onToolCallEndEvent, onToolCallResultEventTool invocation lifecycle
StateonStateSnapshotEvent, onStateDeltaEventFull state snapshots and incremental deltas
MessagesonMessagesSnapshotEventFull message list snapshots
CustomonCustomEvent, onRawEventCustom and raw events for extensibility
High-levelonMessagesChanged, onStateChangedAggregate notifications after any message or state mutation

The proxy pattern#

When you use CopilotKit with a runtime, your frontend never talks directly to your agent. Instead, CopilotKit creates a proxy agent on the frontend that forwards requests through the Copilot Runtime.

On startup, CopilotKit calls the runtime's /info endpoint to discover which agents are available. Each agent is wrapped in a ProxiedCopilotRuntimeAgent — a thin client that extends AG-UI's HttpAgent. From your component's perspective, this proxy behaves identically to a local AG-UI agent: same AbstractAgent interface, same subscribe API, same properties. Under the hood, every run call is an HTTP request to your server, and every response is an SSE stream of AG-UI events flowing back.

What your component sees
tsx
const { agent } = useAgent(); // Returns an AbstractAgent
agent.messages; // Read messages
agent.state; // Read state
agent.subscribe({ /* … */ }); // Subscribe to events
What actually happens
tsx
// useAgent() → AgentRegistry checks /info → wraps each agent in ProxiedCopilotRuntimeAgent
// agent.runAgent() → HTTP POST to runtime → runtime routes to your agent → SSE stream back

This indirection is what enables the runtime to provide authentication, middleware, agent routing, and premium features — without changing how you interact with agents on the frontend.

How the Built-in Agent slots into AG-UI#

Even though BuiltInAgent looks like a "single-function convenience", it's still an AG-UI AbstractAgent under the hood. When you register it with the runtime:

  1. A request comes in to your runtime endpoint
  2. The runtime resolves the target agent by ID ("default", "research-agent", …)
  3. It clones the agent (for thread safety) and populates messages, state, and thread context from the request
  4. The AgentRunner executes the agent, which produces a stream of AG-UI BaseEvents
  5. Events are encoded as SSE and streamed back to the frontend proxy

Because every agent is an AbstractAgent, the same plumbing routes requests to a BuiltInAgent, an HttpAgent pointing at a remote server, or any custom implementation you register alongside — the frontend never has to care.

On this page
Accessing your agent with useAgentSubscribing to AG-UI eventsThe proxy patternHow the Built-in Agent slots into AG-UI