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

# AgentClient

> WebSocket client for connecting to Agents from browsers and Node.js

## Overview

`AgentClient` is a WebSocket client for connecting to Agents from browsers and Node.js. It provides RPC method calls, state synchronization, and identity management.

```typescript theme={null}
import { AgentClient } from "agents/client";

const client = new AgentClient<{ count: number }>({
  host: "localhost:1999",
  agent: "CounterAgent",
  name: "room-123",
  onStateUpdate: (state) => {
    console.log("State:", state);
  }
});

await client.call("increment");
```

## Constructor

<ParamField path="options" type="AgentClientOptions<State>" required>
  <ParamField path="host" type="string" required>
    WebSocket host (e.g., "localhost:1999" or "agent.example.com")
  </ParamField>

  <ParamField path="agent" type="string" required>
    Name of the agent class (kebab-case, e.g., "my-agent")
  </ParamField>

  <ParamField path="name" type="string" default="default">
    Name of the specific Agent instance
  </ParamField>

  <ParamField path="basePath" type="string">
    Full URL path - bypasses agent/name URL construction. When set, connects to this path directly. Server must handle routing manually (e.g., with getAgentByName).
  </ParamField>

  <ParamField path="path" type="string">
    Additional path to append to the URL. Works with both standard routing and basePath.
  </ParamField>

  <ParamField path="onStateUpdate" type="(state: State, source: 'server' | 'client') => void">
    Called when the Agent's state is updated
  </ParamField>

  <ParamField path="onStateUpdateError" type="(error: string) => void">
    Called when a state update fails (e.g., connection is readonly)
  </ParamField>

  <ParamField path="onIdentity" type="(name: string, agent: string) => void">
    Called when the server sends the agent's identity on connect
  </ParamField>

  <ParamField path="onIdentityChange" type="(oldName: string, newName: string, oldAgent: string, newAgent: string) => void">
    Called when identity changes on reconnect (different instance than before)
  </ParamField>
</ParamField>

### Standard Routing

```typescript theme={null}
const client = new AgentClient({
  host: "localhost:1999",
  agent: "chat-agent",
  name: "room-123"
});
// Connects to: ws://localhost:1999/agents/chat-agent/room-123
```

### Custom Routing with basePath

```typescript theme={null}
const client = new AgentClient({
  host: "agent.example.com",
  basePath: "user", // Server routes based on auth
  onIdentity: (name, agent) => {
    console.log("Connected to:", agent, name);
  }
});
// Connects to: wss://agent.example.com/user
```

### With Path Suffix

```typescript theme={null}
const client = new AgentClient({
  host: "localhost:1999",
  agent: "my-agent",
  name: "room",
  path: "settings"
});
// Connects to: ws://localhost:1999/agents/my-agent/room/settings
```

## Properties

### agent

<ResponseField name="agent" type="string" required>
  The agent class name (kebab-case). Updated when identity message is received.
</ResponseField>

### name

<ResponseField name="name" type="string" required>
  The agent instance name. Updated when identity message is received.
</ResponseField>

### identified

<ResponseField name="identified" type="boolean" required>
  Whether the client has received identity from the server. Becomes true after the first identity message, resets to false on connection close.
</ResponseField>

### ready

<ResponseField name="ready" type="Promise<void>" required>
  Promise that resolves when identity has been received from the server. Useful for waiting before making calls that depend on knowing the instance. Resets on connection close.

  ```typescript theme={null}
  await client.ready;
  console.log("Connected to:", client.name);
  ```
</ResponseField>

## Methods

### call()

Call a method on the Agent.

<ParamField path="method" type="string" required>
  Name of the method to call
</ParamField>

<ParamField path="args" type="unknown[]">
  Arguments to pass to the method
</ParamField>

<ParamField path="options" type="CallOptions">
  <ParamField path="timeout" type="number">
    Timeout in milliseconds. If the call doesn't complete within this time, it will be rejected.
  </ParamField>

  <ParamField path="stream" type="StreamOptions">
    <ParamField path="onChunk" type="(chunk: unknown) => void">
      Called when a chunk of data is received
    </ParamField>

    <ParamField path="onDone" type="(finalChunk: unknown) => void">
      Called when the stream ends
    </ParamField>

    <ParamField path="onError" type="(error: string) => void">
      Called when an error occurs
    </ParamField>
  </ParamField>
</ParamField>

**Returns:** `Promise<T>` - Promise that resolves with the method's return value

#### Basic Call

```typescript theme={null}
const result = await client.call("increment");
console.log("Result:", result);
```

#### With Arguments

```typescript theme={null}
const sum = await client.call("add", [5, 3]);
console.log("Sum:", sum);
```

#### With Timeout

```typescript theme={null}
try {
  const result = await client.call("slowMethod", [], {
    timeout: 5000 // 5 seconds
  });
} catch (error) {
  console.error("Timeout or error:", error);
}
```

#### Streaming Call

```typescript theme={null}
const chunks: string[] = [];

await client.call("generateText", ["Hello"], {
  stream: {
    onChunk: (chunk) => {
      chunks.push(chunk.text);
    },
    onDone: (final) => {
      console.log("Stream complete:", final);
    },
    onError: (error) => {
      console.error("Stream error:", error);
    }
  }
});
```

### setState()

Update the Agent's state from the client.

<ParamField path="state" type="State" required>
  New state to set
</ParamField>

```typescript theme={null}
client.setState({ count: 42 });
```

<Note>
  If the connection is readonly, the server will respond with a state update error.
</Note>

### close()

Close the connection and immediately reject all pending RPC calls.

<ParamField path="code" type="number">
  WebSocket close code
</ParamField>

<ParamField path="reason" type="string">
  Close reason
</ParamField>

```typescript theme={null}
client.close(1000, "User closed connection");
```

## Events

AgentClient extends PartySocket, so all PartySocket events are available:

### onopen

```typescript theme={null}
const client = new AgentClient({
  agent: "MyAgent",
  name: "default",
  onOpen: () => {
    console.log("Connected!");
  }
});
```

### onmessage

Internal protocol messages are handled automatically. Override to handle custom messages:

```typescript theme={null}
const client = new AgentClient({
  agent: "MyAgent",
  name: "default",
  onMessage: (event) => {
    // Custom message handling
    console.log("Message:", event.data);
  }
});
```

### onclose

```typescript theme={null}
const client = new AgentClient({
  agent: "MyAgent",
  name: "default",
  onClose: (event) => {
    console.log("Disconnected:", event.code, event.reason);
  }
});
```

### onerror

```typescript theme={null}
const client = new AgentClient({
  agent: "MyAgent",
  name: "default",
  onError: (event) => {
    console.error("Error:", event);
  }
});
```

## Identity Management

The server sends an identity message on connect:

```json theme={null}
{
  "type": "cf_agent_identity",
  "name": "room-123",
  "agent": "chat-agent"
}
```

This is useful when using `basePath` for custom routing:

```typescript theme={null}
const client = new AgentClient({
  host: "agent.example.com",
  basePath: "user",
  onIdentity: (name, agent) => {
    console.log("Connected to instance:", name);
    console.log("Agent class:", agent);
  }
});
```

### Identity Changes

If the server routes to a different instance on reconnect:

```typescript theme={null}
const client = new AgentClient({
  host: "agent.example.com",
  basePath: "user",
  onIdentityChange: (oldName, newName, oldAgent, newAgent) => {
    console.warn(`Reconnected to different instance: ${oldName} → ${newName}`);
  }
});
```

## State Synchronization

The client automatically receives state updates:

```typescript theme={null}
const client = new AgentClient<{ count: number }>({
  host: "localhost:1999",
  agent: "counter-agent",
  name: "default",
  onStateUpdate: (state, source) => {
    console.log(`State updated from ${source}:`, state.count);
  }
});

// Update from client
client.setState({ count: 10 });
// Triggers: onStateUpdate({ count: 10 }, "client")

// Server updates state
// Triggers: onStateUpdate({ count: 11 }, "server")
```

### Readonly Connections

If the connection is readonly, state updates will fail:

```typescript theme={null}
const client = new AgentClient({
  host: "localhost:1999",
  agent: "my-agent",
  name: "viewer",
  onStateUpdateError: (error) => {
    console.error("State update failed:", error);
    // "Connection is readonly"
  }
});

client.setState({ data: "test" });
// Triggers onStateUpdateError
```

## Best Practices

### Wait for Ready

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

// Wait for identity before making calls
await client.ready;
console.log("Connected to:", client.name);

const result = await client.call("method");
```

### Handle Errors

```typescript theme={null}
try {
  const result = await client.call("riskyMethod", [data]);
} catch (error) {
  if (error.message === "Connection closed") {
    // Handle disconnect
  } else {
    // Handle RPC error
  }
}
```

### Clean Up

```typescript theme={null}
// Close connection when done
client.close(1000, "Done");
```

## Related

* [useAgent Hook](/api/use-agent-hook) - React hook for Agents
* [@callable](/api/callable) - Define callable methods
* [Agent Class](/api/agent-class) - Agent base class
