INTEGRITY Документация

Клиентский SDK

Подключайтесь к агентам из любой среды выполнения JavaScript: в браузере, Node.js, Deno, Bun или edge-функциях, используя WebSockets или HTTP. SDK обеспечивает синхронизацию состояния в реальном времени, вызовы методов RPC и потоковую передачу ответов.

Обзор

Клиентский SDK предлагает два способа подключения через WebSocket и один способ отправки HTTP-запросов.

Клиент Вариант использования
useAgent React-хук с автоматическим переподключением и управлением состоянием
AgentClient Класс Vanilla JavaScript/TypeScript для любой среды
agentFetch HTTP-запросы, когда WebSocket не требуется

Все клиенты предоставляют:

быстрый старт

React

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>;
}
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>;
}

Vanilla JavaScript

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!"]);
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!"]);

Подключение к агентам

Именование Agent

agent параметр, это имя класса вашего агента. Оно автоматически преобразуется из camelCase в kebab-case для URL:

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

Имена экземпляров

name параметр определяет конкретный экземпляр агента. Если его не указать, используется значение по умолчанию "default":

// 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" });
// 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" });

Варианты подключения

Оба useAgent и AgentClient принимают параметры соединения:

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),
});
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),
});

Параметры асинхронного запроса

Для токенов аутентификации или других асинхронных данных передайте функцию, которая возвращает Promise:

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
});
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
});

Функция query кэшируется и повторно вызывается только тогда, когда:

Синхронизация состояния

Agents могут поддерживать состояние, которое синхронизируется в обоих направлениях со всеми подключёнными клиентами.

Чтение текущего состояния

Оба useAgent и AgentClient предоставляет state свойство, которое отражает текущее состояние агента. Изначально оно равно undefined пока с сервера не будет получено первое сообщение о состоянии.

const agent = useAgent({ agent: "GameAgent", name: "game-123" });

// Read the current state at any time
console.log("Current score:", agent.state?.score);
const agent = useAgent({ agent: "GameAgent", name: "game-123" });

// Read the current state at any time
console.log("Current score:", agent.state?.score);

С useAgent, обновления состояния запускают повторный рендер React, поэтому agent.state всегда отражает последнее значение в вашем JSX. При использовании AgentClient, state поле обновляется синхронно при каждой входящей трансляции с сервера или setState вызов.

Получение обновлений состояния

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);
	},
});
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);
	},
});

Отправка обновлений состояния

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

Когда вы вызываете setState():

  1. Состояние отправляется агенту через WebSocket
  2. Агента onStateChanged() метод вызывается
  3. Агент рассылает новое состояние всем подключённым клиентам
  4. Ваш onStateUpdate колбэк срабатывает с source: "client"

Поток состояния

sequenceDiagram
    participant Client
    participant Agent
    Client->>Agent: setState()
    Agent-->>Client: onStateUpdate (broadcast)

Вызов методов агента (RPC)

Вызывайте методы вашего агента, декорированные @callable().

Использование call()

// 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");
// 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");

Использование прокси-заглушки

stub свойство обеспечивает более простой синтаксис для вызова методов:

// 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);
// 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

Для полной типовой безопасности передайте свой класс Agent как параметр типа:

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

// Now stub methods are fully typed
const result = await agent.stub.processData({ input: "test" });
import type { MyAgent } from "./agents/my-agent";

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

// Now stub methods are fully typed
const result = await agent.stub.processData({ input: "test" });

Потоковые ответы

Пометить вызываемый метод как потоковый. Фреймворк передаёт StreamingResponse в качестве первого аргумента:

// Agent-side
import { Agent, callable } from "agents";

class MyAgent extends Agent {
	@callable({ streaming: true })
	async generateText(stream, prompt) {
		for await (const chunk of llm.stream(prompt)) {
			stream.send(chunk);
		}
		stream.end();
	}
}

// Client-side
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);
	},
});
// Agent-side
import { Agent, callable, type StreamingResponse } from "agents";

class MyAgent extends Agent {
	@callable({ streaming: true })
	async generateText(stream: StreamingResponse, prompt: string) {
		for await (const chunk of llm.stream(prompt)) {
			stream.send(chunk);
		}
		stream.end();
	}
}

// Client-side
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);
	},
});

HTTP-запросы с помощью agentFetch

Для разовых запросов без поддержания соединения WebSocket:

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 with body
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" }),
	},
);
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 with body
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" }),
	},
);

Когда использовать agentFetch в сравнении с WebSocket:

Используйте agentFetch Используйте useAgent/AgentClient
Одноразовые запросы Требуются обновления в реальном времени
Межсерверные вызовы Двунаправленная связь
Простой API в стиле REST Синхронизация состояния
Постоянное соединение не требуется Несколько вызовов RPC

Интеграция MCP-сервера

Если ваш агент использует серверы MCP (Model Context Protocol), можно получать обновления об их состоянии:

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(", ")}`);
		}
	},
});
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(", ")}`);
		}
	},
});

Обработка ошибок

Ошибки подключения

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

Ошибки RPC

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

Ошибки потоковой передачи

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

Рекомендации

1. Используйте типизированные стабы

// Prefer this:
const user = await agent.stub.getUser(id);

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

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

2. Переподключение выполняется автоматически

Клиент автоматически переподключается, а агент при каждом подключении автоматически отправляет текущее состояние. Ваш onStateUpdate колбэк сработает с последним состоянием: ручная повторная синхронизация не требуется. Если вы используете асинхронный query функцию для аутентификации, кэш автоматически сбрасывается при отключении, что гарантирует получение свежих токенов при повторном подключении.

3. Оптимизируйте кэширование запросов

// 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
});
// 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
});

4. Очистите соединения

В чистом JS закрывайте соединения по завершении:

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

// When done:
client.close();
const client = new AgentClient({ agent: "MyAgent", host: "..." });

// When done:
client.close();

React useAgent автоматически выполняет очистку при размонтировании.

Справочник по React-хуку

UseAgentOptions

type UseAgentOptions<State> = {
	// Required
	agent: string; // Agent class name

	// Optional
	name?: string; // Instance name (default: "default")
	host?: string; // Custom host
	path?: string; // Custom path prefix

	// Query parameters
	query?: Record<string, string> | (() => Promise<Record<string, string>>);
	queryDeps?: unknown[]; // Dependencies for async query
	cacheTtl?: number; // Query cache TTL in ms (default: 5 min)

	// Callbacks
	onStateUpdate?: (state: State, source: "server" | "client") => void;
	onMcpUpdate?: (mcpServers: MCPServersState) => void;
	onOpen?: () => void;
	onClose?: () => void;
	onError?: (error: Event) => void;
	onMessage?: (message: MessageEvent) => void;
};

Возвращаемое значение

useAgent хук возвращает объект со следующими свойствами и методами:

Свойство/Метод Тип Описание
agent string Имя агента в формате kebab-case
name string Имя экземпляра
setState(state) void Отправка состояния агенту
call(method, args?, options?) Promise Вызов метода агента
stub Proxy Типизированные вызовы методов
send(data) void Отправить необработанное сообщение WebSocket
close() void Закрыть соединение
reconnect() void Принудительное переподключение

Справочник по Vanilla JS

AgentClientOptions

type AgentClientOptions<State> = {
	// Required
	agent: string; // Agent class name
	host: string; // Worker host

	// Optional
	name?: string; // Instance name (default: "default")
	path?: string; // Custom path prefix
	query?: Record<string, string>;

	// Callbacks
	onStateUpdate?: (state: State, source: "server" | "client") => void;
};

Методы AgentClient

Свойство/Метод Тип Описание
agent string Имя агента в формате kebab-case
name string Имя экземпляра
setState(state) void Отправка состояния агенту
call(method, args?, options?) Promise Вызов метода агента
send(data) void Отправить необработанное сообщение WebSocket
close() void Закрыть соединение
reconnect() void Принудительное переподключение

Клиент также поддерживает слушатели событий WebSocket:

client.addEventListener("open", () => {});
client.addEventListener("close", () => {});
client.addEventListener("error", () => {});
client.addEventListener("message", () => {});
client.addEventListener("open", () => {});
client.addEventListener("close", () => {});
client.addEventListener("error", () => {});
client.addEventListener("message", () => {});

События агентных инструментов

Если ваш UI чата отображает сохранённые дочерние запуски из Agents как инструменты, используйте useAgentToolEvents() наряду с useAgent() и useAgentChat(). Hook подписывается на родительское соединение, воспроизводит сохранённые временные шкалы дочерних агентов и группирует запуски по идентификатору родительского вызова инструмента.

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

const agent = useAgent({ agent: "Assistant", name: userId });
const { messages } = useAgentChat({ agent });
const agentTools = useAgentToolEvents({ agent });
import { useAgent, useAgentToolEvents } from "agents/react";
import { useAgentChat } from "@cloudflare/ai-chat/react";

const agent = useAgent({ agent: "Assistant", name: userId });
const { messages } = useAgentChat({ agent });
const agentTools = useAgentToolEvents({ agent });

Следующие шаги

Маршрутизация

Паттерны URL и варианты собственной маршрутизации.

Вызываемые методы

RPC поверх WebSocket для вызовов методов между клиентом и сервером.

Аутентификация между доменами

Защищайте WebSocket-соединения между доменами.

Создайте чат-агента

Полная интеграция клиента с AI-чатом.