Skip to content
Built with

Chat client SDK examples ​

Build & Deploy

Small, copy-ready snippets for the chat client SDK guide. Based on the Cloudflare Agents documentation (Client SDK, Chat agents); check there for the latest API.

Minimal React chat ​

tsx
import { useAgent } from "agents/react";
import { useAgentChat } from "@cloudflare/ai-chat/react";

export function Chat({ userId }: { userId: string }) {
  const agent = useAgent({ agent: "ChatAgent", name: userId });
  const { messages, sendMessage, status, stop } = useAgentChat({ agent });
  return (
    <>
      {messages.map((m) => (
        <p key={m.id}><b>{m.role}:</b> {m.parts.map((p) => (p.type === "text" ? p.text : "")).join("")}</p>
      ))}
      <form onSubmit={(e) => { e.preventDefault(); const i = e.currentTarget.q; sendMessage({ text: i.value }); i.value = ""; }}>
        <input name="q" />
        {status === "streaming" ? <button type="button" onClick={stop}>Stop</button> : <button disabled={status !== "ready"}>Send</button>}
      </form>
    </>
  );
}

Auth token on connect ​

ts
const agent = useAgent({
  agent: "ChatAgent",
  name: userId,
  query: async () => ({ token: await getToken() }),
  queryDeps: [userId],
  cacheTtl: 55 * 60 * 1000, // refresh before a 1-hour token expires
});

Check the token in the agent's onConnect (or in your Worker before routing) and close the connection if it is invalid.

Vue (no React) ​

ts
import { useChat } from "@ai-sdk/vue";
import { AgentClient } from "agents/client";
import { WebSocketChatTransport } from "agents/chat/transport";

const agent = new AgentClient({ agent: "ChatAgent", name: userId, host: location.host });
const { messages, sendMessage, status } = useChat({ transport: new WebSocketChatTransport({ agent }) });

Client-side tool (browser location) ​

ts
useAgentChat({
  agent,
  onToolCall: async ({ toolCall, addToolOutput }) => {
    if (toolCall.toolName !== "getLocation") return;
    const pos = await new Promise<GeolocationPosition>((ok, no) => navigator.geolocation.getCurrentPosition(ok, no));
    addToolOutput({ toolCallId: toolCall.toolCallId, output: { lat: pos.coords.latitude, lng: pos.coords.longitude } });
  },
});

Approve or reject a tool call ​

tsx
import { getToolApproval, getToolPartState } from "@cloudflare/ai-chat/react";

function Approval({ part, respond }) {
  const a = getToolApproval(part);
  if (getToolPartState(part) !== "waiting-approval" || !a) return null;
  return (
    <>
      <button onClick={() => respond({ id: a.id, approved: true })}>Approve</button>
      <button onClick={() => respond({ id: a.id, approved: false })}>Reject</button>
    </>
  );
}
// <Approval part={part} respond={addToolApprovalResponse} />

Extra data per message ​

ts
// client
useAgentChat({ agent, body: () => ({ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone }) });

// server, inside onChatMessage(_onFinish, options)
const { timezone } = options?.body ?? {};

One-off HTTP call ​

ts
import { agentFetch } from "agents/client";

const res = await agentFetch(
  { agent: "ReportAgent", name: "daily", host: "my-worker.example.workers.dev" },
  { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ run: true }) },
);

Source: Cloudflare Agents documentation (developers.cloudflare.com), summarized in our own words by implemented.stream. Last checked 2026-10-17.

implemented.stream AI