Skip to main content

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.

The useAgent hook provides a React-friendly way to connect to agents with automatic cleanup, state synchronization, and reconnection handling.

Installation

npm install agents partysocket

Basic Usage

import { useAgent } from "agents/react";

function ChatRoom() {
  const agent = useAgent({
    agent: "ChatAgent",
    name: "room-123",
    onStateUpdate: (state) => {
      console.log("New state:", state);
    }
  });

  const sendMessage = async () => {
    await agent.call("sendMessage", ["Hello!"]);
  };

  return (
    <button onClick={sendMessage}>
      Send Message
    </button>
  );
}

Hook Options

UseAgentOptions

agent
string
required
Name of the agent class to connect to. Automatically converted from camelCase to kebab-case for the URL.
name
string
default:"default"
Name of the specific agent instance.
host
string
Custom host for the WebSocket connection. Defaults to the current origin.
path
string
Custom path prefix for the connection URL.
query
Record<string, string | null> | (() => Promise<Record<string, string | null>>)
Query parameters to send with the connection. Can be a static object or an async function that returns query parameters.
queryDeps
unknown[]
Dependencies array for the async query function. When any dependency changes, the query function is re-executed.
cacheTtl
number
default:"300000"
Cache TTL in milliseconds for async query results. Default is 5 minutes (300000ms).
onStateUpdate
(state: State, source: 'server' | 'client') => void
Callback invoked when the agent’s state is updated. The source parameter indicates whether the update came from the server or was pushed by the client.
onStateUpdateError
(error: string) => void
Callback invoked when a state update fails (e.g., connection is readonly).
onMcpUpdate
(mcpServers: MCPServersState) => void
Callback invoked when MCP server state is updated.
onIdentity
(name: string, agent: string) => void
Callback invoked when the server sends the agent’s identity on connect. Useful when using basePath, as the actual instance name is determined server-side.
onIdentityChange
(oldName: string, newName: string, oldAgent: string, newAgent: string) => void
Callback invoked when identity changes on reconnect. If not provided and identity changes, a warning will be logged.
onOpen
() => void
Callback invoked when the WebSocket connection opens.
onClose
() => void
Callback invoked when the WebSocket connection closes.
onError
(error: Event) => void
Callback invoked when a WebSocket error occurs.
onMessage
(message: MessageEvent) => void
Callback invoked when a raw WebSocket message is received.

Return Value

The hook returns a PartySocket instance with additional agent-specific properties and methods:
agent
string
The kebab-case agent name.
name
string
The agent instance name.
identified
boolean
Whether the client has received identity from the server.
ready
Promise<void>
Promise that resolves when identity has been received from the server. Resets on connection close.
setState
(state: State) => void
Push state updates to the agent.
call
<T>(method: string, args?: unknown[], streamOptions?: StreamOptions) => Promise<T>
Call a method on the agent.
stub
Proxy
Proxy object for typed method calls.
send
(data: string | ArrayBuffer | Blob) => void
Send raw WebSocket message.
close
() => void
Close the WebSocket connection.
reconnect
() => void
Force reconnection.

Type Safety

Pass your agent class and state type as type parameters for full type safety:
import type { MyAgent, MyAgentState } from "./agents/my-agent";

function MyComponent() {
  const agent = useAgent<MyAgent, MyAgentState>({
    agent: "MyAgent",
    name: "instance-1",
    onStateUpdate: (state) => {
      // state is typed as MyAgentState
      console.log(state.count);
    }
  });

  // Method calls are fully typed
  const handleClick = async () => {
    const result = await agent.stub.processData({ input: "test" });
    // result type is inferred from MyAgent.processData return type
  };

  return <button onClick={handleClick}>Process</button>;
}

State Management

Receiving State Updates

The onStateUpdate callback receives both the new state and its source:
const agent = useAgent({
  agent: "CounterAgent",
  name: "counter-1",
  onStateUpdate: (state, source) => {
    if (source === "server") {
      console.log("Server pushed state:", state);
    } else {
      console.log("Client pushed state:", state);
    }
    setLocalState(state);
  }
});

Pushing State Updates

const incrementCounter = () => {
  agent.setState({ count: localState.count + 1 });
};
When you call setState(), your onStateUpdate callback will fire with source: "client" after the agent broadcasts the update.

Async Query Parameters

For authentication tokens or other async data, use an async query function:
function AuthenticatedChat({ userId }: { userId: string }) {
  const agent = useAgent({
    agent: "ChatAgent",
    name: "chat-room",
    query: async () => {
      const token = await getAuthToken();
      return { token, userId };
    },
    queryDeps: [userId],
    cacheTtl: 60 * 1000 // 1 minute
  });

  // ...
}
1

Query Execution

The query function is called before establishing the WebSocket connection.
2

Caching

The result is cached for the duration specified by cacheTtl (default: 5 minutes).
3

Re-execution

The query is re-executed when:
  • Any value in queryDeps changes
  • The cacheTtl expires
  • The component remounts

Calling Agent Methods

Using call()

const handleSubmit = async () => {
  try {
    const result = await agent.call("createPost", [title, content]);
    console.log("Post created:", result);
  } catch (error) {
    console.error("Failed to create post:", error);
  }
};

Using the Stub Proxy

const handleSubmit = async () => {
  try {
    const result = await agent.stub.createPost(title, content);
    console.log("Post created:", result);
  } catch (error) {
    console.error("Failed to create post:", error);
  }
};
The stub proxy provides better TypeScript inference and a more natural calling syntax.

Streaming Responses

Handle streaming responses with the onChunk, onDone, and onError callbacks:
function AIChat() {
  const [output, setOutput] = useState("");
  const [isStreaming, setIsStreaming] = useState(false);
  const agent = useAgent({ agent: "AIAgent", name: "chat" });

  const handleGenerate = async () => {
    setIsStreaming(true);
    setOutput("");

    await agent.call("generateText", [prompt], {
      onChunk: (chunk) => {
        setOutput((prev) => prev + chunk);
      },
      onDone: () => {
        setIsStreaming(false);
      },
      onError: (error) => {
        setIsStreaming(false);
        console.error("Stream error:", error);
      }
    });
  };

  return (
    <div>
      <button onClick={handleGenerate} disabled={isStreaming}>
        {isStreaming ? "Generating..." : "Generate"}
      </button>
      <pre>{output}</pre>
    </div>
  );
}

Lifecycle Management

Automatic Cleanup

The hook automatically closes the WebSocket connection when the component unmounts:
function TemporaryConnection() {
  const agent = useAgent({
    agent: "MyAgent",
    name: "temp",
    onClose: () => {
      console.log("Connection closed");
    }
  });

  // Connection is automatically closed when component unmounts
  return <div>Connected to {agent.name}</div>;
}

Manual Reconnection

Force a reconnection with the reconnect() method:
const handleReconnect = () => {
  agent.reconnect();
};

Waiting for Identity

Use the ready promise to wait for the agent to send its identity:
const agent = useAgent({
  agent: "MyAgent",
  name: "instance-1"
});

useEffect(() => {
  agent.ready.then(() => {
    console.log(`Connected to ${agent.name}`);
  });
}, [agent]);

Connection Events

Handle connection lifecycle events with callbacks:
const agent = useAgent({
  agent: "MyAgent",
  name: "my-instance",
  onOpen: () => {
    console.log("Connection opened");
  },
  onClose: () => {
    console.log("Connection closed, will auto-reconnect");
  },
  onError: (error) => {
    console.error("Connection error:", error);
  }
});
The client automatically reconnects on connection loss. You do not need to manually handle reconnection logic.

MCP Server Updates

Receive updates about MCP server state:
function MCPStatus() {
  const [mcpServers, setMcpServers] = useState<MCPServersState>({});

  const agent = useAgent({
    agent: "AssistantAgent",
    name: "session",
    onMcpUpdate: (servers) => {
      setMcpServers(servers);
    }
  });

  return (
    <div>
      {Object.entries(mcpServers).map(([id, server]) => (
        <div key={id}>
          <h3>{id}</h3>
          <p>Status: {server.connectionState}</p>
          <p>Tools: {server.tools?.map((t) => t.name).join(", ")}</p>
        </div>
      ))}
    </div>
  );
}

Examples

Real-time Counter

import { useAgent } from "agents/react";
import { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);

  const agent = useAgent({
    agent: "CounterAgent",
    name: "shared-counter",
    onStateUpdate: (state) => {
      setCount(state.count);
    }
  });

  const increment = () => {
    agent.setState({ count: count + 1 });
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

Authenticated Connection

import { useAgent } from "agents/react";
import { useAuth } from "./hooks/use-auth";

function PrivateChat() {
  const { user } = useAuth();

  const agent = useAgent({
    agent: "PrivateChatAgent",
    name: "private-room",
    query: async () => {
      const token = await getAuthToken();
      return { token, userId: user.id };
    },
    queryDeps: [user.id],
    cacheTtl: 55 * 60 * 1000 // Refresh 5 min before 1 hour expiry
  });

  // ...
}

Streaming AI Response

import { useAgent } from "agents/react";
import { useState } from "react";

function AIAssistant() {
  const [response, setResponse] = useState("");
  const [isGenerating, setIsGenerating] = useState(false);

  const agent = useAgent({
    agent: "AIAgent",
    name: "assistant"
  });

  const handleGenerate = async (prompt: string) => {
    setIsGenerating(true);
    setResponse("");

    await agent.call("generateResponse", [prompt], {
      onChunk: (chunk) => {
        setResponse((prev) => prev + chunk);
      },
      onDone: () => {
        setIsGenerating(false);
      },
      onError: (error) => {
        setIsGenerating(false);
        console.error(error);
      }
    });
  };

  return (
    <div>
      <button
        onClick={() => handleGenerate("Hello!")}
        disabled={isGenerating}
      >
        {isGenerating ? "Generating..." : "Generate"}
      </button>
      <pre>{response}</pre>
    </div>
  );
}

Best Practices

Use Type Parameters

Pass your agent and state types for full type safety and autocomplete.

Handle Reconnection

The hook automatically reconnects. Your onStateUpdate will fire with the latest state on reconnect.

Cache Auth Tokens

Use cacheTtl and queryDeps to optimize auth token fetching.

Clean Up Side Effects

Use useEffect cleanup functions for any side effects triggered by state updates.

See Also

Client SDK Overview

Learn about the full client SDK capabilities

Vanilla JS Client

Use AgentClient in non-React environments

Build docs developers (and LLMs) love