In CopilotKit, an agent is any component that implements the AbstractAgent interface and can process user messages, execute tools, and emit AG-UI events. Agents are the “brain” of your AI application - they contain the logic for understanding user intent and generating responses.
CopilotKit is agent-framework agnostic. You can use LangGraph, CrewAI, the built-in agent, or build your own custom agent.
All agents in CopilotKit extend the AbstractAgent base class from @ag-ui/client:
abstract class AbstractAgent { // Unique identifier for this agent agentId?: string; // Current thread ID threadId?: string; // Execute the agent with input and receive events abstract run(input: RunAgentInput): Observable<BaseEvent>; // Abort the current run abstract abortRun(): void; // Create a fresh instance of this agent abstract clone(): AbstractAgent; // Subscribe to agent state changes subscribe(handlers: AgentSubscriptionHandlers): Subscription; // Message and state management messages: Message[]; state: State; isRunning: boolean;}
This interface ensures all agents work consistently across the three-layer architecture.
A ProxiedCopilotRuntimeAgent is the frontend representation of a remote agent. It translates agent operations into HTTP requests to the runtime and streams SSE events back.
const agent = new ProxiedCopilotRuntimeAgent({ runtimeUrl: "http://localhost:4000", agentId: "my-agent", transport: "rest"});// Running the agent makes an HTTP requestconst observable = agent.run({ threadId: "thread_123", runId: "run_456", messages: [{ role: "user", content: "Hello!" }], tools: [], context: {}, state: {}});
The BuiltInAgent is CopilotKit’s default agent implementation, powered by the Vercel AI SDK. It’s perfect for getting started or when you don’t need a complex agent framework.
For development and testing, you can register agents directly on the frontend:
import { CopilotKitCore } from "@copilotkitnext/core";const core = new CopilotKitCore({ agents__unsafe_dev_only: { "my-agent": new MyCustomAgent("my-agent") }});
The agents__unsafe_dev_only option exposes your agent logic to the client. Only use this in development or when your agent contains no sensitive logic.
In production, agents are registered on the runtime:
import { CopilotRuntime } from "@copilotkitnext/runtime";import { BuiltInAgent } from "@copilotkitnext/agent";const runtime = new CopilotRuntime({ agents: { "assistant": new BuiltInAgent({ agentId: "assistant", model: openai("gpt-4") }), "researcher": new MyCustomAgent("researcher") }});
The frontend discovers these agents automatically:
// Frontend codeconst core = new CopilotKitCore({ runtimeUrl: "http://localhost:4000"});// Runtime fetches /info and creates ProxiedAgents// Now you can use the agents:const agent = core.getAgent("assistant");
Tools - Agent-specific tools via agentId parameter
// Agent-specific tooluseFrontendTool({ name: "analyzeCode", agentId: "code-assistant", // Only available to this agent parameters: z.object({ code: z.string() }), execute: async ({ code }) => { return analysis; }});// Global tool (available to all agents)useFrontendTool({ name: "getUser", // No agentId - available to all agents parameters: z.object({}), execute: async () => { return currentUser; }});
// Agent state is passed with each runconst result = await agent.runAgent({ threadId: "thread_123", messages: [...], state: { userPreferences: { theme: "dark" }, sessionData: { ... } }});// State is returned and can be persistedconst updatedState = result.state;