Open5

Cloudflare Agents SDK

yuheitomiyuheitomi

Cloudflare Agents SDK がよく分からないのでメモ

yuheitomiyuheitomi

本質的には Durable Objects をラッパーしている。Wrangler.jsonc でのバインディングも durable_objects として記載。なので、Durable Objects の挙動を理解した方が良さそうではある。

yuheitomiyuheitomi

とりあえず最低限動くコード。

Agents.ts (src/agents/agent.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;

index.ts (src/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"]
    }
  ]
}
yuheitomiyuheitomi

実行例。 :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}
yuheitomiyuheitomi

ほぼ Durable Objects なので、あえて Agents SDK として使う理由としては、ルーティング機能を使いたい場合かもしれない。であれば Hono などを使えば Durable Objets のまま使った方が分かりやすい気もする。

一方で、今回はまだ試していないが React と使える Client API もある。これが使いたい場合は Agents SDK を選択することになりそう。→ https://developers.cloudflare.com/agents/api-reference/agents-api/#client-api