← Vytvářejte agenty na Cloudflare / agents / runtime / communication
Směrování
Tento návod vysvětluje, jak se požadavky směrují k agentům, jak funguje pojmenovávání a jaké existují vzory pro organizaci vašich agentů.
Jak funguje routing
Když přijde požadavek, routeAgentRequest() prozkoumá URL adresu a přesměruje ji na příslušnou instanci agenta:
https://your-worker.dev/agents/{agent-name}/{instance-name}
└────┬────┘ └─────┬─────┘
Class name Unique instance ID
(kebab-case)Příklady URL adres:
| URL | Agent Class | Instance |
|---|---|---|
/agents/counter/user-123 |
Counter |
user-123 |
/agents/chat-room/lobby |
ChatRoom |
lobby |
/agents/my-agent/default |
MyAgent |
default |
Rozlišení názvů
Názvy tříd Agent se pro URL automaticky převádějí na kebab-case:
| Název třídy | URL Path |
|---|---|
Counter |
/agents/counter/... |
MyAgent |
/agents/my-agent/... |
ChatRoom |
/agents/chat-room/... |
AIAssistant |
/agents/ai-assistant/... |
Router odpovídá jak originálnímu názvu, tak verzi v kebab-case, takže můžete použít kterýkoli z nich:
useAgent({ agent: "Counter" })→/agents/counter/...useAgent({ agent: "counter" })→/agents/counter/...
Používání routeAgentRequest()
routeAgentRequest() funkce je hlavním vstupním bodem pro směrování agenta:
import { routeAgentRequest } from "agents";
export default {
async fetch(request, env, ctx) {
// Route to agents - returns Response or undefined
const agentResponse = await routeAgentRequest(request, env);
if (agentResponse) {
return agentResponse;
}
// No agent matched - handle other routes
return new Response("Not found", { status: 404 });
},
};import { routeAgentRequest } from "agents";
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
// Route to agents - returns Response or undefined
const agentResponse = await routeAgentRequest(request, env);
if (agentResponse) {
return agentResponse;
}
// No agent matched - handle other routes
return new Response("Not found", { status: 404 });
},
} satisfies ExportedHandler<Env>;Vzory pojmenování instancí
Název instance (poslední část URL adresy) určuje, která instance agenta požadavek zpracuje. Každý jedinečný název získá vlastního izolovaného agenta s vlastním stavem.
Agenti pro jednotlivé uživatele
Každý uživatel získá vlastní instanci agenta:
// Client
const agent = useAgent({
agent: "UserProfile",
name: `user-${userId}`, // e.g., "user-abc123"
});// Client
const agent = useAgent({
agent: "UserProfile",
name: `user-${userId}`, // e.g., "user-abc123"
});/agents/user-profile/user-abc123 → User abc123's agent
/agents/user-profile/user-xyz789 → User xyz789's agent (separate instance)Sdílené místnosti
Více uživatelů sdílí stejnou instanci agenta:
// Client
const agent = useAgent({
agent: "ChatRoom",
name: roomId, // e.g., "general" or "room-42"
});// Client
const agent = useAgent({
agent: "ChatRoom",
name: roomId, // e.g., "general" or "room-42"
});/agents/chat-room/general → All users in "general" share this agentGlobální singleton
Jedna instance pro celou aplikaci:
// Client
const agent = useAgent({
agent: "AppConfig",
name: "default", // Or any consistent name
});// Client
const agent = useAgent({
agent: "AppConfig",
name: "default", // Or any consistent name
});Dynamické pojmenování
Generujte názvy instancí na základě kontextu:
// Per-session
const agent = useAgent({
agent: "Session",
name: sessionId,
});
// Per-document
const agent = useAgent({
agent: "Document",
name: `doc-${documentId}`,
});
// Per-game
const agent = useAgent({
agent: "Game",
name: `game-${gameId}-${Date.now()}`,
});// Per-session
const agent = useAgent({
agent: "Session",
name: sessionId,
});
// Per-document
const agent = useAgent({
agent: "Document",
name: `doc-${documentId}`,
});
// Per-game
const agent = useAgent({
agent: "Game",
name: `game-${gameId}-${Date.now()}`,
});Vlastní směrování URL
Pro pokročilé případy použití, kde potřebujete kontrolu nad strukturou URL, můžete obejít výchozí /agents/{agent}/{name} vzor.
Používání basePath (na straně klienta)
basePath možnost umožňuje klientům připojit se k jakékoli cestě URL:
// Client connects to /user instead of /agents/user-agent/...
const agent = useAgent({
agent: "UserAgent", // Required but ignored when basePath is set
basePath: "user", // → connects to /user
});// Client connects to /user instead of /agents/user-agent/...
const agent = useAgent({
agent: "UserAgent", // Required but ignored when basePath is set
basePath: "user", // → connects to /user
});Toto se hodí, když:
- Chcete čisté URL adresy bez
/agents/prefix - Název instance se určuje na straně serveru (například z autentizace nebo relace)
- Integrujete se s existující strukturou URL
Výběr instance na straně serveru
Při použití basePath, server musí zajistit směrování. Použijte getAgentByName() k získání instance agenta, poté předejte požadavek pomocí fetch():
export default {
async fetch(request, env) {
const url = new URL(request.url);
// Custom routing - server determines instance from session
if (url.pathname.startsWith("/user/")) {
const session = await getSession(request);
const agent = await getAgentByName(env.UserAgent, session.userId);
return agent.fetch(request); // Forward request directly to agent
}
// Default routing for standard /agents/... paths
return (
(await routeAgentRequest(request, env)) ??
new Response("Not found", { status: 404 })
);
},
};export default {
async fetch(request: Request, env: Env) {
const url = new URL(request.url);
// Custom routing - server determines instance from session
if (url.pathname.startsWith("/user/")) {
const session = await getSession(request);
const agent = await getAgentByName(env.UserAgent, session.userId);
return agent.fetch(request); // Forward request directly to agent
}
// Default routing for standard /agents/... paths
return (
(await routeAgentRequest(request, env)) ??
new Response("Not found", { status: 404 })
);
},
} satisfies ExportedHandler<Env>;Vlastní cesta s dynamickou instancí
Směrujte různé cesty na různé instance:
// Route /chat/{room} to ChatRoom agent
if (url.pathname.startsWith("/chat/")) {
const roomId = url.pathname.replace("/chat/", "");
const agent = await getAgentByName(env.ChatRoom, roomId);
return agent.fetch(request);
}
// Route /doc/{id} to Document agent
if (url.pathname.startsWith("/doc/")) {
const docId = url.pathname.replace("/doc/", "");
const agent = await getAgentByName(env.Document, docId);
return agent.fetch(request);
}// Route /chat/{room} to ChatRoom agent
if (url.pathname.startsWith("/chat/")) {
const roomId = url.pathname.replace("/chat/", "");
const agent = await getAgentByName(env.ChatRoom, roomId);
return agent.fetch(request);
}
// Route /doc/{id} to Document agent
if (url.pathname.startsWith("/doc/")) {
const docId = url.pathname.replace("/doc/", "");
const agent = await getAgentByName(env.Document, docId);
return agent.fetch(request);
}Přijímání identity instance (na straně klienta)
Při použití basePath, klient neví, ke které instanci se připojil, dokud mu server tuto informaci nevrátí. Agent svou identitu odešle automaticky při připojení:
const agent = useAgent({
agent: "UserAgent",
basePath: "user",
onIdentity: (name, agentType) => {
console.log(`Connected to ${agentType} instance: ${name}`);
// e.g., "Connected to user-agent instance: user-123"
},
});
// Reactive state - re-renders when identity is received
return (
<div>
{agent.identified ? `Connected to: ${agent.name}` : "Connecting..."}
</div>
);const agent = useAgent({
agent: "UserAgent",
basePath: "user",
onIdentity: (name, agentType) => {
console.log(`Connected to ${agentType} instance: ${name}`);
// e.g., "Connected to user-agent instance: user-123"
},
});
// Reactive state - re-renders when identity is received
return (
<div>
{agent.identified ? `Connected to: ${agent.name}` : "Connecting..."}
</div>
);Pro AgentClient:
const agent = new AgentClient({
agent: "UserAgent",
basePath: "user",
host: "example.com",
onIdentity: (name, agentType) => {
// Update UI with actual instance name
setInstanceName(name);
},
});
// Wait for identity before proceeding
await agent.ready;
console.log(agent.name); // Now has the server-determined nameconst agent = new AgentClient({
agent: "UserAgent",
basePath: "user",
host: "example.com",
onIdentity: (name, agentType) => {
// Update UI with actual instance name
setInstanceName(name);
},
});
// Wait for identity before proceeding
await agent.ready;
console.log(agent.name); // Now has the server-determined nameZpracování změn identity při opětovném připojení
Pokud se identita při novém připojení změní (například relace vypršela a uživatel se přihlásí jako někdo jiný), můžete to ošetřit pomocí onIdentityChange:
const agent = useAgent({
agent: "UserAgent",
basePath: "user",
onIdentityChange: (oldName, newName, oldAgent, newAgent) => {
console.log(`Session changed: ${oldName} → ${newName}`);
// Refresh state, show notification, etc.
},
});const agent = useAgent({
agent: "UserAgent",
basePath: "user",
onIdentityChange: (oldName, newName, oldAgent, newAgent) => {
console.log(`Session changed: ${oldName} → ${newName}`);
// Refresh state, show notification, etc.
},
});Pokud onIdentityChange není zadán a identita se změní, zaznamená se varování, které pomůže odhalit neočekávané změny relace.
Zakázání identity z bezpečnostních důvodů
Pokud názvy instancí obsahují citlivá data (ID relací, interní ID uživatelů), můžete odesílání identity vypnout:
class SecureAgent extends Agent {
// Do not expose instance names to clients
static options = { sendIdentityOnConnect: false };
}class SecureAgent extends Agent {
// Do not expose instance names to clients
static options = { sendIdentityOnConnect: false };
}Když je identita vypnutá:
agent.identifiedzůstáváfalseagent.readyse nikdy nevyřeší (místo toho použijte aktualizace stavu)onIdentityaonIdentityChangese nikdy nevolají
Kdy použít vlastní směrování
| Scénář | Přístup |
|---|---|
| Standardní přístup agenta | Výchozí /agents/{agent}/{name} |
| Instance z auth/session | basePath + getAgentByName + fetch |
Čisté adresy URL (bez /agents/ prefix) |
basePath + vlastní směrování |
| Starší struktura URL | basePath + vlastní směrování |
| Komplexní logika směrování | Vlastní směrování ve Workeru |
Možnosti směrování
Obojí routeAgentRequest() a getAgentByName() přijímají možnosti pro přizpůsobení chování směrování.
CORS
Pro cross-origin požadavky (běžné, pokud je váš frontend na jiné doméně):
const response = await routeAgentRequest(request, env, {
cors: true, // Enable default CORS headers
});const response = await routeAgentRequest(request, env, {
cors: true, // Enable default CORS headers
});Nebo s vlastními hlavičkami CORS:
const response = await routeAgentRequest(request, env, {
cors: {
"Access-Control-Allow-Origin": "https://myapp.com",
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
},
});const response = await routeAgentRequest(request, env, {
cors: {
"Access-Control-Allow-Origin": "https://myapp.com",
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
},
});Location hints
U aplikací citlivých na latenci naznačte, kde má agent běžet:
// With getAgentByName
const agent = await getAgentByName(env.MyAgent, "instance-name", {
locationHint: "enam", // Eastern North America
});
// With routeAgentRequest (applies to all matched agents)
const response = await routeAgentRequest(request, env, {
locationHint: "enam",
});// With getAgentByName
const agent = await getAgentByName(env.MyAgent, "instance-name", {
locationHint: "enam", // Eastern North America
});
// With routeAgentRequest (applies to all matched agents)
const response = await routeAgentRequest(request, env, {
locationHint: "enam",
});Dostupné nápovědy k umístění: wnam, enam, sam, weur, eeur, apac, oc, afr, me
Jurisdikce
Pro požadavky na umístění dat:
// With getAgentByName
const agent = await getAgentByName(env.MyAgent, "instance-name", {
jurisdiction: "eu", // EU jurisdiction
});
// With routeAgentRequest (applies to all matched agents)
const response = await routeAgentRequest(request, env, {
jurisdiction: "eu",
});// With getAgentByName
const agent = await getAgentByName(env.MyAgent, "instance-name", {
jurisdiction: "eu", // EU jurisdiction
});
// With routeAgentRequest (applies to all matched agents)
const response = await routeAgentRequest(request, env, {
jurisdiction: "eu",
});Props
Vzhledem k tomu, že agenty instancuje runtime a nejsou konstruovány přímo, props poskytuje způsob, jak předat inicializační argumenty:
const agent = await getAgentByName(env.MyAgent, "instance-name", {
props: {
userId: session.userId,
config: { maxRetries: 3 },
},
});const agent = await getAgentByName(env.MyAgent, "instance-name", {
props: {
userId: session.userId,
config: { maxRetries: 3 },
},
});Props se předávají do agentova onStart metoda životního cyklu:
class MyAgent extends Agent {
userId;
config;
async onStart(props) {
this.userId = props?.userId;
this.config = props?.config;
}
}class MyAgent extends Agent<Env, State> {
private userId?: string;
private config?: { maxRetries: number };
async onStart(props?: { userId: string; config: { maxRetries: number } }) {
this.userId = props?.userId;
this.config = props?.config;
}
}Při použití props hodnotou routeAgentRequest, stejné props se předají tomu agentovi, který odpovídá dané URL. To se dobře hodí pro univerzální kontext, jako je autentizace:
export default {
async fetch(request, env) {
const session = await getSession(request);
return routeAgentRequest(request, env, {
props: { userId: session.userId, role: session.role },
});
},
};export default {
async fetch(request, env) {
const session = await getSession(request);
return routeAgentRequest(request, env, {
props: { userId: session.userId, role: session.role },
});
},
} satisfies ExportedHandler<Env>;Pro inicializaci specifickou pro agenta použijte getAgentByName místo toho tam, kde přesně určujete, který agent props obdrží.
Opakování směrování
Použijte routingRetry hodnotou getAgentByName() když má kód na straně serveru opakovat přechodná selhání směrování Durable Object:
const agent = await getAgentByName(env.MyAgent, "instance-name", {
routingRetry: {
maxAttempts: 3,
},
});const agent = await getAgentByName(env.MyAgent, "instance-name", {
routingRetry: {
maxAttempts: 3,
},
});Tato možnost se hodí pro přeposílání požadavků a RPC cesty, kde by se krátkodobé selhání směrování mělo před vrácením chyby volajícímu nejprve zopakovat.
Hooky
routeAgentRequest podporuje hooky pro zachytávání požadavků, než se dostanou k agentům:
const response = await routeAgentRequest(request, env, {
onBeforeConnect: (req, lobby) => {
// Called before WebSocket connections
// Return a Response to reject, Request to modify, or void to continue
},
onBeforeRequest: (req, lobby) => {
// Called before HTTP requests
// Return a Response to reject, Request to modify, or void to continue
},
});const response = await routeAgentRequest(request, env, {
onBeforeConnect: (req, lobby) => {
// Called before WebSocket connections
// Return a Response to reject, Request to modify, or void to continue
},
onBeforeRequest: (req, lobby) => {
// Called before HTTP requests
// Return a Response to reject, Request to modify, or void to continue
},
});Tyto hooky se hodí pro ověřování a validaci. Podrobnosti najdete v Autentizace mezi doménami pro podrobné příklady.
Přístup k agentovi na straně serveru
K agentům máte přístup z kódu Worker pomocí getAgentByName() pro volání RPC:
import { getAgentByName, routeAgentRequest } from "agents";
export default {
async fetch(request, env) {
const url = new URL(request.url);
// API endpoint that interacts with an agent
if (url.pathname === "/api/increment") {
const counter = await getAgentByName(env.Counter, "global-counter");
const newCount = await counter.increment();
return Response.json({ count: newCount });
}
// Regular agent routing
return (
(await routeAgentRequest(request, env)) ??
new Response("Not found", { status: 404 })
);
},
};import { getAgentByName, routeAgentRequest } from "agents";
export default {
async fetch(request: Request, env: Env) {
const url = new URL(request.url);
// API endpoint that interacts with an agent
if (url.pathname === "/api/increment") {
const counter = await getAgentByName(env.Counter, "global-counter");
const newCount = await counter.increment();
return Response.json({ count: newCount });
}
// Regular agent routing
return (
(await routeAgentRequest(request, env)) ??
new Response("Not found", { status: 404 })
);
},
} satisfies ExportedHandler<Env>;Pro možnosti jako locationHint, jurisdiction, a props, přečtěte si Možnosti směrování.
Podcesty a metody HTTP
Požadavky mohou za názvem instance obsahovat dílčí cesty. Ty se předávají do vašeho agenta onRequest() handler:
/agents/api/v1/users → agent: "api", instance: "v1", path: "/users"
/agents/api/v1/users/123 → agent: "api", instance: "v1", path: "/users/123"Zpracování podcest ve vašem agentovi:
export class API extends Agent {
async onRequest(request) {
const url = new URL(request.url);
// url.pathname contains the full path including /agents/api/v1/...
// Extract the sub-path after your agent's base path
const path = url.pathname.replace(/^\/agents\/api\/[^/]+/, "");
if (request.method === "GET" && path === "/users") {
return Response.json(await this.getUsers());
}
if (request.method === "POST" && path === "/users") {
const data = await request.json();
return Response.json(await this.createUser(data));
}
return new Response("Not found", { status: 404 });
}
}export class API extends Agent {
async onRequest(request: Request): Promise<Response> {
const url = new URL(request.url);
// url.pathname contains the full path including /agents/api/v1/...
// Extract the sub-path after your agent's base path
const path = url.pathname.replace(/^\/agents\/api\/[^/]+/, "");
if (request.method === "GET" && path === "/users") {
return Response.json(await this.getUsers());
}
if (request.method === "POST" && path === "/users") {
const data = await request.json();
return Response.json(await this.createUser(data));
}
return new Response("Not found", { status: 404 });
}
}Více agentů
V jednom projektu můžete mít více tříd agentů. Každá má svůj vlastní jmenný prostor:
// server.ts
export { Counter } from "./agents/counter";
export { ChatRoom } from "./agents/chat-room";
export { UserProfile } from "./agents/user-profile";
export default {
async fetch(request, env) {
return (
(await routeAgentRequest(request, env)) ??
new Response("Not found", { status: 404 })
);
},
};// server.ts
export { Counter } from "./agents/counter";
export { ChatRoom } from "./agents/chat-room";
export { UserProfile } from "./agents/user-profile";
export default {
async fetch(request: Request, env: Env) {
return (
(await routeAgentRequest(request, env)) ??
new Response("Not found", { status: 404 })
);
},
} satisfies ExportedHandler<Env>;{
"durable_objects": {
"bindings": [
{ "name": "Counter", "class_name": "Counter" },
{ "name": "ChatRoom", "class_name": "ChatRoom" },
{ "name": "UserProfile", "class_name": "UserProfile" },
],
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["Counter", "ChatRoom", "UserProfile"],
},
],
}[[durable_objects.bindings]]
name = "Counter"
class_name = "Counter"
[[durable_objects.bindings]]
name = "ChatRoom"
class_name = "ChatRoom"
[[durable_objects.bindings]]
name = "UserProfile"
class_name = "UserProfile"
[[migrations]]
tag = "v1"
new_sqlite_classes = [ "Counter", "ChatRoom", "UserProfile" ]Ke každému agentovi se přistupuje přes jeho vlastní cestu:
/agents/counter/...
/agents/chat-room/...
/agents/user-profile/...Tok požadavku
Zde je znázorněno, jak požadavek prochází systémem:
flowchart TD
A["HTTP Request<br/>or WebSocket"] --> B["routeAgentRequest<br/>Parse URL path"]
B --> C["Find binding in<br/>env by name"]
C --> D["Get/create DO<br/>by instance ID"]
D --> E["Agent Instance"]
E --> F{"Protocol?"}
F -->|WebSocket| G["onConnect(), onMessage"]
F -->|HTTP| H["onRequest()"]
Směrování s ověřováním
Požadavky můžete ověřit několika způsoby ještě předtím, než dorazí k vašemu agentovi.
Používání autentizačních hooků
routeAgentRequest() funkce poskytuje onBeforeConnect a onBeforeRequest hooky pro ověřování:
import { Agent, routeAgentRequest } from "agents";
export default {
async fetch(request, env) {
return (
(await routeAgentRequest(request, env, {
// Run before WebSocket connections
onBeforeConnect: async (request) => {
const token = new URL(request.url).searchParams.get("token");
if (!(await verifyToken(token, env))) {
// Return a response to reject the connection
return new Response("Unauthorized", { status: 401 });
}
// Return nothing to allow the connection
},
// Run before HTTP requests
onBeforeRequest: async (request) => {
const auth = request.headers.get("Authorization");
if (!auth || !(await verifyAuth(auth, env))) {
return new Response("Unauthorized", { status: 401 });
}
},
// Optional: prepend a prefix to agent instance names
prefix: "user-",
})) ?? new Response("Not found", { status: 404 })
);
},
};import { Agent, routeAgentRequest } from "agents";
export default {
async fetch(request: Request, env: Env) {
return (
(await routeAgentRequest(request, env, {
// Run before WebSocket connections
onBeforeConnect: async (request) => {
const token = new URL(request.url).searchParams.get("token");
if (!(await verifyToken(token, env))) {
// Return a response to reject the connection
return new Response("Unauthorized", { status: 401 });
}
// Return nothing to allow the connection
},
// Run before HTTP requests
onBeforeRequest: async (request) => {
const auth = request.headers.get("Authorization");
if (!auth || !(await verifyAuth(auth, env))) {
return new Response("Unauthorized", { status: 401 });
}
},
// Optional: prepend a prefix to agent instance names
prefix: "user-",
})) ?? new Response("Not found", { status: 404 })
);
},
} satisfies ExportedHandler<Env>;Ruční ověřování
Zkontrolujte ověření před voláním routeAgentRequest():
export default {
async fetch(request, env) {
const url = new URL(request.url);
// Protect agent routes
if (url.pathname.startsWith("/agents/")) {
const user = await authenticate(request, env);
if (!user) {
return new Response("Unauthorized", { status: 401 });
}
// Optionally, enforce that users can only access their own agents
const instanceName = url.pathname.split("/")[3];
if (instanceName !== `user-${user.id}`) {
return new Response("Forbidden", { status: 403 });
}
}
return (
(await routeAgentRequest(request, env)) ??
new Response("Not found", { status: 404 })
);
},
};export default {
async fetch(request: Request, env: Env) {
const url = new URL(request.url);
// Protect agent routes
if (url.pathname.startsWith("/agents/")) {
const user = await authenticate(request, env);
if (!user) {
return new Response("Unauthorized", { status: 401 });
}
// Optionally, enforce that users can only access their own agents
const instanceName = url.pathname.split("/")[3];
if (instanceName !== `user-${user.id}`) {
return new Response("Forbidden", { status: 403 });
}
}
return (
(await routeAgentRequest(request, env)) ??
new Response("Not found", { status: 404 })
);
},
} satisfies ExportedHandler<Env>;Používání frameworku (Hono)
Pokud používáte framework, jako je Hono ↗, se ověřte v middlewaru před voláním agenta:
import { Agent, getAgentByName } from "agents";
import { Hono } from "hono";
const app = new Hono();
// Authentication middleware
app.use("/agents/*", async (c, next) => {
const token = c.req.header("Authorization")?.replace("Bearer ", "");
if (!token || !(await verifyToken(token, c.env))) {
return c.json({ error: "Unauthorized" }, 401);
}
await next();
});
// Route to a specific agent
app.all("/agents/code-review/:id/*", async (c) => {
const id = c.req.param("id");
const agent = await getAgentByName(c.env.CodeReviewAgent, id);
return agent.fetch(c.req.raw);
});
export default app;import { Agent, getAgentByName } from "agents";
import { Hono } from "hono";
const app = new Hono<{ Bindings: Env }>();
// Authentication middleware
app.use("/agents/*", async (c, next) => {
const token = c.req.header("Authorization")?.replace("Bearer ", "");
if (!token || !(await verifyToken(token, c.env))) {
return c.json({ error: "Unauthorized" }, 401);
}
await next();
});
// Route to a specific agent
app.all("/agents/code-review/:id/*", async (c) => {
const id = c.req.param("id");
const agent = await getAgentByName(c.env.CodeReviewAgent, id);
return agent.fetch(c.req.raw);
});
export default app;Vzory autentizace přes WebSocket (tokeny v URL, obnovení JWT) najdete v Autentizace mezi doménami.
Řešení potíží
Jmenný prostor agenta nebyl nalezen
Chybová zpráva uvádí dostupné agenty. Zkontrolujte:
- Třída Agent je exportována z vašeho vstupního bodu.
- Název třídy v kódu odpovídá
class_namevwrangler.jsonc. - URL adresa používá správný název ve formátu kebab-case.
Požadavek vrátí 404
- Ověřte vzor URL adresy:
/agents/{agent-name}/{instance-name}. - Zkontrolujte, že
routeAgentRequest()se volá před vaším handlerem pro 404. - Ujistěte se, že odpověď z
routeAgentRequest()se vrací (nejen volá).
Připojení WebSocket selže
- Neupravujte odpověď od
routeAgentRequest()pro upgrady WebSocket. - Ujistěte se, že je povoleno CORS, pokud se připojujete z jiného origin.
- Skutečnou chybu zkontrolujte v nástrojích pro vývojáře v prohlížeči.
basePath nefunguje
- Ujistěte se, že váš Worker zpracovává vlastní cestu a přeposílá ji agentovi.
- Použijte
getAgentByName()+agent.fetch(request)k předávání požadavků. -
agentparametr je stále povinný, ale ignoruje se, kdyžbasePathje nastaven. - Zkontrolujte, zda trasa na straně serveru odpovídá klientské
basePath.
Referenční dokumentace API
routeAgentRequest(request, env, options?)
Směruje požadavek k příslušnému agentovi.
| Parametr | Typ | Popis |
|---|---|---|
request |
Request |
Příchozí požadavek |
env |
Env |
Prostředí s vazbami agenta |
options.cors |
boolean | HeadersInit |
Povolte hlavičky CORS |
options.props |
Record<string, unknown> |
Props předané agentovi, který požadavek zpracovává |
options.locationHint |
string |
Preferovaná lokalita pro instance agenta |
options.jurisdiction |
string |
Jurisdikce dat pro instance agentů |
options.onBeforeConnect |
Function |
Callback před WebSocket připojeními |
options.onBeforeRequest |
Function |
Callback před HTTP požadavky |
Vrací: Promise<Response | undefined> - Odpověď při shodě, undefined, pokud neexistuje odpovídající trasa agenta.
getAgentByName(namespace, name, options?)
Získat instanci agenta podle názvu pro RPC na straně serveru nebo přeposílání požadavků.
| Parametr | Typ | Popis |
|---|---|---|
namespace |
DurableObjectNamespace<T> |
Vazba Agent z env |
name |
string |
Název instance |
options.locationHint |
string |
Preferovaná lokalita |
options.jurisdiction |
string |
Jurisdikce dat |
options.props |
Record<string, unknown> |
Inicializační vlastnosti pro onStart |
options.routingRetry |
object |
Konfigurace opakování pro přechodná selhání směrování Durable Object |
Vrací: Promise<DurableObjectStub<T>> - Typovaný stub pro volání metod agenta nebo předávání požadavků.
useAgent(options) / AgentClient možnosti
Možnosti připojení klienta pro vlastní směrování:
| Možnost | Typ | Popis |
|---|---|---|
agent |
string |
Název třídy Agent (povinné) |
name |
string |
Název instance (výchozí: "default") |
basePath |
string |
Úplná cesta URL: obchází konstrukci URL adresy agent/name |
path |
string |
Doplňková cesta, která se připojí k URL |
onIdentity |
(name, agent) => void |
Volá se, když server odešle identitu |
onIdentityChange |
(oldName, newName, oldAgent, newAgent) => void |
Volá se při změně identity při opětovném připojení |
Vlastnosti návratové hodnoty (React hook):
| Vlastnost | Typ | Popis |
|---|---|---|
name |
string |
Aktuální název instance (reaktivní) |
agent |
string |
Aktuální název třídy agenta (reaktivní) |
identified |
boolean |
Zda byla přijata identita (reaktivní) |
ready |
Promise<void> |
Vyřeší se po přijetí identity |
Agent.options (server)
Statické možnosti konfigurace agenta:
| Možnost | Typ | Výchozí | Popis |
|---|---|---|---|
hibernate |
boolean |
true |
Zda by měl agent při nečinnosti hibernovat |
sendIdentityOnConnect |
boolean |
true |
Zda při připojení odeslat identitu klientům |
hungScheduleTimeoutSeconds |
number |
30 |
Časový limit, po kterém je běžící plán považován za zaseknutý |
class SecureAgent extends Agent {
static options = { sendIdentityOnConnect: false };
}class SecureAgent extends Agent {
static options = { sendIdentityOnConnect: false };
}