このガイドでは、リクエストがエージェントへどうルーティングされるか、命名の仕組み、エージェントを整理するパターンを説明します。
リクエストが届くと、routeAgentRequest() は URL を調べ、適切なエージェントインスタンスへルーティングします。
https://your-worker.dev/agents/{agent-name}/{instance-name}
└────┬────┘ └─────┬─────┘
クラス名 一意なインスタンス ID
(kebab-case)URL の例:
| URL | エージェントクラス | インスタンス |
|---|---|---|
/agents/counter/user-123 |
Counter |
user-123 |
/agents/chat-room/lobby |
ChatRoom |
lobby |
/agents/my-agent/default |
MyAgent |
default |
エージェントクラス名は、URL 向けに自動で kebab-case に変換されます。
| クラス名 | URL パス |
|---|---|
Counter |
/agents/counter/... |
MyAgent |
/agents/my-agent/... |
ChatRoom |
/agents/chat-room/... |
AIAssistant |
/agents/ai-assistant/... |
ルーターは元の名前と kebab-case 版の両方に一致するため、どちらでも使えます。
useAgent({ agent: "Counter" })→/agents/counter/...useAgent({ agent: "counter" })→/agents/counter/...
routeAgentRequest() 関数は、エージェントルーティングの主なエントリポイントです。
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>;既知のエージェント ID 向けのパス名を作るには、buildAgentPath() を使います。この関数はルート経路と、入れ子の各 /sub/ 経路を処理します。
import { buildAgentPath, buildAgentUrl } from "agents";
const address = [
{ className: "Inbox", name: userId },
{ className: "Chat", name: chatId },
];
buildAgentPath(address, { leafPath: "/callbacks/job" });
// /agents/inbox/{userId}/sub/chat/{chatId}/callbacks/job
buildAgentUrl("https://app.example.com", address, {
leafPath: "/callbacks/job",
});
// URL("https://app.example.com/agents/inbox/...")import { buildAgentPath, buildAgentUrl } from "agents";
const address = [
{ className: "Inbox", name: userId },
{ className: "Chat", name: chatId },
];
buildAgentPath(address, { leafPath: "/callbacks/job" });
// /agents/inbox/{userId}/sub/chat/{chatId}/callbacks/job
buildAgentUrl("https://app.example.com", address, {
leafPath: "/callbacks/job",
});
// URL("https://app.example.com/agents/inbox/...")エージェント内では、this.selfPath がルート優先の ID を提供します。ルート Durable Object のバインディング名がクラス名と異なる場合は、rootBinding としてバインディング名を渡します。パス名は HTTP リクエストと WebSocket 接続の両方に対応します。
カスタムのルートプレフィックスを使う場合は、同じ prefix を buildAgentPath() と routeAgentRequest() に渡します。コールバックと webhook の例は サブエージェント を参照してください。
インスタンス名(URL の最後の部分)は、どのエージェントインスタンスがリクエストを処理するかを決めます。一意な名前ごとに、独自の状態を持つ隔離されたエージェントが作られます。
各ユーザーが自身のエージェントインスタンスを持ちます。
// 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)複数ユーザーが同じエージェントインスタンスを共有します。
// 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 agentアプリケーション全体で 1 つのインスタンスです。
// Client
const agent = useAgent({
agent: "AppConfig",
name: "default", // Or any consistent name
});// Client
const agent = useAgent({
agent: "AppConfig",
name: "default", // Or any consistent name
});コンテキストに基づいてインスタンス名を生成します。
// 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()}`,
});デフォルトの /agents/{agent}/{name} パターンを迂回し、URL 構造を制御する必要がある高度な用途では、次を使えます。
basePath オプションを使うと、クライアントは任意の 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
});次のときに便利です。
/agents/プレフィックスなしのきれいな URL が欲しい- インスタンス名をサーバー側で決める(認証 / セッションなど)
- 既存の URL 構造と連携する
basePath を使うとき、サーバーがルーティングを処理する必要があります。getAgentByName() でエージェントインスタンスを取得し、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>;異なるパスを異なるインスタンスへルーティングします。
// 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);
}basePath を使うとき、サーバーがこの情報を返すまで、クライアントはどのインスタンスに接続したかを知りません。エージェントは接続時に自身の ID を自動送信します。
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>
);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 name再接続時に ID が変わる場合(セッション期限切れ後、別ユーザーとしてログインするなど)は、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.
},
});onIdentityChange がなく、ID が変わった場合は、想定外のセッション変更を見つけるために警告がログされます。
インスタンス名に機微データ(セッション ID、内部ユーザー ID)が含まれる場合、ID の送信を無効にできます。
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 };
}ID が無効なとき:
agent.identifiedはfalseのままですagent.readyは解決しません(代わりに状態更新を使います)onIdentityとonIdentityChangeは呼ばれません
| シナリオ | アプローチ |
|---|---|
| 標準のエージェントアクセス | デフォルトの /agents/{agent}/{name} |
| 認証 / セッションからのインスタンス | basePath + getAgentByName + fetch |
きれいな URL(/agents/ プレフィックスなし) |
basePath + カスタムルーティング |
| レガシー URL 構造 | basePath + カスタムルーティング |
| 複雑なルーティングロジック | Worker 内のカスタムルーティング |
routeAgentRequest() と getAgentByName() はどちらも、ルーティング動作をカスタマイズするオプションを受け付けます。
クロスオリジンリクエスト(フロントエンドが別ドメインにある場合など)では:
const response = await routeAgentRequest(request, env, {
cors: true, // Enable default CORS headers
});const response = await routeAgentRequest(request, env, {
cors: true, // Enable default CORS headers
});またはカスタム 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",
},
});レイテンシに敏感なアプリケーションでは、エージェントの実行場所をヒントとして渡せます。
// 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",
});利用可能なロケーションヒント: wnam、enam、sam、weur、eeur、apac、oc、afr、me
データ所在地の要件がある場合:
// 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 を使います。
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 はエージェントの onStart ライフサイクルメソッドに渡されます。
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;
}
}routeAgentRequest で props を使うと、URL に一致したエージェントへ同じ props が渡されます。認証などの共通コンテキストに向いています。
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>;エージェント固有の初期化では、どのエージェントが props を受け取るかを制御できる getAgentByName を使います。
サーバー側コードが一時的な Durable Object ルーティング失敗を再試行すべきときは、getAgentByName() で routingRetry を使います。
const agent = await getAgentByName(env.MyAgent, "instance-name", {
routingRetry: {
maxAttempts: 3,
},
});const agent = await getAgentByName(env.MyAgent, "instance-name", {
routingRetry: {
maxAttempts: 3,
},
});このオプションは、短時間のルーティング失敗を呼び出し元へエラーを返す前に再試行すべき、リクエスト転送と RPC 経路に便利です。
routeAgentRequest は、リクエストがエージェントに届く前に傍受するフックに対応します。
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
},
});これらのフックは認証と検証に便利です。詳細な例は クロスドメイン認証 を参照してください。
Worker コードから getAgentByName() を使い、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>;locationHint、jurisdiction、props などのオプションは ルーティングオプション を参照してください。
リクエストは、インスタンス名のあとにサブパスを含められます。これらはエージェントの onRequest() ハンドラーに渡されます。
/agents/api/v1/users → agent: "api", instance: "v1", path: "/users"
/agents/api/v1/users/123 → agent: "api", instance: "v1", path: "/users/123"エージェント内でサブパスを処理します。
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 });
}
}1 つのプロジェクトに複数のエージェントクラスを持てます。それぞれが独自の名前空間を持ちます。
// 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" ]各エージェントは独自のパス経由でアクセスします。
/agents/counter/...
/agents/chat-room/...
/agents/user-profile/...リクエストがシステムを流れる様子は次のとおりです。
flowchart TD
A["HTTP リクエスト<br/>または WebSocket"] --> B["routeAgentRequest<br/>URL パスを解析"]
B --> C["名前で env 内の<br/>バインディングを探す"]
C --> D["インスタンス ID で<br/>DO を取得 / 作成"]
D --> E["エージェントインスタンス"]
E --> F{"プロトコル?"}
F -->|WebSocket| G["onConnect()、onMessage"]
F -->|HTTP| H["onRequest()"]
リクエストがエージェントに届く前に認証する方法はいくつかあります。
routeAgentRequest() 関数は、認証向けに onBeforeConnect と onBeforeRequest フックを提供します。
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>;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>;Hono ↗ などのフレームワークを使う場合は、エージェントを呼ぶ前にミドルウェアで認証します。
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;WebSocket 認証パターン(URL 内のトークン、JWT 更新)は、クロスドメイン認証 を参照してください。
エラーメッセージは利用可能なエージェントを一覧します。次を確認します。
- エージェントクラスがエントリポイントからエクスポートされていること。
- コード内のクラス名が
wrangler.jsoncのclass_nameと一致すること。 - URL が正しい kebab-case 名を使っていること。
- URL パターン
/agents/{agent-name}/{instance-name}を確認します。 - 404 ハンドラーの前に
routeAgentRequest()が呼ばれていることを確認します。 routeAgentRequest()からの応答が返されていること(呼ばれただけではないこと)を確認します。
- WebSocket アップグレードでは、
routeAgentRequest()からの応答を変更しないでください。 - 別オリジンから接続する場合は、CORS が有効であることを確認します。
- 実際のエラーはブラウザーの開発者ツールで確認します。
- Worker がカスタムパスを処理し、エージェントへ転送していることを確認します。
- リクエストの転送には
getAgentByName()+agent.fetch(request)を使います。 basePathが設定されているとき、agentパラメーターは必須ですが無視されます。- サーバー側ルートがクライアントの
basePathと一致することを確認します。
リクエストを適切なエージェントへルーティングします。
| パラメーター | 型 | 説明 |
|---|---|---|
request |
Request |
受信リクエスト |
env |
Env |
エージェントバインディング付きの環境 |
options.cors |
boolean | HeadersInit |
CORS ヘッダーを有効にする |
options.props |
Record<string, unknown> |
リクエストを処理するエージェントへ渡す props |
options.locationHint |
string |
エージェントインスタンスの優先ロケーション |
options.jurisdiction |
string |
エージェントインスタンスのデータ管轄 |
options.onBeforeConnect |
Function |
WebSocket 接続前のコールバック |
options.onBeforeRequest |
Function |
HTTP リクエスト前のコールバック |
戻り値: Promise<Response | undefined> — 一致した場合は Response、エージェントルートがない場合は undefined。
サーバー側 RPC またはリクエスト転送のために、名前でエージェントインスタンスを取得します。
| パラメーター | 型 | 説明 |
|---|---|---|
namespace |
DurableObjectNamespace<T> |
env からのエージェントバインディング |
name |
string |
インスタンス名 |
options.locationHint |
string |
優先ロケーション |
options.jurisdiction |
string |
データ管轄 |
options.props |
Record<string, unknown> |
onStart 向けの初期化プロパティ |
options.routingRetry |
object |
一時的な Durable Object ルーティング失敗向けの再試行設定 |
戻り値: Promise<DurableObjectStub<T>> — エージェントメソッドの呼び出しまたはリクエスト転送用の型付きスタブ。
カスタムルーティング向けのクライアント接続オプションです。
| オプション | 型 | 説明 |
|---|---|---|
agent |
string |
エージェントクラス名(必須) |
name |
string |
インスタンス名(デフォルト: "default") |
basePath |
string |
完全な URL パス。agent/name の URL 組み立てを迂回します |
path |
string |
URL に追加するパス |
onIdentity |
(name, agent) => void |
サーバーが ID を送ったときに呼ばれます |
onIdentityChange |
(oldName, newName, oldAgent, newAgent) => void |
再接続時に ID が変わったときに呼ばれます |
戻り値のプロパティ(React フック):
| プロパティ | 型 | 説明 |
|---|---|---|
name |
string |
現在のインスタンス名(リアクティブ) |
agent |
string |
現在のエージェントクラス名(リアクティブ) |
identified |
boolean |
ID を受け取ったかどうか(リアクティブ) |
ready |
Promise<void> |
ID を受け取ると解決します |
エージェント設定の静的オプションです。
| オプション | 型 | デフォルト | 説明 |
|---|---|---|---|
hibernate |
boolean |
true |
非アクティブ時にエージェントをハイバネートするかどうか |
sendIdentityOnConnect |
boolean |
true |
接続時にクライアントへ ID を送るかどうか |
hungScheduleTimeoutSeconds |
number |
30 |
実行中のスケジュールがハングと見なされるまでのタイムアウト |
class SecureAgent extends Agent {
static options = { sendIdentityOnConnect: false };
}class SecureAgent extends Agent {
static options = { sendIdentityOnConnect: false };
}