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

# Client SDK Overview

> Connect to agents from any JavaScript runtime using WebSockets or HTTP

Connect to agents from any JavaScript runtime — browsers, Node.js, Deno, Bun, or edge functions — using WebSockets or HTTP. The SDK provides real-time state synchronization, RPC method calls, and streaming responses.

## Available Clients

The client SDK offers two ways to connect with a websocket connection, and one way to make HTTP requests.

<CardGroup cols={3}>
  <Card title="useAgent" icon="react" href="/client/react-hooks">
    React hook with automatic reconnection and state management
  </Card>

  <Card title="AgentClient" icon="code" href="/client/vanilla-js">
    Vanilla JavaScript/TypeScript class for any environment
  </Card>

  <Card title="agentFetch" icon="globe" href="/client/vanilla-js#http-requests">
    HTTP requests when WebSocket is not needed
  </Card>
</CardGroup>

## Core Features

All clients provide:

* **Bidirectional state sync** - Push and receive state updates in real-time
* **RPC calls** - Call agent methods with typed arguments and return values
* **Streaming** - Handle chunked responses for AI completions
* **Auto-reconnection** - Built on [PartySocket](https://docs.partykit.io/reference/partysocket-api/) for reliable connections

## Quick Start

<Tabs>
  <Tab title="React">
    ```tsx theme={null}
    import { useAgent } from "agents/react";

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

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

      return <button onClick={sendMessage}>Send</button>;
    }
    ```
  </Tab>

  <Tab title="Vanilla JS">
    ```typescript theme={null}
    import { AgentClient } from "agents/client";

    const client = new AgentClient({
      agent: "ChatAgent",
      name: "room-123",
      host: "your-worker.your-subdomain.workers.dev",
      onStateUpdate: (state) => {
        console.log("New state:", state);
      }
    });

    // Call a method
    const response = await client.call("sendMessage", ["Hello!"]);
    ```
  </Tab>
</Tabs>

## Connecting to Agents

### Agent Naming

The `agent` parameter is your agent class name. It is automatically converted from camelCase to kebab-case for the URL:

```typescript theme={null}
// These are equivalent:
useAgent({ agent: "ChatAgent" }); // → /agents/chat-agent/...
useAgent({ agent: "MyCustomAgent" }); // → /agents/my-custom-agent/...
useAgent({ agent: "LOUD_AGENT" }); // → /agents/loud-agent/...
```

### Instance Names

The `name` parameter identifies a specific agent instance. If omitted, defaults to `"default"`:

```typescript theme={null}
// Connect to a specific chat room
useAgent({ agent: "ChatAgent", name: "room-123" });

// Connect to a user's personal agent
useAgent({ agent: "UserAgent", name: userId });

// Uses "default" instance
useAgent({ agent: "ChatAgent" });
```

### Connection Options

Both `useAgent` and `AgentClient` accept PartySocket options:

```typescript theme={null}
useAgent({
  agent: "ChatAgent",
  name: "room-123",

  // Connection settings
  host: "my-worker.workers.dev", // Custom host (defaults to current origin)
  path: "/custom/path", // Custom path prefix

  // Query parameters (sent on connection)
  query: {
    token: "abc123",
    version: "2"
  },

  // Event handlers
  onOpen: () => console.log("Connected"),
  onClose: () => console.log("Disconnected"),
  onError: (error) => console.error("Error:", error)
});
```

### Async Query Parameters

For authentication tokens or other async data, pass a function that returns a Promise:

```typescript theme={null}
useAgent({
  agent: "ChatAgent",
  name: "room-123",

  // Async query - called before connecting
  query: async () => {
    const token = await getAuthToken();
    return { token };
  },

  // Dependencies that trigger re-fetching the query
  queryDeps: [userId],

  // Cache TTL for the query result (default: 5 minutes)
  cacheTtl: 60 * 1000 // 1 minute
});
```

<Info>
  The query function is cached and only re-called when `queryDeps` change, `cacheTtl` expires, or the component remounts.
</Info>

## State Synchronization

Agents can maintain state that syncs bidirectionally with all connected clients.

### Receiving State Updates

```typescript theme={null}
const agent = useAgent({
  agent: "GameAgent",
  name: "game-123",
  onStateUpdate: (state, source) => {
    // state: The new state from the agent
    // source: "server" (agent pushed) or "client" (you pushed)
    console.log(`State updated from ${source}:`, state);
    setGameState(state);
  }
});
```

### Pushing State Updates

```typescript theme={null}
// Update the agent's state from the client
agent.setState({ score: 100, level: 5 });
```

When you call `setState()`:

<Steps>
  <Step title="Send to Agent">
    The state is sent to the agent over WebSocket
  </Step>

  <Step title="Agent Processes">
    The agent's `onStateChanged()` method is called
  </Step>

  <Step title="Broadcast to Clients">
    The agent broadcasts the new state to all connected clients
  </Step>

  <Step title="Callback Fires">
    Your `onStateUpdate` callback fires with `source: "client"`
  </Step>
</Steps>

## Calling Agent Methods (RPC)

Call methods on your agent that are decorated with `@callable()`.

<Note>
  The `@callable()` decorator is only required for methods called from external runtimes (browsers, other services). When calling from within the same Worker, you can use standard [Durable Object RPC](https://developers.cloudflare.com/durable-objects/best-practices/create-durable-object-stubs-and-send-requests/#invoke-rpc-methods) directly on the stub without the decorator.
</Note>

### Using call()

```typescript theme={null}
// Basic call
const result = await agent.call("getUser", [userId]);

// Call with multiple arguments
const result = await agent.call("createPost", [title, content, tags]);

// Call with no arguments
const result = await agent.call("getStats");
```

### Using the Stub Proxy

The `stub` property provides a cleaner syntax for method calls:

```typescript theme={null}
// Instead of:
const user = await agent.call("getUser", ["user-123"]);

// You can write:
const user = await agent.stub.getUser("user-123");

// Multiple arguments work naturally:
const post = await agent.stub.createPost(title, content, tags);
```

### TypeScript Integration

For full type safety, pass your Agent class as a type parameter:

```typescript theme={null}
import type { MyAgent } from "./agents/my-agent";

const agent = useAgent<MyAgent, MyAgentState>({
  agent: "MyAgent",
  name: "instance-1"
});

// Now stub methods are fully typed!
const result = await agent.stub.processData({ input: "test" });
//    ^? Awaited<ReturnType<MyAgent["processData"]>>
```

### Streaming Responses

For methods that return `StreamingResponse`, handle chunks as they arrive:

<CodeGroup>
  ```typescript agent.ts theme={null}
  @callable()
  async generateText(prompt: string) {
    return new StreamingResponse(async (stream) => {
      for await (const chunk of llm.stream(prompt)) {
        await stream.write(chunk);
      }
    });
  }
  ```

  ```typescript client.ts theme={null}
  await agent.call("generateText", [prompt], {
    onChunk: (chunk) => {
      // Called for each chunk
      appendToOutput(chunk);
    },
    onDone: (finalResult) => {
      // Called when stream completes
      console.log("Complete:", finalResult);
    },
    onError: (error) => {
      // Called if streaming fails
      console.error("Stream error:", error);
    }
  });
  ```
</CodeGroup>

## MCP Server Integration

If your agent uses MCP (Model Context Protocol) servers, you can receive updates about their state:

```typescript theme={null}
const agent = useAgent({
  agent: "AssistantAgent",
  name: "session-123",
  onMcpUpdate: (mcpServers) => {
    // mcpServers is a record of server states
    for (const [serverId, server] of Object.entries(mcpServers)) {
      console.log(`${serverId}: ${server.connectionState}`);
      console.log(`Tools: ${server.tools?.map((t) => t.name).join(", ")}`);
    }
  }
});
```

## Error Handling

### Connection Errors

```typescript theme={null}
const agent = useAgent({
  agent: "MyAgent",
  onError: (error) => {
    console.error("WebSocket error:", error);
  },
  onClose: () => {
    console.log("Connection closed, will auto-reconnect...");
  }
});
```

### RPC Errors

```typescript theme={null}
try {
  const result = await agent.call("riskyMethod", [data]);
} catch (error) {
  // Error thrown by the agent method
  console.error("RPC failed:", error.message);
}
```

### Streaming Errors

```typescript theme={null}
await agent.call("streamingMethod", [data], {
  onChunk: (chunk) => handleChunk(chunk),
  onError: (errorMessage) => {
    // Stream-specific error handling
    console.error("Stream error:", errorMessage);
  }
});
```

## Best Practices

### Use Typed Stubs

```typescript theme={null}
// Prefer this:
const user = await agent.stub.getUser(id);

// Over this:
const user = await agent.call("getUser", [id]);
```

### Reconnection is Automatic

The client auto-reconnects and the agent automatically sends the current state on each connection. Your `onStateUpdate` callback will fire with the latest state — no manual re-sync needed.

### Optimize Query Caching

```typescript theme={null}
// For auth tokens that expire hourly:
useAgent({
  query: async () => ({ token: await getToken() }),
  cacheTtl: 55 * 60 * 1000, // Refresh 5 min before expiry
  queryDeps: [userId] // Refresh if user changes
});
```

### Clean Up Connections

In vanilla JS, close connections when done:

```typescript theme={null}
const client = new AgentClient({ agent: "MyAgent", host: "..." });

// When done:
client.close();
```

<Check>
  React's `useAgent` handles cleanup automatically on unmount.
</Check>

## Next Steps

<CardGroup cols={2}>
  <Card title="React Hooks" icon="react" href="/client/react-hooks">
    Learn about the useAgent hook and React-specific features
  </Card>

  <Card title="Vanilla JS" icon="code" href="/client/vanilla-js">
    Explore AgentClient and agentFetch for non-React environments
  </Card>
</CardGroup>
