agents 0.21.0 → 0.23.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 (258) hide show
  1. package/README.md +21 -1
  2. package/dist/{agent-tool-types-CzGGB-20.d.ts → agent-routing-DE5zmCQ8.d.ts} +1844 -1336
  3. package/dist/agent-routing.d.ts +14 -0
  4. package/dist/agent-routing.js +187 -0
  5. package/dist/agent-routing.js.map +1 -0
  6. package/dist/agent-tool-types.d.ts +26 -26
  7. package/dist/{agent-tools-zR2d5uij.d.ts → agent-tools-DtXMTDGM.d.ts} +7 -7
  8. package/dist/agent-tools.d.ts +21 -21
  9. package/dist/agent-tools.js +2 -1
  10. package/dist/agent-tools.js.map +1 -1
  11. package/dist/browser/ai.js +6 -2
  12. package/dist/browser/ai.js.map +1 -1
  13. package/dist/browser/tanstack-ai.js.map +1 -1
  14. package/dist/callable-decorator-DP__HhBA.d.ts +72 -0
  15. package/dist/callable-decorator.d.ts +18 -0
  16. package/dist/callable-decorator.js +71 -0
  17. package/dist/callable-decorator.js.map +1 -0
  18. package/dist/capability-BjSKYpzg.js +42 -0
  19. package/dist/capability-BjSKYpzg.js.map +1 -0
  20. package/dist/capability-runner-Be_-PLR1.d.ts +459 -0
  21. package/dist/channel-Bnm4S7T2.d.ts +491 -0
  22. package/dist/channels/ai-sdk.d.ts +46 -0
  23. package/dist/channels/ai-sdk.js +120 -0
  24. package/dist/channels/ai-sdk.js.map +1 -0
  25. package/dist/channels/email.d.ts +95 -0
  26. package/dist/channels/email.js +323 -0
  27. package/dist/channels/email.js.map +1 -0
  28. package/dist/channels/index.d.ts +233 -0
  29. package/dist/channels/index.js +608 -0
  30. package/dist/channels/index.js.map +1 -0
  31. package/dist/channels/slack.d.ts +140 -0
  32. package/dist/channels/slack.js +614 -0
  33. package/dist/channels/slack.js.map +1 -0
  34. package/dist/channels/tanstack-ai.d.ts +39 -0
  35. package/dist/channels/tanstack-ai.js +17 -0
  36. package/dist/channels/tanstack-ai.js.map +1 -0
  37. package/dist/channels/telegram.d.ts +106 -0
  38. package/dist/channels/telegram.js +427 -0
  39. package/dist/channels/telegram.js.map +1 -0
  40. package/dist/channels/voice.d.ts +45 -0
  41. package/dist/channels/voice.js +122 -0
  42. package/dist/channels/voice.js.map +1 -0
  43. package/dist/chat/index.d.ts +2328 -2015
  44. package/dist/chat/index.js +891 -521
  45. package/dist/chat/index.js.map +1 -1
  46. package/dist/chat/react.d.ts +14 -1
  47. package/dist/chat/react.js +82 -52
  48. package/dist/chat/react.js.map +1 -1
  49. package/dist/chat/transport.js +1 -1
  50. package/dist/chat-sdk/index.d.ts +7 -7
  51. package/dist/chat-sdk/index.js +1 -1
  52. package/dist/{client-zqKcsyFa.js → client-jagG8a9_.js} +129 -37
  53. package/dist/client-jagG8a9_.js.map +1 -0
  54. package/dist/client.d.ts +1 -1
  55. package/dist/client.js +1 -1
  56. package/dist/{cloudflare-BduZwmYK.js → cloudflare-Dzvc7V2N.js} +10 -3
  57. package/dist/{cloudflare-BduZwmYK.js.map → cloudflare-Dzvc7V2N.js.map} +1 -1
  58. package/dist/context/index.d.ts +216 -0
  59. package/dist/context/index.js +454 -0
  60. package/dist/context/index.js.map +1 -0
  61. package/dist/current-agent-Da_C9a3b.d.ts +266 -0
  62. package/dist/current-agent-DhoDkSnH.js +51 -0
  63. package/dist/current-agent-DhoDkSnH.js.map +1 -0
  64. package/dist/diagnostics-BzvaX2UT.js +45 -0
  65. package/dist/diagnostics-BzvaX2UT.js.map +1 -0
  66. package/dist/diagnostics-C4jcz3VK.js +360 -0
  67. package/dist/diagnostics-C4jcz3VK.js.map +1 -0
  68. package/dist/{do-oauth-client-provider-VTZj2VtM.d.ts → do-oauth-client-provider-Tmf1vgKz.d.ts} +2 -2
  69. package/dist/{email-CL27preh.d.ts → email-7TatiTnl.d.ts} +38 -9
  70. package/dist/email-send.d.ts +15 -0
  71. package/dist/email-send.js +32 -0
  72. package/dist/email-send.js.map +1 -0
  73. package/dist/email.d.ts +14 -10
  74. package/dist/email.js.map +1 -1
  75. package/dist/{handler-stateless-C_bo-Ytq.d.ts → handler-stateless-DxYpJ_XF.d.ts} +3 -3
  76. package/dist/{handler-stateless-CIkKPETH.js → handler-stateless-VvrWSAVA.js} +5 -5
  77. package/dist/handler-stateless-VvrWSAVA.js.map +1 -0
  78. package/dist/index-BB0kqhIz.d.ts +101 -0
  79. package/dist/index-XDkuQ7zm.d.ts +89 -0
  80. package/dist/{index-BRnybD6X.d.ts → index-YSKgfgg9.d.ts} +21 -31
  81. package/dist/index.d.ts +113 -101
  82. package/dist/index.js +11 -7234
  83. package/dist/ingress-BfetZbMO.js +83 -0
  84. package/dist/ingress-BfetZbMO.js.map +1 -0
  85. package/dist/internal-CYlgHl1l.js +59 -0
  86. package/dist/internal-CYlgHl1l.js.map +1 -0
  87. package/dist/internal_context-BlxFEWfn.d.ts +19 -0
  88. package/dist/internal_context.d.ts +10 -4
  89. package/dist/internal_context.js +1 -10
  90. package/dist/{client-invoker-BNSZxAkv.d.ts → invoker-CG0_p_Wq.d.ts} +2 -2
  91. package/dist/{client-invoker-VNZ7X0nn.js → invoker-CHMnoxIA.js} +2 -2
  92. package/dist/invoker-CHMnoxIA.js.map +1 -0
  93. package/dist/lifecycle/index.d.ts +66 -0
  94. package/dist/lifecycle/index.js +4 -0
  95. package/dist/lifecycle-CMRGjZdw.js +1299 -0
  96. package/dist/lifecycle-CMRGjZdw.js.map +1 -0
  97. package/dist/mcp/{do-oauth-client-provider.d.ts → client/do-oauth-client-provider.d.ts} +1 -1
  98. package/dist/mcp/{do-oauth-client-provider.js → client/do-oauth-client-provider.js} +1 -1
  99. package/dist/mcp/client/do-oauth-client-provider.js.map +1 -0
  100. package/dist/mcp/client/index.d.ts +42 -0
  101. package/dist/mcp/{client.js → client/index.js} +1 -1
  102. package/dist/mcp/{x402.d.ts → client/x402.d.ts} +2 -2
  103. package/dist/mcp/{x402.js → client/x402.js} +2 -2
  104. package/dist/mcp/client/x402.js.map +1 -0
  105. package/dist/mcp/index.d.ts +36 -36
  106. package/dist/mcp/index.js +14 -16
  107. package/dist/mcp/index.js.map +1 -1
  108. package/dist/mcp/{server.d.ts → server/index.d.ts} +1 -1
  109. package/dist/mcp/{server.js → server/index.js} +1 -1
  110. package/dist/observability/ai/index.js +50 -35
  111. package/dist/observability/ai/index.js.map +1 -1
  112. package/dist/observability/index.d.ts +4 -4
  113. package/dist/observability/index.js +3 -50
  114. package/dist/observability/index.js.map +1 -1
  115. package/dist/{protocol-Dqc2MQxo.js → protocol-B0nh6KNf.js} +19 -21
  116. package/dist/protocol-B0nh6KNf.js.map +1 -0
  117. package/dist/react.d.ts +4 -4
  118. package/dist/react.js +1 -1
  119. package/dist/{retries-CAvxtG9d.d.ts → retries-D9Ds-1lz.d.ts} +17 -6
  120. package/dist/retries.d.ts +8 -6
  121. package/dist/retries.js +13 -1
  122. package/dist/retries.js.map +1 -1
  123. package/dist/routing/index.d.ts +137 -0
  124. package/dist/routing/index.js +244 -0
  125. package/dist/routing/index.js.map +1 -0
  126. package/dist/sanitize-D9TujEK8.js +79 -0
  127. package/dist/sanitize-D9TujEK8.js.map +1 -0
  128. package/dist/schedule.d.ts +25 -94
  129. package/dist/schedule.js +1 -98
  130. package/dist/schedule.js.map +1 -1
  131. package/dist/scheduler-DD9NdYbF.js +665 -0
  132. package/dist/scheduler-DD9NdYbF.js.map +1 -0
  133. package/dist/scheduler-Dwh85ZGl.d.ts +223 -0
  134. package/dist/schedules/index.d.ts +22 -0
  135. package/dist/schedules/index.js +2 -0
  136. package/dist/schedules/parser.d.ts +79 -0
  137. package/dist/schedules/parser.js +103 -0
  138. package/dist/schedules/parser.js.map +1 -0
  139. package/dist/sentence-chunker-BAidJ4DA.d.ts +68 -0
  140. package/dist/serializable.d.ts +1 -1
  141. package/dist/sessions/index.d.ts +441 -0
  142. package/dist/sessions/index.js +2063 -0
  143. package/dist/sessions/index.js.map +1 -0
  144. package/dist/skills/index.d.ts +99 -0
  145. package/dist/skills/index.js +254 -5
  146. package/dist/skills/index.js.map +1 -1
  147. package/dist/sql-error-CPY-GXyI.d.ts +12 -0
  148. package/dist/sql-error.d.ts +2 -0
  149. package/dist/sql-error.js +16 -0
  150. package/dist/sql-error.js.map +1 -0
  151. package/dist/src-DlSHshb2.js +6963 -0
  152. package/dist/src-DlSHshb2.js.map +1 -0
  153. package/dist/streams/index.d.ts +120 -0
  154. package/dist/streams/index.js +107 -0
  155. package/dist/streams/index.js.map +1 -0
  156. package/dist/streams-D6tJ0NN9.d.ts +370 -0
  157. package/dist/streams-DZKgAj9b.js +709 -0
  158. package/dist/streams-DZKgAj9b.js.map +1 -0
  159. package/dist/sub-routing.d.ts +12 -12
  160. package/dist/surface-bZZJqBka.js +17 -0
  161. package/dist/surface-bZZJqBka.js.map +1 -0
  162. package/dist/tasks/index.d.ts +64 -0
  163. package/dist/tasks/index.js +2 -0
  164. package/dist/tasks-BRJ5zgya.d.ts +517 -0
  165. package/dist/tasks-ylZgBjhj.js +1656 -0
  166. package/dist/tasks-ylZgBjhj.js.map +1 -0
  167. package/dist/text-segment-joiner-BtAFQSA_.js +57 -0
  168. package/dist/text-segment-joiner-BtAFQSA_.js.map +1 -0
  169. package/dist/text-stream-CpdiKrJB.js +272 -0
  170. package/dist/text-stream-CpdiKrJB.js.map +1 -0
  171. package/dist/tokens-nHAKcN6M.js +52 -0
  172. package/dist/tokens-nHAKcN6M.js.map +1 -0
  173. package/dist/tool-schema-CBjGPrsQ.js +31 -0
  174. package/dist/tool-schema-CBjGPrsQ.js.map +1 -0
  175. package/dist/types-B7LojTe4.d.ts +202 -0
  176. package/dist/types-_Faxb570.d.ts +439 -0
  177. package/dist/voice/client.d.ts +226 -0
  178. package/dist/voice/client.js +932 -0
  179. package/dist/voice/client.js.map +1 -0
  180. package/dist/voice/errors.d.ts +43 -0
  181. package/dist/voice/errors.js +41 -0
  182. package/dist/voice/errors.js.map +1 -0
  183. package/dist/voice/index.d.ts +271 -0
  184. package/dist/voice/index.js +1812 -0
  185. package/dist/voice/index.js.map +1 -0
  186. package/dist/voice/react.d.ts +167 -0
  187. package/dist/voice/react.js +234 -0
  188. package/dist/voice/react.js.map +1 -0
  189. package/dist/voice/sfu.d.ts +71 -0
  190. package/dist/voice/sfu.js +157 -0
  191. package/dist/voice/sfu.js.map +1 -0
  192. package/dist/voice/text.d.ts +6 -0
  193. package/dist/voice/text.js +2 -0
  194. package/dist/voice/types.d.ts +58 -0
  195. package/dist/voice/types.js +18 -0
  196. package/dist/voice/types.js.map +1 -0
  197. package/dist/voice/workers-ai.d.ts +136 -0
  198. package/dist/voice/workers-ai.js +568 -0
  199. package/dist/voice/workers-ai.js.map +1 -0
  200. package/dist/websockets/index.d.ts +192 -0
  201. package/dist/websockets/index.js +2 -0
  202. package/dist/websockets-DUfRHPRq.js +502 -0
  203. package/dist/websockets-DUfRHPRq.js.map +1 -0
  204. package/dist/workflow-types.d.ts +25 -25
  205. package/dist/workflows.d.ts +22 -22
  206. package/dist/workflows.js +2 -1
  207. package/dist/workflows.js.map +1 -1
  208. package/dist/{ws-chat-transport-CIoOBbO7.js → ws-chat-transport-rWwta645.js} +152 -15
  209. package/dist/ws-chat-transport-rWwta645.js.map +1 -0
  210. package/docs/agent-class.md +29 -87
  211. package/docs/agent-tools.md +2 -1
  212. package/docs/channels.md +323 -0
  213. package/docs/chat-agents.md +19 -25
  214. package/docs/context.md +131 -0
  215. package/docs/durable-execution.md +1 -1
  216. package/docs/http-websockets.md +1 -11
  217. package/docs/human-in-the-loop.md +1 -1
  218. package/docs/index.md +16 -12
  219. package/docs/lifecycle.md +370 -0
  220. package/docs/long-running-agents.md +4 -6
  221. package/docs/mcp-client.md +55 -0
  222. package/docs/mcp-servers.md +5 -1
  223. package/docs/observability.md +11 -11
  224. package/docs/resumable-streaming.md +2 -2
  225. package/docs/routing.md +105 -0
  226. package/docs/scheduling.md +175 -15
  227. package/docs/server-driven-messages.md +1 -1
  228. package/docs/sessions.md +237 -871
  229. package/docs/streams.md +213 -0
  230. package/docs/sub-agents.md +185 -125
  231. package/docs/tasks.md +246 -0
  232. package/docs/voice.md +745 -0
  233. package/package.json +144 -33
  234. package/dist/cli/index.js +0 -26
  235. package/dist/cli/index.js.map +0 -1
  236. package/dist/client-invoker-VNZ7X0nn.js.map +0 -1
  237. package/dist/client-zqKcsyFa.js.map +0 -1
  238. package/dist/compaction-helpers-iiKMr2TQ.js +0 -340
  239. package/dist/compaction-helpers-iiKMr2TQ.js.map +0 -1
  240. package/dist/compaction-helpers-wUz6M3us.d.ts +0 -621
  241. package/dist/experimental/memory/session/index.d.ts +0 -670
  242. package/dist/experimental/memory/session/index.js +0 -2374
  243. package/dist/experimental/memory/session/index.js.map +0 -1
  244. package/dist/experimental/memory/utils/index.d.ts +0 -96
  245. package/dist/experimental/memory/utils/index.js +0 -79
  246. package/dist/experimental/memory/utils/index.js.map +0 -1
  247. package/dist/handler-stateless-CIkKPETH.js.map +0 -1
  248. package/dist/index.js.map +0 -1
  249. package/dist/internal_context-Dg4Cgjcu.d.ts +0 -37
  250. package/dist/internal_context.js.map +0 -1
  251. package/dist/mcp/client.d.ts +0 -42
  252. package/dist/mcp/do-oauth-client-provider.js.map +0 -1
  253. package/dist/mcp/x402.js.map +0 -1
  254. package/dist/protocol-Dqc2MQxo.js.map +0 -1
  255. package/dist/tool-output-truncation-CNnnGZQ3.js +0 -98
  256. package/dist/tool-output-truncation-CNnnGZQ3.js.map +0 -1
  257. package/dist/ws-chat-transport-CIoOBbO7.js.map +0 -1
  258. /package/dist/{cli/index.d.ts → index-BVVgDSdq.d.ts} +0 -0
package/docs/tasks.md ADDED
@@ -0,0 +1,246 @@
1
+ # Tasks
2
+
3
+ > **Experimental.** Everything exported from `agents/tasks` may change
4
+ > between releases while the durable execution surface stabilizes.
5
+
6
+ `agents/tasks` adds durable, replayable background work to a [Lifecycle
7
+ Object](./lifecycle.md). One `Tasks` capability owns any number of named
8
+ Task definitions. A run of a definition survives process loss, deployments,
9
+ and hibernation: completed steps return journaled results, sleeps consult
10
+ persisted deadlines, and execution continues from the first unfinished step.
11
+
12
+ The capability never touches the Durable Object's physical alarm. Every
13
+ non-terminal run's deadline is mirrored as one job in the Lifecycle work
14
+ queue (a retime is a same-id replace), and Lifecycle derives the single
15
+ physical alarm from queue state — so Tasks, the
16
+ [Scheduler](./scheduling.md), and other capabilities coexist on the same
17
+ object.
18
+
19
+ ## Install and define
20
+
21
+ Declare definitions in the constructor — like `Scheduler` callbacks — and
22
+ install the capability with the lifecycle:
23
+
24
+ ```ts
25
+ import { DurableObject } from "cloudflare:workers";
26
+ import { Tasks, type TaskStep } from "agents/tasks";
27
+ import { Lifecycle } from "agents/lifecycle";
28
+
29
+ interface ReportInput {
30
+ reportId: string;
31
+ topic: string;
32
+ }
33
+
34
+ export class ReportObject extends DurableObject<Env> {
35
+ readonly tasks = new Tasks({
36
+ definitions: {
37
+ "build-report@v1": async (input: ReportInput, step: TaskStep) => {
38
+ await step.status("Researching");
39
+
40
+ const research = await step.do(
41
+ "research",
42
+ { retries: { limit: 4, delay: "2 seconds", backoff: "exponential" } },
43
+ ({ signal }) => this.research(input.topic, { signal })
44
+ );
45
+
46
+ await step.sleep("editorial-delay", "30 seconds");
47
+ await step.status("Publishing");
48
+
49
+ const objectKey = `reports/${input.reportId}.json`;
50
+ await step.do("publish", ({ idempotencyKey }) =>
51
+ this.publish(objectKey, research, { idempotencyKey })
52
+ );
53
+
54
+ return { reportId: input.reportId, objectKey };
55
+ }
56
+ }
57
+ });
58
+
59
+ readonly lifecycle = Lifecycle.install(this).use(this.tasks);
60
+ }
61
+ ```
62
+
63
+ The constructor map is the registry. Storage persists only the definition
64
+ name, and the map is rebuilt on every Durable Object wake, so recovery of
65
+ in-flight runs is correct by construction — there is nothing to register at
66
+ the right moment and no lock to trip over. Handlers are ordinary arrows that
67
+ capture `this`. Version the name (`"build-report@v2"`) instead of changing an
68
+ in-flight definition's step layout.
69
+
70
+ ## On an Agent
71
+
72
+ `Agent` installs the capability automatically as `this.tasks` (experimental).
73
+ Declare definitions on the overridable `taskDefinitions` field — the same
74
+ every-wake rebuild guarantee, resolved lazily so field order never matters:
75
+
76
+ ```ts
77
+ import { Agent } from "agents";
78
+ import type { TaskHandlers, TaskStep } from "agents/tasks";
79
+
80
+ export class ReportAgent extends Agent<Env> {
81
+ override readonly taskDefinitions = {
82
+ "build-report@v1": async (input: ReportInput, step: TaskStep) => {
83
+ // ...same step API; handlers run in the Agent's invocation context,
84
+ // so getCurrentAgent() works throughout.
85
+ }
86
+ } satisfies TaskHandlers;
87
+ }
88
+ ```
89
+
90
+ Task deadlines share the Agent's physical alarm with schedules, keep-alive,
91
+ and the rest of the Agent's durable work through the Lifecycle job queue.
92
+ Internally, Agent's own chat frameworks (Think, AIChatAgent, and Think's
93
+ messenger replies) run their turns on this same capability.
94
+
95
+ ## Starting runs
96
+
97
+ ```ts
98
+ const receipt = await this.tasks.run("build-report@v1", input, {
99
+ idempotencyKey: `report:${input.reportId}`
100
+ });
101
+ ```
102
+
103
+ `run()` durably accepts the work and returns a receipt without waiting for
104
+ completion. The same `idempotencyKey` (or a caller-selected `runId`) joins
105
+ the existing run instead of creating a second one; `accepted: false` on the
106
+ receipt marks that join. Pass `metadata` to retain JSON alongside the run and
107
+ `retain: false` to remove the record after terminal settlement.
108
+
109
+ `run()` and `handle()` type the definition name and its input against the
110
+ declared map. A handle is a typed lens scoped to one definition — its `run`,
111
+ `get`, `getByIdempotencyKey`, and `cancel` see only that definition's runs,
112
+ and it can be created at any time:
113
+
114
+ ```ts
115
+ const buildReport = this.tasks.handle("build-report@v1");
116
+ const run = await buildReport.get(receipt.runId); // result typed by the map
117
+ ```
118
+
119
+ Inputs, step results, metadata, and final results must be JSON-serializable
120
+ and at most 1 MiB serialized.
121
+
122
+ ## The step API
123
+
124
+ | Method | Behavior |
125
+ | ----------------------------- | ------------------------------------------------------------------------------------------------------------ |
126
+ | `step.do(name, config?, cb)` | Run a named step once; journaled results replay without re-executing. `config` sets `retries` and `timeout`. |
127
+ | `step.sleep(name, duration)` | Persist a wake deadline and suspend; no isolate stays resident while waiting. |
128
+ | `step.sleepUntil(name, when)` | Sleep until a wall-clock time. |
129
+ | `step.status(message)` | Update observable progress; replays stay silent over old ground. |
130
+ | `step.idempotencyKey(name)` | The stable external deduplication key `step.do(name, …)` receives. |
131
+
132
+ Each `do` attempt receives `{ attempt, idempotencyKey, signal }`. The signal
133
+ aborts on cancellation and on the attempt timeout (default 5 minutes); a
134
+ callback that ignores it still loses the attempt, and a stale attempt's late
135
+ writes are rejected.
136
+
137
+ A callback that throws retries on a durable delay (default: 5 attempts,
138
+ exponential backoff). Throw `NonRetryableError` to fail the run immediately.
139
+
140
+ ## Replay semantics
141
+
142
+ On every execution attempt the handler runs again from its first line.
143
+ Therefore:
144
+
145
+ - put every externally visible side effect inside a `step.do()`;
146
+ - keep code between steps deterministic and cheap — capture `Date.now()` or
147
+ randomness as a step result before branching on it;
148
+ - give loop steps stable names (`` `import:${index}` ``);
149
+ - treat execution as at-least-once: an interrupted step runs again, so pass
150
+ the attempt's `idempotencyKey` to external systems that support
151
+ deduplication.
152
+
153
+ If a replay observes a journal its code cannot have written — a known step
154
+ name under a different kind, or a name used twice — the run fails with a
155
+ `TaskReplayDivergedError` or `DuplicateTaskStepError` rather than guessing.
156
+ A run whose definition name is no longer registered after a deployment fails
157
+ with a `MissingTaskDefinitionError`; it is never silently deleted or run
158
+ against a different handler.
159
+
160
+ ## Interruption and replay
161
+
162
+ There is no separate recovery mode: an unclean interruption — an attempt
163
+ claimed by an isolate that died — simply replays the handler on the next
164
+ wake. Completed steps return journaled results, sleeps consult their
165
+ persisted deadlines, and durable state carries everything else. Two
166
+ patterns make replay safe for irreversible effects:
167
+
168
+ - **Idempotency keys.** Every step attempt receives a stable
169
+ `idempotencyKey` (identical across attempts and replays); pass it to the
170
+ external service so a repeat of the same step deduplicates:
171
+
172
+ ```ts
173
+ "capture-payment@v1": async (input: PaymentInput, step: TaskStep) => {
174
+ return step.do("capture", ({ idempotencyKey }) =>
175
+ this.payments.capture(input, { idempotencyKey })
176
+ );
177
+ }
178
+ ```
179
+
180
+ - **Durable evidence.** When progress lives in durable state — a
181
+ [stream](./streams.md)'s cursor, a rows-written count — read it at the
182
+ top of the work and resume from it. A producer that starts its loop at
183
+ `stream.cursor` never duplicates a chunk, no matter how many times it
184
+ replays.
185
+
186
+ The interrupted step itself is first-class evidence: `step.interrupted`
187
+ is `{ name, attempt }` when the previous attempt's isolate died
188
+ mid-execution (and `null` on a clean attempt), so a handler can branch
189
+ before re-entering irreversible work:
190
+
191
+ ```ts
192
+ "send-report@v1": async (input: ReportInput, step: TaskStep) => {
193
+ if (step.interrupted?.name === "deliver") {
194
+ // the delivery may or may not have left the building — check first
195
+ }
196
+ ...
197
+ }
198
+ ```
199
+
200
+ A step callback that throws is not an interruption; the retry policy owns
201
+ it, with the run parked `waiting` between attempts. Interruptions also emit
202
+ a `task:attempt:interrupted` event carrying the same step name.
203
+
204
+ ## Inspection and control
205
+
206
+ ```ts
207
+ const snapshot = await this.tasks.get(receipt.runId);
208
+ const joined = await this.tasks.getByIdempotencyKey("report:42");
209
+ const recent = await this.tasks.list({ definition: "build-report@v1" });
210
+ await this.tasks.cancel(receipt.runId, "superseded");
211
+ await this.tasks.delete({ settledBefore: new Date(Date.now() - 86_400_000) });
212
+ ```
213
+
214
+ A snapshot is discriminated by `state`:
215
+
216
+ | State | Meaning |
217
+ | ----------- | ------------------------------------------------------------------ |
218
+ | `pending` | Accepted, first attempt not yet claimed. |
219
+ | `running` | An attempt is executing (`attempt`, `startedAt`, `statusMessage`). |
220
+ | `waiting` | Parked on a durable deadline (`reason`: `sleep` or `retry`). |
221
+ | `completed` | Settled with `result`. |
222
+ | `failed` | Settled with a safe `error` projection. |
223
+ | `cancelled` | Settled by cancellation, with its optional `reason`. |
224
+
225
+ Cancellation is cooperative: a parked run settles immediately, a live attempt
226
+ is aborted through its signal and settles at its next step boundary. An
227
+ external effect already accepted cannot be undone.
228
+
229
+ ## Choosing an API
230
+
231
+ | Requirement | Use |
232
+ | ---------------------------------------------------------------- | -------------------------------------- |
233
+ | Normal request handling or short async work | ordinary `await` |
234
+ | Wake a named callback at a time or cron cadence | [scheduling](./scheduling.md) |
235
+ | Durable object-local background work with steps, retries, sleeps | a Task |
236
+ | Cross-service orchestration with a managed dashboard | [Cloudflare Workflows](./workflows.md) |
237
+
238
+ ## Current limits
239
+
240
+ The first release is deliberately narrow: no `waitForCompletion` mode on
241
+ `run()`, and no runs on routed sub-agents (facet-hosted work stays on the
242
+ legacy fiber engine until owner-path routed dispatch lands). The legacy
243
+ `runFiber()`/`startFiber()` APIs are released public API and remain
244
+ unchanged, still recovered by their own scan. The design and its evolution
245
+ are recorded in
246
+ [`design/rfc-fibers.md`](https://github.com/cloudflare/agents/blob/main/design/rfc-fibers.md).