agents 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. package/README.md +8 -9
  2. package/dist/abortable-C1SpfVoi.js +21 -0
  3. package/dist/abortable-C1SpfVoi.js.map +1 -0
  4. package/dist/{agent-routing-0DR0Tk2v.d.ts → agent-routing-QDcchcQP.d.ts} +16 -16
  5. package/dist/agent-routing.d.ts +1 -1
  6. package/dist/agent-tool-types.d.ts +1 -1
  7. package/dist/{agent-tools-YrATZJu2.d.ts → agent-tools-DHL2XI7u.d.ts} +2 -2
  8. package/dist/agent-tools.d.ts +1 -1
  9. package/dist/ai-ahruGw7e.d.ts +239 -0
  10. package/dist/ai-sdk-Bdsf6mSA.js +2444 -0
  11. package/dist/ai-sdk-Bdsf6mSA.js.map +1 -0
  12. package/dist/apply-chunks-1FheRb9W.js +99 -0
  13. package/dist/apply-chunks-1FheRb9W.js.map +1 -0
  14. package/dist/broadcast-state-CEyI4uAK.js +69 -0
  15. package/dist/broadcast-state-CEyI4uAK.js.map +1 -0
  16. package/dist/browser/ai.d.ts +8 -227
  17. package/dist/browser/ai.js +259 -1
  18. package/dist/browser/ai.js.map +1 -0
  19. package/dist/browser/index.d.ts +56 -46
  20. package/dist/browser/index.js +4 -361
  21. package/dist/browser/{ai-sdk.d.ts → tools/ai-sdk.d.ts} +7 -7
  22. package/dist/browser/{ai-sdk.js → tools/ai-sdk.js} +6 -5
  23. package/dist/browser/tools/ai-sdk.js.map +1 -0
  24. package/dist/browser/tools/pi.d.ts +111 -0
  25. package/dist/browser/tools/pi.js +119 -0
  26. package/dist/browser/tools/pi.js.map +1 -0
  27. package/dist/browser/{tanstack-ai.d.ts → tools/tanstack-ai.d.ts} +39 -37
  28. package/dist/browser/{tanstack-ai.js → tools/tanstack-ai.js} +73 -59
  29. package/dist/browser/tools/tanstack-ai.js.map +1 -0
  30. package/dist/browser-CEdNlsaD.js +481 -0
  31. package/dist/browser-CEdNlsaD.js.map +1 -0
  32. package/dist/{browser-DE3d-RLk.d.ts → browser-D30VlpcA.d.ts} +63 -37
  33. package/dist/{browser-tool-CQ10e6Kj.js → browser-tool-4iomavs_.js} +198 -62
  34. package/dist/browser-tool-4iomavs_.js.map +1 -0
  35. package/dist/{browser-tool-DuNdlwZ9.d.ts → browser-tool-vtrPOV8e.d.ts} +25 -6
  36. package/dist/{capability-B4WbF81e.js → capability-DBAKc6UZ.js} +1 -3
  37. package/dist/capability-DBAKc6UZ.js.map +1 -0
  38. package/dist/{capability-runner-DBAnGr6L.d.ts → capability-runner-BiVUtjqC.d.ts} +9 -7
  39. package/dist/channel-Bak_6zDP.d.ts +333 -0
  40. package/dist/chat/index.d.ts +11 -9
  41. package/dist/chat/index.js +5 -194
  42. package/dist/chat/index.js.map +1 -1
  43. package/dist/chat/react.d.ts +2 -4
  44. package/dist/chat/react.js +3 -1
  45. package/dist/chat/react.js.map +1 -1
  46. package/dist/chat-sdk/index.d.ts +1 -1
  47. package/dist/chat-sdk/index.js +1 -1
  48. package/dist/cli.js +144 -0
  49. package/dist/{client-je3koD9Z.d.ts → client-BGIQKJhX.d.ts} +2 -2
  50. package/dist/{client-fyQrLGkD.js → client-BnYbNT3z.js} +29 -5
  51. package/dist/client-BnYbNT3z.js.map +1 -0
  52. package/dist/client-tools-aIBO0Fk7.d.ts +53 -0
  53. package/dist/client.d.ts +1 -1
  54. package/dist/{connector-58XDGvc3.js → connector-CtZylXdk.js} +3 -603
  55. package/dist/connector-CtZylXdk.js.map +1 -0
  56. package/dist/{connector-Cl-VqPmA.d.ts → connector-DEXzVoaY.d.ts} +9 -374
  57. package/dist/conversations-FjHDRZyD.d.ts +192 -0
  58. package/dist/{current-agent-vAk_5JMt.d.ts → current-agent-CKgT5d1O.d.ts} +3 -5
  59. package/dist/current-agent-DhoDkSnH.js.map +1 -1
  60. package/dist/daemon-core-Buubj-y1.js +481 -0
  61. package/dist/daemon-core-Buubj-y1.js.map +1 -0
  62. package/dist/daemon-core-CbohVPAu.d.ts +132 -0
  63. package/dist/{do-oauth-client-provider-Tmf1vgKz.d.ts → do-oauth-client-provider-DfsUcpc3.d.ts} +7 -1
  64. package/dist/{durable-object-lifecycle-HhgOMWq9.d.ts → durable-object-lifecycle-DOI_bzCH.d.ts} +2 -2
  65. package/dist/{channels/email.d.ts → experimental/channels/email/index.d.ts} +25 -12
  66. package/dist/{channels/email.js → experimental/channels/email/index.js} +13 -35
  67. package/dist/experimental/channels/email/index.js.map +1 -0
  68. package/dist/experimental/channels/index.d.ts +270 -0
  69. package/dist/experimental/channels/index.js +1186 -0
  70. package/dist/experimental/channels/index.js.map +1 -0
  71. package/dist/{channels/slack.d.ts → experimental/channels/slack/index.d.ts} +19 -9
  72. package/dist/experimental/channels/slack/index.js +267 -0
  73. package/dist/experimental/channels/slack/index.js.map +1 -0
  74. package/dist/{channels/telegram.d.ts → experimental/channels/telegram/index.d.ts} +19 -9
  75. package/dist/experimental/channels/telegram/index.js +198 -0
  76. package/dist/experimental/channels/telegram/index.js.map +1 -0
  77. package/dist/experimental/channels/web/ai-sdk.d.ts +55 -0
  78. package/dist/experimental/channels/web/ai-sdk.js +266 -0
  79. package/dist/experimental/channels/web/ai-sdk.js.map +1 -0
  80. package/dist/experimental/channels/web/client.d.ts +97 -0
  81. package/dist/experimental/channels/web/client.js +349 -0
  82. package/dist/experimental/channels/web/client.js.map +1 -0
  83. package/dist/experimental/channels/web/index.d.ts +189 -0
  84. package/dist/experimental/channels/web/index.js +332 -0
  85. package/dist/experimental/channels/web/index.js.map +1 -0
  86. package/dist/gateway-BFO6vRDn.d.ts +100 -0
  87. package/dist/handle-zAzh0UW2.d.ts +460 -0
  88. package/dist/harness/ai-sdk/index.d.ts +175 -0
  89. package/dist/harness/ai-sdk/index.js +605 -0
  90. package/dist/harness/ai-sdk/index.js.map +1 -0
  91. package/dist/harness/container/daemon/index.d.ts +76 -0
  92. package/dist/harness/container/daemon/index.js +3 -0
  93. package/dist/harness/container/index.d.ts +740 -0
  94. package/dist/harness/container/index.js +2152 -0
  95. package/dist/harness/container/index.js.map +1 -0
  96. package/dist/harness/container/runtime/index.d.ts +144 -0
  97. package/dist/harness/container/runtime/index.js +1082 -0
  98. package/dist/harness/container/runtime/index.js.map +1 -0
  99. package/dist/harness/opencode/index.d.ts +369 -0
  100. package/dist/harness/opencode/index.js +1072 -0
  101. package/dist/harness/opencode/index.js.map +1 -0
  102. package/dist/harness/pi/index.d.ts +3 -2
  103. package/dist/harness/pi/index.js +3 -3
  104. package/dist/harness/store/index.d.ts +24 -0
  105. package/dist/harness/store/index.js +2 -0
  106. package/dist/harness/think/index.d.ts +821 -0
  107. package/dist/harness/think/index.js +2721 -0
  108. package/dist/harness/think/index.js.map +1 -0
  109. package/dist/harness-B6B9S3rb.d.ts +203 -0
  110. package/dist/{images-iiTDSyRu.js → images-Ce9SCu3X.js} +2 -248
  111. package/dist/images-Ce9SCu3X.js.map +1 -0
  112. package/dist/{index-BreL0YrQ.d.ts → index-BEL3ZV-s.d.ts} +2 -6
  113. package/dist/index-CBt8oRJt.d.ts +198 -0
  114. package/dist/index.d.ts +5 -5
  115. package/dist/index.js +2 -2
  116. package/dist/ingress-EFbrS547.js +9 -0
  117. package/dist/ingress-EFbrS547.js.map +1 -0
  118. package/dist/input-schema-BQykTEp_.js +20 -0
  119. package/dist/input-schema-BQykTEp_.js.map +1 -0
  120. package/dist/input-schema-D2QAtHZH.js +23 -0
  121. package/dist/input-schema-D2QAtHZH.js.map +1 -0
  122. package/dist/internal-kmw70xwR.js +46 -0
  123. package/dist/internal-kmw70xwR.js.map +1 -0
  124. package/dist/internal_context.d.ts +1 -1
  125. package/dist/lifecycle/index.d.ts +3 -3
  126. package/dist/lifecycle/index.js +2 -2
  127. package/dist/{lifecycle-CFu6OV03.js → lifecycle-DGorpAmA.js} +2 -4
  128. package/dist/lifecycle-DGorpAmA.js.map +1 -0
  129. package/dist/mcp/client/do-oauth-client-provider.d.ts +1 -1
  130. package/dist/mcp/client/do-oauth-client-provider.js +9 -0
  131. package/dist/mcp/client/do-oauth-client-provider.js.map +1 -1
  132. package/dist/mcp/client/index.d.ts +1 -1
  133. package/dist/mcp/client/index.js +1 -1
  134. package/dist/mcp/client/x402.d.ts +35 -4
  135. package/dist/mcp/client/x402.js +24 -3
  136. package/dist/mcp/client/x402.js.map +1 -1
  137. package/dist/mcp/index.d.ts +1 -1
  138. package/dist/mcp/index.js +2 -2
  139. package/dist/models/ai-sdk/index.d.ts +16 -14
  140. package/dist/models/ai-sdk/index.js +1 -2442
  141. package/dist/models/opencode/index.d.ts +65 -0
  142. package/dist/models/opencode/index.js +285 -0
  143. package/dist/models/opencode/index.js.map +1 -0
  144. package/dist/models/pi-ai/index.d.ts +9 -7
  145. package/dist/models/pi-ai/index.js +2 -1
  146. package/dist/models/pi-ai/index.js.map +1 -1
  147. package/dist/options-CiIsJHXR.d.ts +130 -0
  148. package/dist/protocol-BEgrJYC5.d.ts +331 -0
  149. package/dist/protocol-CukuI73M.d.ts +386 -0
  150. package/dist/protocol-cOklVBBD.js +227 -0
  151. package/dist/protocol-cOklVBBD.js.map +1 -0
  152. package/dist/{protocol-kHsr-f0X.js → protocol-eXeJxhgu.js} +2 -67
  153. package/dist/protocol-eXeJxhgu.js.map +1 -0
  154. package/dist/protocol-y2sSY584.js +148 -0
  155. package/dist/protocol-y2sSY584.js.map +1 -0
  156. package/dist/queue/index.d.ts +1 -1
  157. package/dist/queue/index.js +1 -1
  158. package/dist/{queue-BB-zfIYF.js → queue-CcIjVYTE.js} +2 -2
  159. package/dist/{queue-BB-zfIYF.js.map → queue-CcIjVYTE.js.map} +1 -1
  160. package/dist/react.d.ts +2 -2
  161. package/dist/routing/index.d.ts +2 -2
  162. package/dist/routing/index.js +1 -1
  163. package/dist/{scheduler-RdACNXDP.d.ts → scheduler-BCLESHSC.d.ts} +2 -12
  164. package/dist/{scheduler-DZ3xQfeK.js → scheduler-FIHv2-kJ.js} +2 -4
  165. package/dist/scheduler-FIHv2-kJ.js.map +1 -0
  166. package/dist/schedules/index.d.ts +1 -1
  167. package/dist/schedules/index.js +1 -1
  168. package/dist/serializable.d.ts +1 -1
  169. package/dist/session-store-Do4xkDcf.js +606 -0
  170. package/dist/session-store-Do4xkDcf.js.map +1 -0
  171. package/dist/session-store-DoPY12xM.d.ts +383 -0
  172. package/dist/sessions/index.d.ts +11 -434
  173. package/dist/sessions/index.js +1 -2271
  174. package/dist/sessions-_vN5BEZX.js +2272 -0
  175. package/dist/sessions-_vN5BEZX.js.map +1 -0
  176. package/dist/settings-C45hDliX.js +253 -0
  177. package/dist/settings-C45hDliX.js.map +1 -0
  178. package/dist/{transport-PfFnt-Ld.d.ts → settings-NgGwF7Qt.d.ts} +14 -208
  179. package/dist/{src-BZeu-SCD.js → src-CQxJFv4l.js} +8 -8
  180. package/dist/src-CQxJFv4l.js.map +1 -0
  181. package/dist/stall-watchdog-BpRF2uwG.js +195 -0
  182. package/dist/stall-watchdog-BpRF2uwG.js.map +1 -0
  183. package/dist/state/index.d.ts +1 -1
  184. package/dist/state/index.js +1 -3
  185. package/dist/state/index.js.map +1 -1
  186. package/dist/store-BKM4Xm9M.d.ts +332 -0
  187. package/dist/store-CslVzfN7.js +458 -0
  188. package/dist/store-CslVzfN7.js.map +1 -0
  189. package/dist/streams/index.d.ts +1 -1
  190. package/dist/streams/index.js +1 -1
  191. package/dist/{streams-DW-UCOUc.js → streams-lsHMJhRW.js} +17 -4
  192. package/dist/streams-lsHMJhRW.js.map +1 -0
  193. package/dist/{streams-Cmkj9QfW.d.ts → streams-vrCtbUIn.d.ts} +2 -2
  194. package/dist/sub-routing.d.ts +1 -1
  195. package/dist/tasks/index.d.ts +1 -1
  196. package/dist/tasks/index.js +1 -1
  197. package/dist/{tasks-68DESxf0.js → tasks-BN_5AWqI.js} +3 -2
  198. package/dist/tasks-BN_5AWqI.js.map +1 -0
  199. package/dist/{tasks-9YxYtByh.d.ts → tasks-E89KdwkS.d.ts} +2 -2
  200. package/dist/tool-CTp72Jb_.d.ts +278 -0
  201. package/dist/tool-CxKsvxjm.js +1126 -0
  202. package/dist/tool-CxKsvxjm.js.map +1 -0
  203. package/dist/tool-DoVberpN.d.ts +301 -0
  204. package/dist/tool-cQRkwSZZ.js +410 -0
  205. package/dist/tool-cQRkwSZZ.js.map +1 -0
  206. package/dist/tool-helpers-O5BDVEAY.js +58 -0
  207. package/dist/tool-helpers-O5BDVEAY.js.map +1 -0
  208. package/dist/transport-k2mFrtL8.d.ts +200 -0
  209. package/dist/turns-DCV3ycDl.js +317 -0
  210. package/dist/turns-DCV3ycDl.js.map +1 -0
  211. package/dist/voice/client.js +1 -1
  212. package/dist/voice/index.d.ts +2 -2
  213. package/dist/voice/index.js +1 -1
  214. package/dist/web/fetch/index.d.ts +89 -0
  215. package/dist/web/fetch/index.js +20 -0
  216. package/dist/web/fetch/index.js.map +1 -0
  217. package/dist/web/fetch/tools/ai-sdk.d.ts +80 -0
  218. package/dist/web/fetch/tools/ai-sdk.js +47 -0
  219. package/dist/web/fetch/tools/ai-sdk.js.map +1 -0
  220. package/dist/web/fetch/tools/pi.d.ts +84 -0
  221. package/dist/web/fetch/tools/pi.js +88 -0
  222. package/dist/web/fetch/tools/pi.js.map +1 -0
  223. package/dist/web/fetch/tools/tanstack-ai.d.ts +78 -0
  224. package/dist/web/fetch/tools/tanstack-ai.js +45 -0
  225. package/dist/web/fetch/tools/tanstack-ai.js.map +1 -0
  226. package/dist/web/search/index.d.ts +58 -0
  227. package/dist/web/search/index.js +2 -0
  228. package/dist/web/search/tools/ai-sdk.d.ts +77 -0
  229. package/dist/web/search/tools/ai-sdk.js +46 -0
  230. package/dist/web/search/tools/ai-sdk.js.map +1 -0
  231. package/dist/web/search/tools/pi.d.ts +82 -0
  232. package/dist/web/search/tools/pi.js +89 -0
  233. package/dist/web/search/tools/pi.js.map +1 -0
  234. package/dist/web/search/tools/tanstack-ai.d.ts +71 -0
  235. package/dist/web/search/tools/tanstack-ai.js +46 -0
  236. package/dist/web/search/tools/tanstack-ai.js.map +1 -0
  237. package/dist/websockets/index.d.ts +12 -296
  238. package/dist/websockets/index.js +1 -1
  239. package/dist/{websockets-Ci-LZFHH.js → websockets-C3zy8YR0.js} +20 -8
  240. package/dist/websockets-C3zy8YR0.js.map +1 -0
  241. package/dist/{wire-types-CrjKvDyi.d.ts → wire-types-Cv0iwjk5.d.ts} +3 -51
  242. package/dist/workflow-types.d.ts +1 -1
  243. package/dist/workflows.d.ts +1 -1
  244. package/dist/workflows.js +1 -1
  245. package/docs/browse-the-web.md +29 -1
  246. package/docs/fetch-the-web.md +276 -0
  247. package/docs/harnesses/pi.md +25 -0
  248. package/docs/harnesses/think.md +215 -0
  249. package/docs/index.md +99 -75
  250. package/docs/lifecycle.md +42 -3
  251. package/docs/queue.md +2 -3
  252. package/docs/scheduling.md +2 -6
  253. package/docs/search-the-web.md +135 -0
  254. package/package.json +148 -44
  255. package/dist/ai-fm7xx1BK.js +0 -312
  256. package/dist/ai-fm7xx1BK.js.map +0 -1
  257. package/dist/browser/ai-sdk.js.map +0 -1
  258. package/dist/browser/index.js.map +0 -1
  259. package/dist/browser/tanstack-ai.js.map +0 -1
  260. package/dist/browser-tool-CQ10e6Kj.js.map +0 -1
  261. package/dist/capability-B4WbF81e.js.map +0 -1
  262. package/dist/channel-Bnm4S7T2.d.ts +0 -491
  263. package/dist/channels/ai-sdk.d.ts +0 -46
  264. package/dist/channels/ai-sdk.js +0 -120
  265. package/dist/channels/ai-sdk.js.map +0 -1
  266. package/dist/channels/email.js.map +0 -1
  267. package/dist/channels/index.d.ts +0 -233
  268. package/dist/channels/index.js +0 -608
  269. package/dist/channels/index.js.map +0 -1
  270. package/dist/channels/slack.js +0 -614
  271. package/dist/channels/slack.js.map +0 -1
  272. package/dist/channels/tanstack-ai.d.ts +0 -39
  273. package/dist/channels/tanstack-ai.js +0 -17
  274. package/dist/channels/tanstack-ai.js.map +0 -1
  275. package/dist/channels/telegram.js +0 -427
  276. package/dist/channels/telegram.js.map +0 -1
  277. package/dist/channels/voice.d.ts +0 -45
  278. package/dist/channels/voice.js +0 -122
  279. package/dist/channels/voice.js.map +0 -1
  280. package/dist/client-fyQrLGkD.js.map +0 -1
  281. package/dist/connector-58XDGvc3.js.map +0 -1
  282. package/dist/images-iiTDSyRu.js.map +0 -1
  283. package/dist/index-BB0kqhIz.d.ts +0 -101
  284. package/dist/ingress-BfetZbMO.js +0 -83
  285. package/dist/ingress-BfetZbMO.js.map +0 -1
  286. package/dist/internal-CYlgHl1l.js +0 -59
  287. package/dist/internal-CYlgHl1l.js.map +0 -1
  288. package/dist/lifecycle-CFu6OV03.js.map +0 -1
  289. package/dist/models/ai-sdk/index.js.map +0 -1
  290. package/dist/protocol-kHsr-f0X.js.map +0 -1
  291. package/dist/scheduler-DZ3xQfeK.js.map +0 -1
  292. package/dist/sessions/index.js.map +0 -1
  293. package/dist/src-BZeu-SCD.js.map +0 -1
  294. package/dist/streams-DW-UCOUc.js.map +0 -1
  295. package/dist/surface-bZZJqBka.js +0 -17
  296. package/dist/surface-bZZJqBka.js.map +0 -1
  297. package/dist/tasks-68DESxf0.js.map +0 -1
  298. package/dist/tool-schema-CBjGPrsQ.js +0 -31
  299. package/dist/tool-schema-CBjGPrsQ.js.map +0 -1
  300. package/dist/websockets-Ci-LZFHH.js.map +0 -1
  301. package/docs/channels.md +0 -323
package/docs/index.md CHANGED
@@ -1,6 +1,25 @@
1
1
  # Agents Documentation
2
2
 
3
- Build stateful AI agents on Cloudflare Workers. Every agent is a Durable Object — an addressable, hibernatable actor with its own SQLite database, WebSockets, and scheduling — so you can afford one durable agent per user, account, task, or conversation, with near-zero cost while idle.
3
+ Build stateful AI agents on Cloudflare Workers. An agent is a Durable Object: an addressable actor with its own SQLite database, alarms, and WebSockets. You can run one durable agent per user, account, task, or conversation, and pay close to nothing while it is idle.
4
+
5
+ Every agent starts the same way. Extend `DurableObject`, install a [Lifecycle](./lifecycle.md), and add the capabilities you need:
6
+
7
+ ```ts
8
+ import { DurableObject } from "cloudflare:workers";
9
+ import { Lifecycle } from "agents/lifecycle";
10
+ import { MCPClientManager } from "agents/mcp/client";
11
+ import { Scheduler } from "agents/schedules";
12
+
13
+ export class Assistant extends DurableObject<Env> {
14
+ readonly mcp = new MCPClientManager("assistant", "1.0.0");
15
+ readonly scheduler = new Scheduler({ callbacks: {} });
16
+ readonly lifecycle = Lifecycle.install(this)
17
+ .use(this.mcp)
18
+ .use(this.scheduler);
19
+ }
20
+ ```
21
+
22
+ The Lifecycle runs startup, routes requests to capabilities, and owns the object's durable job queue and its single alarm. Capabilities are independent pieces that share it.
4
23
 
5
24
  ## Related package documentation
6
25
 
@@ -9,86 +28,95 @@ Build stateful AI agents on Cloudflare Workers. Every agent is a Durable Object
9
28
 
10
29
  ## Choose your path
11
30
 
12
- Pick the base class that matches what you are building. They share the same Durable Object foundation, so you can start small and move up without re-platforming.
31
+ | You are building... | Use |
32
+ | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
33
+ | An agent that runs a model loop with tools and recovery | [Pi harness](./harnesses/pi.md) on a Durable Object |
34
+ | Your own agent loop | [Sessions](./sessions.md), [Streams](./streams.md), and [Tasks](./tasks.md) on a Durable Object |
35
+ | A chat or reasoning agent with every default built in | [`Think`](https://github.com/cloudflare/agents/blob/main/docs/think/index.md) |
36
+ | A chat UI that owns the loop and the stream | [`AIChatAgent`](./chat-agents.md), built on the `Agent` class |
37
+ | Real-time state sync, `@callable` methods, email, voice | The [`Agent` class](./agent-class.md), which installs a preset of capabilities for you |
38
+ | Durable multi-step processes (not chat) | [Workflows](./workflows.md) |
39
+
40
+ ## Getting started
13
41
 
14
- | You are building... | Use | Why |
15
- | -------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
16
- | Stateful backend logic, real-time sync, custom protocols | [`Agent`](./agent-class.md) | The core class: state, WebSockets, scheduling, SQL, and sub-agents. No opinions about chat or LLMs. |
17
- | A chat UI where you own the loop, the stream, and the response | [`AIChatAgent`](./chat-agents.md) | A thin chat-protocol adapter for `useAgentChat`. Bring your own agentic loop and custom streaming. |
18
- | A durable, general-purpose reasoning agent | [`Think`](https://github.com/cloudflare/agents/blob/main/docs/think/index.md) | Opinionated runtime: agentic loop, sessions, tools, memory, compaction, recovery, and multi-channel delivery built in. |
19
- | A voice agent (speech in, speech out) | [Voice mixins](./voice.md) | `withVoice` adds real-time STT/TTS, interruption and barge-in, and conversation persistence to an agent. |
20
- | Durable multi-step processes (not chat) | [Workflows](./workflows.md) | Long-running, retryable step orchestration with Cloudflare Workflows. |
42
+ - [Getting Started](./getting-started.md) - Quick start guide for new users
43
+ - [Adding to an Existing Project](./adding-to-existing-project.md) - Integrate agents into your app
21
44
 
22
- Not sure? Start with [`Agent`](./agent-class.md) for raw building blocks, or [`Think`](https://github.com/cloudflare/agents/blob/main/docs/think/index.md) if you want a chat or reasoning agent that already handles the hard parts.
45
+ ## Lifecycle
23
46
 
24
- ## What makes these production-grade
47
+ - [Durable Object Lifecycle](./lifecycle.md) - Install a Lifecycle on a Durable Object, write capabilities, and use the job queue
48
+ - [getCurrentAgent()](./get-current-agent.md) - Accessing the current object, request, and connection across async calls
25
49
 
26
- The differentiator is not "we have durable state" — it is what happens when a turn is interrupted. Agents built on this SDK keep their promises across Durable Object eviction, deploys, client disconnects, and human waits:
50
+ ## Harnesses
27
51
 
28
- - **Turn recovery** — an in-flight LLM turn survives Durable Object eviction and resumes instead of silently dying. See [Chat & Fiber Recovery](./chat-agents.md#stream-recovery) and [Durable Execution](./durable-execution.md).
29
- - **Resumable streams** — a disconnected client rejoins the same stream rather than losing the response. See [Resumable Streaming](./resumable-streaming.md).
30
- - **Recovery-aware delivery** — Think snapshots channel delivery as `accepted`, `streaming`, or `completed`, so a restart replays a not-yet-streamed answer but posts a safe interruption notice rather than risking a duplicate partial reply. See [Messengers — Delivery and Recovery](https://github.com/cloudflare/agents/blob/main/docs/think/messengers.md#delivery-and-recovery).
31
- - **Durable submissions** — webhooks and RPC callers submit a turn with an idempotency key and check status later, instead of holding a request open. See [Programmatic Submissions](https://github.com/cloudflare/agents/blob/main/docs/think/programmatic-submissions.md).
32
- - **Human-in-the-loop without hangs** — a turn can pause for approval and resume later. A human wait is a first-class state, not a stuck request. See [Human in the Loop](./human-in-the-loop.md).
52
+ - [Pi harness (Beta)](./harnesses/pi.md) - Host pi-durable sessions in a Durable Object with durable storage and lifecycle wakeups
53
+ - [Think harness (Experimental)](./harnesses/think.md) - Run Think's agent loop as a Lifecycle capability, with transcripts in Sessions, output in Streams, and turns that survive eviction
54
+ - [Think (Experimental)](https://github.com/cloudflare/agents/blob/main/docs/think/index.md) - Opinionated chat agent with built-in memory, tools, and streaming. Extends `Think`, which builds on `Agent`.
33
55
 
34
- ## Getting Started
56
+ ## Capabilities
35
57
 
36
- - [Getting Started](./getting-started.md) - Quick start guide for new users
37
- - [Adding to an Existing Project](./adding-to-existing-project.md) - Integrate agents into your app
38
- - [Understanding the Agent Class](./agent-class.md) - Deep dive into the Agent class architecture
58
+ Install each capability with `lifecycle.use()`. Capabilities marked experimental may change between releases.
39
59
 
40
- ## Core Concepts
60
+ | Capability | Import | Status | Docs |
61
+ | ------------------ | ------------------- | ------------ | --------------------------------------------------------------- |
62
+ | `PiHarness` | `agents/harness/pi` | Beta | [Pi harness](./harnesses/pi.md) |
63
+ | `MCPClientManager` | `agents/mcp/client` | Stable | [MCP client](./mcp-client.md) |
64
+ | `Scheduler` | `agents/schedules` | Stable | [Scheduling](./scheduling.md) |
65
+ | `State` | `agents/state` | Stable | [Lifecycle](./lifecycle.md#websockets-are-an-opt-in-capability) |
66
+ | `WebSockets` | `agents/websockets` | Stable | [Lifecycle](./lifecycle.md#websockets-are-an-opt-in-capability) |
67
+ | `Queue` | `agents/queue` | Experimental | [Queue](./queue.md) |
68
+ | `RoutedAgents` | `agents/routing` | Experimental | [Routing](./routing.md) |
69
+ | `Browser` | `agents/browser` | Experimental | [Browse the Web](./browse-the-web.md) |
70
+ | `Sessions` | `agents/sessions` | Experimental | [Sessions](./sessions.md) |
71
+ | `Streams` | `agents/streams` | Experimental | [Streams](./streams.md) |
72
+ | `Tasks` | `agents/tasks` | Experimental | [Tasks](./tasks.md) |
41
73
 
42
- - [State Management](./state.md) - Managing agent state with `setState()`, `initialState`, and `onStateChanged()`
74
+ Building your own harness? Sessions stores the conversation, Streams holds durable incremental output, and Tasks runs replayable background work. [Models](./models.md) and [Models for pi-ai](./models-pi-ai.md) give you one provider for Workers AI and third-party models. [Context](./context.md) and [Workspace](https://github.com/cloudflare/agents/blob/main/docs/shell/index.md) are also available.
75
+
76
+ ## Agent class
77
+
78
+ `Agent` extends `DurableObject`, installs a Lifecycle, and adds `Scheduler`, `Queue`, `MCPClientManager`, `State`, `WebSockets`, `Tasks`, and dynamic agents for you. Its methods (`this.schedule()`, `this.queue()`, `this.setState()`) delegate to those capabilities. Features below are documented for `Agent` and its subclasses.
79
+
80
+ ### Core
81
+
82
+ - [Understanding the Agent Class](./agent-class.md) - How the Agent class is built on the Lifecycle
83
+ - [State Management](./state.md) - `setState()`, `initialState`, and `onStateChanged()`
43
84
  - [Routing](./routing.md) - How `routeAgentRequest()` and agent naming works, plus `RoutedAgents` for a hub that routes to many independent Agents
44
85
  - [Dynamic agents](./sub-agents.md) - Facet-backed child agents for code the parent supervises (dynamic/generated code, per-run tool agents, sandboxes) — not the recommended primitive for many independent peers like chats
45
86
  - [HTTP & WebSockets](./http-websockets.md) - Request handling and real-time connections
46
87
  - [Callable Methods](./callable-methods.md) - The `@callable` decorator and client-server method calls
47
88
  - [Readonly Connections](./readonly-connections.md) - Restricting which connections can modify state
48
- - [getCurrentAgent()](./get-current-agent.md) - Accessing agent context across async calls
89
+ - [Client SDK](./client-sdk.md) - Connecting from React (`useAgent`) and vanilla JS (`AgentClient`), state sync, and RPC calls
49
90
 
50
- ## Client SDK
91
+ ### Background processing
51
92
 
52
- - [Client SDK](./client-sdk.md) - Connecting from React (`useAgent`) and vanilla JS (`AgentClient`), state sync, and RPC calls
93
+ - [Queue](./queue.md) - Durable background task execution
94
+ - [Scheduling](./scheduling.md) - Delayed, scheduled, and cron-based tasks
95
+ - [Retries](./retries.md) - Automatic retries with exponential backoff and jitter
96
+ - [Durable Execution](./durable-execution.md) - `runFiber()`, `startFiber()`, `stash()`, and crash recovery for long tasks
97
+ - [Workflows](./workflows.md) - Durable multi-step processing with Cloudflare Workflows
98
+ - [Human in the Loop](./human-in-the-loop.md) - Approval flows and manual intervention
53
99
 
54
- ## Communication Channels
100
+ ### Communication channels
55
101
 
56
102
  - [Email Service](./email.md) - Sending, receiving, and replying to emails
57
103
  - [Webhooks](./webhooks.md) - Receiving and sending webhook events
58
104
  - [Push Notifications](./push-notifications.md) - Browser push notifications via Web Push API and scheduled delivery
59
105
  - TODO: [SMS](./sms.md) - Text message integration (Twilio, etc.)
60
106
  - [Voice Agents](./voice.md) - Build voice agents with real-time speech-to-text, text-to-speech, and conversation persistence
61
- - [Channels](./channels.md) - Send and receive messages through Slack, Telegram, email, browser voice, or custom adapters
62
107
  - [Chat SDK State](./chat-sdk.md) - Store Chat SDK subscriptions, locks, queues, and history in Agents sub-agents
63
108
 
64
- ## Background Processing
65
-
66
- - [Queue](./queue.md) - Durable background task execution
67
- - [Scheduling](./scheduling.md) - Delayed, scheduled, and cron-based tasks
68
- - [Retries](./retries.md) - Automatic retries with exponential backoff and jitter
69
- - [Durable Execution](./durable-execution.md) - `runFiber()`, `startFiber()`, `stash()`, and crash recovery for long tasks
70
- - [Workflows](./workflows.md) - Durable multi-step processing with Cloudflare Workflows
71
- - [Human in the Loop](./human-in-the-loop.md) - Approval flows and manual intervention
72
-
73
- ## AI Integration
109
+ ### Chat and AI
74
110
 
75
- - TODO: [AI SDK Integration](./ai-sdk.md) - Using Vercel AI SDK with agents
76
- - TODO: [TanStack Integration](./tanstack.md) - Using TanStack AI with agents
77
111
  - [Chat Agents](./chat-agents.md) - `AIChatAgent` class and `useAgentChat` React hook
78
112
  - [Chat & Fiber Recovery](./chat-agents.md#stream-recovery) - Recover LLM turns after Durable Object eviction
79
113
  - [Agent Tools](./agent-tools.md) - Run chat-capable sub-agents as tools with streaming child timelines
80
114
  - [Server-Driven Messages](./server-driven-messages.md) - Autonomous agent workflows: scheduled follow-ups, queue processing, webhooks, chained reasoning
81
- - TODO: [Using AI Models](./using-ai-models.md) - OpenAI, Anthropic, Workers AI, and other providers
82
- - [Models (Experimental)](./models.md) - `createAI` — one AI SDK provider for Workers AI and third-party catalog models, same string space
83
- - [Models for pi-ai (Beta)](./models-pi-ai.md) - `createAI` for pi-ai: Workers AI ids and third-party models through AI Gateway, as a pi-ai provider
84
- - [Pi harness (Beta)](./harnesses/pi.md) - Host pi-durable sessions in a Durable Object with durable storage and lifecycle wakeups
85
- - TODO: [RAG (Retrieval Augmented Generation)](./rag.md) - Vector search with Vectorize
86
- - [Sessions (Experimental)](./sessions.md) - Durable message trees, streamed history, compaction, search, and lossless attachment offload
87
- - [Context (Experimental)](./context.md) - System-prompt blocks, frozen prompts, writable/searchable/loadable providers, and their tools
88
- - [Workspace (Experimental)](https://github.com/cloudflare/agents/blob/main/docs/shell/index.md) - Durable virtual filesystem backed by SQLite + R2
89
- - [Codemode (Experimental)](https://github.com/cloudflare/agents/blob/main/docs/agents/codemode.md) - LLM-generated executable code for tool orchestration
90
115
  - [Client Tools Continuation](./client-tools-continuation.md) - Handling tool calls across client/server
91
116
  - [Resumable Streaming](./resumable-streaming.md) - Automatic stream resumption on client disconnect
117
+ - [Long-Running Agents](./long-running-agents.md) - Building agents that persist for weeks or months: lifecycle, recovery, async operations, and planning
118
+ - TODO: [SQL API](./sql.md) - Using `this.sql` for direct database queries
119
+ - TODO: [Memory & Persistence](./memory.md) - Long-term storage patterns
92
120
 
93
121
  ## Think (Experimental)
94
122
 
@@ -103,50 +131,46 @@ The differentiator is not "we have durable state" — it is what happens when a
103
131
  - [Sub-agents and Programmatic Turns](https://github.com/cloudflare/agents/blob/main/docs/think/sub-agents.md) - RPC streaming, `saveMessages`, recovery
104
132
  - [Programmatic Submissions](https://github.com/cloudflare/agents/blob/main/docs/think/programmatic-submissions.md) - Durable Think turn admission for webhooks and RPC callers
105
133
 
134
+ ## Models and tools
135
+
136
+ - TODO: [AI SDK Integration](./ai-sdk.md) - Using Vercel AI SDK with agents
137
+ - TODO: [TanStack Integration](./tanstack.md) - Using TanStack AI with agents
138
+ - TODO: [Using AI Models](./using-ai-models.md) - OpenAI, Anthropic, Workers AI, and other providers
139
+ - [Models (Experimental)](./models.md) - `createAI` — one AI SDK provider for Workers AI and third-party catalog models, same string space
140
+ - [Models for pi-ai (Beta)](./models-pi-ai.md) - `createAI` for pi-ai: Workers AI ids and third-party models through AI Gateway, as a pi-ai provider
141
+ - [Context (Experimental)](./context.md) - System-prompt blocks, frozen prompts, writable/searchable/loadable providers, and their tools
142
+ - [Workspace (Experimental)](https://github.com/cloudflare/agents/blob/main/docs/shell/index.md) - Durable virtual filesystem backed by SQLite + R2
143
+ - [Codemode (Experimental)](./codemode.md) - LLM-generated executable code for tool orchestration
144
+ - [Browse the Web (Experimental)](./browse-the-web.md) - Full CDP access for web inspection, scraping, and debugging
145
+ - [Search the Web (Beta)](./search-the-web.md) - A `websearch` tool over Cloudflare's Web Search API for the pi harness, the AI SDK, and TanStack AI
146
+ - [Fetch the Web (Beta)](./fetch-the-web.md) - A `web_fetch` tool that reads a URL as Markdown, JSON, or text, with a host-controlled URL policy, for the pi harness, the AI SDK, TanStack AI, and Think
147
+ - TODO: [Cloudflare Sandboxes](./sandboxes.md) - Isolated environments for coding agents, ffmpeg, and heavy compute
148
+ - TODO: [RAG (Retrieval Augmented Generation)](./rag.md) - Vector search with Vectorize
149
+
106
150
  ## MCP (Model Context Protocol)
107
151
 
108
152
  - [Creating MCP Servers](./mcp-servers.md) - Build MCP servers with `McpAgent`
109
153
  - [Securing MCP Servers](./securing-mcp-servers.md) - OAuth and authentication for MCP
110
- - [Connecting to MCP Servers](./mcp-client.md) - `addMcpServer()` and consuming external MCP tools
154
+ - [Connecting to MCP Servers](./mcp-client.md) - `MCPClientManager` on a Durable Object, or `addMcpServer()` on an Agent
111
155
  - [MCP Transports](./mcp-transports.md) - Transport options: Streamable HTTP, SSE, and RPC
112
156
 
113
- ## Authentication & Security
114
-
115
- - TODO: [Securing your Agents](./securing-agents.md) - Authentication, authorization, and access control
116
- - [Cross-Domain Authentication](./cross-domain-authentication.md) - Auth across different domains
117
-
118
- ## Observability & Debugging
157
+ ## Operations
119
158
 
159
+ - [Configuration](./configuration.md) - wrangler.jsonc setup, types, secrets, and deployment
120
160
  - [Observability](./observability.md) - Monitoring and tracing agent activity
161
+ - [Cross-Domain Authentication](./cross-domain-authentication.md) - Auth across different domains
162
+ - TODO: [Securing your Agents](./securing-agents.md) - Authentication, authorization, and access control
121
163
  - TODO: [Testing](./testing.md) - Unit tests, integration tests, mocking agents
122
164
  - TODO: [Evals](./evals.md) - Evaluating AI agent quality and behavior
123
-
124
- ## Agent Studio
125
-
126
165
  - TODO: [Agent Studio](./agent-studio.md) - Local dev tool for inspecting and interacting with agent instances
127
166
 
128
- ## Compute Environments
129
-
130
- - [Browse the Web (Experimental)](./browse-the-web.md) - Full CDP access for web inspection, scraping, and debugging
131
- - TODO: [Cloudflare Sandboxes](./sandboxes.md) - Isolated environments for coding agents, ffmpeg, and heavy compute
132
-
133
- ## Advanced Topics
134
-
135
- - [Long-Running Agents](./long-running-agents.md) - Building agents that persist for weeks or months: lifecycle, recovery, async operations, and planning
136
- - TODO: [SQL API](./sql.md) - Using `this.sql` for direct database queries
137
- - TODO: [Memory & Persistence](./memory.md) - Long-term storage patterns
138
- - [Configuration](./configuration.md) - wrangler.jsonc setup, types, secrets, and deployment
139
-
140
- ## Migration Guides
167
+ ## Migration guides
141
168
 
142
169
  - [Migration to AI SDK v5](./migration-to-ai-sdk-v5.md)
143
170
  - [Migration to AI SDK v6](./migration-to-ai-sdk-v6.md)
144
171
 
145
172
  ## Reference
146
173
 
147
- - [Durable Object Lifecycle](./lifecycle.md) - Compose reusable durable components outside the Agent base class
148
- - [Tasks](./tasks.md) - Durable, replayable background work with journaled steps and durable sleeps (experimental)
149
- - [Streams](./streams.md) - Durable incremental output: chunk log, cursor, replay-then-tail reads (experimental)
150
174
  - TODO: [API Reference](./api-reference.md) - Complete API documentation
151
175
  - TODO: [FAQ / How is this different from Durable Objects?](./faq.md)
152
176
  - TODO: [Resources & Further Reading](./resources.md)
package/docs/lifecycle.md CHANGED
@@ -1,8 +1,7 @@
1
1
  # Durable Object lifecycle
2
2
 
3
- > **Experimental.** Everything exported from `agents/lifecycle` — and the
4
- > capabilities built on it, including `Scheduler` — may change between
5
- > releases while the composition surface stabilizes.
3
+ `agents/lifecycle` is stable. Most capabilities built on it are still
4
+ experimental; each capability's page says which.
6
5
 
7
6
  `agents/lifecycle` lets reusable durable capabilities work in both `Agent` and a
8
7
  plain Cloudflare Durable Object. It uses composition: your class extends the
@@ -156,6 +155,46 @@ Host-specific bindings, authentication, and protocol adapters remain explicit
156
155
  constructor dependencies. Lifecycle never grants a capability the complete
157
156
  host implicitly.
158
157
 
158
+ A capability's public operations can run before startup, because
159
+ [native RPC](#native-rpc) bypasses the automatic startup on fetch, alarm and
160
+ WebSocket events. If an operation starts work that `onStart` also awaits, such
161
+ as lazily opening a store, it must call `await this.lifecycle.ready()` first:
162
+
163
+ ```ts
164
+ class Store extends LifecycleCapability {
165
+ #opening: Promise<Database> | undefined;
166
+
167
+ constructor() {
168
+ super("store");
169
+ }
170
+
171
+ async onStart(): Promise<void> {
172
+ await this.#open();
173
+ }
174
+
175
+ async get(key: string): Promise<string | undefined> {
176
+ const db = await this.#open();
177
+ return db.get(key);
178
+ }
179
+
180
+ async #open(): Promise<Database> {
181
+ // Without this, an RPC that calls get() before startup begins the open
182
+ // outside startup, and onStart then waits on it behind a closed gate.
183
+ await this.lifecycle.ready();
184
+ this.#opening ??= openDatabase(this.lifecycle.storage);
185
+ return this.#opening;
186
+ }
187
+ }
188
+ ```
189
+
190
+ Startup holds the input gate (`blockConcurrencyWhile`) while `onStart` runs, so
191
+ work begun outside startup has its timers and I/O held back and never finishes.
192
+ `onStart` waits on it until startup times out after 30 seconds and the object
193
+ is reset. Whether it happens depends on whether the RPC arrives first, so it
194
+ shows up as an intermittent timeout. `ready()` resolves immediately inside
195
+ startup, so `onStart` can call the same guarded method. `Tasks`, `Streams`,
196
+ `Scheduler`, `Queue` and `PiHarness` guard their operations this way.
197
+
159
198
  Capability hooks run outside host context, but user callbacks run through
160
199
  `this.lifecycle.runInHostContext(fn)` inside the host invocation context.
161
200
  Scheduler and Queue dispatch their registered callbacks through this
package/docs/queue.md CHANGED
@@ -7,9 +7,8 @@ survives the object leaving memory.
7
7
 
8
8
  ## Queue Lifecycle capability
9
9
 
10
- > **Experimental.** The `Queue` capability and the `agents/lifecycle` surface
11
- > it builds on may change between releases. Agent's established queue methods
12
- > (`this.queue()` and friends) are stable.
10
+ > **Experimental.** The `Queue` capability may change between releases.
11
+ > Agent's queue methods (`this.queue()` and friends) are stable.
13
12
 
14
13
  `Queue` is a reusable Lifecycle capability. A plain Lifecycle Object can
15
14
  install it without extending `Agent`:
@@ -17,10 +17,6 @@ Under the hood, scheduling uses [Durable Object alarms](https://developers.cloud
17
17
 
18
18
  ## Scheduler Lifecycle primitive
19
19
 
20
- > **Experimental.** The `Scheduler` primitive and the `agents/lifecycle`
21
- > surface it builds on may change between releases. Agent's established
22
- > scheduling methods (`this.schedule()` and friends) are stable.
23
-
24
20
  `Scheduler` is a reusable Lifecycle capability. A plain Lifecycle Object can
25
21
  install it without extending `Agent`:
26
22
 
@@ -836,8 +832,8 @@ When using this schema with OpenAI models via the AI SDK, you must pass `provide
836
832
 
837
833
  ## API Reference
838
834
 
839
- Two surfaces share these semantics: the experimental `Scheduler` primitive
840
- (`agents/schedules`, methods on the scheduler instance) and the stable `Agent`
835
+ Two surfaces share these semantics: the `Scheduler` capability
836
+ (`agents/schedules`, methods on the scheduler instance) and the `Agent`
841
837
  methods (on the Agent class, delegating to `this.scheduler`).
842
838
 
843
839
  ### Scheduler primitive
@@ -0,0 +1,135 @@
1
+ # Search the Web (Beta)
2
+
3
+ `agents/websearch` gives a model a `web_search` tool over Cloudflare's [Web Search API](https://developers.cloudflare.com/web-search/), called through the `AI` binding and billed by the account's AI Gateway. The same tool is available for the pi harness, the AI SDK, and TanStack AI.
4
+
5
+ This page covers what the SDK adds on top of the API. For the binding, the providers, pricing, payment, and the error codes, see the [Web Search API docs](https://developers.cloudflare.com/web-search/).
6
+
7
+ > **Beta** — this feature may have breaking changes in future releases.
8
+
9
+ ## Quick Start
10
+
11
+ You need:
12
+
13
+ - An `AI` binding: `"ai": { "binding": "AI" }` in `wrangler.jsonc`.
14
+ - workerd 1.20260924.1 or later, which is where `env.AI.websearch()` arrived. It ships with wrangler 4.141.0 and `@cloudflare/vite-plugin` 1.60.2.
15
+ - AI Gateway credits or a provider key on the gateway, in the account the Worker runs in. That account pays for every search. The `AI` binding always calls Cloudflare, so under `wrangler dev` searches run against, and bill, the account you are logged in to.
16
+
17
+ Then add the tool to your harness. Every adapter takes the same options; the TanStack AI adapter also takes `name`, because TanStack AI tools carry their name in the definition.
18
+
19
+ Pi harness:
20
+
21
+ ```ts
22
+ import { webSearchTool } from "agents/websearch/pi";
23
+
24
+ this.registry.install({
25
+ name: "tools",
26
+ tools: [webSearchTool({ binding: this.env.AI, provider: "exa" })]
27
+ });
28
+ ```
29
+
30
+ AI SDK:
31
+
32
+ ```ts
33
+ import { webSearchTool } from "agents/websearch/ai-sdk";
34
+
35
+ const result = streamText({
36
+ model,
37
+ tools: { web_search: webSearchTool({ binding: this.env.AI }) },
38
+ messages
39
+ });
40
+ ```
41
+
42
+ If you convert UI messages yourself, pass the same tools to `convertToModelMessages(messages, { tools })`. Without them, the AI SDK sends earlier search results back to the model as the full JSON response instead of the trimmed text. `AiSdkHarness` does this for you.
43
+
44
+ TanStack AI:
45
+
46
+ ```ts
47
+ import { webSearchTool } from "agents/websearch/tanstack-ai";
48
+
49
+ const tools = [webSearchTool({ binding: this.env.AI })];
50
+ ```
51
+
52
+ ## Options
53
+
54
+ The model's input is `{ query, limit? }` and nothing else. The host fixes everything that affects cost or data handling. An invalid `limit`, `maxDescriptionChars`, `timeoutMs`, or `byokAlias` throws a `RangeError` when the tool is created:
55
+
56
+ | Option | Default | Notes |
57
+ | --------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
58
+ | `binding` | — | The `AI` binding. Or pass `source` instead (see [Other sources](#other-sources)). |
59
+ | `gateway` | `"default"` | AI Gateway id. |
60
+ | `provider` | platform default | `"ceramic"`, `"exa"`, or `"linkup"`. The model cannot choose or change it. |
61
+ | `byokAlias` | — | Bill a provider key stored on the gateway. Passed through as the API defines it. |
62
+ | `limit` | `5` | Results per search when the model does not ask for a count, and the most it gets when it asks for more. The tool description tells the model this number. |
63
+ | `maxDescriptionChars` | `600` | Per-result description length in the model's view. `Infinity` passes descriptions through whole. |
64
+ | `description` | built-in description | Replaces the tool description the model sees. |
65
+ | `timeoutMs` | `30000` | Give up on a search after this long, as a retryable `web_search_timeout` failure. |
66
+
67
+ ## Model Interface
68
+
69
+ The model gets text: a numbered list of title, URL, and description, with descriptions trimmed to `maxDescriptionChars`. Some providers return descriptions of several thousand characters per result, so the default keeps a five-result search to a few kilobytes of context.
70
+
71
+ ```
72
+ 3 results for "cloudflare web search api":
73
+
74
+ 1. Introducing the Web Search API
75
+ https://blog.cloudflare.com/introducing-web-search-api/
76
+ Today we are launching the Web Search API in open beta…
77
+
78
+ 2. …
79
+ ```
80
+
81
+ The host gets the full API response, without trimming, as `WebSearchToolOutput`: `items` with their whole descriptions and every documented field, `metadata` with `requestId` and `latencyMs`, plus `provider`. Items without a URL are dropped, a missing title falls back to the URL, and fields the API does not document are left out:
82
+
83
+ - **Pi**: in the tool result's `details`, as `{ ok: true, output }`. The tool is `replay: "safe"`: if a search is interrupted mid-call, for example by an eviction, pi runs it again when the session recovers, and that is a second billed search. Completed results are stored and not searched again.
84
+ - **AI SDK**: as the return value of `execute`, so `onFinish`, UI message parts, and logs see the full response. `toModelOutput` renders the text for the model.
85
+ - **TanStack AI**: the server tool returns the rendered text, so the host gets the same text the model does.
86
+
87
+ `renderWebSearchResults(output, { maxDescriptionChars })` from `agents/websearch` is the renderer, if you want the same text elsewhere.
88
+
89
+ The API has no pagination. The tool description tells the model to search again with a rephrased query when it wants more or different results.
90
+
91
+ Results are for discovery. To let the model read the pages it finds, add the [`web_fetch` tool](./fetch-the-web.md) beside `web_search`; the `web_search` description tells the model to fetch result URLs with `web_fetch` when it is available.
92
+
93
+ ## Failures
94
+
95
+ A failed search becomes a `WebSearchError` with `status`, `code`, `retryable`, and `requestId` (AI Gateway's id for the request, for the gateway log). Every error has a `code`: the API's own when it sends one, for example `web_search_payment_required`, otherwise one derived from the HTTP status, such as `web_search_rate_limited` or `web_search_unavailable`. On a runtime older than the one above, the binding has no `websearch()` and the search fails with code `web_search_unsupported_runtime`.
96
+
97
+ The error's `message` is written for you, and can say to top up credits or configure a key. The model gets different text that tells it what to do next: fix the query, retry once, or carry on without search.
98
+
99
+ - **Pi**: the tool returns an error result with the model's text, and `details` is `{ ok: false, message, status, code, retryable, requestId }`.
100
+ - **AI SDK** and **TanStack AI**: the tool throws a `WebSearchError`, which is how those frameworks report tool errors. Its `message` is the model's text, and its `cause` is the original error with the API's detail.
101
+
102
+ Every adapter entry point re-exports `WebSearchError`, so `instanceof` checks do not need a second import.
103
+
104
+ If the harness cancels the call, the search is aborted and the abort propagates instead of becoming a failed result.
105
+
106
+ ## Other sources
107
+
108
+ `createAIWebSearch` and `createHTTPWebSearch` from `agents/websearch` return a `WebSearchSource`: an object whose `search({ query, limit? }, { signal? })` returns the API response (`limit` defaults to 5), with no model involved. Use them from scheduled jobs, or outside Workers:
109
+
110
+ ```ts
111
+ import { createHTTPWebSearch } from "agents/websearch";
112
+
113
+ const search = createHTTPWebSearch({
114
+ accountId: env.CF_ACCOUNT_ID,
115
+ apiToken: env.CF_API_TOKEN,
116
+ provider: "linkup"
117
+ });
118
+ const { items } = await search.search({
119
+ query: "cloudflare agents sdk",
120
+ limit: 3
121
+ });
122
+ ```
123
+
124
+ Any `WebSearchSource` can be passed to a tool as `source` instead of `binding`. That is how tests substitute a fake, and how you wrap a source with caching or logging. Spread the source you wrap so its `provider` is kept:
125
+
126
+ ```ts
127
+ webSearchTool({
128
+ source: {
129
+ search: async ({ query }) => ({
130
+ items: [{ url: "https://example.com", title: query }],
131
+ metadata: { query, requestId: "test", latencyMs: 0 }
132
+ })
133
+ }
134
+ });
135
+ ```