showcase/shell-docs/src/content/reference/hooks/useAgent.mdx
useAgent is a React hook that returns an AG-UI AbstractAgent instance. The hook subscribes to agent state changes and triggers re-renders when the agent's state, messages, or execution status changes.
Throws error if no agent is configured with the specified agentId.
import { useAgent } from "@copilotkit/react-core/v2";
function useAgent(options?: UseAgentProps): {
agent: AbstractAgent;
isReady: boolean;
};
Pass an empty array `[]` to prevent automatic re-renders.
### Core Properties
<PropertyReference name="agentId" type="string | undefined">
Unique identifier for the agent instance.
</PropertyReference>
<PropertyReference name="description" type="string">
Human-readable description of the agent's purpose.
</PropertyReference>
<PropertyReference name="threadId" type="string">
Unique identifier for the current conversation thread.
</PropertyReference>
<PropertyReference name="messages" type="Message[]">
Array of conversation messages. Each message contains:
- `id: string` - Unique message identifier
- `role: "user" | "assistant" | "system"` - Message role
- `content: string` - Message content
</PropertyReference>
<PropertyReference name="state" type="any">
Shared state object synchronized between application and agent. Both can read and modify this state.
</PropertyReference>
<PropertyReference name="isRunning" type="boolean">
Indicates whether the agent is currently executing.
</PropertyReference>
### Methods
<PropertyReference name="runAgent" type="(parameters?: RunAgentParameters, subscriber?: AgentSubscriber) => Promise<RunAgentResult>">
Manually triggers agent execution. Resolves with a `RunAgentResult` (`{ result, newMessages }`) once the run finalizes. `result` is the final value of the run and `newMessages` are the messages produced during it.
**Parameters:**
- `parameters.forwardedProps?: any` - Data to pass to the agent execution context
**Example:**
```tsx
const { result, newMessages } = await agent.runAgent({
forwardedProps: {
command: { resume: "user response" }
}
});
```
</PropertyReference>
<PropertyReference name="setState" type="(newState: any) => void">
Updates the shared state. Changes are immediately available to both application and agent.
**Example:**
```tsx
agent.setState({
...agent.state,
theme: "dark"
});
```
</PropertyReference>
<PropertyReference name="subscribe" type="(subscriber: AgentSubscriber) => { unsubscribe: () => void }">
Subscribes to agent events. Returns cleanup function.
**Subscriber Events:**
- `onCustomEvent?: ({ event: { name: string, value: any } }) => void` - Custom events
- `onRunStartedEvent?: () => void` - Agent execution starts
- `onRunFinalized?: () => void` - Agent execution completes
- `onStateChanged?: (state: any) => void` - State changes
- `onMessagesChanged?: (messages: Message[]) => void` - Messages added/modified
</PropertyReference>
<PropertyReference name="addMessage" type="(message: Message) => void">
Adds a single message to the conversation and notifies subscribers.
</PropertyReference>
<PropertyReference name="addMessages" type="(messages: Message[]) => void">
Adds multiple messages to the conversation and notifies subscribers once.
</PropertyReference>
<PropertyReference name="setMessages" type="(messages: Message[]) => void">
Replaces the entire message history with a new array of messages.
</PropertyReference>
<PropertyReference name="abortRun" type="() => void">
Aborts the currently running agent execution.
</PropertyReference>
<PropertyReference name="clone" type="() => AbstractAgent">
Creates a deep copy of the agent with cloned messages, state, and configuration.
</PropertyReference>
`agent` is always a fully-constructed instance, so calling its methods is
always safe. While `isReady` is `false`, the instance is a placeholder that
is swapped for the real agent once the runtime finishes syncing — at which
point `agent` changes reference and dependent effects re-run. Guard on
`isReady` when you only want to act against the real agent, e.g. subscribing
to run-lifecycle events you don't want to miss during the provisional
window.
function AgentStatus() {
const { agent } = useAgent();
return (
<div>
<div>Agent: {agent.agentId}</div>
<div>Messages: {agent.messages.length}</div>
<div>Running: {agent.isRunning ? "Yes" : "No"}</div>
</div>
);
}
function StateController() {
const { agent } = useAgent();
return (
<div>
<pre>{JSON.stringify(agent.state, null, 2)}</pre>
<button onClick={() => agent.setState({ ...agent.state, count: 1 })}>
Update State
</button>
</div>
);
}
function EventListener() {
const { agent, isReady } = useAgent();
useEffect(() => {
// Guard on `isReady` so the subscription lands on the real agent rather
// than the provisional one shown while the runtime is still connecting.
// Depending on `agent` re-subscribes automatically once the real agent
// is bound.
if (!isReady) return;
const { unsubscribe } = agent.subscribe({
onRunStartedEvent: () => console.log("Started"),
onRunFinalized: () => console.log("Finished"),
});
return unsubscribe;
}, [agent, isReady]);
return null;
}
function MultiAgentView() {
const { agent: primary } = useAgent({ agentId: "primary" });
const { agent: support } = useAgent({ agentId: "support" });
return (
<div>
<div>Primary: {primary.messages.length} messages</div>
<div>Support: {support.messages.length} messages</div>
</div>
);
}
// Only re-render when messages change
function MessageCount() {
const { agent } = useAgent({
updates: [UseAgentUpdate.OnMessagesChanged],
});
return <div>Messages: {agent.messages.length}</div>;
}
updates parameter)agent is a fully-constructed provisional stand-in and isReady is false; once the runtime syncs, agent swaps to the real instance and isReady becomes true. Guard on isReady for work that must target the real agent (e.g. one-time subscriptions)agentIdsetState() are immediately available to both app and agent