INTEGRITY Dokumentace

Rychlý start

Vytvářejte AI agenty, kteří přetrvávají, přemýšlejí a jednají. Agenti běží na globální síti Cloudflare, udržují stav napříč požadavky a v reálném čase se připojují ke klientům přes WebSockets.

Co vytvoříte: Agent počítadla s perzistentním stavem, který se v reálném čase synchronizuje s frontendem v React.

Čas: ~10 minut

Vytvořte nový projekt

npm create cloudflare@latest -- --template cloudflare/agents-starter

Poté nainstalujte závislosti a spusťte vývojový server:

cd agents-starter
npm install
npm run dev

Tím se vytvoří projekt s:

Startovní šablona obsahuje dvě důležité integrace SDK. Pokud projekt nastavujete ručně, přidejte obě:

tsconfig.json : rozšiřuje agents/tsconfig, který nastavuje target: "ES2021" a další doporučené volby:

{
	"extends": "agents/tsconfig"
}

vite.config.ts : zahrnuje agents() plugin, který řeší transformace dekorátorů TC39 (vyžadované pro @callable() ve Vite 8):

import { cloudflare } from "@cloudflare/vite-plugin";
import react from "@vitejs/plugin-react";
import agents from "agents/vite";
import { defineConfig } from "vite";

export default defineConfig({
	plugins: [agents(), react(), cloudflare()],
});

Otevřete http://localhost:5173 ↗ a podívejte se na svého agenta v akci.

Váš první agent

Sestavte jednoduchého agenta počítadla od začátku. Nahraďte src/server.ts:

import { Agent, routeAgentRequest, callable } from "agents";

// Define the state shape

// Create the agent
export class CounterAgent extends Agent {
	// Initial state for new instances
	initialState = { count: 0 };

	// Methods marked with @callable can be called from the client
	@callable()
	increment() {
		this.setState({ count: this.state.count + 1 });
		return this.state.count;
	}

	@callable()
	decrement() {
		this.setState({ count: this.state.count - 1 });
		return this.state.count;
	}

	@callable()
	reset() {
		this.setState({ count: 0 });
	}
}

// Route requests to agents
export default {
	async fetch(request, env, ctx) {
		return (
			(await routeAgentRequest(request, env)) ??
			new Response("Not found", { status: 404 })
		);
	},
};
src/server.ts
import { Agent, routeAgentRequest, callable } from "agents";

// Define the state shape
export type CounterState = {
	count: number;
};

// Create the agent
export class CounterAgent extends Agent<Env, CounterState> {
	// Initial state for new instances
	initialState: CounterState = { count: 0 };

	// Methods marked with @callable can be called from the client
	@callable()
	increment() {
		this.setState({ count: this.state.count + 1 });
		return this.state.count;
	}

	@callable()
	decrement() {
		this.setState({ count: this.state.count - 1 });
		return this.state.count;
	}

	@callable()
	reset() {
		this.setState({ count: 0 });
	}
}

// Route requests to agents
export default {
	async fetch(request: Request, env: Env, ctx: ExecutionContext) {
		return (
			(await routeAgentRequest(request, env)) ??
			new Response("Not found", { status: 404 })
		);
	},
} satisfies ExportedHandler<Env>;

Aktualizujte wrangler.jsonc k registraci agenta:

{
	"name": "my-agent",
	"main": "src/server.ts",
	// Set this to today's date
	"compatibility_date": "2026-08-28",
	"compatibility_flags": ["nodejs_compat"],
	"durable_objects": {
		"bindings": [
			{
				"name": "CounterAgent",
				"class_name": "CounterAgent",
			},
		],
	},
	"migrations": [
		{
			"tag": "v1",
			"new_sqlite_classes": ["CounterAgent"],
		},
	],
}
name = "my-agent"
main = "src/server.ts"
# Set this to today's date
compatibility_date = "2026-08-28"
compatibility_flags = [ "nodejs_compat" ]

[[durable_objects.bindings]]
name = "CounterAgent"
class_name = "CounterAgent"

[[migrations]]
tag = "v1"
new_sqlite_classes = [ "CounterAgent" ]

Klíčové body:

Připojení z Reactu

Nahraďte src/client.tsx:

src/client.tsx
import "./styles.css";
import { createRoot } from "react-dom/client";
import { useState } from "react";
import { useAgent } from "agents/react";
import type { CounterAgent, CounterState } from "./server";

export default function App() {
	const [count, setCount] = useState(0);

	// Connect to the Counter agent
	const agent = useAgent<CounterAgent, CounterState>({
		agent: "CounterAgent",
		onStateUpdate: (state) => setCount(state.count),
	});

	return (
		<div style={{ padding: "2rem", fontFamily: "system-ui" }}>
			<h1>Counter Agent</h1>
			<p style={{ fontSize: "3rem" }}>{count}</p>
			<div style={{ display: "flex", gap: "1rem" }}>
				<button onClick={() => agent.stub.decrement()}>-</button>
				<button onClick={() => agent.stub.reset()}>Reset</button>
				<button onClick={() => agent.stub.increment()}>+</button>
			</div>
		</div>
	);
}

const root = createRoot(document.getElementById("root")!);
root.render(<App />);

Klíčové body:

Jak to funguje

Když jste klikli na tlačítko:

  1. Klient nazvaný agent.stub.increment() přes WebSocket
  2. Agent spustil increment(), aktualizovaný stav s setState()
  3. Stav se automaticky ukládá do SQLite
  4. Vysílání odeslané všem připojeným klientům
  5. React aktualizováno přes onStateUpdate
flowchart LR
    A["Browser<br/>(React)"] <-->|WebSocket| B["Agent<br/>(Counter)"]
    B --> C["SQLite<br/>(State)"]

Klíčové koncepty

Koncept Co to znamená
Instance Agent Každý jedinečný název získá vlastního agenta. CounterAgent:user-123 je oddělený od CounterAgent:user-456
Trvalý stav Stav přežije restarty, nasazení i hibernaci. Je uložen v SQLite
Synchronizace v reálném čase Všichni klienti připojení ke stejnému agentovi dostávají aktualizace stavu okamžitě
Hibernace Když není připojen žádný klient, agent hibernuje (bez nákladů). Probudí se při dalším požadavku

Připojení z čistého JavaScriptu

Pokud nepoužíváte React:

import { AgentClient } from "agents/client";

const agent = new AgentClient({
	agent: "CounterAgent",
	name: "my-counter", // optional, defaults to "default"
	onStateUpdate: (state) => {
		console.log("New count:", state.count);
	},
});

// Call methods
await agent.call("increment");
await agent.call("reset");
import { AgentClient } from "agents/client";

const agent = new AgentClient({
	agent: "CounterAgent",
	name: "my-counter", // optional, defaults to "default"
	onStateUpdate: (state) => {
		console.log("New count:", state.count);
	},
});

// Call methods
await agent.call("increment");
await agent.call("reset");

Deploy to Cloudflare

npm run deploy

Váš agent je nyní aktivní v globální síti Cloudflare a běží blízko vašich uživatelů.

Běžné vzory integrace

Agents za autentizací

Před směrováním na agenty zkontrolujte ověření:

export default {
	async fetch(request, env) {
		// Check auth for agent routes
		if (request.url.includes("/agents/")) {
			const authResult = await checkAuth(request, env);
			if (!authResult.valid) {
				return new Response("Unauthorized", { status: 401 });
			}
		}

		const agentResponse = await routeAgentRequest(request, env);
		if (agentResponse) return agentResponse;

		// ... rest of routing
	},
};
export default {
	async fetch(request: Request, env: Env) {
		// Check auth for agent routes
		if (request.url.includes("/agents/")) {
			const authResult = await checkAuth(request, env);
			if (!authResult.valid) {
				return new Response("Unauthorized", { status: 401 });
			}
		}

		const agentResponse = await routeAgentRequest(request, env);
		if (agentResponse) return agentResponse;

		// ... rest of routing
	},
} satisfies ExportedHandler<Env>;

Vlastní prefix cesty agenta

Ve výchozím nastavení jsou agenti směrováni na /agents/{agent-name}/{instance-name}. Toto můžete přizpůsobit:

import { routeAgentRequest } from "agents";

const agentResponse = await routeAgentRequest(request, env, {
	prefix: "/api/agents", // Now routes at /api/agents/{agent-name}/{instance-name}
});
import { routeAgentRequest } from "agents";

const agentResponse = await routeAgentRequest(request, env, {
	prefix: "/api/agents", // Now routes at /api/agents/{agent-name}/{instance-name}
});

Viz Směrování pro další možnosti, včetně CORS, vlastního pojmenování instancí a nápověd k umístění.

Přístup k agentům ze serverového kódu

S agenty můžete pracovat přímo z kódu Worker:

import { getAgentByName } from "agents";

export default {
	async fetch(request, env) {
		if (request.url.endsWith("/api/increment")) {
			// Get a specific agent instance
			const counter = await getAgentByName(env.CounterAgent, "shared-counter");
			const newCount = await counter.increment();
			return Response.json({ count: newCount });
		}
		// ...
	},
};
import { getAgentByName } from "agents";

export default {
	async fetch(request: Request, env: Env) {
		if (request.url.endsWith("/api/increment")) {
			// Get a specific agent instance
			const counter = await getAgentByName(env.CounterAgent, "shared-counter");
			const newCount = await counter.increment();
			return Response.json({ count: newCount });
		}
		// ...
	},
} satisfies ExportedHandler<Env>;

Přidání více agentů

Přidejte další agenty rozšířením konfigurace:

// src/agents/chat.ts
export class Chat extends Agent {
	// ...
}

// src/agents/scheduler.ts
export class Scheduler extends Agent {
	// ...
}
// src/agents/chat.ts
export class Chat extends Agent {
	// ...
}

// src/agents/scheduler.ts
export class Scheduler extends Agent {
	// ...
}

Aktualizujte konfigurační soubor Wrangler:

{
  "$schema": "./node_modules/wrangler/config-schema.json",
  "durable_objects": {
    "bindings": [
      {
        "name": "CounterAgent",
        "class_name": "CounterAgent"
      },
      {
        "name": "Chat",
        "class_name": "Chat"
      },
      {
        "name": "Scheduler",
        "class_name": "Scheduler"
      }
    ]
  },
  "migrations": [
    {
      "tag": "v1",
      "new_sqlite_classes": [
        "CounterAgent",
        "Chat",
        "Scheduler"
      ]
    }
  ]
}
[[durable_objects.bindings]]
name = "CounterAgent"
class_name = "CounterAgent"

[[durable_objects.bindings]]
name = "Chat"
class_name = "Chat"

[[durable_objects.bindings]]
name = "Scheduler"
class_name = "Scheduler"

[[migrations]]
tag = "v1"
new_sqlite_classes = ["CounterAgent", "Chat", "Scheduler"]

Exportujte všechny agenty ze svého vstupního bodu:

export { CounterAgent } from "./agents/counter";
export { Chat } from "./agents/chat";
export { Scheduler } from "./agents/scheduler";
export { CounterAgent } from "./agents/counter";
export { Chat } from "./agents/chat";
export { Scheduler } from "./agents/scheduler";

Řešení potíží

Agent nenalezen nebo chyby 404

  1. Zkontrolujte export - Třída Agent musí být exportována z hlavního vstupního bodu.
  2. Zkontrolujte vazbu - class_name v konfiguračním souboru Wrangler musí přesně odpovídat exportovanému názvu třídy.
  3. Zkontrolujte trasu - Výchozí trasa je /agents/{'{agent-name}'}/{'{instance-name}'}. Název agenta na klientovi odpovídá názvu třídy (nerozlišuje se velikost písmen).

Chyba No such Durable Object class

Přidejte migraci do konfiguračního souboru Wrangler:

{
  "$schema": "./node_modules/wrangler/config-schema.json",
  "migrations": [
    {
      "tag": "v1",
      "new_sqlite_classes": [
        "YourAgentClass"
      ]
    }
  ]
}
[[migrations]]
tag = "v1"
new_sqlite_classes = ["YourAgentClass"]

Připojení WebSocket selže

Ujistěte se, že vaše směrování předává odpověď beze změny:

// Correct - return the response directly
const agentResponse = await routeAgentRequest(request, env);
if (agentResponse) return agentResponse;

// Wrong - this breaks WebSocket connections
if (agentResponse) return new Response(agentResponse.body);
// Correct - return the response directly
const agentResponse = await routeAgentRequest(request, env);
if (agentResponse) return agentResponse;

// Wrong - this breaks WebSocket connections
if (agentResponse) return new Response(agentResponse.body);

Stav se neukládá

Zkontrolujte, že:

  1. Voláte this.setState(), nikoli úpravou this.state přímo.
  2. Třída agenta je v new_sqlite_classes v migracích.
  3. Připojujete se ke stejnému názvu instance agenta.
  4. onStateUpdate callback je propojený ve vašem klientovi.
  5. Připojení WebSocket je navázáno (zkontrolujte nástroje pro vývojáře v prohlížeči).

chyby typu "Method X is not callable"

Ujistěte se, že jsou vaše metody dekorovány pomocí @callable():

import { Agent, callable } from "agents";

export class MyAgent extends Agent {
	@callable()
	increment() {
		// ...
	}
}
import { Agent, callable } from "agents";

export class MyAgent extends Agent {
	@callable()
	increment() {
		// ...
	}
}

Typové chyby s agent.stub

Přidejte parametry typu agenta a stavu:

import { useAgent } from "agents/react";

// Pass the agent and state types to useAgent
const agent = useAgent({
	agent: "CounterAgent",
	onStateUpdate: (state) => setCount(state.count),
});

// Now agent.stub is fully typed
agent.stub.increment();
import { useAgent } from "agents/react";
import type { CounterAgent, CounterState } from "./server";

// Pass the agent and state types to useAgent
const agent = useAgent<CounterAgent, CounterState>({
	agent: "CounterAgent",
	onStateUpdate: (state) => setCount(state.count),
});

// Now agent.stub is fully typed
agent.stub.increment();

SyntaxError: Invalid or unexpected token hodnotou @callable()

Pokud váš vývojový server selže s SyntaxError: Invalid or unexpected token, nastavte "target": "ES2021" ve vašem tsconfig.json. Tím se zajistí, že transpiler esbuild v rámci Vite převede dekorátory TC39 do staršího zápisu, místo aby je ponechal jako nativní syntaxi.

{
	"compilerOptions": {
		"target": "ES2021"
	}
}

Další kroky

Nyní, když máte funkčního agenta, prozkoumejte tato témata:

Běžné další kroky

Zjistěte, jak Viz
Přidání AI/LLM funkcí Používání modelů AI
Zpřístupnění nástrojů přes MCP MCP servery
Spouštění úloh na pozadí Plánování úloh
Zpracování e-mailů Směrování e-mailů
Použití Cloudflare Workflows Spouštění Workflows

Zjistit více

Správa stavu

Bližší pohled na setState(), initialState a onStateChanged().

Client SDK

Úplná referenční příručka API pro useAgent a AgentClient.

Volatelné metody

Zpřístupní metody klientům pomocí @callable().

Plánování úloh

Spouštějte úlohy s prodlevou, podle plánu nebo pomocí cronu.

Vnitřní fungování třídy Agent

Referenční příručka pro celý životní cyklus a metody.

Agents API

Kompletní referenční dokumentace API pro Agents SDK.