Open5
Cloudflare Agents SDK
Cloudflare Agents SDK がよく分からないのでメモ
本質的には Durable Objects をラッパーしている。Wrangler.jsonc でのバインディングも durable_objects
として記載。なので、Durable Objects の挙動を理解した方が良さそうではある。
とりあえず最低限動くコード。
src/agents/agent.ts
)
Agents.ts (- エージェントの定義。実態は
Durable Objects
なので、this.setState()
は Durable Objects のステート管理を行っていると想定。 - このサンプルコードは AI は使っていないが、実際は
onRequest()
でエージェントの動きを実装。
import { Agent } from "agents";
interface State {
count: number;
}
export class CounterAgent extends Agent<Env, State> {
initialState: State = {
count: 1,
};
async onStart() {
console.log("Starting agent");
}
async onRequest(request: Request): Promise<Response> {
console.log("Request received", request);
if (request.method === "GET") {
const state = this.state;
const count = state.count;
console.log("Count", count);
const newCount = count + 1;
this.setState({ count: newCount });
return new Response(JSON.stringify({ count: newCount }));
}
return new Response("Not found", { status: 404 });
}
}
export default CounterAgent;
src/index.ts
)
index.ts (- routeAgentRequest はエージェントのルーティングに使う。
/agents/:agent/:name
がエンドポイントになる。エージェント名はkebab-case
に変換されるので、今回はcounter-agent
になる。:name
はグローバルで一律に決まるユニークな名前。 - routeAgentRequest を使ってエンドポイントとしてエージェンを使う以外に、リクエストハンドラーの中でエージェントを直接呼び出すこともできる。→ https://developers.cloudflare.com/agents/api-reference/calling-agents/
import { type AgentNamespace, routeAgentRequest } from "agents";
import type { CounterAgent } from "./agents/agent";
interface Env {
CounterAgent: AgentNamespace<CounterAgent>;
}
export default {
async fetch(request, env, ctx): Promise<Response> {
const response = await routeAgentRequest(request, env);
if (!response) {
return new Response("Not found", { status: 404 });
}
return response;
},
} satisfies ExportedHandler<Env>;
export * from "./agents/agent";
./wrangler.jsonc
)
wrangler.jsonc (- ここは Durable Objects としてバインドする。
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "test-agents",
"main": "src/index.ts",
"compatibility_date": "2025-04-25",
"compatibility_flags": ["nodejs_compat"],
"observability": {
"enabled": true
},
"durable_objects": {
"bindings": [
{
"name": "CounterAgent",
"class_name": "CounterAgent"
}
]
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["CounterAgent"]
}
]
}
実行例。 :name
ごとにステートが独立管理されている。
❯ curl -X GET http://localhost:8787/agents/counter-agent/agent-1
{"count":1}⏎
❯ curl -X GET http://localhost:8787/agents/counter-agent/agent-1
{"count":2}⏎
❯ curl -X GET http://localhost:8787/agents/counter-agent/agent-1
{"count":3}⏎
❯ curl -X GET http://localhost:8787/agents/counter-agent/agent-2
{"count":1}⏎
ほぼ Durable Objects なので、あえて Agents SDK として使う理由としては、ルーティング機能を使いたい場合かもしれない。であれば Hono などを使えば Durable Objets のまま使った方が分かりやすい気もする。
一方で、今回はまだ試していないが React と使える Client API もある。これが使いたい場合は Agents SDK を選択することになりそう。→ https://developers.cloudflare.com/agents/api-reference/agents-api/#client-api