agents 0.24.0 → 0.26.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 (170) hide show
  1. package/dist/{agent-routing-B2XLNMxq.d.ts → agent-routing-0DR0Tk2v.d.ts} +205 -132
  2. package/dist/agent-routing.d.ts +1 -1
  3. package/dist/agent-routing.js.map +1 -1
  4. package/dist/agent-tool-types.d.ts +28 -22
  5. package/dist/agent-tool-types.js +23 -1
  6. package/dist/agent-tool-types.js.map +1 -1
  7. package/dist/{agent-tools-y7zLfw4Q.js → agent-tools-CdJC-8Dc.js} +72 -9
  8. package/dist/agent-tools-CdJC-8Dc.js.map +1 -0
  9. package/dist/{agent-tools-Dj5Mzlw7.d.ts → agent-tools-YrATZJu2.d.ts} +34 -20
  10. package/dist/agent-tools.d.ts +20 -18
  11. package/dist/agent-tools.js.map +1 -1
  12. package/dist/ai-fm7xx1BK.js +312 -0
  13. package/dist/ai-fm7xx1BK.js.map +1 -0
  14. package/dist/base64-redaction-C1Uu29t5.js +59 -0
  15. package/dist/base64-redaction-C1Uu29t5.js.map +1 -0
  16. package/dist/browser/ai-sdk.d.ts +90 -0
  17. package/dist/browser/ai-sdk.js +51 -0
  18. package/dist/browser/ai-sdk.js.map +1 -0
  19. package/dist/browser/ai.d.ts +4 -4
  20. package/dist/browser/ai.js +1 -347
  21. package/dist/browser/index.d.ts +81 -79
  22. package/dist/browser/index.js +361 -2
  23. package/dist/browser/index.js.map +1 -0
  24. package/dist/browser/tanstack-ai.d.ts +96 -1
  25. package/dist/browser/tanstack-ai.js +62 -2
  26. package/dist/browser/tanstack-ai.js.map +1 -1
  27. package/dist/browser-DE3d-RLk.d.ts +275 -0
  28. package/dist/browser-tool-CQ10e6Kj.js +480 -0
  29. package/dist/browser-tool-CQ10e6Kj.js.map +1 -0
  30. package/dist/browser-tool-DuNdlwZ9.d.ts +73 -0
  31. package/dist/capability-B4WbF81e.js.map +1 -1
  32. package/dist/{capability-runner-BUBa6Ake.d.ts → capability-runner-DBAnGr6L.d.ts} +7 -2
  33. package/dist/chat/index.d.ts +340 -234
  34. package/dist/chat/index.js +592 -66
  35. package/dist/chat/index.js.map +1 -1
  36. package/dist/chat/react.d.ts +42 -2
  37. package/dist/chat/react.js +191 -35
  38. package/dist/chat/react.js.map +1 -1
  39. package/dist/chat/transport.d.ts +1 -1
  40. package/dist/chat/transport.js +1 -1
  41. package/dist/chat-sdk/index.d.ts +17 -3
  42. package/dist/chat-sdk/index.js +28 -2
  43. package/dist/chat-sdk/index.js.map +1 -1
  44. package/dist/{client-C9DAjZIY.js → client-4OlMIJx-.js} +102 -29
  45. package/dist/client-4OlMIJx-.js.map +1 -0
  46. package/dist/{client-BxdkCuVy.d.ts → client-je3koD9Z.d.ts} +45 -10
  47. package/dist/client.d.ts +7 -5
  48. package/dist/client.js +2 -2
  49. package/dist/{connector-CptFKzRh.js → connector-58XDGvc3.js} +251 -120
  50. package/dist/connector-58XDGvc3.js.map +1 -0
  51. package/dist/{connector-CkQD4MK3.d.ts → connector-Cl-VqPmA.d.ts} +244 -146
  52. package/dist/context/index.d.ts +29 -0
  53. package/dist/context/index.js +64 -17
  54. package/dist/context/index.js.map +1 -1
  55. package/dist/current-agent-DhoDkSnH.js.map +1 -1
  56. package/dist/{current-agent-C4w86kcN.d.ts → current-agent-vAk_5JMt.d.ts} +4 -4
  57. package/dist/{durable-object-lifecycle-ei7M7lqB.d.ts → durable-object-lifecycle-HhgOMWq9.d.ts} +15 -7
  58. package/dist/harness/pi/index.d.ts +344 -0
  59. package/dist/harness/pi/index.js +873 -0
  60. package/dist/harness/pi/index.js.map +1 -0
  61. package/dist/images-iiTDSyRu.js +1631 -0
  62. package/dist/images-iiTDSyRu.js.map +1 -0
  63. package/dist/{index-Dlgtd3Mj.d.ts → index-BreL0YrQ.d.ts} +2 -2
  64. package/dist/index-kbSUIer3.d.ts +343 -0
  65. package/dist/index.d.ts +46 -44
  66. package/dist/index.js +1 -1
  67. package/dist/internal_context.d.ts +1 -1
  68. package/dist/lifecycle/index.d.ts +3 -3
  69. package/dist/lifecycle/index.js +1 -1
  70. package/dist/{lifecycle-Mm_jQh7r.js → lifecycle-CFu6OV03.js} +39 -10
  71. package/dist/{lifecycle-Mm_jQh7r.js.map → lifecycle-CFu6OV03.js.map} +1 -1
  72. package/dist/mcp/client/index.d.ts +20 -20
  73. package/dist/mcp/client/x402.js +21 -19
  74. package/dist/mcp/client/x402.js.map +1 -1
  75. package/dist/mcp/index.d.ts +35 -35
  76. package/dist/mcp/index.js +1 -1
  77. package/dist/{message-builder-BymO4N_D.js → message-builder-DAl9AhHH.js} +89 -4
  78. package/dist/message-builder-DAl9AhHH.js.map +1 -0
  79. package/dist/models/ai-sdk/index.d.ts +353 -0
  80. package/dist/models/ai-sdk/index.js +2443 -0
  81. package/dist/models/ai-sdk/index.js.map +1 -0
  82. package/dist/models/pi-ai/index.d.ts +313 -0
  83. package/dist/models/pi-ai/index.js +1795 -0
  84. package/dist/models/pi-ai/index.js.map +1 -0
  85. package/dist/observability/ai/index.js +20 -4
  86. package/dist/observability/ai/index.js.map +1 -1
  87. package/dist/{protocol-B0nh6KNf.js → protocol-kHsr-f0X.js} +26 -12
  88. package/dist/{protocol-B0nh6KNf.js.map → protocol-kHsr-f0X.js.map} +1 -1
  89. package/dist/queue/index.d.ts +3 -3
  90. package/dist/queue/index.js +1 -1
  91. package/dist/{queue-BC9F5cUo.js → queue-BB-zfIYF.js} +2 -2
  92. package/dist/{queue-BC9F5cUo.js.map → queue-BB-zfIYF.js.map} +1 -1
  93. package/dist/react.d.ts +6 -6
  94. package/dist/react.js +160 -64
  95. package/dist/react.js.map +1 -1
  96. package/dist/{retries-D9B2UCq3.d.ts → retries-CV6AkXmQ.d.ts} +18 -9
  97. package/dist/retries.d.ts +11 -9
  98. package/dist/retries.js +11 -1
  99. package/dist/retries.js.map +1 -1
  100. package/dist/routing/index.d.ts +2 -2
  101. package/dist/routing/index.js +1 -1
  102. package/dist/{scheduler-D_KHqxBa.js → scheduler-DZ3xQfeK.js} +2 -2
  103. package/dist/{scheduler-D_KHqxBa.js.map → scheduler-DZ3xQfeK.js.map} +1 -1
  104. package/dist/{scheduler-BGq6M5Kd.d.ts → scheduler-RdACNXDP.d.ts} +3 -3
  105. package/dist/schedules/index.d.ts +1 -1
  106. package/dist/schedules/index.js +1 -1
  107. package/dist/serializable.d.ts +1 -1
  108. package/dist/sessions/index.d.ts +70 -3
  109. package/dist/sessions/index.js +276 -67
  110. package/dist/sessions/index.js.map +1 -1
  111. package/dist/skills/index.d.ts +29 -314
  112. package/dist/socket-address.d.ts +16 -0
  113. package/dist/socket-address.js +19 -0
  114. package/dist/socket-address.js.map +1 -0
  115. package/dist/{src-BNU3ZiJM.js → src-BZeu-SCD.js} +423 -115
  116. package/dist/src-BZeu-SCD.js.map +1 -0
  117. package/dist/state/index.d.ts +1 -1
  118. package/dist/state/index.js +1 -1
  119. package/dist/streams/index.d.ts +1 -1
  120. package/dist/streams/index.js +1 -1
  121. package/dist/{streams-BcE8JP2X.d.ts → streams-Cmkj9QfW.d.ts} +4 -2
  122. package/dist/{streams-CCPRV6dt.js → streams-DW-UCOUc.js} +9 -2
  123. package/dist/streams-DW-UCOUc.js.map +1 -0
  124. package/dist/sub-routing.d.ts +12 -12
  125. package/dist/tasks/index.d.ts +1 -1
  126. package/dist/tasks/index.js +1 -1
  127. package/dist/{tasks-D4nLqVSI.js → tasks-68DESxf0.js} +2 -2
  128. package/dist/{tasks-D4nLqVSI.js.map → tasks-68DESxf0.js.map} +1 -1
  129. package/dist/{tasks-V2lCT8ZV.d.ts → tasks-9YxYtByh.d.ts} +2 -2
  130. package/dist/transport-PfFnt-Ld.d.ts +525 -0
  131. package/dist/{types-DCD6BNZH.d.ts → types-BA4anrjI.d.ts} +2 -2
  132. package/dist/voice/index.d.ts +2 -2
  133. package/dist/websockets/index.d.ts +23 -6
  134. package/dist/websockets/index.js +1 -1
  135. package/dist/{websockets-D7IzWbZb.js → websockets-Ci-LZFHH.js} +45 -20
  136. package/dist/{websockets-D7IzWbZb.js.map → websockets-Ci-LZFHH.js.map} +1 -1
  137. package/dist/wire-types-CnMt6_HR.js.map +1 -1
  138. package/dist/wire-types-CrjKvDyi.d.ts +300 -0
  139. package/dist/workflow-types.d.ts +25 -25
  140. package/dist/workflows.d.ts +21 -21
  141. package/dist/workflows.js +1 -1
  142. package/dist/{ws-chat-transport-UNRIS2xl.d.ts → ws-chat-transport-BbT1A5Lc.d.ts} +51 -2
  143. package/dist/{ws-chat-transport-rWwta645.js → ws-chat-transport-cqMKq3IY.js} +143 -16
  144. package/dist/ws-chat-transport-cqMKq3IY.js.map +1 -0
  145. package/docs/agent-tools.md +29 -4
  146. package/docs/browse-the-web.md +87 -5
  147. package/docs/chat-agents.md +124 -16
  148. package/docs/context.md +27 -0
  149. package/docs/durable-execution.md +2 -0
  150. package/docs/harnesses/pi.md +173 -0
  151. package/docs/human-in-the-loop.md +4 -0
  152. package/docs/index.md +3 -0
  153. package/docs/lifecycle.md +20 -4
  154. package/docs/models-pi-ai.md +325 -0
  155. package/docs/models.md +504 -0
  156. package/docs/resumable-streaming.md +2 -0
  157. package/docs/routing.md +13 -13
  158. package/docs/sessions.md +36 -1
  159. package/docs/state.md +1 -0
  160. package/docs/sub-agents.md +9 -0
  161. package/package.json +40 -2
  162. package/dist/agent-tools-y7zLfw4Q.js.map +0 -1
  163. package/dist/browser/ai.js.map +0 -1
  164. package/dist/client-C9DAjZIY.js.map +0 -1
  165. package/dist/client-tools-aIBO0Fk7.d.ts +0 -53
  166. package/dist/connector-CptFKzRh.js.map +0 -1
  167. package/dist/message-builder-BymO4N_D.js.map +0 -1
  168. package/dist/src-BNU3ZiJM.js.map +0 -1
  169. package/dist/streams-CCPRV6dt.js.map +0 -1
  170. package/dist/ws-chat-transport-rWwta645.js.map +0 -1
@@ -1,27 +1,27 @@
1
1
  import { camelCaseToKebabCase, isInternalJsStubProp } from "./utils.js";
2
2
  import { getAgentByName } from "./agent-routing.js";
3
- import { AGENT_TOOL_MILESTONE_PART } from "./agent-tool-types.js";
3
+ import { AGENT_TOOL_MILESTONE_PART, isAgentToolLifecycleChunk } from "./agent-tool-types.js";
4
4
  import { n as getCurrentAgent$1, t as __DO_NOT_USE_WILL_BREAK__agentContext } from "./current-agent-DhoDkSnH.js";
5
5
  import "./internal_context.js";
6
6
  import { copyCallableMetadata, decoratedMethods, getCallableMetadata, isCallableMethod } from "./callable-decorator.js";
7
7
  import "./types.js";
8
8
  import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "./classPrivateFieldGet2-DZBYAB34.js";
9
+ import { t as _classPrivateMethodInitSpec } from "./classPrivateMethodInitSpec-qMjJ6sHQ.js";
9
10
  import { signAgentHeaders } from "./email.js";
10
11
  import { sendAgentEmail } from "./email-send.js";
11
12
  import { n as withInvocationScope, r as writeSpanAttributes, t as tracer } from "./cloudflare-Dzvc7V2N.js";
12
13
  import { parseSubAgentPath } from "./sub-routing.js";
13
- import { a as getConnectionFlag, c as isConnectionReadonly, d as setConnectionProtocolEnabled, f as setConnectionReadonly, i as ensureConnectionWrapped, l as registerInternalConnectionKeys, o as getConnectionRawState, s as isConnectionProtocolEnabled, t as WebSockets, u as setConnectionFlag } from "./websockets-D7IzWbZb.js";
14
+ import { a as getConnectionFlag, c as isConnectionReadonly, d as setConnectionProtocolEnabled, f as setConnectionReadonly, i as ensureConnectionWrapped, l as registerInternalConnectionKeys, o as getConnectionRawState, s as isConnectionProtocolEnabled, t as WebSockets, u as setConnectionFlag } from "./websockets-Ci-LZFHH.js";
14
15
  import { t as LifecycleCapability } from "./capability-B4WbF81e.js";
15
- import { t as _classPrivateMethodInitSpec } from "./classPrivateMethodInitSpec-qMjJ6sHQ.js";
16
- import { a as abortWithoutAlarmRetry, i as setLifecycleRouteTransport, n as setLifecycleEventSink, r as setLifecycleHostInvoker, t as Lifecycle } from "./lifecycle-Mm_jQh7r.js";
16
+ import { a as abortWithoutAlarmRetry, i as setLifecycleRouteTransport, n as setLifecycleEventSink, r as setLifecycleHostInvoker, t as Lifecycle } from "./lifecycle-CFu6OV03.js";
17
17
  import { isErrorRetryable, tryN, validateRetryOptions } from "./retries.js";
18
18
  import { SqlError } from "./sql-error.js";
19
19
  import { a as ensureMcpServerTable, d as DisposableStore, i as normalizeServerId, l as RPC_DO_PREFIX, o as MCPConnectionState, t as MCPClientManager } from "./client-fyQrLGkD.js";
20
20
  import { DurableObjectOAuthClientProvider } from "./mcp/client/do-oauth-client-provider.js";
21
21
  import { genericObservability } from "./observability/index.js";
22
- import { n as setSchedulerCallbackResolver, t as Scheduler } from "./scheduler-D_KHqxBa.js";
23
- import { n as setQueueCallbackResolver, t as Queue } from "./queue-BC9F5cUo.js";
24
- import { n as setTaskDefinitionResolver, r as setTaskRoutedMemoryLimitHandler, t as Tasks } from "./tasks-D4nLqVSI.js";
22
+ import { n as setSchedulerCallbackResolver, t as Scheduler } from "./scheduler-DZ3xQfeK.js";
23
+ import { n as setQueueCallbackResolver, t as Queue } from "./queue-BB-zfIYF.js";
24
+ import { n as setTaskDefinitionResolver, r as setTaskRoutedMemoryLimitHandler, t as Tasks } from "./tasks-68DESxf0.js";
25
25
  import { State } from "./state/index.js";
26
26
  import { AsyncLocalStorage } from "node:async_hooks";
27
27
  import { DurableObject, RpcTarget, exports } from "cloudflare:workers";
@@ -296,12 +296,47 @@ function _addColumnIfNotExists(sql) {
296
296
  */
297
297
  const CF_SUB_AGENT_OUTER_URL_KEY = "_cf_subAgentOuterUrl";
298
298
  const CF_SUB_AGENT_TAGS_KEY = "_cf_subAgentTags";
299
+ /**
300
+ * Set on a socket closed because its sub-agent was deleted. Its late
301
+ * message/close events are dropped, so they can't reach a same-name
302
+ * replacement created after the delete. Storage-frozen — never rename.
303
+ */
304
+ const CF_SUB_AGENT_DELETED_KEY = "_cf_subAgentDeleted";
299
305
  /** Wire-frozen internal header carrying the outer URL on WS upgrades. */
300
306
  const SUB_AGENT_OUTER_URL_HEADER = "x-cf-agents-subagent-url";
307
+ /**
308
+ * The close frame a rejected sub-agent WebSocket receives in place of the
309
+ * `onBeforeSubAgent` response, which a browser cannot read from a failed
310
+ * handshake. A 4xx closes with `4000 + status`, which clients treat as
311
+ * final; anything else closes with 1011 so the client retries.
312
+ */
313
+ function subAgentRejectionClose(response) {
314
+ const { status } = response;
315
+ return {
316
+ code: status >= 400 && status < 500 ? 4e3 + status : 1011,
317
+ reason: `Sub-agent connection rejected (${status})`
318
+ };
319
+ }
320
+ /**
321
+ * Upgrade a rejected sub-agent WebSocket only to close it, so the client
322
+ * sees a close frame instead of a failed handshake that reconnects forever.
323
+ */
324
+ function rejectSubAgentWebSocket(response) {
325
+ const { code, reason } = subAgentRejectionClose(response);
326
+ const [client, server] = Object.values(new WebSocketPair());
327
+ server.accept();
328
+ server.close(code, reason);
329
+ return new Response(null, {
330
+ status: 101,
331
+ webSocket: client
332
+ });
333
+ }
301
334
  var _host = /* @__PURE__ */ new WeakMap();
302
335
  var _facetKeepAliveTokens = /* @__PURE__ */ new WeakMap();
303
336
  var _bridgeContext = /* @__PURE__ */ new WeakMap();
304
337
  var _virtualConnections = /* @__PURE__ */ new WeakMap();
338
+ var _virtualConnectionsHydrated = /* @__PURE__ */ new WeakMap();
339
+ var _virtualConnectionsHydration = /* @__PURE__ */ new WeakMap();
305
340
  var _connectionOperationTails = /* @__PURE__ */ new WeakMap();
306
341
  var _broadcastOperationTail = /* @__PURE__ */ new WeakMap();
307
342
  var _DynamicAgentsInternal_brand = /* @__PURE__ */ new WeakSet();
@@ -335,6 +370,8 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
335
370
  _classPrivateFieldInitSpec(this, _facetKeepAliveTokens, /* @__PURE__ */ new Set());
336
371
  _classPrivateFieldInitSpec(this, _bridgeContext, new AsyncLocalStorage());
337
372
  _classPrivateFieldInitSpec(this, _virtualConnections, /* @__PURE__ */ new Map());
373
+ _classPrivateFieldInitSpec(this, _virtualConnectionsHydrated, false);
374
+ _classPrivateFieldInitSpec(this, _virtualConnectionsHydration, void 0);
338
375
  _classPrivateFieldInitSpec(this, _connectionOperationTails, /* @__PURE__ */ new Map());
339
376
  _classPrivateFieldInitSpec(this, _broadcastOperationTail, void 0);
340
377
  _classPrivateFieldSet2(_host, this, host);
@@ -389,7 +426,7 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
389
426
  if (!_classPrivateFieldGet2(_host, this).hasSubAgent(next.className, next.name)) {
390
427
  const stalePath = targetPath.slice(0, selfPath.length + 1);
391
428
  if (_classPrivateFieldGet2(_host, this)._isFacet) await (await this.rootAlarmOwner())._cf_cleanupFacetPrefix(stalePath);
392
- else await _classPrivateFieldGet2(_host, this)._cf_cleanupFacetPrefix(stalePath);
429
+ else await this.cleanupPrefix(stalePath);
393
430
  return false;
394
431
  }
395
432
  return (await _classPrivateFieldGet2(_host, this)._cf_resolveSubAgent(next.className, next.name))._cf_routeLifecycle(target, envelope);
@@ -403,7 +440,7 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
403
440
  if (!root) throw new Error("Facet routing requires a root parent.");
404
441
  const binding = _classPrivateFieldGet2(_host, this).ctx.exports?.[root.className];
405
442
  if (!binding) throw new Error(`Unable to resolve root "${root.className}" for facet routing.`);
406
- return await getAgentByName(binding, root.name);
443
+ return binding.get(binding.idFromName(root.name));
407
444
  }
408
445
  rootResolvesToSelf() {
409
446
  const root = _classPrivateFieldGet2(_host, this)._parentPath[0];
@@ -505,6 +542,7 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
505
542
  * rows on the target facet after recovery.
506
543
  */
507
544
  async checkRunFibersAtPath(ownerPath) {
545
+ await _classPrivateFieldGet2(_host, this).__unsafe_ensureInitialized();
508
546
  const selfPath = _classPrivateFieldGet2(_host, this).selfPath;
509
547
  if (!_classPrivateFieldGet2(_host, this)._isSameAgentPathPrefix(selfPath, ownerPath)) throw new Error(`Facet fiber owner path does not descend from ${JSON.stringify(selfPath)}.`);
510
548
  if (selfPath.length === ownerPath.length) {
@@ -548,11 +586,12 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
548
586
  if (targetPath.length === 0) throw new Error("_cf_destroyDescendantFacet: target path must not be empty.");
549
587
  if (selfPath.length >= targetPath.length) throw new Error("_cf_destroyDescendantFacet: target must be a strict descendant.");
550
588
  if (!_classPrivateFieldGet2(_host, this)._isSameAgentPathPrefix(selfPath, targetPath)) throw new Error("_cf_destroyDescendantFacet: target path does not descend from this agent.");
551
- if (_classPrivateFieldGet2(_host, this)._parentPath.length === 0) await _classPrivateFieldGet2(_host, this)._cf_cleanupFacetPrefix(targetPath);
589
+ if (_classPrivateFieldGet2(_host, this)._parentPath.length === 0) await this.cleanupPrefix(targetPath);
552
590
  if (selfPath.length === targetPath.length - 1) {
553
591
  const target = targetPath[targetPath.length - 1];
554
592
  const ctx = _classPrivateFieldGet2(_host, this).ctx;
555
593
  if (!ctx.facets) throw new Error("destroy() (delegated from facet) is not supported in this runtime — `ctx.facets` is unavailable. Update to the latest `compatibility_date` in your wrangler.jsonc.");
594
+ await _assertClassBrand(_DynamicAgentsInternal_brand, this, _closeConnectionsForDeletedPath).call(this, targetPath);
556
595
  try {
557
596
  ctx.facets.delete(`${target.className}\0${target.name}`);
558
597
  } catch {}
@@ -628,16 +667,31 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
628
667
  className,
629
668
  name
630
669
  }];
631
- if (_classPrivateFieldGet2(_host, this)._isFacet) await (await this.rootAlarmOwner())._cf_cleanupFacetPrefix(childPath);
632
- else await _classPrivateFieldGet2(_host, this)._cf_cleanupFacetPrefix(childPath);
670
+ const root = _classPrivateFieldGet2(_host, this)._isFacet ? await this.rootAlarmOwner() : void 0;
671
+ await _assertClassBrand(_DynamicAgentsInternal_brand, this, _closeConnectionsForDeletedPath).call(this, childPath, root);
633
672
  try {
634
673
  ctx.facets.delete(facetKey);
635
674
  } catch {}
636
675
  this.registry.forget(className, name);
676
+ if (root) await root._cf_cleanupFacetPrefix(childPath);
677
+ else await this.cleanupPrefix(childPath);
678
+ }
679
+ /** Root-side: close sockets whose `/sub/...` target is under `prefix`. */
680
+ closeConnectionsForPrefix(prefix, code, reason) {
681
+ for (const connection of _classPrivateFieldGet2(_host, this)._webSockets.getConnections()) {
682
+ const targetPath = this.connectionTargetPath(connection);
683
+ if (!targetPath) continue;
684
+ if (!_classPrivateFieldGet2(_host, this)._isSameAgentPathPrefix(prefix, targetPath)) continue;
685
+ _classPrivateFieldGet2(_host, this)._unsafe_setConnectionFlag(connection, CF_SUB_AGENT_DELETED_KEY, true);
686
+ try {
687
+ connection.close(code, reason);
688
+ } catch {}
689
+ }
637
690
  }
638
691
  /** Drop all facet-side virtual connections (test/rehydration hook). */
639
692
  clearVirtualConnections() {
640
693
  _classPrivateFieldGet2(_virtualConnections, this).clear();
694
+ _classPrivateFieldSet2(_virtualConnectionsHydrated, this, false);
641
695
  }
642
696
  /** Facet-side lookup of a virtual connection by id. */
643
697
  getVirtualConnection(id) {
@@ -715,6 +769,7 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
715
769
  await completion;
716
770
  }
717
771
  async broadcastToParent(message, without) {
772
+ if (_assertClassBrand(_DynamicAgentsInternal_brand, this, _broadcastHasNoRecipients).call(this, without)) return;
718
773
  await this.routeBroadcast(_classPrivateFieldGet2(_host, this).selfPath, message, without);
719
774
  }
720
775
  async broadcastToPath(ownerPath, message, without) {
@@ -779,21 +834,27 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
779
834
  return parseSubAgentPath(request.url, { knownClasses: ctx.exports ? Object.keys(ctx.exports) : void 0 }) !== null;
780
835
  }
781
836
  async forwardWebSocketConnect(connection, request, options) {
782
- const routed = await _assertClassBrand(_DynamicAgentsInternal_brand, this, _resolveConnection).call(this, connection, request, options);
783
- if (!routed) return false;
837
+ const routed = await _assertClassBrand(_DynamicAgentsInternal_brand, this, _resolveConnection).call(this, connection, {
838
+ create: true,
839
+ request,
840
+ gate: options.gate
841
+ });
842
+ if (routed.status !== "ok") return false;
784
843
  await routed.child._cf_handleSubAgentWebSocketConnect(_assertClassBrand(_DynamicAgentsInternal_brand, this, _createConnectionBridge).call(this, connection), routed.meta);
785
844
  return true;
786
845
  }
787
846
  async forwardWebSocketMessage(connection, message, replyBridge) {
788
- const routed = await _assertClassBrand(_DynamicAgentsInternal_brand, this, _resolveConnection).call(this, connection);
789
- if (!routed) return false;
847
+ const routed = await _assertClassBrand(_DynamicAgentsInternal_brand, this, _resolveConnection).call(this, connection, { create: false });
848
+ if (routed.status === "no-match") return false;
849
+ if (routed.status === "dropped") return true;
790
850
  const bridge = _assertClassBrand(_DynamicAgentsInternal_brand, this, _createConnectionBridge).call(this, connection);
791
851
  await routed.child._cf_handleSubAgentWebSocketMessage(message, bridge, routed.meta, replyBridge ?? bridge);
792
852
  return true;
793
853
  }
794
854
  async forwardWebSocketClose(connection, code, reason, wasClean) {
795
- const routed = await _assertClassBrand(_DynamicAgentsInternal_brand, this, _resolveConnection).call(this, connection);
796
- if (!routed) return false;
855
+ const routed = await _assertClassBrand(_DynamicAgentsInternal_brand, this, _resolveConnection).call(this, connection, { create: false });
856
+ if (routed.status === "no-match") return false;
857
+ if (routed.status === "dropped") return true;
797
858
  await routed.child._cf_handleSubAgentWebSocketClose(code, reason, wasClean, _assertClassBrand(_DynamicAgentsInternal_brand, this, _createConnectionBridge).call(this, connection), routed.meta);
798
859
  return true;
799
860
  }
@@ -922,7 +983,8 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
922
983
  if (!_classPrivateFieldGet2(_host, this)._isFacet || _classPrivateFieldGet2(_host, this)._parentPath.length === 0) return;
923
984
  if (this.rootResolvesToSelf()) return;
924
985
  const metas = await (await this.rootAlarmOwner())._cf_subAgentConnectionMetas(_classPrivateFieldGet2(_host, this).selfPath);
925
- for (const meta of metas) _classPrivateFieldGet2(_virtualConnections, this).set(meta.id, { meta });
986
+ for (const meta of metas) if (!_classPrivateFieldGet2(_virtualConnections, this).has(meta.id)) _classPrivateFieldGet2(_virtualConnections, this).set(meta.id, { meta });
987
+ _classPrivateFieldSet2(_virtualConnectionsHydrated, this, true);
926
988
  }
927
989
  getRawConnectionState(connection) {
928
990
  return getConnectionRawState(connection);
@@ -964,6 +1026,7 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
964
1026
  * one RPC method. Stateless — no cached references.
965
1027
  */
966
1028
  async invoke(className, name, method, args) {
1029
+ await _classPrivateFieldGet2(_host, this).__unsafe_ensureInitialized();
967
1030
  const stub = await this.resolve(className, name);
968
1031
  return await this.invokeStubMethod(stub, className, method, args);
969
1032
  }
@@ -974,6 +1037,7 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
974
1037
  * to the next facet using that facet's own `ctx.facets`.
975
1038
  */
976
1039
  async invokePath(path, method, args) {
1040
+ await _classPrivateFieldGet2(_host, this).__unsafe_ensureInitialized();
977
1041
  const [self, next, ...rest] = path;
978
1042
  if (!self) throw new Error(`Sub-agent path invocation requires a non-empty path.`);
979
1043
  const ownClassName = _classPrivateFieldGet2(_host, this).constructor.name;
@@ -1017,6 +1081,46 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
1017
1081
  await _classPrivateFieldGet2(_host, this)._syncHostJobs();
1018
1082
  }
1019
1083
  };
1084
+ /**
1085
+ * Non-creating counterpart to {@link resolve} for WebSocket message/close
1086
+ * forwarding. Returns `null` when the child has no registry row, and never
1087
+ * writes one. The connection's initial connect already went through
1088
+ * {@link resolve} on this hop, so the runtime/export checks there hold.
1089
+ */
1090
+ async function _resolveExisting(className, name) {
1091
+ const row = this.registry.row(className, name);
1092
+ if (!row) return null;
1093
+ const ctx = _classPrivateFieldGet2(_host, this).ctx;
1094
+ const identityName = row.identity_version === "path-v2" && typeof row.identity_name === "string" ? row.identity_name : name;
1095
+ const rootClassName = _classPrivateFieldGet2(_host, this)._parentPath[0]?.className ?? _classPrivateFieldGet2(_host, this).constructor.name;
1096
+ const rootNs = ctx.exports[rootClassName];
1097
+ const stub = ctx.facets.get(`${className}\0${name}`, () => ({
1098
+ class: ctx.exports[className],
1099
+ id: rootNs.idFromName(identityName)
1100
+ }));
1101
+ const childParentPath = _classPrivateFieldGet2(_host, this).selfPath;
1102
+ try {
1103
+ await _classPrivateFieldGet2(_host, this)._runFacetInitInvocation(async () => {
1104
+ await stub._cf_initAsFacet(name, childParentPath, identityName);
1105
+ });
1106
+ } catch (error) {
1107
+ if (!this.registry.row(className, name)) return null;
1108
+ throw error;
1109
+ }
1110
+ return stub;
1111
+ }
1112
+ /**
1113
+ * Close every client socket targeting `path` or a descendant, so a client
1114
+ * attached to a deleted facet gets an explicit close instead of a socket
1115
+ * that goes nowhere (#2003). Only the root owns real sockets.
1116
+ */
1117
+ async function _closeConnectionsForDeletedPath(path, root) {
1118
+ if (!_classPrivateFieldGet2(_host, this)._isFacet) {
1119
+ this.closeConnectionsForPrefix(path, 1001, "Sub-agent deleted");
1120
+ return;
1121
+ }
1122
+ await (root ?? await this.rootAlarmOwner())._cf_closeSubAgentConnectionsForPrefix(path, 1001, "Sub-agent deleted");
1123
+ }
1020
1124
  function _reportConnectionOperationFailure(connectionId, operation, error) {
1021
1125
  console.error("[Agent] Sub-agent connection operation failed:", {
1022
1126
  connectionId,
@@ -1024,6 +1128,29 @@ function _reportConnectionOperationFailure(connectionId, operation, error) {
1024
1128
  error
1025
1129
  });
1026
1130
  }
1131
+ /**
1132
+ * Whether a hydrated mirror proves no root socket targets this facet
1133
+ * outside `without`. Stale mirror entries only cost a root call; a socket
1134
+ * missing from a hydrated mirror has not had its connect forwarded here
1135
+ * yet, so it has not been through `onConnect`. Synchronous so a skipped
1136
+ * broadcast never reorders later operations.
1137
+ */
1138
+ function _broadcastHasNoRecipients(without) {
1139
+ if (!_classPrivateFieldGet2(_virtualConnectionsHydrated, this)) {
1140
+ _assertClassBrand(_DynamicAgentsInternal_brand, this, _hydrateVirtualConnectionsInBackground).call(this);
1141
+ return false;
1142
+ }
1143
+ for (const id of _classPrivateFieldGet2(_virtualConnections, this).keys()) if (!without?.includes(id)) return false;
1144
+ return true;
1145
+ }
1146
+ function _hydrateVirtualConnectionsInBackground() {
1147
+ if (_classPrivateFieldGet2(_virtualConnectionsHydration, this)) return;
1148
+ const hydration = this.hydrateConnectionsFromRoot().catch(() => {}).finally(() => {
1149
+ _classPrivateFieldSet2(_virtualConnectionsHydration, this, void 0);
1150
+ });
1151
+ _classPrivateFieldSet2(_virtualConnectionsHydration, this, hydration);
1152
+ _classPrivateFieldGet2(_host, this).ctx.waitUntil(hydration);
1153
+ }
1027
1154
  function _connectionMetaForPath(connection, ownerPath) {
1028
1155
  ensureConnectionWrapped(connection);
1029
1156
  const outerUri = _classPrivateFieldGet2(_host, this)._unsafe_getConnectionFlag(connection, CF_SUB_AGENT_OUTER_URL_KEY);
@@ -1074,20 +1201,31 @@ function _createConnectionBridge(connection) {
1074
1201
  return _classPrivateFieldGet2(_host, this)._cf_broadcastToSubAgent(ownerPath, message, without);
1075
1202
  });
1076
1203
  }
1077
- async function _resolveConnection(connection, request, options = { gate: false }) {
1204
+ /**
1205
+ * Resolve a connection's `/sub/{class}/{name}` target.
1206
+ *
1207
+ * `create: true` (the initial connect) may wake or create the child, like
1208
+ * `subAgent()`. `create: false` (message/close on an already-forwarded
1209
+ * connection) only attaches to a child that still has a registry row; a
1210
+ * deleted child resolves to `"dropped"`, which the caller must treat as
1211
+ * consumed so a stale frame can't recreate it (#2003).
1212
+ */
1213
+ async function _resolveConnection(connection, options) {
1078
1214
  ensureConnectionWrapped(connection);
1079
1215
  const outerUri = _classPrivateFieldGet2(_host, this)._unsafe_getConnectionFlag(connection, CF_SUB_AGENT_OUTER_URL_KEY);
1080
1216
  const uri = typeof outerUri === "string" ? outerUri : connection.uri;
1081
- if (!uri) return null;
1217
+ if (!uri) return { status: "no-match" };
1218
+ if (_classPrivateFieldGet2(_host, this)._unsafe_getConnectionFlag(connection, "_cf_subAgentDeleted")) return { status: "dropped" };
1082
1219
  const ctx = _classPrivateFieldGet2(_host, this).ctx;
1083
1220
  let match = parseSubAgentPath(uri, { knownClasses: ctx.exports ? Object.keys(ctx.exports) : void 0 });
1084
- if (!match) return null;
1221
+ if (!match) return { status: "no-match" };
1085
1222
  if (_classPrivateFieldGet2(_host, this)._ParentClass.name === match.childClass && _classPrivateFieldGet2(_host, this).name === match.childName) {
1086
1223
  const tailUri = new URL(uri);
1087
1224
  tailUri.pathname = match.remainingPath;
1088
1225
  match = parseSubAgentPath(tailUri.toString(), { knownClasses: ctx.exports ? Object.keys(ctx.exports) : void 0 });
1089
- if (!match) return null;
1226
+ if (!match) return { status: "no-match" };
1090
1227
  }
1228
+ const { request } = options;
1091
1229
  let forwardReq = request;
1092
1230
  if (request && options.gate) {
1093
1231
  const decision = await _classPrivateFieldGet2(_host, this).onBeforeSubAgent(request, {
@@ -1095,25 +1233,28 @@ async function _resolveConnection(connection, request, options = { gate: false }
1095
1233
  name: match.childName
1096
1234
  });
1097
1235
  if (decision instanceof Response) {
1098
- connection.close(1008, "Sub-agent connection rejected");
1099
- return null;
1236
+ const { code, reason } = subAgentRejectionClose(decision);
1237
+ connection.close(code, reason);
1238
+ return { status: "dropped" };
1100
1239
  }
1101
1240
  forwardReq = decision instanceof Request ? decision : request;
1102
1241
  }
1103
- const child = await this.resolve(match.childClass, match.childName);
1242
+ const child = options.create ? await this.resolve(match.childClass, match.childName) : await _assertClassBrand(_DynamicAgentsInternal_brand, this, _resolveExisting).call(this, match.childClass, match.childName);
1243
+ if (!child) return { status: "dropped" };
1104
1244
  const childUri = new URL(forwardReq?.url ?? uri);
1105
1245
  childUri.pathname = match.remainingPath;
1106
1246
  const raw = this.getRawConnectionState(connection);
1107
1247
  const rawTags = raw != null && typeof raw === "object" ? raw[CF_SUB_AGENT_TAGS_KEY] : void 0;
1108
1248
  const tags = Array.isArray(rawTags) ? rawTags.filter((tag) => typeof tag === "string") : [...connection.tags];
1109
1249
  return {
1250
+ status: "ok",
1110
1251
  child,
1111
1252
  meta: {
1112
1253
  id: connection.id,
1113
1254
  uri: childUri.toString(),
1114
1255
  tags,
1115
1256
  state: this.getForwardedState(connection),
1116
- requestHeaders: forwardReq ? [...forwardReq.headers] : void 0
1257
+ requestHeaders: forwardReq ? [...forwardReq.headers].filter(([name]) => name !== SUB_AGENT_OUTER_URL_HEADER) : void 0
1117
1258
  }
1118
1259
  };
1119
1260
  }
@@ -1248,7 +1389,7 @@ const DETACHED_NOTIFY_CALLBACK = "_cfDetachedNotifyFinish";
1248
1389
  * every capability uses for its own schema version) and checks it on wake to
1249
1390
  * skip DDL on established DOs.
1250
1391
  */
1251
- const CURRENT_SCHEMA_VERSION = 11;
1392
+ const CURRENT_SCHEMA_VERSION = 14;
1252
1393
  const SCHEMA_VERSION_KEY = "cf_agents:schema_version";
1253
1394
  const LEGACY_SCHEMA_VERSION_ROW_ID = "cf_schema_version";
1254
1395
  const DEFAULT_STATE = {};
@@ -1323,9 +1464,9 @@ const DEFAULT_AGENT_STATIC_OPTIONS = {
1323
1464
  /**
1324
1465
  * Optional hard wall-clock ceiling (ms) on a single agent-tool re-attach
1325
1466
  * (#1630). Caps the total wait even as the no-progress budget re-arms across
1326
- * stream-closes. Defaults to `Infinity` (no implicit cap), mirroring
1327
- * chat-recovery's `maxRecoveryWork` (#1672): a healthy, still-advancing child
1328
- * is followed for as long as it makes progress — a hung child is bounded by
1467
+ * stream-closes. Defaults to `Infinity` (no implicit cap, #1672): a healthy,
1468
+ * still-advancing child is followed for as long as it makes progress — a
1469
+ * hung child is bounded by
1329
1470
  * the no-progress budget, and a content-runaway by the child's own
1330
1471
  * `maxRecoveryWork` / `shouldKeepRecovering`. Set a finite value to impose a
1331
1472
  * wall-clock cap (which also tears the child down on `window-exceeded`).
@@ -1345,13 +1486,21 @@ const DEFAULT_AGENT_STATIC_OPTIONS = {
1345
1486
  };
1346
1487
  /** Compatibility alias for the lifecycle-owned current Agent accessor. */
1347
1488
  const getCurrentAgent = getCurrentAgent$1;
1489
+ const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor;
1490
+ /** Functions produced by {@link withAgentContext}, so they are wrapped once. */
1491
+ const agentContextWrappers = /* @__PURE__ */ new WeakSet();
1348
1492
  /**
1349
1493
  * Restore Agent context when a public method is entered outside a Lifecycle
1350
1494
  * hook, notably through native Durable Object RPC or cross-Agent re-entry.
1351
1495
  * Lifecycle already owns context for its capability and semantic user hooks.
1496
+ *
1497
+ * Native RPC bypasses the lifecycle's runtime handlers, so an `async` method
1498
+ * entered from outside this Agent's context first starts the lifecycle when
1499
+ * the call is the one that wakes a cold instance. Synchronous methods are
1500
+ * never deferred, so they keep their synchronous return type.
1352
1501
  */
1353
1502
  function withAgentContext(method) {
1354
- return function(...args) {
1503
+ const enter = function(...args) {
1355
1504
  const { agent } = getCurrentAgent();
1356
1505
  if (agent === this) return method.apply(this, args);
1357
1506
  return runInInvocation({
@@ -1363,6 +1512,16 @@ function withAgentContext(method) {
1363
1512
  return method.apply(this, args);
1364
1513
  });
1365
1514
  };
1515
+ if (!(method instanceof AsyncFunction)) {
1516
+ agentContextWrappers.add(enter);
1517
+ return enter;
1518
+ }
1519
+ const enterStarted = async function(...args) {
1520
+ if (getCurrentAgent().agent !== this && !this.lifecycle.isStarted()) await this.lifecycle.start();
1521
+ return enter.apply(this, args);
1522
+ };
1523
+ agentContextWrappers.add(enterStarted);
1524
+ return enterStarted;
1366
1525
  }
1367
1526
  /**
1368
1527
  * Base class for creating Agent implementations
@@ -1573,7 +1732,10 @@ var Agent = class Agent extends DurableObject {
1573
1732
  id TEXT PRIMARY KEY NOT NULL,
1574
1733
  name TEXT NOT NULL,
1575
1734
  snapshot TEXT,
1576
- created_at INTEGER NOT NULL
1735
+ created_at INTEGER NOT NULL,
1736
+ completed_at INTEGER,
1737
+ outcome TEXT,
1738
+ error_message TEXT
1577
1739
  )
1578
1740
  `;
1579
1741
  this.sql`
@@ -1652,6 +1814,10 @@ var Agent = class Agent extends DurableObject {
1652
1814
  addColumnIfNotExists("ALTER TABLE cf_agent_tool_runs ADD COLUMN detached_no_progress_budget_ms INTEGER");
1653
1815
  addColumnIfNotExists("ALTER TABLE cf_agent_tool_runs ADD COLUMN last_progress_at INTEGER");
1654
1816
  addColumnIfNotExists("ALTER TABLE cf_agent_tool_runs ADD COLUMN detached_on_milestones TEXT");
1817
+ addColumnIfNotExists("ALTER TABLE cf_agents_runs ADD COLUMN completed_at INTEGER");
1818
+ addColumnIfNotExists("ALTER TABLE cf_agents_runs ADD COLUMN outcome TEXT");
1819
+ addColumnIfNotExists("ALTER TABLE cf_agents_runs ADD COLUMN error_message TEXT");
1820
+ addColumnIfNotExists("ALTER TABLE cf_agent_tool_runs ADD COLUMN event_delivery TEXT");
1655
1821
  this.ctx.storage.kv.put(SCHEMA_VERSION_KEY, CURRENT_SCHEMA_VERSION);
1656
1822
  }
1657
1823
  this._schemaInitialization = {
@@ -1928,6 +2094,14 @@ var Agent = class Agent extends DurableObject {
1928
2094
  }, async () => {
1929
2095
  if (this.shouldConnectionBeReadonly(connection, ctx)) this.setConnectionReadonly(connection, true);
1930
2096
  if (this.shouldSendProtocolMessages(connection, ctx)) {
2097
+ const wasExcludedFromStateInitBroadcast = this._protocolBroadcastExcludeIds.has(connection.id);
2098
+ let currentState;
2099
+ this._protocolBroadcastExcludeIds.add(connection.id);
2100
+ try {
2101
+ currentState = this.state;
2102
+ } finally {
2103
+ if (!wasExcludedFromStateInitBroadcast) this._protocolBroadcastExcludeIds.delete(connection.id);
2104
+ }
1931
2105
  if (this._resolvedOptions.sendIdentityOnConnect) {
1932
2106
  const ctor = this.constructor;
1933
2107
  if (ctor.options?.sendIdentityOnConnect === void 0 && !_sendIdentityWarnedClasses.has(ctor) && !this._isFacet) {
@@ -1936,20 +2110,11 @@ var Agent = class Agent extends DurableObject {
1936
2110
  console.warn(`[Agent] ${ctor.name}: sending instance name "${this.name}" to clients via sendIdentityOnConnect (the name is not visible in the URL with custom routing). If this name is sensitive, add \`static options = { sendIdentityOnConnect: false }\` to opt out. Set it to true to silence this message.`);
1937
2111
  }
1938
2112
  }
1939
- this._webSockets.sendIdentity(connection, {
2113
+ this._webSockets.sendConnectFrames(connection, {
1940
2114
  name: this.name,
1941
2115
  agent: camelCaseToKebabCase(this._ParentClass.name)
1942
2116
  });
1943
- }
1944
- const wasExcludedFromStateInitBroadcast = this._protocolBroadcastExcludeIds.has(connection.id);
1945
- let currentState;
1946
- this._protocolBroadcastExcludeIds.add(connection.id);
1947
- try {
1948
- currentState = this.state;
1949
- } finally {
1950
- if (!wasExcludedFromStateInitBroadcast) this._protocolBroadcastExcludeIds.delete(connection.id);
1951
- }
1952
- if (currentState !== void 0) this._webSockets.sendState(connection);
2117
+ } else if (currentState !== void 0) this._webSockets.sendState(connection);
1953
2118
  connection.send(JSON.stringify({
1954
2119
  mcp: this.getMcpServers(),
1955
2120
  type: "cf_agent_mcp_servers"
@@ -2366,19 +2531,21 @@ var Agent = class Agent extends DurableObject {
2366
2531
  proto = Object.getPrototypeOf(proto);
2367
2532
  }
2368
2533
  }
2534
+ const seen = /* @__PURE__ */ new Set();
2369
2535
  let proto = Object.getPrototypeOf(this);
2370
- let depth = 0;
2371
- while (proto && proto !== Object.prototype && depth < 10) {
2536
+ while (proto && proto !== Agent.prototype && proto !== Object.prototype) {
2372
2537
  const methodNames = Object.getOwnPropertyNames(proto);
2373
2538
  for (const methodName of methodNames) {
2539
+ if (seen.has(methodName)) continue;
2540
+ seen.add(methodName);
2374
2541
  const descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
2375
- if (baseMethods.has(methodName) || methodName.startsWith("_") || !descriptor || !!descriptor.get || typeof descriptor.value !== "function") continue;
2376
- const wrappedFunction = withAgentContext(this[methodName]);
2377
- if (this._isCallable(methodName)) copyCallableMetadata(this[methodName], wrappedFunction);
2542
+ if (baseMethods.has(methodName) || methodName.startsWith("_") || !descriptor || !!descriptor.get || typeof descriptor.value !== "function" || agentContextWrappers.has(descriptor.value)) continue;
2543
+ const method = descriptor.value;
2544
+ const wrappedFunction = withAgentContext(method);
2545
+ if (this._isCallable(methodName)) copyCallableMetadata(method, wrappedFunction);
2378
2546
  this.constructor.prototype[methodName] = wrappedFunction;
2379
2547
  }
2380
2548
  proto = Object.getPrototypeOf(proto);
2381
- depth++;
2382
2549
  }
2383
2550
  }
2384
2551
  onError(connectionOrError, error) {
@@ -2487,7 +2654,8 @@ var Agent = class Agent extends DurableObject {
2487
2654
  return this._dynamicAgents.routeLifecycleToTarget(target, envelope);
2488
2655
  }
2489
2656
  /** Single native-RPC aperture for routed Lifecycle capabilities. */
2490
- _cf_routeLifecycle(target, envelope) {
2657
+ async _cf_routeLifecycle(target, envelope) {
2658
+ await this.__unsafe_ensureInitialized();
2491
2659
  return this._dynamicAgents.routeLifecycle(target, envelope);
2492
2660
  }
2493
2661
  _rootAlarmOwner() {
@@ -2504,6 +2672,7 @@ var Agent = class Agent extends DurableObject {
2504
2672
  * @internal
2505
2673
  */
2506
2674
  async _cf_cleanupFacetPrefix(ownerPath) {
2675
+ await this.__unsafe_ensureInitialized();
2507
2676
  await this._dynamicAgents.cleanupPrefix(ownerPath);
2508
2677
  }
2509
2678
  /**
@@ -2512,7 +2681,8 @@ var Agent = class Agent extends DurableObject {
2512
2681
  * physical alarm, so this lets facet work use the root alarm heartbeat.
2513
2682
  * @internal
2514
2683
  */
2515
- _cf_acquireFacetKeepAlive(ownerPath) {
2684
+ async _cf_acquireFacetKeepAlive(ownerPath) {
2685
+ await this.__unsafe_ensureInitialized();
2516
2686
  return this._dynamicAgents.acquireKeepAlive(ownerPath);
2517
2687
  }
2518
2688
  /**
@@ -2520,8 +2690,9 @@ var Agent = class Agent extends DurableObject {
2520
2690
  * Idempotent so disposer calls can safely race or run twice.
2521
2691
  * @internal
2522
2692
  */
2523
- _cf_releaseFacetKeepAlive(token) {
2524
- return this._dynamicAgents.releaseKeepAlive(token);
2693
+ async _cf_releaseFacetKeepAlive(token) {
2694
+ await this.__unsafe_ensureInitialized();
2695
+ await this._dynamicAgents.releaseKeepAlive(token);
2525
2696
  }
2526
2697
  /**
2527
2698
  * Register a facet's durable run row in the root-side index so root
@@ -2529,15 +2700,17 @@ var Agent = class Agent extends DurableObject {
2529
2700
  * The facet remains authoritative for snapshots and recovery hooks.
2530
2701
  * @internal
2531
2702
  */
2532
- _cf_registerFacetRun(ownerPath, runId) {
2533
- return this._dynamicAgents.registerRun(ownerPath, runId);
2703
+ async _cf_registerFacetRun(ownerPath, runId) {
2704
+ await this.__unsafe_ensureInitialized();
2705
+ await this._dynamicAgents.registerRun(ownerPath, runId);
2534
2706
  }
2535
2707
  /**
2536
2708
  * Remove a completed facet fiber from the root-side index.
2537
2709
  * @internal
2538
2710
  */
2539
- _cf_unregisterFacetRun(ownerPath, runId) {
2540
- return this._dynamicAgents.unregisterRun(ownerPath, runId);
2711
+ async _cf_unregisterFacetRun(ownerPath, runId) {
2712
+ await this.__unsafe_ensureInitialized();
2713
+ await this._dynamicAgents.unregisterRun(ownerPath, runId);
2541
2714
  }
2542
2715
  /**
2543
2716
  * Schedule a task to be executed in the future
@@ -3222,6 +3395,7 @@ var Agent = class Agent extends DurableObject {
3222
3395
  };
3223
3396
  let root;
3224
3397
  let registeredFacetRun = false;
3398
+ let bodyOutcome;
3225
3399
  let dispose = () => {};
3226
3400
  try {
3227
3401
  if ("initialSnapshot" in (options ?? {})) writeSnapshot(options?.initialSnapshot);
@@ -3235,16 +3409,29 @@ var Agent = class Agent extends DurableObject {
3235
3409
  writeSnapshot(options?.wrapStash ? options.wrapStash(data) : data);
3236
3410
  };
3237
3411
  try {
3238
- const result = await _fiberALS.run({
3239
- id,
3240
- signal,
3241
- stash
3242
- }, () => fn({
3243
- id,
3244
- signal,
3245
- stash,
3246
- snapshot: null
3247
- }));
3412
+ let result;
3413
+ try {
3414
+ result = await _fiberALS.run({
3415
+ id,
3416
+ signal,
3417
+ stash
3418
+ }, () => fn({
3419
+ id,
3420
+ signal,
3421
+ stash,
3422
+ snapshot: null
3423
+ }));
3424
+ } catch (error) {
3425
+ bodyOutcome = {
3426
+ status: signal.aborted ? "aborted" : "error",
3427
+ error: this._fiberErrorMessage(error)
3428
+ };
3429
+ throw error;
3430
+ }
3431
+ bodyOutcome = {
3432
+ status: "completed",
3433
+ error: null
3434
+ };
3248
3435
  options?.beforeRunCleanup?.({ ok: true });
3249
3436
  this._emit("fiber:run:completed", {
3250
3437
  fiberId: id,
@@ -3269,18 +3456,29 @@ var Agent = class Agent extends DurableObject {
3269
3456
  }
3270
3457
  } finally {
3271
3458
  this._runFiberActiveFibers.delete(id);
3459
+ let rowDeleted = false;
3272
3460
  try {
3273
3461
  this._withAgentSpan("finalize_fiber", "fiber", {
3274
3462
  "cloudflare.agents.fiber.id": id,
3275
3463
  "cloudflare.agents.fiber.name": name
3276
3464
  }, () => {
3465
+ if (bodyOutcome) try {
3466
+ this.sql`
3467
+ UPDATE cf_agents_runs
3468
+ SET completed_at = ${Date.now()},
3469
+ outcome = ${bodyOutcome.status},
3470
+ error_message = ${bodyOutcome.error}
3471
+ WHERE id = ${id}
3472
+ `;
3473
+ } catch {}
3277
3474
  this.sql`DELETE FROM cf_agents_runs WHERE id = ${id}`;
3278
3475
  });
3476
+ rowDeleted = true;
3279
3477
  } catch (error) {
3280
3478
  console.error(`[Agent] Failed to finalize fiber "${name}" (${id}); leaving run row for recovery:`, error);
3281
3479
  }
3282
3480
  dispose();
3283
- if (root && registeredFacetRun) try {
3481
+ if (root && registeredFacetRun && rowDeleted) try {
3284
3482
  await root._cf_unregisterFacetRun(this.selfPath, id);
3285
3483
  } catch (e) {
3286
3484
  console.error("[Agent] Failed to unregister facet fiber:", e);
@@ -3337,7 +3535,11 @@ var Agent = class Agent extends DurableObject {
3337
3535
  const fiberRecoveryMaxAgeMs = this._resolvedOptions.fiberRecoveryMaxAgeMs;
3338
3536
  let madeProgress = false;
3339
3537
  try {
3340
- const rows = this.sql`SELECT id, name, snapshot, created_at FROM cf_agents_runs`;
3538
+ const rows = this.sql`
3539
+ SELECT id, name, snapshot, created_at, completed_at, outcome,
3540
+ error_message
3541
+ FROM cf_agents_runs
3542
+ `;
3341
3543
  for (const row of rows) {
3342
3544
  if (scanDeadlineMs > 0 && Date.now() - scanStartedAt > scanDeadlineMs) {
3343
3545
  this._emit("fiber:recovery:skipped", {
@@ -3349,6 +3551,27 @@ var Agent = class Agent extends DurableObject {
3349
3551
  break;
3350
3552
  }
3351
3553
  if (this._runFiberActiveFibers.has(row.id)) continue;
3554
+ const managedRow = this._readFiber(row.id);
3555
+ if (row.completed_at !== null && (!managedRow || row.outcome !== null)) {
3556
+ if (managedRow) this.sql`
3557
+ UPDATE cf_agents_fibers
3558
+ SET status = ${row.outcome},
3559
+ error_message = ${row.error_message},
3560
+ completed_at = ${row.completed_at}
3561
+ WHERE fiber_id = ${row.id}
3562
+ AND status IN ('pending', 'running')
3563
+ `;
3564
+ this.sql`DELETE FROM cf_agents_runs WHERE id = ${row.id}`;
3565
+ madeProgress = true;
3566
+ if (managedRow) this._notifyManagedFiberTerminal(row.id);
3567
+ continue;
3568
+ }
3569
+ if (managedRow && this._isTerminalFiberStatus(managedRow.status)) {
3570
+ this.sql`DELETE FROM cf_agents_runs WHERE id = ${row.id}`;
3571
+ madeProgress = true;
3572
+ this._notifyManagedFiberTerminal(row.id);
3573
+ continue;
3574
+ }
3352
3575
  const snapshot = this._parseFiberRecoverySnapshot(row.id, row.snapshot);
3353
3576
  const ctx = {
3354
3577
  id: row.id,
@@ -3357,7 +3580,6 @@ var Agent = class Agent extends DurableObject {
3357
3580
  createdAt: row.created_at,
3358
3581
  recoveryReason: "interrupted"
3359
3582
  };
3360
- const managedRow = this._readFiber(row.id);
3361
3583
  this._emit("fiber:recovery:detected", {
3362
3584
  ...this._fiberRecoveryPayload(ctx, managedRow),
3363
3585
  elapsedMs: Date.now() - row.created_at
@@ -3370,12 +3592,6 @@ var Agent = class Agent extends DurableObject {
3370
3592
  elapsedMs: Date.now() - row.created_at
3371
3593
  });
3372
3594
  if (managedRow) {
3373
- if (this._isTerminalFiberStatus(managedRow.status)) {
3374
- this.sql`DELETE FROM cf_agents_runs WHERE id = ${row.id}`;
3375
- madeProgress = true;
3376
- this._notifyManagedFiberTerminal(row.id);
3377
- continue;
3378
- }
3379
3595
  const completedAt = Date.now();
3380
3596
  this.sql`
3381
3597
  UPDATE cf_agents_fibers
@@ -3513,8 +3729,9 @@ var Agent = class Agent extends DurableObject {
3513
3729
  * cleanup as `parent.deleteSubAgent(Cls, name)` from the parent.
3514
3730
  * @internal
3515
3731
  */
3516
- _cf_destroyDescendantFacet(targetPath) {
3517
- return this._dynamicAgents.destroyDescendant(targetPath);
3732
+ async _cf_destroyDescendantFacet(targetPath) {
3733
+ await this.__unsafe_ensureInitialized();
3734
+ await this._dynamicAgents.destroyDescendant(targetPath);
3518
3735
  }
3519
3736
  /**
3520
3737
  * Whether any runFiber recovery work is still outstanding: orphaned
@@ -3552,6 +3769,15 @@ var Agent = class Agent extends DurableObject {
3552
3769
  */
3553
3770
  async _syncHostJobs() {
3554
3771
  if (this._destroyed) return;
3772
+ if (this._isFacet) {
3773
+ const work = this.lifecycle.jobs;
3774
+ for (const id of [
3775
+ HOST_JOB_DESTROY_ID,
3776
+ HOST_JOB_KEEP_ALIVE_ID,
3777
+ HOST_JOB_HOUSEKEEPING_ID
3778
+ ]) if (work.get(id)) await work.cancel(id);
3779
+ return;
3780
+ }
3555
3781
  await this._withAgentSpan("schedule_agent_alarm", "alarm", {}, async () => {
3556
3782
  const work = this.lifecycle.jobs;
3557
3783
  const nowMs = Date.now();
@@ -3683,9 +3909,10 @@ var Agent = class Agent extends DurableObject {
3683
3909
  className: match.childClass,
3684
3910
  name: match.childName
3685
3911
  });
3686
- if (decision instanceof Response) return decision;
3912
+ const isWebSocketUpgrade = request.headers.get("Upgrade")?.toLowerCase() === "websocket";
3913
+ if (decision instanceof Response) return isWebSocketUpgrade && !decision.webSocket ? rejectSubAgentWebSocket(decision) : decision;
3687
3914
  const forwardReq = decision instanceof Request ? decision : request;
3688
- if (request.headers.get("Upgrade")?.toLowerCase() === "websocket") {
3915
+ if (isWebSocketUpgrade) {
3689
3916
  const acceptHeaders = new Headers(forwardReq.headers);
3690
3917
  const routedUrl = new URL(forwardReq.url);
3691
3918
  routedUrl.pathname = new URL(request.url).pathname;
@@ -3722,18 +3949,27 @@ var Agent = class Agent extends DurableObject {
3722
3949
  }
3723
3950
  }
3724
3951
  async _cf_broadcastToSubAgent(ownerPath, message, without) {
3952
+ await this.__unsafe_ensureInitialized();
3725
3953
  await this._dynamicAgents.broadcastToPath(ownerPath, message, without);
3726
3954
  }
3727
- _cf_subAgentConnectionMetas(ownerPath) {
3955
+ async _cf_subAgentConnectionMetas(ownerPath) {
3956
+ await this.__unsafe_ensureInitialized();
3728
3957
  return this._dynamicAgents.connectionMetas(ownerPath);
3729
3958
  }
3730
- _cf_sendToSubAgentConnection(connectionId, message) {
3731
- return this._dynamicAgents.sendToConnection(connectionId, message);
3959
+ async _cf_sendToSubAgentConnection(connectionId, message) {
3960
+ await this.__unsafe_ensureInitialized();
3961
+ await this._dynamicAgents.sendToConnection(connectionId, message);
3962
+ }
3963
+ async _cf_closeSubAgentConnection(connectionId, code, reason) {
3964
+ await this.__unsafe_ensureInitialized();
3965
+ await this._dynamicAgents.closeConnection(connectionId, code, reason);
3732
3966
  }
3733
- _cf_closeSubAgentConnection(connectionId, code, reason) {
3734
- return this._dynamicAgents.closeConnection(connectionId, code, reason);
3967
+ async _cf_closeSubAgentConnectionsForPrefix(prefix, code, reason) {
3968
+ await this.__unsafe_ensureInitialized();
3969
+ this._dynamicAgents.closeConnectionsForPrefix(prefix, code, reason);
3735
3970
  }
3736
- _cf_setSubAgentConnectionState(connectionId, state) {
3971
+ async _cf_setSubAgentConnectionState(connectionId, state) {
3972
+ await this.__unsafe_ensureInitialized();
3737
3973
  return this._dynamicAgents.setConnectionState(connectionId, state);
3738
3974
  }
3739
3975
  _cf_connectionTargetsSubAgent(connection) {
@@ -4049,6 +4285,9 @@ var Agent = class Agent extends DurableObject {
4049
4285
  const runId = options.runId ?? nanoid(12);
4050
4286
  const agentType = cls.name;
4051
4287
  const detached = this._parseDetachedOption(options.detached);
4288
+ const eventDelivery = options.eventDelivery ?? "full";
4289
+ if (eventDelivery !== "full" && eventDelivery !== "terminal") throw new Error(`runAgentTool: eventDelivery must be "full" or "terminal", got ${JSON.stringify(eventDelivery)}.`);
4290
+ if (detached && eventDelivery === "terminal") throw new Error("runAgentTool: eventDelivery \"terminal\" is not supported for detached runs.");
4052
4291
  const existing = this._readAgentToolRun(runId);
4053
4292
  if (existing) {
4054
4293
  if (detached) {
@@ -4139,13 +4378,14 @@ var Agent = class Agent extends DurableObject {
4139
4378
  input_redacted, status, display_metadata, display_order, started_at,
4140
4379
  detached, detached_on_finish, detached_notify_source,
4141
4380
  detached_max_budget_at, detached_no_progress_budget_ms,
4142
- detached_on_milestones
4381
+ detached_on_milestones, event_delivery
4143
4382
  ) VALUES (
4144
4383
  ${runId}, ${options.parentToolCallId ?? null}, ${agentType},
4145
4384
  ${inputPreviewJson}, 1, 'starting', ${displayJson}, ${displayOrder},
4146
4385
  ${startedAt}, ${detached ? 1 : 0}, ${detached?.onFinishName ?? null},
4147
4386
  ${detached?.notifySource ?? null}, ${detachedMaxBudgetAt},
4148
- ${detachedNoProgressBudgetMs}, ${detachedOnMilestonesJson}
4387
+ ${detachedNoProgressBudgetMs}, ${detachedOnMilestonesJson},
4388
+ ${eventDelivery === "terminal" ? "terminal" : null}
4149
4389
  )
4150
4390
  `;
4151
4391
  const runInfo = {
@@ -4170,7 +4410,10 @@ var Agent = class Agent extends DurableObject {
4170
4410
  });
4171
4411
  const child = await this.subAgent(cls, runId);
4172
4412
  const adapter = this._asAgentToolChildAdapter(child);
4173
- const childStart = await adapter.startAgentToolRun(options.input, { runId });
4413
+ const childStart = await adapter.startAgentToolRun(options.input, {
4414
+ runId,
4415
+ ...eventDelivery === "terminal" ? { eventDelivery } : {}
4416
+ });
4174
4417
  this._markAgentToolRunning(runId);
4175
4418
  if (detached) {
4176
4419
  if (options.signal) console.warn(`[agents] runAgentTool: \`signal\` is ignored for a detached run (${runId}); a detached child must outlive the spawning turn. Use cancelAgentTool(runId) to cancel it.`);
@@ -4781,29 +5024,79 @@ var Agent = class Agent extends DurableObject {
4781
5024
  else this.broadcast(body);
4782
5025
  }
4783
5026
  _broadcastAgentToolChunks(parentToolCallId, runId, chunks, sequence, replay, connection) {
5027
+ const terminalOnly = this._isTerminalOnlyAgentToolRun(runId);
4784
5028
  let next = sequence;
4785
- for (const chunk of chunks) this._broadcastAgentToolEvent(parentToolCallId, next++, {
4786
- kind: "chunk",
4787
- runId,
4788
- body: chunk.body
4789
- }, replay, connection);
5029
+ for (const chunk of chunks) {
5030
+ const chunkSequence = next++;
5031
+ if (terminalOnly && !isAgentToolLifecycleChunk(chunk.body)) continue;
5032
+ this._broadcastAgentToolEvent(parentToolCallId, chunkSequence, {
5033
+ kind: "chunk",
5034
+ runId,
5035
+ body: chunk.body
5036
+ }, replay, connection);
5037
+ }
4790
5038
  return next;
4791
5039
  }
4792
- async _broadcastAgentToolStoredChunks(row, sequence, replay, connection) {
4793
- const child = await this._cf_resolveSubAgent(row.agent_type, row.run_id);
5040
+ _isTerminalOnlyAgentToolRun(runId) {
5041
+ return this.sql`
5042
+ SELECT event_delivery FROM cf_agent_tool_runs WHERE run_id = ${runId}
5043
+ `[0]?.event_delivery === "terminal";
5044
+ }
5045
+ async _broadcastAgentToolStoredChunks(row, sequence, replay, connection, timeoutMs) {
5046
+ const deadline = this._agentToolRecoveryDeadline(timeoutMs);
5047
+ const resolving = this._cf_resolveSubAgent(row.agent_type, row.run_id);
5048
+ const child = deadline === void 0 ? await resolving : await this._settleWithinRecoveryTimeout(resolving, deadline());
5049
+ if (child === void 0) return sequence;
4794
5050
  const adapter = this._asAgentToolChildAdapter(child);
4795
- return this._broadcastAgentToolStoredChunksFromAdapter(adapter, row, sequence, replay, connection);
5051
+ return this._broadcastAgentToolStoredChunksFromAdapter(adapter, row, sequence, replay, connection, deadline?.());
5052
+ }
5053
+ /**
5054
+ * One budget shared by every step of a bounded recovery read, so a run's
5055
+ * total time stays within `timeoutMs`. Returns the remaining milliseconds,
5056
+ * never below 1 because a non-positive timeout means "unbounded".
5057
+ */
5058
+ _agentToolRecoveryDeadline(timeoutMs) {
5059
+ if (timeoutMs === void 0 || timeoutMs <= 0) return void 0;
5060
+ const deadline = Date.now() + timeoutMs;
5061
+ return () => Math.max(1, deadline - Date.now());
4796
5062
  }
4797
5063
  async _broadcastAgentToolStoredChunksFromAdapter(adapter, row, sequence, replay, connection, timeoutMs) {
4798
- const chunks = await this._getAgentToolChunksForRecovery(adapter, row.run_id, timeoutMs);
4799
- if (!chunks) return sequence;
4800
- return this._broadcastAgentToolChunks(row.parent_tool_call_id ?? void 0, row.run_id, chunks, sequence, replay, connection);
5064
+ const deadline = this._agentToolRecoveryDeadline(timeoutMs);
5065
+ const chunks = await this._getAgentToolChunksForRecovery(adapter, row.run_id, deadline?.());
5066
+ const next = chunks ? this._broadcastAgentToolChunks(row.parent_tool_call_id ?? void 0, row.run_id, chunks, sequence, replay, connection) : sequence;
5067
+ return this._broadcastAgentToolMilestones(adapter, row, next, replay, connection, deadline?.());
5068
+ }
5069
+ /**
5070
+ * Milestones are persisted on the child run rather than in its chunk log, so
5071
+ * replay re-emits them from the child's inspection. The client dedupes them
5072
+ * on the milestone's own sequence, so a milestone already seen live is a no-op.
5073
+ * They carry the next stored-chunk sequence without consuming it, matching
5074
+ * the live path.
5075
+ */
5076
+ async _broadcastAgentToolMilestones(adapter, row, sequence, replay, connection, timeoutMs) {
5077
+ const milestones = (await this._settleWithinRecoveryTimeout(adapter.inspectAgentToolRun(row.run_id, { reconcile: false }), timeoutMs))?.milestones ?? [];
5078
+ for (const milestone of milestones) this._broadcastAgentToolEvent(row.parent_tool_call_id ?? void 0, sequence, {
5079
+ kind: "chunk",
5080
+ runId: row.run_id,
5081
+ body: JSON.stringify({
5082
+ type: AGENT_TOOL_MILESTONE_PART,
5083
+ data: {
5084
+ name: milestone.name,
5085
+ sequence: milestone.sequence,
5086
+ at: milestone.at,
5087
+ ...milestone.data !== void 0 ? { data: milestone.data } : {}
5088
+ }
5089
+ })
5090
+ }, replay, connection);
5091
+ return sequence;
4801
5092
  }
4802
5093
  async _forwardAgentToolStream(stream, parentToolCallId, runId, sequence, signal, idleTimeoutMs) {
4803
5094
  let next = sequence;
5095
+ let forwarded = false;
4804
5096
  if (signal?.aborted) return {
4805
5097
  next,
4806
- ended: "aborted"
5098
+ ended: "aborted",
5099
+ forwarded
4807
5100
  };
4808
5101
  let ended = "done";
4809
5102
  const reader = stream.getReader();
@@ -4831,12 +5124,18 @@ var Agent = class Agent extends DurableObject {
4831
5124
  idleTimer = setTimeout(() => resolveIdle?.(), idleTimeoutMs);
4832
5125
  };
4833
5126
  let forwardedSinceProgress = false;
5127
+ const terminalOnly = this._isTerminalOnlyAgentToolRun(runId);
4834
5128
  try {
4835
5129
  const forwardChunk = (chunk) => {
4836
- this._broadcastAgentToolEvent(parentToolCallId, next++, {
5130
+ const lifecycle = isAgentToolLifecycleChunk(chunk.body);
5131
+ const unstoredId = typeof chunk.unstoredId === "string" ? chunk.unstoredId : void 0;
5132
+ const chunkSequence = lifecycle || unstoredId !== void 0 ? next : next++;
5133
+ forwarded = true;
5134
+ if (!terminalOnly || lifecycle) this._broadcastAgentToolEvent(parentToolCallId, chunkSequence, {
4837
5135
  kind: "chunk",
4838
5136
  runId,
4839
- body: chunk.body
5137
+ body: chunk.body,
5138
+ ...unstoredId !== void 0 ? { unstoredId } : {}
4840
5139
  });
4841
5140
  this._observeForwardedProgress(runId, chunk.body);
4842
5141
  forwardedSinceProgress = true;
@@ -4904,7 +5203,8 @@ var Agent = class Agent extends DurableObject {
4904
5203
  }
4905
5204
  return {
4906
5205
  next,
4907
- ended
5206
+ ended,
5207
+ forwarded
4908
5208
  };
4909
5209
  }
4910
5210
  /**
@@ -5105,9 +5405,9 @@ var Agent = class Agent extends DurableObject {
5105
5405
  * dies and recovers again during deploy churn is still collected. A genuinely
5106
5406
  * silent/hung child can never block recovery forever: it seals `interrupted`
5107
5407
  * after one `noProgressTimeoutMs` window. `maxWindowMs` is an OPTIONAL hard
5108
- * wall-clock ceiling (default `Infinity` — uncapped, mirroring #1672's
5109
- * `maxRecoveryWork`); set it finite to also bound a child that keeps
5110
- * progressing, which seals `window-exceeded` and tears the child down.
5408
+ * wall-clock ceiling (default `Infinity` — uncapped, #1672); set it finite
5409
+ * to also bound a child that keeps progressing, which seals
5410
+ * `window-exceeded` and tears the child down.
5111
5411
  *
5112
5412
  * Returns the terminal `result` (and `completedAt`) when the child reaches a
5113
5413
  * terminal status, plus the advanced broadcast `sequence`. Returns
@@ -5152,18 +5452,22 @@ var Agent = class Agent extends DurableObject {
5152
5452
  try {
5153
5453
  while (!ceilingController.signal.aborted) {
5154
5454
  let afterSequence = -1;
5455
+ let storedCount = 0;
5155
5456
  try {
5156
5457
  const existing = await adapter.getAgentToolChunks(row.run_id);
5157
5458
  const last = existing[existing.length - 1];
5158
5459
  if (last) afterSequence = last.sequence;
5460
+ storedCount = existing.length;
5159
5461
  } catch {}
5160
- const beforeSequence = nextSequence;
5462
+ nextSequence = storedCount + 1;
5161
5463
  let streamEnded = "idle";
5464
+ let forwardedAny = false;
5162
5465
  try {
5163
5466
  const stream = await adapter.tailAgentToolRun(row.run_id, { afterSequence });
5164
5467
  const forwarded = await this._forwardAgentToolStream(stream, row.parent_tool_call_id ?? void 0, row.run_id, nextSequence, ceilingController.signal, noProgressTimeoutMs);
5165
5468
  nextSequence = forwarded.next;
5166
5469
  streamEnded = forwarded.ended;
5470
+ forwardedAny = forwarded.forwarded;
5167
5471
  } catch {}
5168
5472
  const terminal = await collectTerminal(nextSequence);
5169
5473
  if (terminal) return terminal;
@@ -5172,7 +5476,7 @@ var Agent = class Agent extends DurableObject {
5172
5476
  break;
5173
5477
  }
5174
5478
  if (streamEnded !== "done") break;
5175
- if (nextSequence <= beforeSequence) break;
5479
+ if (!forwardedAny) break;
5176
5480
  }
5177
5481
  } finally {
5178
5482
  if (ceilingTimer !== void 0) clearTimeout(ceilingTimer);
@@ -5202,7 +5506,7 @@ var Agent = class Agent extends DurableObject {
5202
5506
  display: this._parseAgentToolJson(row.display_metadata)
5203
5507
  }, true, connection);
5204
5508
  try {
5205
- sequence = await this._broadcastAgentToolStoredChunks(row, sequence, true, connection);
5509
+ sequence = await this._broadcastAgentToolStoredChunks(row, sequence, true, connection, DEFAULT_AGENT_TOOL_RECOVERY_TIMEOUT_MS);
5206
5510
  } catch {}
5207
5511
  if (this._isAgentToolTerminal(row.status)) this._broadcastAgentToolTerminal(parentToolCallId, sequence, {
5208
5512
  runId: row.run_id,
@@ -5389,13 +5693,17 @@ var Agent = class Agent extends DurableObject {
5389
5693
  `.map((row) => row.run_id);
5390
5694
  }
5391
5695
  async _getAgentToolChunksForRecovery(adapter, runId, timeoutMs) {
5392
- const chunks = adapter.getAgentToolChunks(runId).catch(() => void 0);
5393
- if (timeoutMs === void 0 || timeoutMs <= 0) return chunks;
5696
+ return this._settleWithinRecoveryTimeout(adapter.getAgentToolChunks(runId), timeoutMs);
5697
+ }
5698
+ /** Resolve to `undefined` when `promise` rejects or outlasts `timeoutMs`. */
5699
+ async _settleWithinRecoveryTimeout(promise, timeoutMs) {
5700
+ const settled = promise.catch(() => void 0);
5701
+ if (timeoutMs === void 0 || timeoutMs <= 0) return settled;
5394
5702
  let timeoutId;
5395
5703
  const timeout = new Promise((resolve) => {
5396
5704
  timeoutId = setTimeout(() => resolve(void 0), timeoutMs);
5397
5705
  });
5398
- const result = await Promise.race([chunks, timeout]);
5706
+ const result = await Promise.race([settled, timeout]);
5399
5707
  if (timeoutId !== void 0) clearTimeout(timeoutId);
5400
5708
  return result;
5401
5709
  }
@@ -6693,4 +7001,4 @@ var StreamingResponse = class {
6693
7001
  //#endregion
6694
7002
  export { routeAgentEmail as a, getCurrentAgent as i, DEFAULT_AGENT_STATIC_OPTIONS as n, StreamingResponse as r, Agent as t };
6695
7003
 
6696
- //# sourceMappingURL=src-BNU3ZiJM.js.map
7004
+ //# sourceMappingURL=src-BZeu-SCD.js.map