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 AgentClient class and agentFetch function provide a framework-agnostic way to connect to agents from any JavaScript runtime: browsers, Node.js, Deno, Bun, or edge functions.
Installation
npm install agents partysocket
AgentClient
The AgentClient class provides a WebSocket connection to an agent with state synchronization and RPC calls.
Basic Usage
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!" ]);
// Clean up when done
client . close ();
Constructor Options
Name of the agent class to connect to. Automatically converted from camelCase to kebab-case for the URL.
Worker host for the WebSocket connection.
Name of the specific agent instance.
Custom path prefix for the connection URL.
Query parameters to send with the connection.
onStateUpdate
(state: State, source: 'server' | 'client') => void
Callback invoked when the agent’s state is updated.
Callback invoked when a state update fails.
onIdentity
(name: string, agent: string) => void
Callback invoked when the server sends the agent’s identity on connect.
onIdentityChange
(oldName: string, newName: string, oldAgent: string, newAgent: string) => void
Callback invoked when identity changes on reconnect.
Properties
The kebab-case agent name.
The agent instance name. Updated when identity is received from the server.
Whether the client has received identity from the server. Becomes true after the first identity message is received. Resets to false on connection close.
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 so it can be awaited again after reconnect.
Methods
Push state updates to the agent. client . setState ({ count: 42 });
call
<T>(method: string, args?: unknown[], options?: CallOptions | StreamOptions) => Promise<T>
Call a method on the agent. const result = await client . call ( "getUser" , [ "user-123" ]);
send
(data: string | ArrayBuffer | Blob) => void
Send raw WebSocket message. client . send ( JSON . stringify ({ type: "ping" }));
close
(code?: number, reason?: string) => void
Close the WebSocket connection. Immediately rejects all pending RPC calls.
addEventListener
(event: string, listener: EventListener) => void
Add event listeners for WebSocket events (inherited from PartySocket). client . addEventListener ( "open" , () => console . log ( "Connected" ));
client . addEventListener ( "close" , () => console . log ( "Disconnected" ));
client . addEventListener ( "error" , ( e ) => console . error ( "Error:" , e ));
client . addEventListener ( "message" , ( e ) => console . log ( "Message:" , e . data ));
Calling Methods
Basic Calls
// Call with arguments
const user = await client . call ( "getUser" , [ "user-123" ]);
// Call with multiple arguments
const post = await client . call ( "createPost" , [ title , content , tags ]);
// Call with no arguments
const stats = await client . call ( "getStats" );
Call Options
The call method accepts an optional third parameter for configuring timeouts and streaming:
// With timeout
const result = await client . call ( "slowMethod" , [ data ], {
timeout: 10000 // 10 seconds
});
// With streaming
await client . call ( "generateText" , [ prompt ], {
stream: {
onChunk : ( chunk ) => console . log ( "Chunk:" , chunk ),
onDone : ( final ) => console . log ( "Done:" , final ),
onError : ( error ) => console . error ( "Error:" , error )
}
});
// With both timeout and streaming
await client . call ( "generateText" , [ prompt ], {
timeout: 30000 ,
stream: {
onChunk : ( chunk ) => console . log ( "Chunk:" , chunk ),
onDone : ( final ) => console . log ( "Done:" , final ),
onError : ( error ) => console . error ( "Error:" , error )
}
});
For backward compatibility, the legacy format with streaming options directly in the third parameter is still supported: client.call(method, args, { onChunk, onDone, onError }).
Streaming Responses
Handle streaming responses with callbacks:
await client . call ( "generateText" , [ prompt ], {
stream: {
onChunk : ( chunk ) => {
process . stdout . write ( chunk );
},
onDone : ( finalResult ) => {
console . log ( " \n Complete!" );
},
onError : ( error ) => {
console . error ( "Stream error:" , error );
}
}
});
State Management
Receiving State Updates
const client = new AgentClient ({
agent: "GameAgent" ,
name: "game-123" ,
host: "my-worker.workers.dev" ,
onStateUpdate : ( state , source ) => {
console . log ( `State from ${ source } :` , state );
if ( source === "server" ) {
// Agent pushed state
updateUI ( state );
} else {
// We pushed state
console . log ( "Our state was accepted" );
}
}
});
Pushing State Updates
client . setState ({ score: 100 , level: 5 });
When you call setState(), the agent broadcasts the new state to all connected clients. Your onStateUpdate callback will fire with source: "client".
Connection Lifecycle
Waiting for Identity
Use the ready promise to wait for the agent to send its identity:
const client = new AgentClient ({
agent: "MyAgent" ,
name: "instance-1" ,
host: "my-worker.workers.dev"
});
await client . ready ;
console . log ( `Connected to ${ client . agent } / ${ client . name } ` );
Event Listeners
client . addEventListener ( "open" , () => {
console . log ( "Connection opened" );
});
client . addEventListener ( "close" , () => {
console . log ( "Connection closed" );
});
client . addEventListener ( "error" , ( error ) => {
console . error ( "Connection error:" , error );
});
client . addEventListener ( "message" , ( event ) => {
console . log ( "Raw message:" , event . data );
});
Manual Reconnection
The client automatically reconnects on connection loss using PartySocket’s reconnection logic.
Closing the Connection
// Close when done
client . close ();
// Close with custom code and reason
client . close ( 1000 , "Normal closure" );
Calling close() immediately rejects all pending RPC calls. Any calls made after close() will be rejected when the WebSocket close event fires.
Type Safety
Pass your agent class and state type as type parameters:
import type { MyAgent , MyAgentState } from "./agents/my-agent" ;
const client = new AgentClient < MyAgentState >({
agent: "MyAgent" ,
name: "instance-1" ,
host: "my-worker.workers.dev" ,
onStateUpdate : ( state ) => {
// state is typed as MyAgentState
console . log ( state . count );
}
});
HTTP Requests
For one-off requests without maintaining a WebSocket connection, use agentFetch:
Basic Usage
import { agentFetch } from "agents/client" ;
// GET request
const response = await agentFetch ({
agent: "DataAgent" ,
name: "instance-1" ,
host: "my-worker.workers.dev"
});
const data = await response . json ();
POST Request
const response = await agentFetch (
{
agent: "DataAgent" ,
name: "instance-1" ,
host: "my-worker.workers.dev"
},
{
method: "POST" ,
headers: { "Content-Type" : "application/json" },
body: JSON . stringify ({ action: "process" , data: "value" })
}
);
When to Use agentFetch
Use agentFetch
One-time requests
Server-to-server calls
Simple REST-style API
No persistent connection needed
Use AgentClient
Real-time updates needed
Bidirectional communication
State synchronization
Multiple RPC calls
Examples
Simple Counter Client
import { AgentClient } from "agents/client" ;
const client = new AgentClient ({
agent: "CounterAgent" ,
name: "shared-counter" ,
host: "my-worker.workers.dev" ,
onStateUpdate : ( state ) => {
console . log ( "Count:" , state . count );
}
});
// Wait for connection
await client . ready ;
// Increment counter
await client . call ( "increment" );
// Clean up
client . close ();
Streaming AI Client
import { AgentClient } from "agents/client" ;
const client = new AgentClient ({
agent: "AIAgent" ,
name: "assistant" ,
host: "my-worker.workers.dev"
});
await client . ready ;
let fullResponse = "" ;
await client . call ( "generateResponse" , [ "Hello!" ], {
stream: {
onChunk : ( chunk ) => {
fullResponse += chunk ;
process . stdout . write ( chunk );
},
onDone : () => {
console . log ( " \n\n Generation complete!" );
console . log ( "Full response:" , fullResponse );
},
onError : ( error ) => {
console . error ( "Error:" , error );
}
}
});
client . close ();
Node.js Server-to-Agent Communication
import { AgentClient } from "agents/client" ;
import express from "express" ;
const app = express ();
app . use ( express . json ());
app . post ( "/process" , async ( req , res ) => {
const client = new AgentClient ({
agent: "ProcessorAgent" ,
name: req . body . agentId ,
host: "my-worker.workers.dev"
});
try {
await client . ready ;
const result = await client . call ( "process" , [ req . body . data ], {
timeout: 5000
});
res . json ({ success: true , result });
} catch ( error ) {
res . status ( 500 ). json ({ success: false , error: error . message });
} finally {
client . close ();
}
});
app . listen ( 3000 );
Edge Function with agentFetch
import { agentFetch } from "agents/client" ;
export default async function handler ( request : Request ) {
const { agentId } = await request . json ();
const response = await agentFetch (
{
agent: "DataAgent" ,
name: agentId ,
host: "my-worker.workers.dev"
},
{
method: "POST" ,
headers: { "Content-Type" : "application/json" },
body: JSON . stringify ({ action: "getData" })
}
);
const data = await response . json ();
return new Response ( JSON . stringify ( data ), {
headers: { "Content-Type" : "application/json" }
});
}
Error Handling
RPC Errors
try {
const result = await client . call ( "riskyMethod" , [ data ]);
} catch ( error ) {
console . error ( "RPC failed:" , error . message );
}
Connection Errors
client . addEventListener ( "error" , ( error ) => {
console . error ( "WebSocket error:" , error );
});
client . addEventListener ( "close" , ( event ) => {
console . log ( `Connection closed: ${ event . code } ${ event . reason } ` );
});
Streaming Errors
await client . call ( "streamingMethod" , [ data ], {
stream: {
onChunk : ( chunk ) => handleChunk ( chunk ),
onError : ( error ) => {
console . error ( "Stream error:" , error );
// Handle stream-specific errors
}
}
});
Timeout Errors
try {
const result = await client . call ( "slowMethod" , [ data ], {
timeout: 5000
});
} catch ( error ) {
if ( error . message . includes ( "timed out" )) {
console . error ( "Request timed out after 5 seconds" );
}
}
Best Practices
Always close connections when done
In long-running processes, always call close() when you are done with the client to free up resources. const client = new AgentClient ({ agent: "MyAgent" , host: "..." });
try {
await client . call ( "doWork" , [ data ]);
} finally {
client . close ();
}
Wait for ready before making calls
Use the ready promise to ensure the agent identity is received before making RPC calls. await client . ready ;
const result = await client . call ( "method" , [ args ]);
Set appropriate timeouts for long operations
Use the timeout option for operations that may take longer than expected. await client . call ( "longRunningTask" , [ data ], {
timeout: 60000 // 60 seconds
});
Use agentFetch for one-off requests
If you only need to make a single request, use agentFetch instead of creating a WebSocket connection. const response = await agentFetch ({
agent: "MyAgent" ,
name: "instance" ,
host: "my-worker.workers.dev"
});
See Also
Client SDK Overview Learn about the full client SDK capabilities
React Hooks Use the useAgent hook in React applications