[{"data":1,"prerenderedAt":3513},["ShallowReactive",2],{"content-/cloudflare-agent-foundation-4-steps":3,"all-pages-for-dir":3511,"og-image-/cloudflare-agent-foundation-4-steps":3512},{"id":4,"title":5,"body":6,"category":3492,"description":3493,"extension":3494,"meta":3495,"navigation":34,"ogImage":3496,"path":3497,"project_name":3498,"published":3499,"publishedAt":3500,"seo":3501,"stem":3502,"tags":3503,"todo":3509,"unpublished":3499,"updatedAt":3500,"__hash__":3510},"pages/2026-06/2026-06-19/cloudflare-agent-foundation-4-steps.md","Cloudflare で AI エージェント基盤を作る 4 ステップ — Hono → Queues → Workers AI → Agents SDK",{"type":7,"value":8,"toc":3455},"minimark",[9,13,17,21,74,85,89,96,164,171,174,248,251,255,258,272,283,286,299,302,369,372,375,390,393,397,400,403,406,458,464,760,763,819,828,832,835,838,841,848,852,870,876,960,963,2002,2005,2201,2214,2217,2236,2240,2243,2250,2254,2265,2269,2274,2289,2512,2519,2522,2582,2589,2593,2596,2607,2610,2646,2649,2680,2684,2689,3108,3111,3186,3193,3197,3200,3362,3368,3372,3375,3414,3417,3451],[10,11,5],"h1",{"id":12},"cloudflare-で-ai-エージェント基盤を作る-4-ステップ-hono-queues-workers-ai-agents-sdk",[14,15,16],"h2",{"id":16},"結論",[18,19,20],"p",{},"Cloudflare 上に AI エージェントの土台を据えるなら、次の順で積む。",[22,23,26,47,56,65],"ul",{"className":24},[25],"contains-task-list",[27,28,31,36,37,41,42,46],"li",{"className":29},[30],"task-list-item",[32,33],"input",{"disabled":34,"type":35},true,"checkbox"," ",[38,39,40],"strong",{},"Step 1",": Hono で最小の Worker を 1 本書いて ",[43,44,45],"code",{},"wrangler deploy"," する",[27,48,50,36,52,55],{"className":49},[30],[32,51],{"disabled":34,"type":35},[38,53,54],{},"Step 2",": Webhook を受けて Cloudflare Queues に積み、即 200 を返す「門番 Worker」を作る",[27,57,59,36,61,64],{"className":58},[30],[32,60],{"disabled":34,"type":35},[38,62,63],{},"Step 3",": Worker から AI Gateway 経由で LLM を呼び、レスポンスをキャッシュする",[27,66,68,36,70,73],{"className":67},[30],[32,69],{"disabled":34,"type":35},[38,71,72],{},"Step 4",": Agents SDK + Durable Objects で「会話状態を持つエージェント」を 1 体動かす",[18,75,76,77,80,81,84],{},"Wrangler のセットアップとアカウント連携は完了している前提で、各ステップに",[38,78,79],{},"動くコード","と",[38,82,83],{},"動作確認の叩き方","を載せる。1 ステップ 30 分〜2 時間。",[14,86,88],{"id":87},"️-着手の前に-経済合理性チェック後から読み返す自分へ","⚠️ 着手の前に — 経済合理性チェック（後から読み返す自分へ）",[18,90,91,92,95],{},"この計画書は学習動機と「将来必要になったときの備忘」として置いている。",[38,93,94],{},"いま現に自分用に回っている自動化を Cloudflare に移す経済合理性は基本ない","。理由は LLM の課金構造だ。",[97,98,99,115],"table",{},[100,101,102],"thead",{},[103,104,105,109,112],"tr",{},[106,107,108],"th",{},"経路",[106,110,111],{},"LLM コスト",[106,113,114],{},"月額固定費",[116,117,118,132,151],"tbody",{},[103,119,120,126,129],{},[121,122,123],"td",{},[38,124,125],{},"Claude Code (Max $200/月)",[121,127,128],{},"限度内なら $0 / 呼び出し",[121,130,131],{},"$200",[103,133,134,139,148],{},[121,135,136],{},[38,137,138],{},"Cloudflare AI Gateway → Anthropic Sonnet",[121,140,141,147],{},[43,142,146],{"className":143},[144,145],"language-math","math-inline","3 / 1M 入力, ","15 / 1M 出力",[121,149,150],{},"$5 + 従量",[103,152,153,158,161],{},[121,154,155],{},[38,156,157],{},"Cloudflare Workers AI (Llama 3.1 8B 等)",[121,159,160],{},"1k token あたり約 $0.001",[121,162,163],{},"$5",[18,165,166,167,170],{},"Claude Code のサブスクは定額で、レート上限内なら追加コストはゼロ。一方 Cloudflare AI Gateway 経由は",[38,168,169],{},"ゼロベースで token 従量課金","が積み上がる。",[18,172,173],{},"自分用ワークロードをざっくり試算すると次のとおり（Sonnet 相当を AI Gateway 経由で使う前提）。",[97,175,176,189],{},[100,177,178],{},[103,179,180,183,186],{},[106,181,182],{},"ワークロード",[106,184,185],{},"移行した場合",[106,187,188],{},"Claude Code 定額内",[116,190,191,202,212,222,232],{},[103,192,193,196,199],{},[121,194,195],{},"毎朝のダイアリ生成 (~50k token)",[121,197,198],{},"約 $9 / 月",[121,200,201],{},"$0",[103,203,204,207,210],{},[121,205,206],{},"Twitter 下書き (~20k)",[121,208,209],{},"約 $3 / 月",[121,211,201],{},[103,213,214,217,220],{},[121,215,216],{},"決算ビート要約（日次）",[121,218,219],{},"約 $5 / 月",[121,221,201],{},[103,223,224,227,230],{},[121,225,226],{},"月次 ODM / Korea / Japan スクレイピング要約",[121,228,229],{},"約 $2 / 月",[121,231,201],{},[103,233,234,239,244],{},[121,235,236],{},[38,237,238],{},"合計",[121,240,241],{},[38,242,243],{},"約 $20 / 月",[121,245,246],{},[38,247,201],{},[18,249,250],{},"Claude Max を既に払っているなら、移行した分が丸ごと純損失になる。",[252,253,254],"h3",{"id":254},"この計画書を開いてよいタイミング",[18,256,257],{},"次のどちらかが満たされた瞬間にだけ、このページを開く。",[22,259,260,266],{},[27,261,262,265],{},[38,263,264],{},"他人（読者 / クライアント / 家族）がエンドポイントを叩く必要が出た"," — Claude Code のサブスクは多人数共有不可。Webhook 受口や読者向けチャットは Cloudflare で立てるしかない",[27,267,268,271],{},[38,269,270],{},"PC を起動していない時刻に外部からトリガーが入る"," — クライアントが LINE / メールで資料送信、外部 Webhook など。GitHub Actions の cron でカバーできない時間帯依存ジョブも含む",[18,273,274,275,278,279,282],{},"それ以外（自分用の cron 自動化、まとめ、要約、X 下書き、データ取得）は ",[38,276,277],{},"Claude Code + ローカル skill + GitHub Actions cron で完結する","。Cloudflare の Cron Trigger Worker に乗せたくなったときは、",[38,280,281],{},"まず Claude Code の定額枠が本当に詰まっているか","を確認すること。",[14,284,285],{"id":285},"なぜこの順番か",[18,287,288,289,298],{},"きっかけは ",[290,291,297],"a",{"href":292,"target":293,"rel":294},"https://zenn.dev/yusukebe/articles/ccb1f953e48ee1","_blank",[295,296],"noopener","noreferrer","yusukebe「AI エージェントはCloudflareに賭けろ」"," と、それを引用して「Cloudflare Workers + Queues で Webhook の 3 秒ルールを突破した」という X の運用報告だった。後者は、コールドスタートのある Cloud Run の前段に Workers を置くことで、Zoom Webhook / Slack App の「リクエストから 3 秒以内に 200 を返さないとリトライ扱い」という制約を突破した話だ。",[18,300,301],{},"この 2 本を合わせて、AI エージェントに必要な要素を分解するとこうなる。",[97,303,304,317],{},[100,305,306],{},[103,307,308,311,314],{},[106,309,310],{},"要素",[106,312,313],{},"Cloudflare 上の手段",[106,315,316],{},"4 ステップ対応",[116,318,319,329,339,349,359],{},[103,320,321,324,327],{},[121,322,323],{},"HTTP/WS の入口",[121,325,326],{},"Workers",[121,328,40],{},[103,330,331,334,337],{},[121,332,333],{},"非同期処理・タスクキュー",[121,335,336],{},"Queues",[121,338,54],{},[103,340,341,344,347],{},[121,342,343],{},"LLM 呼び出し",[121,345,346],{},"Workers AI / AI Gateway",[121,348,63],{},[103,350,351,354,357],{},[121,352,353],{},"状態保持（セッション・履歴）",[121,355,356],{},"Durable Objects",[121,358,72],{},[103,360,361,364,367],{},[121,362,363],{},"エージェントランタイム",[121,365,366],{},"Agents SDK",[121,368,72],{},[18,370,371],{},"Agents SDK は上 4 つを抱き合わせたフレームワークなので、いきなり Step 4 から入っても動きはする。ただし Worker の挙動・Queues の動き・LLM の呼び方を体験せずにフレームワークの中身が分かるかというと無理なので、下から積む。",[14,373,374],{"id":374},"前提",[22,376,377,384,387],{},[27,378,379,380,383],{},"Wrangler が ",[43,381,382],{},"wrangler whoami"," で自分のアカウントを返す",[27,385,386],{},"Workers Paid Plan ($5 / 月) に加入済み（Queues / Durable Objects / Workers AI のほとんどがここから解放される）",[27,388,389],{},"Node.js 20+ / pnpm",[18,391,392],{},"未加入なら Step 1 までは Free でも動く。Step 2 以降で Paid Plan が必要になる。",[14,394,396],{"id":395},"step-1-hono-で最小の-worker-を-1-本書いてデプロイする","Step 1: Hono で最小の Worker を 1 本書いてデプロイする",[252,398,399],{"id":399},"目的",[18,401,402],{},"「自分の wrangler 環境で、TypeScript で書いた HTTP ハンドラがエッジから返ってくる」状態を作る。以降のステップは全部この上に乗る。",[252,404,405],{"id":405},"コード",[407,408,413],"pre",{"className":409,"code":410,"language":411,"meta":412,"style":412},"language-bash shiki shiki-themes vitesse-light vitesse-light","pnpm create hono@latest cf-agent-step1\n# テンプレ選択: cloudflare-workers\ncd cf-agent-step1\npnpm install\n","bash","",[43,414,415,434,441,450],{"__ignoreMap":412},[416,417,420,424,428,431],"span",{"class":418,"line":419},"line",1,[416,421,423],{"class":422},"senZ8","pnpm",[416,425,427],{"class":426},"sdGka"," create",[416,429,430],{"class":426}," hono@latest",[416,432,433],{"class":426}," cf-agent-step1\n",[416,435,437],{"class":418,"line":436},2,[416,438,440],{"class":439},"sxvE3","# テンプレ選択: cloudflare-workers\n",[416,442,444,448],{"class":418,"line":443},3,[416,445,447],{"class":446},"sz8Xr","cd",[416,449,433],{"class":426},[416,451,453,455],{"class":418,"line":452},4,[416,454,423],{"class":422},[416,456,457],{"class":426}," install\n",[18,459,460,463],{},[43,461,462],{},"src/index.ts"," を書き換える。",[407,465,469],{"className":466,"code":467,"language":468,"meta":412,"style":412},"language-ts shiki shiki-themes vitesse-light vitesse-light","import { Hono } from 'hono'\n\ntype Bindings = {}\n\nconst app = new Hono\u003C{ Bindings: Bindings }>()\n\napp.get('/', (c) => c.text('hello from cf-agent step 1'))\n\napp.get('/ping', (c) =>\n  c.json({\n    ok: true,\n    cf: c.req.raw.cf,\n    ts: new Date().toISOString(),\n  })\n)\n\nexport default app\n","ts",[43,470,471,501,506,522,526,557,562,619,624,653,667,681,708,731,737,743,748],{"__ignoreMap":412},[416,472,473,477,481,485,488,491,495,498],{"class":418,"line":419},[416,474,476],{"class":475},"sHkkW","import",[416,478,480],{"class":479},"shFtX"," {",[416,482,484],{"class":483},"s4oTP"," Hono",[416,486,487],{"class":479}," }",[416,489,490],{"class":475}," from",[416,492,494],{"class":493},"sMJiu"," '",[416,496,497],{"class":426},"hono",[416,499,500],{"class":493},"'\n",[416,502,503],{"class":418,"line":436},[416,504,505],{"emptyLinePlaceholder":34},"\n",[416,507,508,512,516,519],{"class":418,"line":443},[416,509,511],{"class":510},"stQ0i","type",[416,513,515],{"class":514},"sSkh3"," Bindings",[416,517,518],{"class":479}," =",[416,520,521],{"class":479}," {}\n",[416,523,524],{"class":418,"line":452},[416,525,505],{"emptyLinePlaceholder":34},[416,527,529,532,535,537,540,543,546,548,551,554],{"class":418,"line":528},5,[416,530,531],{"class":510},"const ",[416,533,534],{"class":483},"app",[416,536,518],{"class":479},[416,538,539],{"class":510}," new ",[416,541,542],{"class":422},"Hono",[416,544,545],{"class":479},"\u003C{",[416,547,515],{"class":483},[416,549,550],{"class":479},": ",[416,552,553],{"class":514},"Bindings",[416,555,556],{"class":479}," }>()\n",[416,558,560],{"class":418,"line":559},6,[416,561,505],{"emptyLinePlaceholder":34},[416,563,565,567,570,573,576,579,582,584,587,590,593,596,599,602,604,607,609,611,614,616],{"class":418,"line":564},7,[416,566,534],{"class":483},[416,568,569],{"class":479},".",[416,571,572],{"class":422},"get",[416,574,575],{"class":479},"(",[416,577,578],{"class":493},"'",[416,580,581],{"class":426},"/",[416,583,578],{"class":493},[416,585,586],{"class":479},",",[416,588,589],{"class":479}," (",[416,591,592],{"class":483},"c",[416,594,595],{"class":479},")",[416,597,598],{"class":479}," =>",[416,600,601],{"class":483}," c",[416,603,569],{"class":479},[416,605,606],{"class":422},"text",[416,608,575],{"class":479},[416,610,578],{"class":493},[416,612,613],{"class":426},"hello from cf-agent step 1",[416,615,578],{"class":493},[416,617,618],{"class":479},"))\n",[416,620,622],{"class":418,"line":621},8,[416,623,505],{"emptyLinePlaceholder":34},[416,625,627,629,631,633,635,637,640,642,644,646,648,650],{"class":418,"line":626},9,[416,628,534],{"class":483},[416,630,569],{"class":479},[416,632,572],{"class":422},[416,634,575],{"class":479},[416,636,578],{"class":493},[416,638,639],{"class":426},"/ping",[416,641,578],{"class":493},[416,643,586],{"class":479},[416,645,589],{"class":479},[416,647,592],{"class":483},[416,649,595],{"class":479},[416,651,652],{"class":479}," =>\n",[416,654,656,659,661,664],{"class":418,"line":655},10,[416,657,658],{"class":483},"  c",[416,660,569],{"class":479},[416,662,663],{"class":422},"json",[416,665,666],{"class":479},"({\n",[416,668,670,673,675,678],{"class":418,"line":669},11,[416,671,672],{"class":446},"    ok",[416,674,550],{"class":479},[416,676,677],{"class":475},"true",[416,679,680],{"class":479},",\n",[416,682,684,687,689,691,693,696,698,701,703,706],{"class":418,"line":683},12,[416,685,686],{"class":446},"    cf",[416,688,550],{"class":479},[416,690,592],{"class":483},[416,692,569],{"class":479},[416,694,695],{"class":483},"req",[416,697,569],{"class":479},[416,699,700],{"class":483},"raw",[416,702,569],{"class":479},[416,704,705],{"class":483},"cf",[416,707,680],{"class":479},[416,709,711,714,716,719,722,725,728],{"class":418,"line":710},13,[416,712,713],{"class":446},"    ts",[416,715,550],{"class":479},[416,717,718],{"class":510},"new",[416,720,721],{"class":422}," Date",[416,723,724],{"class":479},"().",[416,726,727],{"class":422},"toISOString",[416,729,730],{"class":479},"(),\n",[416,732,734],{"class":418,"line":733},14,[416,735,736],{"class":479},"  })\n",[416,738,740],{"class":418,"line":739},15,[416,741,742],{"class":479},")\n",[416,744,746],{"class":418,"line":745},16,[416,747,505],{"emptyLinePlaceholder":34},[416,749,751,754,757],{"class":418,"line":750},17,[416,752,753],{"class":475},"export",[416,755,756],{"class":475}," default",[416,758,759],{"class":483}," app\n",[252,761,762],{"id":762},"動作確認",[407,764,766],{"className":409,"code":765,"language":411,"meta":412,"style":412},"pnpm dev          # localhost:8787 で起動\ncurl http://localhost:8787/ping\npnpm deploy       # ⇒ https://cf-agent-step1.\u003Caccount>.workers.dev/ にデプロイ\ncurl https://cf-agent-step1.\u003Caccount>.workers.dev/ping\n",[43,767,768,778,786,796],{"__ignoreMap":412},[416,769,770,772,775],{"class":418,"line":419},[416,771,423],{"class":422},[416,773,774],{"class":426}," dev",[416,776,777],{"class":439},"          # localhost:8787 で起動\n",[416,779,780,783],{"class":418,"line":436},[416,781,782],{"class":422},"curl",[416,784,785],{"class":426}," http://localhost:8787/ping\n",[416,787,788,790,793],{"class":418,"line":443},[416,789,423],{"class":422},[416,791,792],{"class":426}," deploy",[416,794,795],{"class":439},"       # ⇒ https://cf-agent-step1.\u003Caccount>.workers.dev/ にデプロイ\n",[416,797,798,800,803,806,809,813,816],{"class":418,"line":452},[416,799,782],{"class":422},[416,801,802],{"class":426}," https://cf-agent-step1.",[416,804,805],{"class":510},"\u003C",[416,807,808],{"class":426},"accoun",[416,810,812],{"class":811},"sG7-3","t",[416,814,815],{"class":510},">",[416,817,818],{"class":426},".workers.dev/ping\n",[18,820,821,823,824,827],{},[43,822,705],{}," フィールドにエッジで判定された国コード等が入っていれば成功。ここで ",[43,825,826],{},"wrangler tail"," を別タブで叩いておくと、本番ログがリアルタイムに流れる。これで Step 1 終わり。",[14,829,831],{"id":830},"step-2-webhook-queues-で3-秒ルールを突破する門番を作る","Step 2: Webhook + Queues で「3 秒ルール」を突破する門番を作る",[252,833,399],{"id":834},"目的-1",[18,836,837],{},"外部サービスからの Webhook を受け取って、署名検証だけして即 200 を返す。重い処理は Queue に逃がす。これが yusukebe 記事の引用ポストが言っていた構成そのもの。",[252,839,840],{"id":840},"構成",[407,842,846],{"className":843,"code":845,"language":606},[844],"language-text","[ 外部サービス ] --POST--> [ Producer Worker ] --send--> [ Cloudflare Queue ]\n                                |\n                                └--200 OK (3秒以内)\n                                                              |\n                                                              v\n                                                     [ Consumer Worker ]\n                                                              |\n                                                              v\n                                                  ( 外部 API / DB / 通知 )\n",[43,847,845],{"__ignoreMap":412},[252,849,851],{"id":850},"queue-を作る","Queue を作る",[407,853,855],{"className":409,"code":854,"language":411,"meta":412,"style":412},"wrangler queues create agent-jobs\n",[43,856,857],{"__ignoreMap":412},[416,858,859,862,865,867],{"class":418,"line":419},[416,860,861],{"class":422},"wrangler",[416,863,864],{"class":426}," queues",[416,866,427],{"class":426},[416,868,869],{"class":426}," agent-jobs\n",[252,871,873],{"id":872},"wranglertoml",[43,874,875],{},"wrangler.toml",[407,877,881],{"className":878,"code":879,"language":880,"meta":412,"style":412},"language-toml shiki shiki-themes vitesse-light vitesse-light","name = \"cf-agent-step2\"\nmain = \"src/index.ts\"\ncompatibility_date = \"2026-06-01\"\n\n# Producer 側（Queue にメッセージを送る）\n[[queues.producers]]\nqueue = \"agent-jobs\"\nbinding = \"AGENT_JOBS\"\n\n# Consumer 側（Queue からメッセージを取り出して処理する）\n[[queues.consumers]]\nqueue = \"agent-jobs\"\nmax_batch_size = 10\nmax_batch_timeout = 5\nmax_retries = 3\ndead_letter_queue = \"agent-jobs-dlq\"\n","toml",[43,882,883,888,893,898,902,907,912,917,922,926,931,936,940,945,950,955],{"__ignoreMap":412},[416,884,885],{"class":418,"line":419},[416,886,887],{},"name = \"cf-agent-step2\"\n",[416,889,890],{"class":418,"line":436},[416,891,892],{},"main = \"src/index.ts\"\n",[416,894,895],{"class":418,"line":443},[416,896,897],{},"compatibility_date = \"2026-06-01\"\n",[416,899,900],{"class":418,"line":452},[416,901,505],{"emptyLinePlaceholder":34},[416,903,904],{"class":418,"line":528},[416,905,906],{},"# Producer 側（Queue にメッセージを送る）\n",[416,908,909],{"class":418,"line":559},[416,910,911],{},"[[queues.producers]]\n",[416,913,914],{"class":418,"line":564},[416,915,916],{},"queue = \"agent-jobs\"\n",[416,918,919],{"class":418,"line":621},[416,920,921],{},"binding = \"AGENT_JOBS\"\n",[416,923,924],{"class":418,"line":626},[416,925,505],{"emptyLinePlaceholder":34},[416,927,928],{"class":418,"line":655},[416,929,930],{},"# Consumer 側（Queue からメッセージを取り出して処理する）\n",[416,932,933],{"class":418,"line":669},[416,934,935],{},"[[queues.consumers]]\n",[416,937,938],{"class":418,"line":683},[416,939,916],{},[416,941,942],{"class":418,"line":710},[416,943,944],{},"max_batch_size = 10\n",[416,946,947],{"class":418,"line":733},[416,948,949],{},"max_batch_timeout = 5\n",[416,951,952],{"class":418,"line":739},[416,953,954],{},"max_retries = 3\n",[416,956,957],{"class":418,"line":745},[416,958,959],{},"dead_letter_queue = \"agent-jobs-dlq\"\n",[252,961,405],{"id":962},"コード-1",[407,964,966],{"className":466,"code":965,"language":468,"meta":412,"style":412},"import { Hono } from 'hono'\n\ntype Bindings = {\n  AGENT_JOBS: Queue\n  WEBHOOK_SECRET: string\n}\n\nconst app = new Hono\u003C{ Bindings: Bindings }>()\n\n// HMAC-SHA256 で署名検証する小さな関数\nconst verifySignature = async (body: string, signature: string, secret: string) => {\n  const key = await crypto.subtle.importKey(\n    'raw',\n    new TextEncoder().encode(secret),\n    { name: 'HMAC', hash: 'SHA-256' },\n    false,\n    ['sign']\n  )\n  const mac = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(body))\n  const expected = Array.from(new Uint8Array(mac))\n    .map((b) => b.toString(16).padStart(2, '0'))\n    .join('')\n  return expected === signature\n}\n\napp.post('/webhook/:source', async (c) => {\n  const source = c.req.param('source')\n  const body = await c.req.text()\n  const signature = c.req.header('x-signature') ?? ''\n\n  if (!(await verifySignature(body, signature, c.env.WEBHOOK_SECRET))) {\n    return c.json({ error: 'invalid signature' }, 401)\n  }\n\n  await c.env.AGENT_JOBS.send({\n    source,\n    payload: JSON.parse(body),\n    receivedAt: new Date().toISOString(),\n  })\n\n  return c.json({ ok: true }, 200)\n})\n\n// Consumer ハンドラ\nexport default {\n  fetch: app.fetch,\n  async queue(batch: MessageBatch, env: Bindings) {\n    for (const msg of batch.messages) {\n      try {\n        const job = msg.body as { source: string; payload: unknown }\n        console.log('process job', job.source, job.payload)\n        // ここで時間のかかる処理（外部 API、DB 書き込み、LLM 呼び出し）\n        msg.ack()\n      } catch (e) {\n        msg.retry()\n      }\n    }\n  },\n}\n",[43,967,968,986,990,1001,1011,1021,1026,1030,1052,1056,1061,1107,1136,1147,1168,1203,1210,1225,1231,1282,1314,1369,1384,1399,1404,1409,1443,1474,1498,1536,1541,1587,1622,1628,1633,1657,1665,1687,1705,1710,1715,1742,1748,1753,1759,1768,1785,1815,1841,1849,1893,1932,1938,1951,1967,1979,1985,1991,1997],{"__ignoreMap":412},[416,969,970,972,974,976,978,980,982,984],{"class":418,"line":419},[416,971,476],{"class":475},[416,973,480],{"class":479},[416,975,484],{"class":483},[416,977,487],{"class":479},[416,979,490],{"class":475},[416,981,494],{"class":493},[416,983,497],{"class":426},[416,985,500],{"class":493},[416,987,988],{"class":418,"line":436},[416,989,505],{"emptyLinePlaceholder":34},[416,991,992,994,996,998],{"class":418,"line":443},[416,993,511],{"class":510},[416,995,515],{"class":514},[416,997,518],{"class":479},[416,999,1000],{"class":479}," {\n",[416,1002,1003,1006,1008],{"class":418,"line":452},[416,1004,1005],{"class":483},"  AGENT_JOBS",[416,1007,550],{"class":479},[416,1009,1010],{"class":514},"Queue\n",[416,1012,1013,1016,1018],{"class":418,"line":528},[416,1014,1015],{"class":483},"  WEBHOOK_SECRET",[416,1017,550],{"class":479},[416,1019,1020],{"class":514},"string\n",[416,1022,1023],{"class":418,"line":559},[416,1024,1025],{"class":479},"}\n",[416,1027,1028],{"class":418,"line":564},[416,1029,505],{"emptyLinePlaceholder":34},[416,1031,1032,1034,1036,1038,1040,1042,1044,1046,1048,1050],{"class":418,"line":621},[416,1033,531],{"class":510},[416,1035,534],{"class":483},[416,1037,518],{"class":479},[416,1039,539],{"class":510},[416,1041,542],{"class":422},[416,1043,545],{"class":479},[416,1045,515],{"class":483},[416,1047,550],{"class":479},[416,1049,553],{"class":514},[416,1051,556],{"class":479},[416,1053,1054],{"class":418,"line":626},[416,1055,505],{"emptyLinePlaceholder":34},[416,1057,1058],{"class":418,"line":655},[416,1059,1060],{"class":439},"// HMAC-SHA256 で署名検証する小さな関数\n",[416,1062,1063,1065,1068,1070,1073,1075,1078,1080,1083,1085,1088,1090,1092,1094,1097,1099,1101,1103,1105],{"class":418,"line":669},[416,1064,531],{"class":510},[416,1066,1067],{"class":422},"verifySignature",[416,1069,518],{"class":479},[416,1071,1072],{"class":510}," async ",[416,1074,575],{"class":479},[416,1076,1077],{"class":483},"body",[416,1079,550],{"class":479},[416,1081,1082],{"class":514},"string",[416,1084,586],{"class":479},[416,1086,1087],{"class":483}," signature",[416,1089,550],{"class":479},[416,1091,1082],{"class":514},[416,1093,586],{"class":479},[416,1095,1096],{"class":483}," secret",[416,1098,550],{"class":479},[416,1100,1082],{"class":514},[416,1102,595],{"class":479},[416,1104,598],{"class":479},[416,1106,1000],{"class":479},[416,1108,1109,1112,1115,1117,1120,1123,1125,1128,1130,1133],{"class":418,"line":683},[416,1110,1111],{"class":510},"  const ",[416,1113,1114],{"class":483},"key",[416,1116,518],{"class":479},[416,1118,1119],{"class":475}," await",[416,1121,1122],{"class":483}," crypto",[416,1124,569],{"class":479},[416,1126,1127],{"class":483},"subtle",[416,1129,569],{"class":479},[416,1131,1132],{"class":422},"importKey",[416,1134,1135],{"class":479},"(\n",[416,1137,1138,1141,1143,1145],{"class":418,"line":710},[416,1139,1140],{"class":493},"    '",[416,1142,700],{"class":426},[416,1144,578],{"class":493},[416,1146,680],{"class":479},[416,1148,1149,1152,1155,1157,1160,1162,1165],{"class":418,"line":733},[416,1150,1151],{"class":510},"    new ",[416,1153,1154],{"class":422},"TextEncoder",[416,1156,724],{"class":479},[416,1158,1159],{"class":422},"encode",[416,1161,575],{"class":479},[416,1163,1164],{"class":483},"secret",[416,1166,1167],{"class":479},"),\n",[416,1169,1170,1173,1176,1178,1180,1183,1185,1188,1191,1193,1195,1198,1200],{"class":418,"line":739},[416,1171,1172],{"class":479},"    { ",[416,1174,1175],{"class":446},"name",[416,1177,550],{"class":479},[416,1179,578],{"class":493},[416,1181,1182],{"class":426},"HMAC",[416,1184,578],{"class":493},[416,1186,1187],{"class":479},", ",[416,1189,1190],{"class":446},"hash",[416,1192,550],{"class":479},[416,1194,578],{"class":493},[416,1196,1197],{"class":426},"SHA-256",[416,1199,578],{"class":493},[416,1201,1202],{"class":479}," },\n",[416,1204,1205,1208],{"class":418,"line":745},[416,1206,1207],{"class":475},"    false",[416,1209,680],{"class":479},[416,1211,1212,1215,1217,1220,1222],{"class":418,"line":750},[416,1213,1214],{"class":479},"    [",[416,1216,578],{"class":493},[416,1218,1219],{"class":426},"sign",[416,1221,578],{"class":493},[416,1223,1224],{"class":479},"]\n",[416,1226,1228],{"class":418,"line":1227},18,[416,1229,1230],{"class":479},"  )\n",[416,1232,1234,1236,1239,1241,1243,1245,1247,1249,1251,1253,1255,1257,1259,1261,1263,1266,1268,1270,1272,1274,1276,1278,1280],{"class":418,"line":1233},19,[416,1235,1111],{"class":510},[416,1237,1238],{"class":483},"mac",[416,1240,518],{"class":479},[416,1242,1119],{"class":475},[416,1244,1122],{"class":483},[416,1246,569],{"class":479},[416,1248,1127],{"class":483},[416,1250,569],{"class":479},[416,1252,1219],{"class":422},[416,1254,575],{"class":479},[416,1256,578],{"class":493},[416,1258,1182],{"class":426},[416,1260,578],{"class":493},[416,1262,586],{"class":479},[416,1264,1265],{"class":483}," key",[416,1267,586],{"class":479},[416,1269,539],{"class":510},[416,1271,1154],{"class":422},[416,1273,724],{"class":479},[416,1275,1159],{"class":422},[416,1277,575],{"class":479},[416,1279,1077],{"class":483},[416,1281,618],{"class":479},[416,1283,1285,1287,1290,1292,1295,1297,1300,1302,1305,1308,1310,1312],{"class":418,"line":1284},20,[416,1286,1111],{"class":510},[416,1288,1289],{"class":483},"expected",[416,1291,518],{"class":479},[416,1293,1294],{"class":483}," Array",[416,1296,569],{"class":479},[416,1298,1299],{"class":422},"from",[416,1301,575],{"class":479},[416,1303,1304],{"class":510},"new ",[416,1306,1307],{"class":422},"Uint8Array",[416,1309,575],{"class":479},[416,1311,1238],{"class":483},[416,1313,618],{"class":479},[416,1315,1317,1320,1323,1326,1329,1331,1333,1336,1338,1341,1343,1347,1350,1353,1355,1358,1360,1362,1365,1367],{"class":418,"line":1316},21,[416,1318,1319],{"class":479},"    .",[416,1321,1322],{"class":422},"map",[416,1324,1325],{"class":479},"((",[416,1327,1328],{"class":483},"b",[416,1330,595],{"class":479},[416,1332,598],{"class":479},[416,1334,1335],{"class":483}," b",[416,1337,569],{"class":479},[416,1339,1340],{"class":422},"toString",[416,1342,575],{"class":479},[416,1344,1346],{"class":1345},"sM54T","16",[416,1348,1349],{"class":479},").",[416,1351,1352],{"class":422},"padStart",[416,1354,575],{"class":479},[416,1356,1357],{"class":1345},"2",[416,1359,586],{"class":479},[416,1361,494],{"class":493},[416,1363,1364],{"class":426},"0",[416,1366,578],{"class":493},[416,1368,618],{"class":479},[416,1370,1372,1374,1377,1379,1382],{"class":418,"line":1371},22,[416,1373,1319],{"class":479},[416,1375,1376],{"class":422},"join",[416,1378,575],{"class":479},[416,1380,1381],{"class":493},"''",[416,1383,742],{"class":479},[416,1385,1387,1390,1393,1396],{"class":418,"line":1386},23,[416,1388,1389],{"class":475},"  return",[416,1391,1392],{"class":483}," expected",[416,1394,1395],{"class":510}," === ",[416,1397,1398],{"class":483},"signature\n",[416,1400,1402],{"class":418,"line":1401},24,[416,1403,1025],{"class":479},[416,1405,1407],{"class":418,"line":1406},25,[416,1408,505],{"emptyLinePlaceholder":34},[416,1410,1412,1414,1416,1419,1421,1423,1426,1428,1430,1433,1435,1437,1439,1441],{"class":418,"line":1411},26,[416,1413,534],{"class":483},[416,1415,569],{"class":479},[416,1417,1418],{"class":422},"post",[416,1420,575],{"class":479},[416,1422,578],{"class":493},[416,1424,1425],{"class":426},"/webhook/:source",[416,1427,578],{"class":493},[416,1429,586],{"class":479},[416,1431,1432],{"class":510}," async",[416,1434,589],{"class":479},[416,1436,592],{"class":483},[416,1438,595],{"class":479},[416,1440,598],{"class":479},[416,1442,1000],{"class":479},[416,1444,1446,1448,1451,1453,1455,1457,1459,1461,1464,1466,1468,1470,1472],{"class":418,"line":1445},27,[416,1447,1111],{"class":510},[416,1449,1450],{"class":483},"source",[416,1452,518],{"class":479},[416,1454,601],{"class":483},[416,1456,569],{"class":479},[416,1458,695],{"class":483},[416,1460,569],{"class":479},[416,1462,1463],{"class":422},"param",[416,1465,575],{"class":479},[416,1467,578],{"class":493},[416,1469,1450],{"class":426},[416,1471,578],{"class":493},[416,1473,742],{"class":479},[416,1475,1477,1479,1481,1483,1485,1487,1489,1491,1493,1495],{"class":418,"line":1476},28,[416,1478,1111],{"class":510},[416,1480,1077],{"class":483},[416,1482,518],{"class":479},[416,1484,1119],{"class":475},[416,1486,601],{"class":483},[416,1488,569],{"class":479},[416,1490,695],{"class":483},[416,1492,569],{"class":479},[416,1494,606],{"class":422},[416,1496,1497],{"class":479},"()\n",[416,1499,1501,1503,1506,1508,1510,1512,1514,1516,1519,1521,1523,1526,1528,1530,1533],{"class":418,"line":1500},29,[416,1502,1111],{"class":510},[416,1504,1505],{"class":483},"signature",[416,1507,518],{"class":479},[416,1509,601],{"class":483},[416,1511,569],{"class":479},[416,1513,695],{"class":483},[416,1515,569],{"class":479},[416,1517,1518],{"class":422},"header",[416,1520,575],{"class":479},[416,1522,578],{"class":493},[416,1524,1525],{"class":426},"x-signature",[416,1527,578],{"class":493},[416,1529,595],{"class":479},[416,1531,1532],{"class":510}," ?? ",[416,1534,1535],{"class":493},"''\n",[416,1537,1539],{"class":418,"line":1538},30,[416,1540,505],{"emptyLinePlaceholder":34},[416,1542,1544,1547,1549,1552,1554,1557,1560,1562,1564,1566,1568,1570,1572,1574,1577,1579,1582,1585],{"class":418,"line":1543},31,[416,1545,1546],{"class":475},"  if",[416,1548,589],{"class":479},[416,1550,1551],{"class":510},"!",[416,1553,575],{"class":479},[416,1555,1556],{"class":475},"await",[416,1558,1559],{"class":422}," verifySignature",[416,1561,575],{"class":479},[416,1563,1077],{"class":483},[416,1565,586],{"class":479},[416,1567,1087],{"class":483},[416,1569,586],{"class":479},[416,1571,601],{"class":483},[416,1573,569],{"class":479},[416,1575,1576],{"class":483},"env",[416,1578,569],{"class":479},[416,1580,1581],{"class":483},"WEBHOOK_SECRET",[416,1583,1584],{"class":479},")))",[416,1586,1000],{"class":479},[416,1588,1590,1593,1595,1597,1599,1602,1605,1607,1609,1612,1614,1617,1620],{"class":418,"line":1589},32,[416,1591,1592],{"class":475},"    return",[416,1594,601],{"class":483},[416,1596,569],{"class":479},[416,1598,663],{"class":422},[416,1600,1601],{"class":479},"({ ",[416,1603,1604],{"class":446},"error",[416,1606,550],{"class":479},[416,1608,578],{"class":493},[416,1610,1611],{"class":426},"invalid signature",[416,1613,578],{"class":493},[416,1615,1616],{"class":479}," },",[416,1618,1619],{"class":1345}," 401",[416,1621,742],{"class":479},[416,1623,1625],{"class":418,"line":1624},33,[416,1626,1627],{"class":479},"  }\n",[416,1629,1631],{"class":418,"line":1630},34,[416,1632,505],{"emptyLinePlaceholder":34},[416,1634,1636,1639,1641,1643,1645,1647,1650,1652,1655],{"class":418,"line":1635},35,[416,1637,1638],{"class":475},"  await",[416,1640,601],{"class":483},[416,1642,569],{"class":479},[416,1644,1576],{"class":483},[416,1646,569],{"class":479},[416,1648,1649],{"class":483},"AGENT_JOBS",[416,1651,569],{"class":479},[416,1653,1654],{"class":422},"send",[416,1656,666],{"class":479},[416,1658,1660,1663],{"class":418,"line":1659},36,[416,1661,1662],{"class":483},"    source",[416,1664,680],{"class":479},[416,1666,1668,1671,1673,1676,1678,1681,1683,1685],{"class":418,"line":1667},37,[416,1669,1670],{"class":446},"    payload",[416,1672,550],{"class":479},[416,1674,1675],{"class":483},"JSON",[416,1677,569],{"class":479},[416,1679,1680],{"class":422},"parse",[416,1682,575],{"class":479},[416,1684,1077],{"class":483},[416,1686,1167],{"class":479},[416,1688,1690,1693,1695,1697,1699,1701,1703],{"class":418,"line":1689},38,[416,1691,1692],{"class":446},"    receivedAt",[416,1694,550],{"class":479},[416,1696,718],{"class":510},[416,1698,721],{"class":422},[416,1700,724],{"class":479},[416,1702,727],{"class":422},[416,1704,730],{"class":479},[416,1706,1708],{"class":418,"line":1707},39,[416,1709,736],{"class":479},[416,1711,1713],{"class":418,"line":1712},40,[416,1714,505],{"emptyLinePlaceholder":34},[416,1716,1718,1720,1722,1724,1726,1728,1731,1733,1735,1737,1740],{"class":418,"line":1717},41,[416,1719,1389],{"class":475},[416,1721,601],{"class":483},[416,1723,569],{"class":479},[416,1725,663],{"class":422},[416,1727,1601],{"class":479},[416,1729,1730],{"class":446},"ok",[416,1732,550],{"class":479},[416,1734,677],{"class":475},[416,1736,1616],{"class":479},[416,1738,1739],{"class":1345}," 200",[416,1741,742],{"class":479},[416,1743,1745],{"class":418,"line":1744},42,[416,1746,1747],{"class":479},"})\n",[416,1749,1751],{"class":418,"line":1750},43,[416,1752,505],{"emptyLinePlaceholder":34},[416,1754,1756],{"class":418,"line":1755},44,[416,1757,1758],{"class":439},"// Consumer ハンドラ\n",[416,1760,1762,1764,1766],{"class":418,"line":1761},45,[416,1763,753],{"class":475},[416,1765,756],{"class":475},[416,1767,1000],{"class":479},[416,1769,1771,1774,1776,1778,1780,1783],{"class":418,"line":1770},46,[416,1772,1773],{"class":446},"  fetch",[416,1775,550],{"class":479},[416,1777,534],{"class":483},[416,1779,569],{"class":479},[416,1781,1782],{"class":483},"fetch",[416,1784,680],{"class":479},[416,1786,1788,1791,1794,1796,1799,1801,1804,1806,1808,1810,1812],{"class":418,"line":1787},47,[416,1789,1790],{"class":510},"  async",[416,1792,1793],{"class":422}," queue",[416,1795,575],{"class":479},[416,1797,1798],{"class":483},"batch",[416,1800,550],{"class":479},[416,1802,1803],{"class":514},"MessageBatch",[416,1805,1187],{"class":479},[416,1807,1576],{"class":483},[416,1809,550],{"class":479},[416,1811,553],{"class":514},[416,1813,1814],{"class":479},") {\n",[416,1816,1818,1821,1823,1825,1828,1831,1834,1836,1839],{"class":418,"line":1817},48,[416,1819,1820],{"class":475},"    for",[416,1822,589],{"class":479},[416,1824,531],{"class":510},[416,1826,1827],{"class":483},"msg",[416,1829,1830],{"class":510}," of",[416,1832,1833],{"class":483}," batch",[416,1835,569],{"class":479},[416,1837,1838],{"class":483},"messages",[416,1840,1814],{"class":479},[416,1842,1844,1847],{"class":418,"line":1843},49,[416,1845,1846],{"class":475},"      try",[416,1848,1000],{"class":479},[416,1850,1852,1855,1858,1860,1863,1865,1867,1870,1872,1875,1877,1879,1882,1885,1887,1890],{"class":418,"line":1851},50,[416,1853,1854],{"class":510},"        const ",[416,1856,1857],{"class":483},"job",[416,1859,518],{"class":479},[416,1861,1862],{"class":483}," msg",[416,1864,569],{"class":479},[416,1866,1077],{"class":483},[416,1868,1869],{"class":475}," as",[416,1871,480],{"class":479},[416,1873,1874],{"class":483}," source",[416,1876,550],{"class":479},[416,1878,1082],{"class":514},[416,1880,1881],{"class":479},";",[416,1883,1884],{"class":483}," payload",[416,1886,550],{"class":479},[416,1888,1889],{"class":514},"unknown",[416,1891,1892],{"class":479}," }\n",[416,1894,1896,1899,1901,1904,1906,1908,1911,1913,1915,1917,1919,1921,1923,1925,1927,1930],{"class":418,"line":1895},51,[416,1897,1898],{"class":483},"        console",[416,1900,569],{"class":479},[416,1902,1903],{"class":422},"log",[416,1905,575],{"class":479},[416,1907,578],{"class":493},[416,1909,1910],{"class":426},"process job",[416,1912,578],{"class":493},[416,1914,1187],{"class":479},[416,1916,1857],{"class":483},[416,1918,569],{"class":479},[416,1920,1450],{"class":483},[416,1922,1187],{"class":479},[416,1924,1857],{"class":483},[416,1926,569],{"class":479},[416,1928,1929],{"class":483},"payload",[416,1931,742],{"class":479},[416,1933,1935],{"class":418,"line":1934},52,[416,1936,1937],{"class":439},"        // ここで時間のかかる処理（外部 API、DB 書き込み、LLM 呼び出し）\n",[416,1939,1941,1944,1946,1949],{"class":418,"line":1940},53,[416,1942,1943],{"class":483},"        msg",[416,1945,569],{"class":479},[416,1947,1948],{"class":422},"ack",[416,1950,1497],{"class":479},[416,1952,1954,1957,1960,1962,1965],{"class":418,"line":1953},54,[416,1955,1956],{"class":479},"      } ",[416,1958,1959],{"class":475},"catch",[416,1961,589],{"class":479},[416,1963,1964],{"class":483},"e",[416,1966,1814],{"class":479},[416,1968,1970,1972,1974,1977],{"class":418,"line":1969},55,[416,1971,1943],{"class":483},[416,1973,569],{"class":479},[416,1975,1976],{"class":422},"retry",[416,1978,1497],{"class":479},[416,1980,1982],{"class":418,"line":1981},56,[416,1983,1984],{"class":479},"      }\n",[416,1986,1988],{"class":418,"line":1987},57,[416,1989,1990],{"class":479},"    }\n",[416,1992,1994],{"class":418,"line":1993},58,[416,1995,1996],{"class":479},"  },\n",[416,1998,2000],{"class":418,"line":1999},59,[416,2001,1025],{"class":479},[252,2003,762],{"id":2004},"動作確認-1",[407,2006,2008],{"className":409,"code":2007,"language":411,"meta":412,"style":412},"wrangler secret put WEBHOOK_SECRET   # 適当な文字列を入力\npnpm deploy\n\n# 別タブで Consumer のログを流す\nwrangler tail\n\n# 署名付きで叩く\nBODY='{\"hello\":\"queue\"}'\nSIG=$(echo -n \"$BODY\" | openssl dgst -sha256 -hmac \"\u003Cさっき入れた文字列>\" -hex | awk '{print $2}')\ncurl -X POST https://cf-agent-step2.\u003Caccount>.workers.dev/webhook/slack \\\n  -H \"content-type: application/json\" \\\n  -H \"x-signature: $SIG\" \\\n  -d \"$BODY\"\n",[43,2009,2010,2025,2032,2036,2041,2048,2052,2057,2072,2135,2162,2176,2189],{"__ignoreMap":412},[416,2011,2012,2014,2016,2019,2022],{"class":418,"line":419},[416,2013,861],{"class":422},[416,2015,1096],{"class":426},[416,2017,2018],{"class":426}," put",[416,2020,2021],{"class":426}," WEBHOOK_SECRET",[416,2023,2024],{"class":439},"   # 適当な文字列を入力\n",[416,2026,2027,2029],{"class":418,"line":436},[416,2028,423],{"class":422},[416,2030,2031],{"class":426}," deploy\n",[416,2033,2034],{"class":418,"line":443},[416,2035,505],{"emptyLinePlaceholder":34},[416,2037,2038],{"class":418,"line":452},[416,2039,2040],{"class":439},"# 別タブで Consumer のログを流す\n",[416,2042,2043,2045],{"class":418,"line":528},[416,2044,861],{"class":422},[416,2046,2047],{"class":426}," tail\n",[416,2049,2050],{"class":418,"line":559},[416,2051,505],{"emptyLinePlaceholder":34},[416,2053,2054],{"class":418,"line":564},[416,2055,2056],{"class":439},"# 署名付きで叩く\n",[416,2058,2059,2062,2065,2067,2070],{"class":418,"line":621},[416,2060,2061],{"class":483},"BODY",[416,2063,2064],{"class":479},"=",[416,2066,578],{"class":493},[416,2068,2069],{"class":426},"{\"hello\":\"queue\"}",[416,2071,500],{"class":493},[416,2073,2074,2077,2080,2083,2087,2090,2093,2096,2099,2102,2105,2108,2111,2113,2116,2118,2121,2123,2126,2128,2131,2133],{"class":418,"line":626},[416,2075,2076],{"class":483},"SIG",[416,2078,2079],{"class":479},"=$(",[416,2081,2082],{"class":446},"echo",[416,2084,2086],{"class":2085},"snbK4"," -n",[416,2088,2089],{"class":493}," \"",[416,2091,2092],{"class":426},"$BODY",[416,2094,2095],{"class":493},"\"",[416,2097,2098],{"class":510}," |",[416,2100,2101],{"class":422}," openssl",[416,2103,2104],{"class":426}," dgst",[416,2106,2107],{"class":2085}," -sha256",[416,2109,2110],{"class":2085}," -hmac",[416,2112,2089],{"class":493},[416,2114,2115],{"class":426},"\u003Cさっき入れた文字列>",[416,2117,2095],{"class":493},[416,2119,2120],{"class":2085}," -hex",[416,2122,2098],{"class":510},[416,2124,2125],{"class":422}," awk",[416,2127,494],{"class":493},[416,2129,2130],{"class":426},"{print $2}",[416,2132,578],{"class":493},[416,2134,742],{"class":479},[416,2136,2137,2139,2142,2145,2148,2150,2152,2154,2156,2159],{"class":418,"line":655},[416,2138,782],{"class":422},[416,2140,2141],{"class":2085}," -X",[416,2143,2144],{"class":426}," POST",[416,2146,2147],{"class":426}," https://cf-agent-step2.",[416,2149,805],{"class":510},[416,2151,808],{"class":426},[416,2153,812],{"class":811},[416,2155,815],{"class":510},[416,2157,2158],{"class":426},".workers.dev/webhook/slack",[416,2160,2161],{"class":2085}," \\\n",[416,2163,2164,2167,2169,2172,2174],{"class":418,"line":669},[416,2165,2166],{"class":2085},"  -H",[416,2168,2089],{"class":493},[416,2170,2171],{"class":426},"content-type: application/json",[416,2173,2095],{"class":493},[416,2175,2161],{"class":2085},[416,2177,2178,2180,2182,2185,2187],{"class":418,"line":683},[416,2179,2166],{"class":2085},[416,2181,2089],{"class":493},[416,2183,2184],{"class":426},"x-signature: $SIG",[416,2186,2095],{"class":493},[416,2188,2161],{"class":2085},[416,2190,2191,2194,2196,2198],{"class":418,"line":710},[416,2192,2193],{"class":2085},"  -d",[416,2195,2089],{"class":493},[416,2197,2092],{"class":426},[416,2199,2200],{"class":493},"\"\n",[18,2202,2203,2205,2206,2209,2210,2213],{},[43,2204,826],{}," に ",[43,2207,2208],{},"process job slack { hello: 'queue' }"," が出たら成功。",[38,2211,2212],{},"HTTP レスポンスは数十 ms で 200 が返り、重い処理は別レーンで進む","という構造が手元で動いた状態になる。",[252,2215,2216],{"id":2216},"確認しておく観点",[22,2218,2219,2222,2233],{},[27,2220,2221],{},"故意に署名を壊して 401 が返ること",[27,2223,2224,2225,2228,2229,2232],{},"Consumer 側で ",[43,2226,2227],{},"throw"," してリトライが効くこと（",[43,2230,2231],{},"max_retries: 3"," で DLQ 行き）",[27,2234,2235],{},"Cloudflare ダッシュボードの Queues タブで「Backlog」「Producer rate」「Consumer rate」のメーターが動くこと",[14,2237,2239],{"id":2238},"step-3-ai-gateway-経由で-llm-を呼んでキャッシュする","Step 3: AI Gateway 経由で LLM を呼んでキャッシュする",[252,2241,399],{"id":2242},"目的-2",[18,2244,2245,2246,2249],{},"エージェントの「推論」部分を 1 本通す。OpenAI / Anthropic / Workers AI のどれを使っても、",[38,2247,2248],{},"AI Gateway を前段に置く","とログ・キャッシュ・レート制限・コスト計測が一元化できる。",[252,2251,2253],{"id":2252},"ai-gateway-を作る","AI Gateway を作る",[18,2255,2256,2257,2260,2261,2264],{},"Cloudflare ダッシュボード → AI → AI Gateway → Create Gateway。\n名前 ",[43,2258,2259],{},"agent-gateway"," で作ると、エンドポイントが ",[43,2262,2263],{},"https://gateway.ai.cloudflare.com/v1/\u003Caccount_id>/agent-gateway/\u003Cprovider>/..."," の形で発行される。",[252,2266,2268],{"id":2267},"workers-ai-経由で動かす最小コード","Workers AI 経由で動かす最小コード",[18,2270,2271,2273],{},[43,2272,875],{}," に追記:",[407,2275,2277],{"className":878,"code":2276,"language":880,"meta":412,"style":412},"[ai]\nbinding = \"AI\"\n",[43,2278,2279,2284],{"__ignoreMap":412},[416,2280,2281],{"class":418,"line":419},[416,2282,2283],{},"[ai]\n",[416,2285,2286],{"class":418,"line":436},[416,2287,2288],{},"binding = \"AI\"\n",[407,2290,2292],{"className":466,"code":2291,"language":468,"meta":412,"style":412},"app.post('/chat', async (c) => {\n  const { prompt } = await c.req.json\u003C{ prompt: string }>()\n\n  // Workers AI（Cloudflare 自前のモデル）を AI Gateway 経由で叩く\n  const result = await c.env.AI.run(\n    '@cf/meta/llama-3.1-8b-instruct',\n    { prompt },\n    {\n      gateway: {\n        id: 'agent-gateway',\n        cacheTtl: 3600,           // 同じ入力なら 1 時間キャッシュ\n        skipCache: false,\n      },\n    }\n  )\n\n  return c.json(result)\n})\n",[43,2293,2294,2325,2361,2365,2370,2399,2410,2419,2424,2432,2447,2463,2475,2480,2484,2488,2492,2508],{"__ignoreMap":412},[416,2295,2296,2298,2300,2302,2304,2306,2309,2311,2313,2315,2317,2319,2321,2323],{"class":418,"line":419},[416,2297,534],{"class":483},[416,2299,569],{"class":479},[416,2301,1418],{"class":422},[416,2303,575],{"class":479},[416,2305,578],{"class":493},[416,2307,2308],{"class":426},"/chat",[416,2310,578],{"class":493},[416,2312,586],{"class":479},[416,2314,1432],{"class":510},[416,2316,589],{"class":479},[416,2318,592],{"class":483},[416,2320,595],{"class":479},[416,2322,598],{"class":479},[416,2324,1000],{"class":479},[416,2326,2327,2329,2332,2335,2337,2339,2341,2343,2345,2347,2349,2351,2353,2355,2357,2359],{"class":418,"line":436},[416,2328,1111],{"class":510},[416,2330,2331],{"class":479},"{",[416,2333,2334],{"class":483}," prompt",[416,2336,487],{"class":479},[416,2338,518],{"class":479},[416,2340,1119],{"class":475},[416,2342,601],{"class":483},[416,2344,569],{"class":479},[416,2346,695],{"class":483},[416,2348,569],{"class":479},[416,2350,663],{"class":422},[416,2352,545],{"class":479},[416,2354,2334],{"class":483},[416,2356,550],{"class":479},[416,2358,1082],{"class":514},[416,2360,556],{"class":479},[416,2362,2363],{"class":418,"line":443},[416,2364,505],{"emptyLinePlaceholder":34},[416,2366,2367],{"class":418,"line":452},[416,2368,2369],{"class":439},"  // Workers AI（Cloudflare 自前のモデル）を AI Gateway 経由で叩く\n",[416,2371,2372,2374,2377,2379,2381,2383,2385,2387,2389,2392,2394,2397],{"class":418,"line":528},[416,2373,1111],{"class":510},[416,2375,2376],{"class":483},"result",[416,2378,518],{"class":479},[416,2380,1119],{"class":475},[416,2382,601],{"class":483},[416,2384,569],{"class":479},[416,2386,1576],{"class":483},[416,2388,569],{"class":479},[416,2390,2391],{"class":483},"AI",[416,2393,569],{"class":479},[416,2395,2396],{"class":422},"run",[416,2398,1135],{"class":479},[416,2400,2401,2403,2406,2408],{"class":418,"line":559},[416,2402,1140],{"class":493},[416,2404,2405],{"class":426},"@cf/meta/llama-3.1-8b-instruct",[416,2407,578],{"class":493},[416,2409,680],{"class":479},[416,2411,2412,2414,2417],{"class":418,"line":564},[416,2413,1172],{"class":479},[416,2415,2416],{"class":483},"prompt",[416,2418,1202],{"class":479},[416,2420,2421],{"class":418,"line":621},[416,2422,2423],{"class":479},"    {\n",[416,2425,2426,2429],{"class":418,"line":626},[416,2427,2428],{"class":446},"      gateway",[416,2430,2431],{"class":479},": {\n",[416,2433,2434,2437,2439,2441,2443,2445],{"class":418,"line":655},[416,2435,2436],{"class":446},"        id",[416,2438,550],{"class":479},[416,2440,578],{"class":493},[416,2442,2259],{"class":426},[416,2444,578],{"class":493},[416,2446,680],{"class":479},[416,2448,2449,2452,2454,2457,2460],{"class":418,"line":669},[416,2450,2451],{"class":446},"        cacheTtl",[416,2453,550],{"class":479},[416,2455,2456],{"class":1345},"3600",[416,2458,2459],{"class":479},",           ",[416,2461,2462],{"class":439},"// 同じ入力なら 1 時間キャッシュ\n",[416,2464,2465,2468,2470,2473],{"class":418,"line":683},[416,2466,2467],{"class":446},"        skipCache",[416,2469,550],{"class":479},[416,2471,2472],{"class":475},"false",[416,2474,680],{"class":479},[416,2476,2477],{"class":418,"line":710},[416,2478,2479],{"class":479},"      },\n",[416,2481,2482],{"class":418,"line":733},[416,2483,1990],{"class":479},[416,2485,2486],{"class":418,"line":739},[416,2487,1230],{"class":479},[416,2489,2490],{"class":418,"line":745},[416,2491,505],{"emptyLinePlaceholder":34},[416,2493,2494,2496,2498,2500,2502,2504,2506],{"class":418,"line":750},[416,2495,1389],{"class":475},[416,2497,601],{"class":483},[416,2499,569],{"class":479},[416,2501,663],{"class":422},[416,2503,575],{"class":479},[416,2505,2376],{"class":483},[416,2507,742],{"class":479},[416,2509,2510],{"class":418,"line":1227},[416,2511,1747],{"class":479},[18,2513,2514,2515,2518],{},"OpenAI / Anthropic を AI Gateway 経由で叩く場合は、SDK の ",[43,2516,2517],{},"baseURL"," を AI Gateway のエンドポイントに差し替えるだけ。",[252,2520,762],{"id":2521},"動作確認-2",[407,2523,2525],{"className":409,"code":2524,"language":411,"meta":412,"style":412},"curl -X POST https://cf-agent-step2.\u003Caccount>.workers.dev/chat \\\n  -H \"content-type: application/json\" \\\n  -d '{\"prompt\":\"give me one sentence haiku about cloudflare\"}'\n\n# 同じ prompt を 2 回叩く → 2 回目は AI Gateway のキャッシュヒットでミリ秒応答\n",[43,2526,2527,2550,2562,2573,2577],{"__ignoreMap":412},[416,2528,2529,2531,2533,2535,2537,2539,2541,2543,2545,2548],{"class":418,"line":419},[416,2530,782],{"class":422},[416,2532,2141],{"class":2085},[416,2534,2144],{"class":426},[416,2536,2147],{"class":426},[416,2538,805],{"class":510},[416,2540,808],{"class":426},[416,2542,812],{"class":811},[416,2544,815],{"class":510},[416,2546,2547],{"class":426},".workers.dev/chat",[416,2549,2161],{"class":2085},[416,2551,2552,2554,2556,2558,2560],{"class":418,"line":436},[416,2553,2166],{"class":2085},[416,2555,2089],{"class":493},[416,2557,2171],{"class":426},[416,2559,2095],{"class":493},[416,2561,2161],{"class":2085},[416,2563,2564,2566,2568,2571],{"class":418,"line":443},[416,2565,2193],{"class":2085},[416,2567,494],{"class":493},[416,2569,2570],{"class":426},"{\"prompt\":\"give me one sentence haiku about cloudflare\"}",[416,2572,500],{"class":493},[416,2574,2575],{"class":418,"line":452},[416,2576,505],{"emptyLinePlaceholder":34},[416,2578,2579],{"class":418,"line":528},[416,2580,2581],{"class":439},"# 同じ prompt を 2 回叩く → 2 回目は AI Gateway のキャッシュヒットでミリ秒応答\n",[18,2583,2584,2585,2588],{},"AI Gateway のダッシュボードに「Requests」「Cached」「Tokens」「Cost」が積み上がる。",[38,2586,2587],{},"この時点で「Webhook → Queue → LLM 呼び出し」のループが Cloudflare 内で完結する","。",[14,2590,2592],{"id":2591},"step-4-agents-sdk-durable-objects-で状態を持つエージェントを-1-体動かす","Step 4: Agents SDK + Durable Objects で「状態を持つエージェント」を 1 体動かす",[252,2594,399],{"id":2595},"目的-3",[18,2597,2598,2599,2602,2603,2606],{},"ここまでの Worker / Queue / LLM 呼び出しに、",[38,2600,2601],{},"エージェントごとの永続状態","と ",[38,2604,2605],{},"WebSocket でのリアルタイム同期","を足す。Agents SDK は内部で Durable Objects を使ってそれを実現する。",[252,2608,2609],{"id":2609},"雛形",[407,2611,2613],{"className":409,"code":2612,"language":411,"meta":412,"style":412},"pnpm create cloudflare@latest cf-agent-step4 -- --template=cloudflare/agents-starter\ncd cf-agent-step4\npnpm install\n",[43,2614,2615,2633,2640],{"__ignoreMap":412},[416,2616,2617,2619,2621,2624,2627,2630],{"class":418,"line":419},[416,2618,423],{"class":422},[416,2620,427],{"class":426},[416,2622,2623],{"class":426}," cloudflare@latest",[416,2625,2626],{"class":426}," cf-agent-step4",[416,2628,2629],{"class":2085}," --",[416,2631,2632],{"class":2085}," --template=cloudflare/agents-starter\n",[416,2634,2635,2637],{"class":418,"line":436},[416,2636,447],{"class":446},[416,2638,2639],{"class":426}," cf-agent-step4\n",[416,2641,2642,2644],{"class":418,"line":443},[416,2643,423],{"class":422},[416,2645,457],{"class":426},[18,2647,2648],{},"雛形には次のものが含まれる。",[22,2650,2651,2665,2675],{},[27,2652,2653,2656,2657,2660,2661,2664],{},[43,2654,2655],{},"src/server.ts"," — Worker のエントリ。",[43,2658,2659],{},"routeAgentRequest()"," で ",[43,2662,2663],{},"/agents/\u003Cagent-name>/\u003Cid>"," を Durable Object に振り分ける",[27,2666,2667,2670,2671,2674],{},[43,2668,2669],{},"src/agent.ts"," — ",[43,2672,2673],{},"Agent"," クラスを継承した自分のエージェント定義",[27,2676,2677,2679],{},[43,2678,875],{}," — Durable Objects の bindings と migrations が初期化済み",[252,2681,2683],{"id":2682},"エージェントを-1-体作る","エージェントを 1 体作る",[18,2685,2686,2688],{},[43,2687,2669],{},":",[407,2690,2692],{"className":466,"code":2691,"language":468,"meta":412,"style":412},"import { Agent } from 'agents'\n\ntype State = {\n  history: Array\u003C{ role: 'user' | 'assistant'; content: string }>\n}\n\nexport class ChatAgent extends Agent\u003CEnv, State> {\n  initialState: State = { history: [] }\n\n  async onMessage(connection, message: string) {\n    const userMsg = { role: 'user' as const, content: message }\n    this.setState({ history: [...this.state.history, userMsg] })\n\n    const result = await this.env.AI.run('@cf/meta/llama-3.1-8b-instruct', {\n      messages: this.state.history,\n    })\n    const reply = { role: 'assistant' as const, content: result.response }\n\n    this.setState({ history: [...this.state.history, reply] })\n    connection.send(JSON.stringify(reply))\n  }\n}\n",[43,2693,2694,2714,2718,2729,2777,2781,2785,2813,2834,2838,2863,2901,2937,2941,2978,2997,3002,3042,3046,3076,3100,3104],{"__ignoreMap":412},[416,2695,2696,2698,2700,2703,2705,2707,2709,2712],{"class":418,"line":419},[416,2697,476],{"class":475},[416,2699,480],{"class":479},[416,2701,2702],{"class":483}," Agent",[416,2704,487],{"class":479},[416,2706,490],{"class":475},[416,2708,494],{"class":493},[416,2710,2711],{"class":426},"agents",[416,2713,500],{"class":493},[416,2715,2716],{"class":418,"line":436},[416,2717,505],{"emptyLinePlaceholder":34},[416,2719,2720,2722,2725,2727],{"class":418,"line":443},[416,2721,511],{"class":510},[416,2723,2724],{"class":514}," State",[416,2726,518],{"class":479},[416,2728,1000],{"class":479},[416,2730,2731,2734,2736,2739,2742,2745,2747,2749,2752,2754,2757,2759,2762,2764,2767,2770,2772,2774],{"class":418,"line":452},[416,2732,2733],{"class":483},"  history",[416,2735,550],{"class":479},[416,2737,2738],{"class":514},"Array",[416,2740,2741],{"class":479},"\u003C{ ",[416,2743,2744],{"class":483},"role",[416,2746,550],{"class":479},[416,2748,578],{"class":493},[416,2750,2751],{"class":426},"user",[416,2753,578],{"class":493},[416,2755,2756],{"class":479}," | ",[416,2758,578],{"class":493},[416,2760,2761],{"class":426},"assistant",[416,2763,578],{"class":493},[416,2765,2766],{"class":479},"; ",[416,2768,2769],{"class":483},"content",[416,2771,550],{"class":479},[416,2773,1082],{"class":514},[416,2775,2776],{"class":479}," }>\n",[416,2778,2779],{"class":418,"line":528},[416,2780,1025],{"class":479},[416,2782,2783],{"class":418,"line":559},[416,2784,505],{"emptyLinePlaceholder":34},[416,2786,2787,2789,2792,2795,2798,2800,2802,2805,2807,2809,2811],{"class":418,"line":564},[416,2788,753],{"class":475},[416,2790,2791],{"class":510}," class",[416,2793,2794],{"class":514}," ChatAgent",[416,2796,2797],{"class":510}," extends",[416,2799,2702],{"class":422},[416,2801,805],{"class":479},[416,2803,2804],{"class":514},"Env",[416,2806,586],{"class":479},[416,2808,2724],{"class":514},[416,2810,815],{"class":479},[416,2812,1000],{"class":479},[416,2814,2815,2818,2820,2823,2825,2828,2831],{"class":418,"line":621},[416,2816,2817],{"class":483},"  initialState",[416,2819,550],{"class":479},[416,2821,2822],{"class":514},"State",[416,2824,518],{"class":479},[416,2826,2827],{"class":479}," { ",[416,2829,2830],{"class":446},"history",[416,2832,2833],{"class":479},": [] }\n",[416,2835,2836],{"class":418,"line":626},[416,2837,505],{"emptyLinePlaceholder":34},[416,2839,2840,2842,2845,2847,2850,2852,2855,2857,2859,2861],{"class":418,"line":655},[416,2841,1790],{"class":510},[416,2843,2844],{"class":422}," onMessage",[416,2846,575],{"class":479},[416,2848,2849],{"class":483},"connection",[416,2851,586],{"class":479},[416,2853,2854],{"class":483}," message",[416,2856,550],{"class":479},[416,2858,1082],{"class":514},[416,2860,595],{"class":479},[416,2862,1000],{"class":479},[416,2864,2865,2868,2871,2873,2875,2877,2879,2881,2883,2885,2887,2890,2892,2894,2896,2899],{"class":418,"line":669},[416,2866,2867],{"class":510},"    const ",[416,2869,2870],{"class":483},"userMsg",[416,2872,518],{"class":479},[416,2874,2827],{"class":479},[416,2876,2744],{"class":446},[416,2878,550],{"class":479},[416,2880,578],{"class":493},[416,2882,2751],{"class":426},[416,2884,578],{"class":493},[416,2886,1869],{"class":475},[416,2888,2889],{"class":510}," const",[416,2891,1187],{"class":479},[416,2893,2769],{"class":446},[416,2895,550],{"class":479},[416,2897,2898],{"class":483},"message",[416,2900,1892],{"class":479},[416,2902,2903,2906,2908,2911,2913,2915,2918,2921,2923,2926,2928,2930,2932,2934],{"class":418,"line":683},[416,2904,2905],{"class":2085},"    this",[416,2907,569],{"class":479},[416,2909,2910],{"class":422},"setState",[416,2912,1601],{"class":479},[416,2914,2830],{"class":446},[416,2916,2917],{"class":479},": [...",[416,2919,2920],{"class":2085},"this",[416,2922,569],{"class":479},[416,2924,2925],{"class":483},"state",[416,2927,569],{"class":479},[416,2929,2830],{"class":483},[416,2931,1187],{"class":479},[416,2933,2870],{"class":483},[416,2935,2936],{"class":479},"] })\n",[416,2938,2939],{"class":418,"line":710},[416,2940,505],{"emptyLinePlaceholder":34},[416,2942,2943,2945,2947,2949,2951,2954,2956,2958,2960,2962,2964,2966,2968,2970,2972,2974,2976],{"class":418,"line":733},[416,2944,2867],{"class":510},[416,2946,2376],{"class":483},[416,2948,518],{"class":479},[416,2950,1119],{"class":475},[416,2952,2953],{"class":2085}," this",[416,2955,569],{"class":479},[416,2957,1576],{"class":483},[416,2959,569],{"class":479},[416,2961,2391],{"class":483},[416,2963,569],{"class":479},[416,2965,2396],{"class":422},[416,2967,575],{"class":479},[416,2969,578],{"class":493},[416,2971,2405],{"class":426},[416,2973,578],{"class":493},[416,2975,586],{"class":479},[416,2977,1000],{"class":479},[416,2979,2980,2983,2985,2987,2989,2991,2993,2995],{"class":418,"line":739},[416,2981,2982],{"class":446},"      messages",[416,2984,550],{"class":479},[416,2986,2920],{"class":2085},[416,2988,569],{"class":479},[416,2990,2925],{"class":483},[416,2992,569],{"class":479},[416,2994,2830],{"class":483},[416,2996,680],{"class":479},[416,2998,2999],{"class":418,"line":745},[416,3000,3001],{"class":479},"    })\n",[416,3003,3004,3006,3009,3011,3013,3015,3017,3019,3021,3023,3025,3027,3029,3031,3033,3035,3037,3040],{"class":418,"line":750},[416,3005,2867],{"class":510},[416,3007,3008],{"class":483},"reply",[416,3010,518],{"class":479},[416,3012,2827],{"class":479},[416,3014,2744],{"class":446},[416,3016,550],{"class":479},[416,3018,578],{"class":493},[416,3020,2761],{"class":426},[416,3022,578],{"class":493},[416,3024,1869],{"class":475},[416,3026,2889],{"class":510},[416,3028,1187],{"class":479},[416,3030,2769],{"class":446},[416,3032,550],{"class":479},[416,3034,2376],{"class":483},[416,3036,569],{"class":479},[416,3038,3039],{"class":483},"response",[416,3041,1892],{"class":479},[416,3043,3044],{"class":418,"line":1227},[416,3045,505],{"emptyLinePlaceholder":34},[416,3047,3048,3050,3052,3054,3056,3058,3060,3062,3064,3066,3068,3070,3072,3074],{"class":418,"line":1233},[416,3049,2905],{"class":2085},[416,3051,569],{"class":479},[416,3053,2910],{"class":422},[416,3055,1601],{"class":479},[416,3057,2830],{"class":446},[416,3059,2917],{"class":479},[416,3061,2920],{"class":2085},[416,3063,569],{"class":479},[416,3065,2925],{"class":483},[416,3067,569],{"class":479},[416,3069,2830],{"class":483},[416,3071,1187],{"class":479},[416,3073,3008],{"class":483},[416,3075,2936],{"class":479},[416,3077,3078,3081,3083,3085,3087,3089,3091,3094,3096,3098],{"class":418,"line":1284},[416,3079,3080],{"class":483},"    connection",[416,3082,569],{"class":479},[416,3084,1654],{"class":422},[416,3086,575],{"class":479},[416,3088,1675],{"class":483},[416,3090,569],{"class":479},[416,3092,3093],{"class":422},"stringify",[416,3095,575],{"class":479},[416,3097,3008],{"class":483},[416,3099,618],{"class":479},[416,3101,3102],{"class":418,"line":1316},[416,3103,1627],{"class":479},[416,3105,3106],{"class":418,"line":1371},[416,3107,1025],{"class":479},[252,3109,762],{"id":3110},"動作確認-3",[407,3112,3114],{"className":409,"code":3113,"language":411,"meta":412,"style":412},"pnpm dev\n# ブラウザのコンソールで\nconst ws = new WebSocket('ws://localhost:8787/agents/chat-agent/my-session-1')\nws.onmessage = (e) => console.log('reply:', e.data)\nws.onopen = () => ws.send('hello, who are you?')\n",[43,3115,3116,3123,3128,3151,3176],{"__ignoreMap":412},[416,3117,3118,3120],{"class":418,"line":419},[416,3119,423],{"class":422},[416,3121,3122],{"class":426}," dev\n",[416,3124,3125],{"class":418,"line":436},[416,3126,3127],{"class":439},"# ブラウザのコンソールで\n",[416,3129,3130,3133,3136,3138,3141,3144,3146,3149],{"class":418,"line":443},[416,3131,3132],{"class":422},"const",[416,3134,3135],{"class":426}," ws",[416,3137,518],{"class":426},[416,3139,3140],{"class":426}," new",[416,3142,3143],{"class":426}," WebSocket",[416,3145,575],{"class":479},[416,3147,3148],{"class":422},"'ws://localhost:8787/agents/chat-agent/my-session-1'",[416,3150,742],{"class":479},[416,3152,3153,3156,3158,3161,3163,3166,3169,3171,3174],{"class":418,"line":452},[416,3154,3155],{"class":422},"ws.onmessage",[416,3157,518],{"class":426},[416,3159,3160],{"class":811}," (e) =",[416,3162,815],{"class":510},[416,3164,3165],{"class":811}," console.log(",[416,3167,3168],{"class":422},"'reply:'",[416,3170,586],{"class":422},[416,3172,3173],{"class":426}," e.data",[416,3175,742],{"class":811},[416,3177,3178,3181,3183],{"class":418,"line":528},[416,3179,3180],{"class":422},"ws.onopen",[416,3182,518],{"class":426},[416,3184,3185],{"class":811}," () => ws.send('hello, who are you?')\n",[18,3187,3188,3189,3192],{},"ブラウザを閉じて開き直しても、同じ ",[43,3190,3191],{},"my-session-1"," に繋ぎ直せば履歴が残っている。これが Durable Objects の「ID ごとに 1 インスタンス」が効いている瞬間。",[252,3194,3196],{"id":3195},"step-2-の門番と繋ぐ","Step 2 の門番と繋ぐ",[18,3198,3199],{},"Step 2 の Consumer Worker から、",[407,3201,3203],{"className":466,"code":3202,"language":468,"meta":412,"style":412},"// Consumer 内\nconst id = env.CHAT_AGENT.idFromName(job.payload.sessionId)\nconst stub = env.CHAT_AGENT.get(id)\nawait stub.fetch('https://internal/agents/chat-agent/' + job.payload.sessionId, {\n  method: 'POST',\n  body: JSON.stringify({ message: job.payload.text }),\n})\n",[43,3204,3205,3210,3247,3272,3310,3326,3358],{"__ignoreMap":412},[416,3206,3207],{"class":418,"line":419},[416,3208,3209],{"class":439},"// Consumer 内\n",[416,3211,3212,3214,3217,3219,3222,3224,3227,3229,3232,3234,3236,3238,3240,3242,3245],{"class":418,"line":436},[416,3213,531],{"class":510},[416,3215,3216],{"class":483},"id",[416,3218,518],{"class":479},[416,3220,3221],{"class":483}," env",[416,3223,569],{"class":479},[416,3225,3226],{"class":483},"CHAT_AGENT",[416,3228,569],{"class":479},[416,3230,3231],{"class":422},"idFromName",[416,3233,575],{"class":479},[416,3235,1857],{"class":483},[416,3237,569],{"class":479},[416,3239,1929],{"class":483},[416,3241,569],{"class":479},[416,3243,3244],{"class":483},"sessionId",[416,3246,742],{"class":479},[416,3248,3249,3251,3254,3256,3258,3260,3262,3264,3266,3268,3270],{"class":418,"line":443},[416,3250,531],{"class":510},[416,3252,3253],{"class":483},"stub",[416,3255,518],{"class":479},[416,3257,3221],{"class":483},[416,3259,569],{"class":479},[416,3261,3226],{"class":483},[416,3263,569],{"class":479},[416,3265,572],{"class":422},[416,3267,575],{"class":479},[416,3269,3216],{"class":483},[416,3271,742],{"class":479},[416,3273,3274,3276,3279,3281,3283,3285,3287,3290,3292,3295,3298,3300,3302,3304,3306,3308],{"class":418,"line":452},[416,3275,1556],{"class":475},[416,3277,3278],{"class":483}," stub",[416,3280,569],{"class":479},[416,3282,1782],{"class":422},[416,3284,575],{"class":479},[416,3286,578],{"class":493},[416,3288,3289],{"class":426},"https://internal/agents/chat-agent/",[416,3291,578],{"class":493},[416,3293,3294],{"class":510}," +",[416,3296,3297],{"class":483}," job",[416,3299,569],{"class":479},[416,3301,1929],{"class":483},[416,3303,569],{"class":479},[416,3305,3244],{"class":483},[416,3307,586],{"class":479},[416,3309,1000],{"class":479},[416,3311,3312,3315,3317,3319,3322,3324],{"class":418,"line":528},[416,3313,3314],{"class":446},"  method",[416,3316,550],{"class":479},[416,3318,578],{"class":493},[416,3320,3321],{"class":426},"POST",[416,3323,578],{"class":493},[416,3325,680],{"class":479},[416,3327,3328,3331,3333,3335,3337,3339,3341,3343,3345,3347,3349,3351,3353,3355],{"class":418,"line":559},[416,3329,3330],{"class":446},"  body",[416,3332,550],{"class":479},[416,3334,1675],{"class":483},[416,3336,569],{"class":479},[416,3338,3093],{"class":422},[416,3340,1601],{"class":479},[416,3342,2898],{"class":446},[416,3344,550],{"class":479},[416,3346,1857],{"class":483},[416,3348,569],{"class":479},[416,3350,1929],{"class":483},[416,3352,569],{"class":479},[416,3354,606],{"class":483},[416,3356,3357],{"class":479}," }),\n",[416,3359,3360],{"class":418,"line":564},[416,3361,1747],{"class":479},[18,3363,3364,3365,2588],{},"のように呼び出せば、「Webhook で受けたメッセージを、Queue 経由で、対応するエージェント Durable Object に渡す」フローが組める。",[38,3366,3367],{},"これがエージェント基盤の最小完成形",[14,3369,3371],{"id":3370},"条件が満たされた時に着手するチェックリスト保留中","条件が満たされた時に着手するチェックリスト（保留中）",[18,3373,3374],{},"冒頭の経済合理性チェックを通過したら、上から順に消化する。",[22,3376,3378,3384,3390,3396,3402,3408],{"className":3377},[25],[27,3379,3381,3383],{"className":3380},[30],[32,3382],{"disabled":34,"type":35}," Step 1 の Worker をデプロイ",[27,3385,3387,3389],{"className":3386},[30],[32,3388],{"disabled":34,"type":35}," Step 2 の Producer / Consumer を本物の Webhook 送出元（クライアント業務 LINE Bot / 読者フォーム / 外部サービス）で叩く",[27,3391,3393,3395],{"className":3392},[30],[32,3394],{"disabled":34,"type":35}," Step 3 の AI Gateway のキャッシュヒット率を測る（読者向けチャットなら同じ質問が積もる前提でキャッシュ設計）",[27,3397,3399,3401],{"className":3398},[30],[32,3400],{"disabled":34,"type":35}," Step 4 の ChatAgent を Step 2 の Consumer に繋ぐ",[27,3403,3405,3407],{"className":3404},[30],[32,3406],{"disabled":34,"type":35}," エージェントの履歴に長文を入れ続けたときの DO ストレージ消費を観察する",[27,3409,3411,3413],{"className":3410},[30],[32,3412],{"disabled":34,"type":35}," Code Mode（LLM に TypeScript を書かせて Dynamic Workers で実行する形）を別記事で試す",[14,3415,3416],{"id":3416},"参考",[22,3418,3419,3424,3431,3438,3445],{},[27,3420,3421],{},[290,3422,297],{"href":292,"target":293,"rel":3423},[295,296],[27,3425,3426],{},[290,3427,3430],{"href":3428,"target":293,"rel":3429},"https://developers.cloudflare.com/queues/",[295,296],"Cloudflare Queues 公式ドキュメント",[27,3432,3433],{},[290,3434,3437],{"href":3435,"target":293,"rel":3436},"https://developers.cloudflare.com/ai-gateway/",[295,296],"AI Gateway 公式ドキュメント",[27,3439,3440],{},[290,3441,3444],{"href":3442,"target":293,"rel":3443},"https://developers.cloudflare.com/agents/",[295,296],"Cloudflare Agents SDK 公式ドキュメント",[27,3446,3447],{},[290,3448,542],{"href":3449,"target":293,"rel":3450},"https://hono.dev/",[295,296],[3452,3453,3454],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .senZ8, html code.shiki .senZ8{--shiki-default:#59873A;--shiki-dark:#59873A}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html pre.shiki code .sxvE3, html code.shiki .sxvE3{--shiki-default:#A0ADA0;--shiki-dark:#A0ADA0}html pre.shiki code .sz8Xr, html code.shiki .sz8Xr{--shiki-default:#998418;--shiki-dark:#998418}html pre.shiki code .sHkkW, html code.shiki .sHkkW{--shiki-default:#1E754F;--shiki-dark:#1E754F}html pre.shiki code .shFtX, html code.shiki .shFtX{--shiki-default:#999999;--shiki-dark:#999999}html pre.shiki code .s4oTP, html code.shiki .s4oTP{--shiki-default:#B07D48;--shiki-dark:#B07D48}html pre.shiki code .sMJiu, html code.shiki .sMJiu{--shiki-default:#B5695977;--shiki-dark:#B5695977}html pre.shiki code .stQ0i, html code.shiki .stQ0i{--shiki-default:#AB5959;--shiki-dark:#AB5959}html pre.shiki code .sSkh3, html code.shiki .sSkh3{--shiki-default:#2E8F82;--shiki-dark:#2E8F82}html pre.shiki code .sG7-3, html code.shiki .sG7-3{--shiki-default:#393A34;--shiki-dark:#393A34}html pre.shiki code .sM54T, html code.shiki .sM54T{--shiki-default:#2F798A;--shiki-dark:#2F798A}html pre.shiki code .snbK4, html code.shiki .snbK4{--shiki-default:#A65E2B;--shiki-dark:#A65E2B}",{"title":412,"searchDepth":436,"depth":436,"links":3456},[3457,3458,3461,3462,3463,3468,3477,3483,3490,3491],{"id":16,"depth":436,"text":16},{"id":87,"depth":436,"text":88,"children":3459},[3460],{"id":254,"depth":443,"text":254},{"id":285,"depth":436,"text":285},{"id":374,"depth":436,"text":374},{"id":395,"depth":436,"text":396,"children":3464},[3465,3466,3467],{"id":399,"depth":443,"text":399},{"id":405,"depth":443,"text":405},{"id":762,"depth":443,"text":762},{"id":830,"depth":436,"text":831,"children":3469},[3470,3471,3472,3473,3474,3475,3476],{"id":834,"depth":443,"text":399},{"id":840,"depth":443,"text":840},{"id":850,"depth":443,"text":851},{"id":872,"depth":443,"text":875},{"id":962,"depth":443,"text":405},{"id":2004,"depth":443,"text":762},{"id":2216,"depth":443,"text":2216},{"id":2238,"depth":436,"text":2239,"children":3478},[3479,3480,3481,3482],{"id":2242,"depth":443,"text":399},{"id":2252,"depth":443,"text":2253},{"id":2267,"depth":443,"text":2268},{"id":2521,"depth":443,"text":762},{"id":2591,"depth":436,"text":2592,"children":3484},[3485,3486,3487,3488,3489],{"id":2595,"depth":443,"text":399},{"id":2609,"depth":443,"text":2609},{"id":2682,"depth":443,"text":2683},{"id":3110,"depth":443,"text":762},{"id":3195,"depth":443,"text":3196},{"id":3370,"depth":436,"text":3371},{"id":3416,"depth":436,"text":3416},"dev","yusukebe の「AI エージェントは Cloudflare に賭けろ」と Webhook の 3 秒ルール突破ポストに触発され、Wrangler セットアップ済みの状態からエージェント基盤を組み上げるまでを 4 ステップで進める計画書兼実装ログ。","md",{},null,"/cloudflare-agent-foundation-4-steps","misc-dev",false,"2026-06-19T00:00:00.000Z",{"title":5,"description":3493},"2026-06/2026-06-19/cloudflare-agent-foundation-4-steps",[3504,3505,542,3506,3507,356,3508],"Cloudflare","Cloudflare Workers","Cloudflare Queues","Workers AI","AI Agent","memo","lL4UKVLYfVJdiX0lv1DL39fW4bGX2iPUO3GHJ95_aoY",[],"https://log.eurekapu.com/og/blog/cloudflare-agent-foundation-4-steps.png?v=2026-06-19T00%3A00%3A00.000Z&title=Cloudflare%20%E3%81%A7%20AI%20%E3%82%A8%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%B3%E3%83%88%E5%9F%BA%E7%9B%A4%E3%82%92%E4%BD%9C%E3%82%8B%204%20%E3%82%B9%E3%83%86%E3%83%83%E3%83%97%20%E2%80%94%20Hono%20%E2%86%92%20Queues%20%E2%86%92%20Workers%20AI%20%E2%86%92%20Agents%20SDK&author=Kei%20Komatsu&sig=975e89dd77603ba1",1782176331032]