Documentation Index
Fetch the complete documentation index at: https://mintlify.com/cloudflare/agents/llms.txt
Use this file to discover all available pages before exploring further.
Overview
useAgent is a React hook for connecting to Agents via WebSocket. It provides real-time state synchronization, typed RPC method calls, and identity management.
import { useAgent } from "agents/react";
function Counter() {
const [state, setState] = useState<{ count: number }>();
const agent = useAgent<{ count: number }>({
agent: "CounterAgent",
name: "default",
onStateUpdate: (newState) => setState(newState)
});
return (
<div>
<p>Count: {state?.count ?? 0}</p>
<button onClick={() => agent.call("increment")}>
Increment
</button>
</div>
);
}
Options
options
UseAgentOptions<State>
required
Name of the agent class (e.g., “MyAgent” → “my-agent”)
Name of the specific Agent instance
Full URL path - bypasses agent/name URL construction. Server must handle routing manually (e.g., with getAgentByName + fetch).
Additional path to append to the URL. Works with both standard routing and basePath.
query
QueryObject | (() => Promise<QueryObject>)
Query parameters - can be static object or async function
Dependencies for async query caching
Cache TTL in milliseconds for auth tokens/time-sensitive data (default: 5 minutes)
onStateUpdate
(state: State, source: 'server' | 'client') => void
Called when the Agent’s state is updated
Called when a state update fails (e.g., connection is readonly)
onMcpUpdate
(mcpServers: MCPServersState) => void
Called when MCP server state is updated
onIdentity
(name: string, agent: string) => void
Called when the server sends the agent’s identity on connect
onIdentityChange
(oldName: string, newName: string, oldAgent: string, newAgent: string) => void
Called when identity changes on reconnect
Whether the connection should be enabled. Useful for conditional connections.
Return Value
Returns a PartySocket instance extended with:
The agent class name (kebab-case)
Whether identity has been received from the server
Promise that resolves when identity is received
setState
(state: State) => void
required
Update the Agent’s state from the client
call
(method: string, args?: unknown[], options?: StreamOptions) => Promise<T>
required
Call a method on the Agent via RPC
Typed RPC stub for calling Agent methods
Basic Usage
State Synchronization
import { useAgent } from "agents/react";
import { useState } from "react";
function Counter() {
const [state, setState] = useState<{ count: number }>();
const agent = useAgent<{ count: number }>({
agent: "CounterAgent",
name: "default",
onStateUpdate: (newState) => setState(newState)
});
return (
<div>
<p>Count: {state?.count ?? 0}</p>
<button onClick={() => agent.call("increment")}>
Increment
</button>
</div>
);
}
Typed RPC with Stub
type CounterAgent = Agent<Env, { count: number }> & {
increment(): Promise<number>;
add(amount: number): Promise<number>;
};
function Counter() {
const agent = useAgent<CounterAgent>({
agent: "CounterAgent",
name: "default"
});
const handleIncrement = async () => {
// Fully typed!
const newCount = await agent.stub.increment();
console.log("New count:", newCount);
};
const handleAdd = async () => {
const newCount = await agent.stub.add(5);
console.log("New count:", newCount);
};
return (
<div>
<button onClick={handleIncrement}>Increment</button>
<button onClick={handleAdd}>Add 5</button>
</div>
);
}
Advanced Usage
Custom Routing with basePath
function UserDashboard() {
const [state, setState] = useState();
// Server routes based on auth context
const agent = useAgent({
agent: "UserAgent",
basePath: "user",
onStateUpdate: setState,
onIdentity: (name, agentClass) => {
console.log(`Connected to ${agentClass} instance: ${name}`);
}
});
return <div>User: {state?.username}</div>;
}
Async Query Parameters
function AuthenticatedChat() {
const agent = useAgent({
agent: "ChatAgent",
name: "room-123",
query: async () => {
const token = await getAuthToken();
return { token };
},
queryDeps: [], // Re-run query when deps change
cacheTtl: 60000 // Cache token for 1 minute
});
return <ChatUI agent={agent} />;
}
Conditional Connection
function Chat({ enabled }: { enabled: boolean }) {
const agent = useAgent({
agent: "ChatAgent",
name: "default",
enabled // Only connect when enabled
});
if (!enabled) {
return <p>Disconnected</p>;
}
return <ChatUI agent={agent} />;
}
MCP Server Updates
function McpTools() {
const [mcpServers, setMcpServers] = useState<MCPServersState>();
const agent = useAgent({
agent: "MyAgent",
name: "default",
onMcpUpdate: (servers) => setMcpServers(servers)
});
return (
<div>
<h3>Available Tools:</h3>
<ul>
{mcpServers?.tools.map(tool => (
<li key={tool.name}>{tool.name}</li>
))}
</ul>
</div>
);
}
Identity Changes
function DynamicAgent() {
const agent = useAgent({
agent: "SessionAgent",
basePath: "session",
onIdentityChange: (oldName, newName) => {
console.warn(`Session changed: ${oldName} → ${newName}`);
// Handle session migration
}
});
return <div>Session: {agent.name}</div>;
}
Streaming RPC
Streaming Text Generation
function Chat() {
const [chunks, setChunks] = useState<string[]>([]);
const [loading, setLoading] = useState(false);
const agent = useAgent({
agent: "ChatAgent",
name: "default"
});
const handleSend = async (message: string) => {
setLoading(true);
setChunks([]);
await agent.call("chat", [message], {
onChunk: (chunk: { text: string }) => {
setChunks(prev => [...prev, chunk.text]);
},
onDone: () => {
setLoading(false);
},
onError: (error) => {
console.error("Stream error:", error);
setLoading(false);
}
});
};
return (
<div>
<div>{chunks.join("")}</div>
<button onClick={() => handleSend("Hello")} disabled={loading}>
Send
</button>
</div>
);
}
Connection State
Wait for Ready
function MyComponent() {
const agent = useAgent({
agent: "MyAgent",
name: "default"
});
useEffect(() => {
agent.ready.then(() => {
console.log("Connected to:", agent.name);
});
}, [agent]);
return <div>Agent: {agent.identified ? agent.name : "Connecting..."}</div>;
}
Connection Events
function ConnectionStatus() {
const [status, setStatus] = useState("connecting");
const agent = useAgent({
agent: "MyAgent",
name: "default",
onOpen: () => setStatus("connected"),
onClose: () => setStatus("disconnected"),
onError: () => setStatus("error")
});
return <div>Status: {status}</div>;
}
Query Caching
Async query results are cached to avoid re-fetching on every render:
function SecureChat({ userId }: { userId: string }) {
const agent = useAgent({
agent: "ChatAgent",
name: "default",
query: async () => {
const token = await fetchToken(userId);
return { token };
},
queryDeps: [userId], // Re-fetch when userId changes
cacheTtl: 5 * 60 * 1000 // Cache for 5 minutes
});
return <ChatUI agent={agent} />;
}
Cache Invalidation
- Cache is invalidated when
queryDeps change
- Cache expires after
cacheTtl milliseconds
- Cache is cleared on connection close (forces re-fetch on reconnect)
Error Handling
RPC Errors
function MyComponent() {
const agent = useAgent({ agent: "MyAgent", name: "default" });
const handleAction = async () => {
try {
await agent.call("riskyMethod");
} catch (error) {
console.error("RPC error:", error.message);
}
};
return <button onClick={handleAction}>Action</button>;
}
State Update Errors
function ReadonlyViewer() {
const agent = useAgent({
agent: "MyAgent",
name: "viewer",
onStateUpdateError: (error) => {
console.error("Cannot update state:", error);
// "Connection is readonly"
}
});
// This will trigger onStateUpdateError if connection is readonly
const handleUpdate = () => {
agent.setState({ data: "test" });
};
return <button onClick={handleUpdate}>Update</button>;
}
Best Practices
function useCounterState() {
const [state, setState] = useState<{ count: number }>();
const agent = useAgent<{ count: number }>({
agent: "CounterAgent",
name: "default",
onStateUpdate: setState
});
return { state, agent };
}
function Counter() {
const { state, agent } = useCounterState();
return (
<div>
<p>Count: {state?.count ?? 0}</p>
<button onClick={() => agent.call("increment")}>
Increment
</button>
</div>
);
}
Memoize Callbacks
function MyComponent() {
const [state, setState] = useState();
const handleStateUpdate = useCallback((newState) => {
setState(newState);
}, []);
const agent = useAgent({
agent: "MyAgent",
name: "default",
onStateUpdate: handleStateUpdate
});
return <div>{/* ... */}</div>;
}
Type Safety
type MyAgentType = Agent<Env, State> & {
myMethod(arg: string): Promise<number>;
};
function TypedComponent() {
const agent = useAgent<MyAgentType>({
agent: "MyAgent",
name: "default"
});
// Fully typed!
const result = await agent.stub.myMethod("hello");
// ^? number
return <div />;
}