agents 0.12.3 → 0.13.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 (88) hide show
  1. package/README.md +7 -7
  2. package/dist/{agent-tool-types-DSteYkkS.d.ts → agent-tool-types-BVgYyKO9.d.ts} +153 -102
  3. package/dist/agent-tool-types.d.ts +1 -1
  4. package/dist/agent-tools-BAdX1vdI.js.map +1 -1
  5. package/dist/{agent-tools-eGTCdVZX.d.ts → agent-tools-C-Ch8Thl.d.ts} +2 -2
  6. package/dist/agent-tools.d.ts +1 -1
  7. package/dist/agent-tools.js.map +1 -1
  8. package/dist/ai-chat-agent.js.map +1 -1
  9. package/dist/ai-chat-v5-migration.js.map +1 -1
  10. package/dist/ai-react.js.map +1 -1
  11. package/dist/ai-types.js.map +1 -1
  12. package/dist/browser/ai.d.ts +2 -2
  13. package/dist/browser/ai.js +1 -1
  14. package/dist/browser/ai.js.map +1 -1
  15. package/dist/browser/index.d.ts +41 -10
  16. package/dist/browser/index.js +1 -1
  17. package/dist/browser/tanstack-ai.d.ts +2 -2
  18. package/dist/browser/tanstack-ai.js +1 -1
  19. package/dist/browser/tanstack-ai.js.map +1 -1
  20. package/dist/chat/index.d.ts +297 -148
  21. package/dist/chat/index.js +43 -14
  22. package/dist/chat/index.js.map +1 -1
  23. package/dist/{classPrivateFieldGet2-Bqby-AHD.js → classPrivateFieldGet2-Evpt0SEr.js} +5 -5
  24. package/dist/cli/index.d.ts +1 -1
  25. package/dist/cli/index.js.map +1 -1
  26. package/dist/client-D1kFXo80.js.map +1 -1
  27. package/dist/client.d.ts +1 -1
  28. package/dist/client.js.map +1 -1
  29. package/dist/codemode/ai.d.ts +1 -1
  30. package/dist/codemode/ai.js.map +1 -1
  31. package/dist/{compaction-helpers-CzCq1-fF.d.ts → compaction-helpers-DAe-xiVY.d.ts} +42 -17
  32. package/dist/{compaction-helpers-CSaqCmdE.js → compaction-helpers-DvcZnvQ1.js} +1 -1
  33. package/dist/{compaction-helpers-CSaqCmdE.js.map → compaction-helpers-DvcZnvQ1.js.map} +1 -1
  34. package/dist/{do-oauth-client-provider-C38aWbFV.d.ts → do-oauth-client-provider-4OKQU9rT.d.ts} +1 -1
  35. package/dist/{email-X72-zjuq.d.ts → email-J0GGS3sa.d.ts} +1 -1
  36. package/dist/email.d.ts +3 -3
  37. package/dist/email.js.map +1 -1
  38. package/dist/experimental/memory/session/index.d.ts +369 -56
  39. package/dist/experimental/memory/session/index.js +553 -138
  40. package/dist/experimental/memory/session/index.js.map +1 -1
  41. package/dist/experimental/memory/utils/index.d.ts +41 -5
  42. package/dist/experimental/memory/utils/index.js +15 -5
  43. package/dist/experimental/memory/utils/index.js.map +1 -1
  44. package/dist/experimental/webmcp.d.ts +9 -3
  45. package/dist/experimental/webmcp.js.map +1 -1
  46. package/dist/{index-Biv6K70p.d.ts → index-DKey3P4s.d.ts} +26 -2
  47. package/dist/index.d.ts +71 -67
  48. package/dist/index.js +211 -108
  49. package/dist/index.js.map +1 -1
  50. package/dist/{internal_context-BvuGZieY.d.ts → internal_context-BZrMS0B5.d.ts} +1 -1
  51. package/dist/internal_context.d.ts +1 -1
  52. package/dist/internal_context.js.map +1 -1
  53. package/dist/mcp/client.d.ts +26 -2
  54. package/dist/mcp/do-oauth-client-provider.d.ts +10 -2
  55. package/dist/mcp/do-oauth-client-provider.js.map +1 -1
  56. package/dist/mcp/index.d.ts +54 -2
  57. package/dist/mcp/index.js +2 -2
  58. package/dist/mcp/index.js.map +1 -1
  59. package/dist/mcp/x402.d.ts +74 -17
  60. package/dist/mcp/x402.js.map +1 -1
  61. package/dist/observability/index.d.ts +16 -2
  62. package/dist/observability/index.js +1 -1
  63. package/dist/observability/index.js.map +1 -1
  64. package/dist/react.d.ts +2 -2
  65. package/dist/react.js.map +1 -1
  66. package/dist/{retries-fLD8cGNf.d.ts → retries-BVdRl5ZE.d.ts} +1 -1
  67. package/dist/retries.d.ts +1 -1
  68. package/dist/retries.js.map +1 -1
  69. package/dist/schedule.js.map +1 -1
  70. package/dist/serializable.d.ts +1 -1
  71. package/dist/{shared-C6l4ZKRN.js → shared-CiKaIK4h.js} +4 -5
  72. package/dist/{shared-C6l4ZKRN.js.map → shared-CiKaIK4h.js.map} +1 -1
  73. package/dist/{shared-Ch9slKdI.d.ts → shared-Cvj92byG.d.ts} +1 -1
  74. package/dist/sub-routing.d.ts +6 -6
  75. package/dist/sub-routing.js.map +1 -1
  76. package/dist/tool-output-truncation-CH-khbZ3.js +98 -0
  77. package/dist/tool-output-truncation-CH-khbZ3.js.map +1 -0
  78. package/dist/{types-DAHCZC_W.d.ts → types-_JjKmv-l.d.ts} +1 -1
  79. package/dist/types.d.ts +1 -1
  80. package/dist/types.js.map +1 -1
  81. package/dist/utils.js.map +1 -1
  82. package/dist/vite.js.map +1 -1
  83. package/dist/{workflow-types-DHs0L0KP.d.ts → workflow-types-Dkzg4hAx.d.ts} +1 -1
  84. package/dist/workflow-types.d.ts +1 -1
  85. package/dist/workflow-types.js.map +1 -1
  86. package/dist/workflows.d.ts +2 -2
  87. package/dist/workflows.js.map +1 -1
  88. package/package.json +11 -11
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { __DO_NOT_USE_WILL_BREAK__agentContext } from "./internal_context.js";
2
2
  import { MessageType } from "./types.js";
3
- import { camelCaseToKebabCase } from "./utils.js";
3
+ import { camelCaseToKebabCase, isInternalJsStubProp } from "./utils.js";
4
4
  import { createHeaderBasedEmailResolver, signAgentHeaders } from "./email.js";
5
- import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, t as _classPrivateFieldGet2 } from "./classPrivateFieldGet2-Bqby-AHD.js";
5
+ import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, t as _classPrivateFieldGet2 } from "./classPrivateFieldGet2-Evpt0SEr.js";
6
6
  import { SUB_PREFIX, getSubAgentByName, parseSubAgentPath, routeSubAgentRequest } from "./sub-routing.js";
7
7
  import { isErrorRetryable, tryN, validateRetryOptions } from "./retries.js";
8
8
  import { o as RPC_DO_PREFIX, r as MCPConnectionState, s as DisposableStore, t as MCPClientManager } from "./client-D1kFXo80.js";
@@ -12,7 +12,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
12
12
  import { parseCronExpression } from "cron-schedule";
13
13
  import { nanoid } from "nanoid";
14
14
  import { EmailMessage } from "cloudflare:email";
15
- import { RpcTarget } from "cloudflare:workers";
15
+ import { RpcTarget, exports } from "cloudflare:workers";
16
16
  import { Server, getServerByName, routePartykitRequest } from "partyserver";
17
17
  //#region src/index.ts
18
18
  let _Symbol$dispose;
@@ -587,6 +587,7 @@ var Agent = class Agent extends Server {
587
587
  this._persistenceHookMode = "none";
588
588
  this._isFacet = false;
589
589
  this._suppressProtocolBroadcasts = false;
590
+ this._protocolBroadcastExcludeIds = /* @__PURE__ */ new Set();
590
591
  this._cf_virtualSubAgentConnections = /* @__PURE__ */ new Map();
591
592
  this._parentPath = [];
592
593
  this._insideOnStart = false;
@@ -770,8 +771,16 @@ var Agent = class Agent extends Server {
770
771
  type: "cf_agent_identity"
771
772
  }));
772
773
  }
773
- if (this.state) connection.send(JSON.stringify({
774
- state: this.state,
774
+ const wasExcludedFromStateInitBroadcast = this._protocolBroadcastExcludeIds.has(connection.id);
775
+ let currentState;
776
+ this._protocolBroadcastExcludeIds.add(connection.id);
777
+ try {
778
+ currentState = this.state;
779
+ } finally {
780
+ if (!wasExcludedFromStateInitBroadcast) this._protocolBroadcastExcludeIds.delete(connection.id);
781
+ }
782
+ if (currentState !== void 0) connection.send(JSON.stringify({
783
+ state: currentState,
775
784
  type: "cf_agent_state"
776
785
  }));
777
786
  connection.send(JSON.stringify({
@@ -823,14 +832,17 @@ var Agent = class Agent extends Server {
823
832
  this.broadcastMcpServers();
824
833
  this._checkOrphanedWorkflows();
825
834
  await this._checkRunFibers();
826
- await this._reconcileAgentToolRuns();
835
+ const recoveredAgentToolFinishes = await this._reconcileAgentToolRuns({ deferFinishHooks: true });
827
836
  this._insideOnStart = true;
828
837
  this._warnedScheduleInOnStart.clear();
838
+ let result;
829
839
  try {
830
- return await _onStart(props);
840
+ result = await _onStart(props);
831
841
  } finally {
832
842
  this._insideOnStart = false;
833
843
  }
844
+ await this._runDeferredAgentToolFinishHooks(recoveredAgentToolFinishes);
845
+ return result;
834
846
  });
835
847
  });
836
848
  };
@@ -866,7 +878,7 @@ var Agent = class Agent extends Server {
866
878
  */
867
879
  _broadcastProtocol(msg, excludeIds = []) {
868
880
  if (this._suppressProtocolBroadcasts) return;
869
- const exclude = [...excludeIds];
881
+ const exclude = [...excludeIds, ...this._protocolBroadcastExcludeIds];
870
882
  for (const conn of this.getConnections()) if (!this.isConnectionProtocolEnabled(conn)) exclude.push(conn.id);
871
883
  this.broadcast(msg, exclude);
872
884
  }
@@ -1101,7 +1113,7 @@ var Agent = class Agent extends Server {
1101
1113
  *
1102
1114
  * IMPORTANT: This hook must be synchronous.
1103
1115
  */
1104
- validateStateChange(nextState, source) {}
1116
+ validateStateChange(_nextState, _source) {}
1105
1117
  /**
1106
1118
  * Called after the Agent's state has been persisted and broadcast to all clients.
1107
1119
  * This is a notification hook — errors here are routed to onError and do not
@@ -1110,7 +1122,7 @@ var Agent = class Agent extends Server {
1110
1122
  * @param state Updated state
1111
1123
  * @param source Source of the state update ("server" or a client connection)
1112
1124
  */
1113
- onStateChanged(state, source) {}
1125
+ onStateChanged(_state, _source) {}
1114
1126
  /**
1115
1127
  * @deprecated Renamed to `onStateChanged` — the behavior is identical.
1116
1128
  * `onStateUpdate` will be removed in the next major version.
@@ -1122,7 +1134,7 @@ var Agent = class Agent extends Server {
1122
1134
  * @param state Updated state
1123
1135
  * @param source Source of the state update ("server" or a client connection)
1124
1136
  */
1125
- onStateUpdate(state, source) {}
1137
+ onStateUpdate(_state, _source) {}
1126
1138
  /**
1127
1139
  * Dispatch to the appropriate persistence hook based on the mode
1128
1140
  * cached in the constructor. No prototype walks at call time.
@@ -2398,11 +2410,16 @@ var Agent = class Agent extends Server {
2398
2410
  if (!this._isSameAgentPathPrefix(selfPath, ownerPath)) throw new Error(`Schedule owner path does not descend from ${JSON.stringify(selfPath)}.`);
2399
2411
  if (selfPath.length === ownerPath.length) {
2400
2412
  await this._executeScheduleCallback(row);
2401
- return;
2413
+ return true;
2402
2414
  }
2403
2415
  const next = ownerPath[selfPath.length];
2404
- if (!this.hasSubAgent(next.className, next.name)) throw new Error(`Scheduled sub-agent ${next.className} "${next.name}" no longer exists.`);
2405
- await (await this._cf_resolveSubAgent(next.className, next.name))._cf_dispatchScheduledCallback(ownerPath, row);
2416
+ if (!this.hasSubAgent(next.className, next.name)) {
2417
+ const stalePath = ownerPath.slice(0, selfPath.length + 1);
2418
+ if (this._isFacet) await (await this._rootAlarmOwner())._cf_cleanupFacetPrefix(stalePath);
2419
+ else await this._cf_cleanupFacetPrefix(stalePath);
2420
+ return false;
2421
+ }
2422
+ return (await this._cf_resolveSubAgent(next.className, next.name))._cf_dispatchScheduledCallback(ownerPath, row);
2406
2423
  }
2407
2424
  /**
2408
2425
  * Recursively destroy a descendant facet identified by
@@ -2586,7 +2603,7 @@ var Agent = class Agent extends Server {
2586
2603
  if (row.type === "interval") this.sql`UPDATE cf_agents_schedules SET running = 1, execution_started_at = ${now} WHERE id = ${row.id}`;
2587
2604
  if (row.owner_path) try {
2588
2605
  const ownerPath = JSON.parse(row.owner_path);
2589
- await this._cf_dispatchScheduledCallback(ownerPath, row);
2606
+ executed = await this._cf_dispatchScheduledCallback(ownerPath, row);
2590
2607
  } catch (e) {
2591
2608
  console.error(`error dispatching scheduled callback "${row.callback}"`, e);
2592
2609
  this._emit("schedule:error", {
@@ -2603,8 +2620,10 @@ var Agent = class Agent extends Server {
2603
2620
  `;
2604
2621
  continue;
2605
2622
  }
2606
- else await this._executeScheduleCallback(row);
2607
- executed = true;
2623
+ else {
2624
+ await this._executeScheduleCallback(row);
2625
+ executed = true;
2626
+ }
2608
2627
  if (this._destroyed) return;
2609
2628
  if (!executed) continue;
2610
2629
  if (row.type === "cron") {
@@ -3073,7 +3092,29 @@ var Agent = class Agent extends Server {
3073
3092
  * @internal
3074
3093
  */
3075
3094
  async _cf_invokeSubAgent(className, name, method, args) {
3076
- const handle = await this._cf_resolveSubAgent(className, name);
3095
+ const stub = await this._cf_resolveSubAgent(className, name);
3096
+ return await this._cf_invokeStubMethod(stub, className, method, args);
3097
+ }
3098
+ /**
3099
+ * Bridge method used by `parentAgent()` when the requested parent is
3100
+ * itself a facet (and therefore has no top-level env namespace).
3101
+ * The root receives the full root-first target path, then each hop
3102
+ * delegates to the next facet using that facet's own `ctx.facets`.
3103
+ *
3104
+ * @internal
3105
+ */
3106
+ async _cf_invokeSubAgentPath(path, method, args) {
3107
+ const [self, next, ...rest] = path;
3108
+ if (!self) throw new Error(`Sub-agent path invocation requires a non-empty path.`);
3109
+ const ownClassName = this.constructor.name;
3110
+ if (self.className !== ownClassName || self.name !== this.name) throw new Error(`Sub-agent path invocation reached ${ownClassName}("${this.name}") but expected ${self.className}("${self.name}").`);
3111
+ if (!next) return await this._cf_invokeStubMethod(this, this.constructor.name, method, args);
3112
+ const child = await this._cf_resolveSubAgent(next.className, next.name);
3113
+ if (rest.length === 0) return await this._cf_invokeStubMethod(child, next.className, method, args);
3114
+ return await child._cf_invokeSubAgentPath([next, ...rest], method, args);
3115
+ }
3116
+ async _cf_invokeStubMethod(stub, className, method, args) {
3117
+ const handle = stub;
3077
3118
  if (typeof handle[method] !== "function") throw new Error(`Method "${method}" not found on ${className}.`);
3078
3119
  return await handle[method](...args);
3079
3120
  }
@@ -3097,11 +3138,11 @@ var Agent = class Agent extends Server {
3097
3138
  *
3098
3139
  * The facet's name (and `this.name` getter) is handled entirely by
3099
3140
  * partyserver via `ctx.id.name`, which is populated because the
3100
- * parent passed an explicit `id: parentNs.idFromName(name)` to
3141
+ * parent passed an explicit named Durable Object id to
3101
3142
  * `ctx.facets.get()` — see {@link _cf_resolveSubAgent}. No
3102
3143
  * `setName()` call or `__ps_name` storage write is needed; the
3103
- * facet's name survives cold wake automatically because the
3104
- * factory re-runs and `idFromName` is deterministic.
3144
+ * facet's name survives cold wake automatically because the factory
3145
+ * re-runs and `idFromName` is deterministic.
3105
3146
  *
3106
3147
  * @internal Called by {@link subAgent}.
3107
3148
  */
@@ -3148,26 +3189,33 @@ var Agent = class Agent extends Server {
3148
3189
  }];
3149
3190
  }
3150
3191
  /**
3151
- * Resolve a typed RPC stub for this facet's **immediate** parent
3192
+ * Resolve a typed parent stub for this facet's **immediate** parent
3152
3193
  * agent.
3153
3194
  *
3154
3195
  * Symmetric with `subAgent(Cls, name)`: while `subAgent` opens a
3155
3196
  * stub from parent to child, `parentAgent` opens one from child
3156
3197
  * to parent. Pass the direct parent's class reference — the
3157
3198
  * framework verifies it matches the last entry of
3158
- * `this.parentPath` at runtime, then looks up `env[Cls.name]` to
3159
- * find the namespace binding.
3199
+ * `this.parentPath` at runtime. If the parent is a top-level
3200
+ * Durable Object, the framework returns the normal namespace stub.
3201
+ * If the parent is itself a facet, the framework returns a bridge
3202
+ * proxy that routes method calls through the root/supervisor and
3203
+ * then down the recorded facet path.
3160
3204
  *
3161
3205
  * `this.parentPath` is root-first, so the direct parent is the
3162
3206
  * **last** entry: `this.parentPath.at(-1)`. For grandparents and
3163
3207
  * further ancestors, iterate `this.parentPath` and use
3164
3208
  * `getAgentByName(env.X, this.parentPath[i].name)` directly.
3165
3209
  *
3166
- * Assumes the standard "binding name matches class name" convention.
3167
- * If your `wrangler.jsonc` binds the parent under a different name
3168
- * (e.g. `{ class_name: "Inbox", name: "MY_INBOX" }`), call
3169
- * `getAgentByName(env.MY_INBOX, this.parentPath.at(-1)!.name)`
3170
- * directly instead.
3210
+ * For top-level parents, the framework first checks `env[Cls.name]`,
3211
+ * then falls back to the Worker `exports` object. This supports
3212
+ * custom binding names as long as the parent class is exported under
3213
+ * its class name.
3214
+ *
3215
+ * Facet-parent stubs route normal HTTP `.fetch()` calls through the
3216
+ * same root bridge as RPC methods. WebSocket upgrade requests are
3217
+ * not supported yet because WebSocket handles cannot be serialized
3218
+ * over RPC.
3171
3219
  *
3172
3220
  * @experimental The API surface may change before stabilizing.
3173
3221
  *
@@ -3175,7 +3223,8 @@ var Agent = class Agent extends Server {
3175
3223
  * @throws If `Cls.name` doesn't match the recorded direct-parent
3176
3224
  * class (guards against accidentally reaching the wrong
3177
3225
  * DO, especially in nested Root → Mid → Leaf chains).
3178
- * @throws If no env binding named `Cls.name` is found.
3226
+ * @throws If no namespace is found for a top-level parent, or no
3227
+ * root namespace is available for a facet parent bridge.
3179
3228
  *
3180
3229
  * @example
3181
3230
  * ```ts
@@ -3192,10 +3241,46 @@ var Agent = class Agent extends Server {
3192
3241
  const parent = this._parentPath[this._parentPath.length - 1];
3193
3242
  if (!parent) throw new Error(`parentAgent(): ${this.constructor.name} is not a facet — only sub-agents (spawned via \`subAgent()\`) have a parent.`);
3194
3243
  if (cls.name !== parent.className) throw new Error(`parentAgent(${cls.name}): this facet's recorded parent class is "${parent.className}", not "${cls.name}". Pass the class whose constructor actually spawned this facet.`);
3195
- const binding = this.env[cls.name];
3196
- if (!binding) throw new Error(`parentAgent(${cls.name}): no top-level binding "${cls.name}" found in env. If the parent is bound under a different name (e.g. "MY_${cls.name.toUpperCase()}"), use \`getAgentByName(env.MY_${cls.name.toUpperCase()}, this.parentPath.at(-1)!.name)\` directly.`);
3244
+ if (this._parentPath.length > 1) return await this._cf_parentAgentFacetProxy(cls.name, this._parentPath);
3245
+ const binding = this._cf_getTopLevelNamespaceByClassName(cls.name);
3246
+ if (!binding) throw new Error(`parentAgent(${cls.name}): no top-level namespace for "${cls.name}" was found in env or worker exports. Make sure the parent class is exported under that class name and registered as a Durable Object binding.`);
3197
3247
  return await getServerByName(binding, parent.name);
3198
3248
  }
3249
+ _cf_getTopLevelNamespaceByClassName(className) {
3250
+ return this._cf_asDurableObjectNamespace(this.env[className]) ?? this._cf_asDurableObjectNamespace(exports[className]);
3251
+ }
3252
+ _cf_asDurableObjectNamespace(candidate) {
3253
+ const binding = candidate;
3254
+ return binding?.idFromName ? binding : void 0;
3255
+ }
3256
+ async _cf_parentAgentFacetProxy(className, parentPath) {
3257
+ const [root] = parentPath;
3258
+ if (!root) throw new Error(`parentAgent(${className}): parent path is empty.`);
3259
+ const rootBinding = this._cf_getTopLevelNamespaceByClassName(root.className);
3260
+ if (!rootBinding) throw new Error(`parentAgent(${className}): direct parent is a facet, but no top-level root namespace "${root.className}" was found in env or worker exports to bridge the call.`);
3261
+ const rootStubPromise = getServerByName(rootBinding, root.name);
3262
+ const targetPath = parentPath.map((step) => ({ ...step }));
3263
+ const invokeBridge = async (method, args) => {
3264
+ return await (await rootStubPromise)._cf_invokeSubAgentPath(targetPath, method, args);
3265
+ };
3266
+ const owner = this;
3267
+ return new Proxy({}, { get(_target, prop) {
3268
+ if (isInternalJsStubProp(prop)) return void 0;
3269
+ if (typeof prop !== "string") return void 0;
3270
+ if (prop === "fetch") return async (input, init) => {
3271
+ if (owner._cf_isWebSocketUpgradeRequest(input, init)) throw new Error(`parentAgent(${className}).fetch() does not support WebSocket upgrade requests yet. Use externally routed sub-agent URLs for WebSocket connections.`);
3272
+ return await invokeBridge(prop, [input, init]);
3273
+ };
3274
+ return async (...args) => {
3275
+ return await invokeBridge(prop, args);
3276
+ };
3277
+ } });
3278
+ }
3279
+ _cf_isWebSocketUpgradeRequest(input, init) {
3280
+ const initHeaders = init?.headers ? new Headers(init.headers) : void 0;
3281
+ const requestHeaders = input instanceof Request ? new Headers(input.headers) : void 0;
3282
+ return initHeaders?.get("Upgrade")?.toLowerCase() === "websocket" || requestHeaders?.get("Upgrade")?.toLowerCase() === "websocket";
3283
+ }
3199
3284
  /**
3200
3285
  * Get or create a named sub-agent — a child Durable Object (facet)
3201
3286
  * with its own isolated SQLite storage running on the same machine.
@@ -3238,7 +3323,7 @@ var Agent = class Agent extends Server {
3238
3323
  } catch {}
3239
3324
  return this._resultFromAgentToolRow(existing);
3240
3325
  }
3241
- return await this._replayAndInterruptAgentToolRun(cls, existing, "Agent tool run was still running, but live-tail reattachment is not supported in this runtime.");
3326
+ return await this._replayAndInterruptAgentToolRun(existing, "Agent tool run was still running, but live-tail reattachment is not supported in this runtime.");
3242
3327
  }
3243
3328
  const displayOrder = options.displayOrder ?? 0;
3244
3329
  const inputPreview = options.inputPreview ?? this._defaultAgentToolPreview(options.input);
@@ -3321,13 +3406,7 @@ var Agent = class Agent extends Server {
3321
3406
  status: "aborted",
3322
3407
  error: options.signal.reason instanceof Error ? options.signal.reason.message : String(options.signal.reason ?? "cancelled")
3323
3408
  };
3324
- this._updateAgentToolTerminal(runId, result);
3325
- this._broadcastAgentToolTerminal(options.parentToolCallId, sequence, result);
3326
- await this.onAgentToolFinish({
3327
- ...runInfo,
3328
- status: "aborted",
3329
- completedAt: Date.now()
3330
- }, result);
3409
+ await this._finishAgentToolRun(runInfo, result, { sequence });
3331
3410
  return result;
3332
3411
  } else {
3333
3412
  parentAbortListener = () => {
@@ -3351,24 +3430,15 @@ var Agent = class Agent extends Server {
3351
3430
  status: "aborted",
3352
3431
  error: options.signal.reason instanceof Error ? options.signal.reason.message : String(options.signal.reason ?? "cancelled")
3353
3432
  };
3354
- this._updateAgentToolTerminal(runId, result);
3355
- this._broadcastAgentToolTerminal(options.parentToolCallId, sequence, result);
3356
- await this.onAgentToolFinish({
3357
- ...runInfo,
3358
- status: "aborted",
3359
- completedAt: Date.now()
3360
- }, result);
3433
+ await this._finishAgentToolRun(runInfo, result, { sequence });
3361
3434
  return result;
3362
3435
  }
3363
3436
  const inspection = await adapter.inspectAgentToolRun(runId) ?? childStart;
3364
3437
  const result = this._terminalResultFromInspection(agentType, inspection);
3365
- this._updateAgentToolTerminal(runId, result, inspection.completedAt);
3366
- this._broadcastAgentToolTerminal(options.parentToolCallId, sequence, result);
3367
- await this.onAgentToolFinish({
3368
- ...runInfo,
3369
- status: result.status,
3370
- completedAt: Date.now()
3371
- }, result);
3438
+ await this._finishAgentToolRun(runInfo, result, {
3439
+ sequence,
3440
+ completedAt: inspection.completedAt
3441
+ });
3372
3442
  return result;
3373
3443
  } catch (error) {
3374
3444
  if (options.signal?.aborted) {
@@ -3379,13 +3449,7 @@ var Agent = class Agent extends Server {
3379
3449
  status: "aborted",
3380
3450
  error: options.signal.reason instanceof Error ? options.signal.reason.message : String(options.signal.reason ?? "cancelled")
3381
3451
  };
3382
- this._updateAgentToolTerminal(runId, result);
3383
- this._broadcastAgentToolTerminal(options.parentToolCallId, sequence, result);
3384
- await this.onAgentToolFinish({
3385
- ...runInfo,
3386
- status: "aborted",
3387
- completedAt: Date.now()
3388
- }, result);
3452
+ await this._finishAgentToolRun(runInfo, result, { sequence });
3389
3453
  return result;
3390
3454
  }
3391
3455
  const result = {
@@ -3394,13 +3458,7 @@ var Agent = class Agent extends Server {
3394
3458
  status: "error",
3395
3459
  error: error instanceof Error ? error.message : String(error)
3396
3460
  };
3397
- this._updateAgentToolTerminal(runId, result);
3398
- this._broadcastAgentToolTerminal(options.parentToolCallId, sequence, result);
3399
- await this.onAgentToolFinish({
3400
- ...runInfo,
3401
- status: "error",
3402
- completedAt: Date.now()
3403
- }, result);
3461
+ await this._finishAgentToolRun(runInfo, result, { sequence });
3404
3462
  return result;
3405
3463
  } finally {
3406
3464
  if (parentAbortListener && options.signal) options.signal.removeEventListener("abort", parentAbortListener);
@@ -3481,6 +3539,19 @@ var Agent = class Agent extends Server {
3481
3539
  ...row.error_message !== null ? { error: row.error_message } : {}
3482
3540
  };
3483
3541
  }
3542
+ _agentToolRunInfoFromRow(row, status = row.status, completedAt = row.completed_at ?? void 0) {
3543
+ return {
3544
+ runId: row.run_id,
3545
+ parentToolCallId: row.parent_tool_call_id ?? void 0,
3546
+ agentType: row.agent_type,
3547
+ inputPreview: this._parseAgentToolJson(row.input_preview),
3548
+ status,
3549
+ display: this._parseAgentToolJson(row.display_metadata),
3550
+ displayOrder: row.display_order,
3551
+ startedAt: row.started_at,
3552
+ completedAt
3553
+ };
3554
+ }
3484
3555
  _terminalResultFromInspection(agentType, inspection) {
3485
3556
  if (inspection.status === "completed") return {
3486
3557
  runId: inspection.runId,
@@ -3502,6 +3573,27 @@ var Agent = class Agent extends Server {
3502
3573
  error: inspection.error ?? "Agent tool run failed"
3503
3574
  };
3504
3575
  }
3576
+ async _finishAgentToolRun(run, result, options) {
3577
+ const completedAt = options?.completedAt ?? Date.now();
3578
+ this._updateAgentToolTerminal(run.runId, result, completedAt);
3579
+ if (options?.sequence !== void 0) this._broadcastAgentToolTerminal(run.parentToolCallId, options.sequence, result);
3580
+ const finish = () => this.onAgentToolFinish({
3581
+ ...run,
3582
+ status: result.status,
3583
+ completedAt
3584
+ }, result);
3585
+ if (options?.deferFinishHook) return finish;
3586
+ await finish();
3587
+ }
3588
+ async _runDeferredAgentToolFinishHooks(hooks) {
3589
+ for (const hook of hooks) try {
3590
+ await hook();
3591
+ } catch (error) {
3592
+ try {
3593
+ await this.onError(error);
3594
+ } catch {}
3595
+ }
3596
+ }
3505
3597
  _updateAgentToolTerminal(runId, result, completedAt = Date.now()) {
3506
3598
  this.sql`
3507
3599
  UPDATE cf_agent_tool_runs
@@ -3561,6 +3653,11 @@ var Agent = class Agent extends Server {
3561
3653
  }, replay, connection);
3562
3654
  return next;
3563
3655
  }
3656
+ async _broadcastAgentToolStoredChunks(row, sequence, replay, connection) {
3657
+ const child = await this._cf_resolveSubAgent(row.agent_type, row.run_id);
3658
+ const chunks = await this._asAgentToolChildAdapter(child).getAgentToolChunks(row.run_id);
3659
+ return this._broadcastAgentToolChunks(row.parent_tool_call_id ?? void 0, row.run_id, chunks, sequence, replay, connection);
3660
+ }
3564
3661
  async _forwardAgentToolStream(stream, parentToolCallId, runId, sequence, signal) {
3565
3662
  let next = sequence;
3566
3663
  if (signal?.aborted) return next;
@@ -3656,13 +3753,10 @@ var Agent = class Agent extends Server {
3656
3753
  if (!cls) throw new Error(`Agent tool class "${className}" is not exported.`);
3657
3754
  return cls;
3658
3755
  }
3659
- async _replayAndInterruptAgentToolRun(cls, row, message) {
3660
- const parentToolCallId = row.parent_tool_call_id ?? void 0;
3756
+ async _replayAndInterruptAgentToolRun(row, message) {
3661
3757
  let sequence = 1;
3662
3758
  try {
3663
- const child = await this.subAgent(cls, row.run_id);
3664
- const chunks = await this._asAgentToolChildAdapter(child).getAgentToolChunks(row.run_id);
3665
- sequence = this._broadcastAgentToolChunks(parentToolCallId, row.run_id, chunks, sequence);
3759
+ sequence = await this._broadcastAgentToolStoredChunks(row, sequence);
3666
3760
  } catch {}
3667
3761
  const result = {
3668
3762
  runId: row.run_id,
@@ -3670,8 +3764,7 @@ var Agent = class Agent extends Server {
3670
3764
  status: "interrupted",
3671
3765
  error: message
3672
3766
  };
3673
- this._updateAgentToolTerminal(row.run_id, result);
3674
- this._broadcastAgentToolTerminal(parentToolCallId, sequence, result);
3767
+ await this._finishAgentToolRun(this._agentToolRunInfoFromRow(row), result, { sequence });
3675
3768
  return result;
3676
3769
  }
3677
3770
  async _replayAgentToolRuns(connection) {
@@ -3693,9 +3786,7 @@ var Agent = class Agent extends Server {
3693
3786
  display: this._parseAgentToolJson(row.display_metadata)
3694
3787
  }, true, connection);
3695
3788
  try {
3696
- const child = await this.subAgent(this._agentToolClassByName(row.agent_type), row.run_id);
3697
- const chunks = await this._asAgentToolChildAdapter(child).getAgentToolChunks(row.run_id);
3698
- sequence = this._broadcastAgentToolChunks(parentToolCallId, row.run_id, chunks, sequence, true, connection);
3789
+ sequence = await this._broadcastAgentToolStoredChunks(row, sequence, true, connection);
3699
3790
  } catch {}
3700
3791
  if (this._isAgentToolTerminal(row.status)) this._broadcastAgentToolTerminal(parentToolCallId, sequence, {
3701
3792
  runId: row.run_id,
@@ -3707,40 +3798,52 @@ var Agent = class Agent extends Server {
3707
3798
  }, true, connection);
3708
3799
  }
3709
3800
  }
3710
- async _reconcileAgentToolRuns() {
3801
+ async _reconcileAgentToolRuns(options) {
3802
+ const deferredFinishes = [];
3711
3803
  const rows = this.sql`
3712
- SELECT run_id, agent_type FROM cf_agent_tool_runs
3804
+ SELECT run_id, parent_tool_call_id, agent_type, input_preview, status,
3805
+ summary, output_json, error_message, display_metadata, display_order,
3806
+ started_at, completed_at
3807
+ FROM cf_agent_tool_runs
3713
3808
  WHERE status IN ('starting', 'running')
3714
3809
  ORDER BY started_at ASC
3715
3810
  `;
3716
- for (const row of rows) try {
3717
- const cls = this._agentToolClassByName(row.agent_type);
3718
- if (!this.hasSubAgent(cls, row.run_id)) {
3719
- this._updateAgentToolTerminal(row.run_id, {
3811
+ for (const row of rows) {
3812
+ let sequence = 1;
3813
+ let completedAt;
3814
+ let result;
3815
+ try {
3816
+ const child = await this._cf_resolveSubAgent(row.agent_type, row.run_id);
3817
+ const inspection = await this._asAgentToolChildAdapter(child).inspectAgentToolRun(row.run_id);
3818
+ try {
3819
+ sequence = await this._broadcastAgentToolStoredChunks(row, sequence);
3820
+ } catch {}
3821
+ if (!inspection || inspection.status === "running" || inspection.status === "starting") result = {
3720
3822
  runId: row.run_id,
3721
3823
  agentType: row.agent_type,
3722
3824
  status: "interrupted",
3723
- error: "Agent tool child was not found during parent recovery."
3724
- });
3725
- continue;
3825
+ error: "Agent tool run was still running, but live-tail reattachment is not supported in this runtime."
3826
+ };
3827
+ else {
3828
+ result = this._terminalResultFromInspection(row.agent_type, inspection);
3829
+ completedAt = inspection.completedAt;
3830
+ }
3831
+ } catch {
3832
+ result = {
3833
+ runId: row.run_id,
3834
+ agentType: row.agent_type,
3835
+ status: "interrupted",
3836
+ error: "Agent tool run could not be inspected during parent recovery."
3837
+ };
3726
3838
  }
3727
- const child = await this.subAgent(cls, row.run_id);
3728
- const inspection = await this._asAgentToolChildAdapter(child).inspectAgentToolRun(row.run_id);
3729
- if (!inspection || inspection.status === "running" || inspection.status === "starting") this._updateAgentToolTerminal(row.run_id, {
3730
- runId: row.run_id,
3731
- agentType: row.agent_type,
3732
- status: "interrupted",
3733
- error: "Agent tool run was still running, but live-tail reattachment is not supported in this runtime."
3734
- });
3735
- else this._updateAgentToolTerminal(row.run_id, this._terminalResultFromInspection(row.agent_type, inspection), inspection.completedAt);
3736
- } catch {
3737
- this._updateAgentToolTerminal(row.run_id, {
3738
- runId: row.run_id,
3739
- agentType: row.agent_type,
3740
- status: "interrupted",
3741
- error: "Agent tool run could not be inspected during parent recovery."
3839
+ const deferredFinish = await this._finishAgentToolRun(this._agentToolRunInfoFromRow(row), result, {
3840
+ sequence,
3841
+ completedAt,
3842
+ deferFinishHook: options?.deferFinishHooks
3742
3843
  });
3844
+ if (deferredFinish) deferredFinishes.push(deferredFinish);
3743
3845
  }
3846
+ return deferredFinishes;
3744
3847
  }
3745
3848
  /**
3746
3849
  * Shared facet resolution — takes a CamelCase class name string
@@ -3759,13 +3862,13 @@ var Agent = class Agent extends Server {
3759
3862
  if (!Cls) throw new Error(`Sub-agent class "${className}" not found in worker exports. Make sure the class is exported from your worker entry point and that the export name matches the class name.`);
3760
3863
  if (name.includes("\0")) throw new Error(`Sub-agent name contains null character (\\0), which is reserved.`);
3761
3864
  const facetKey = `${className}\0${name}`;
3762
- const parentClassName = this.constructor.name;
3763
- const parentNs = ctx.exports[parentClassName];
3764
- if (!parentNs?.idFromName) {
3765
- const minificationHint = /^_*[a-z][a-z0-9]{0,2}$/.test(parentClassName) ? ` The class name "${parentClassName}" looks minified — make sure your bundler preserves class names (e.g. esbuild's \`keepNames: true\`).` : "";
3766
- throw new Error(`Sub-agent bootstrap requires the parent class "${parentClassName}" to be bound as a Durable Object namespace, but ctx.exports["${parentClassName}"] is missing or doesn't expose idFromName.${minificationHint} Make sure the parent agent class is registered in your wrangler.jsonc durable_objects.bindings under its class name.`);
3865
+ const rootClassName = this._parentPath[0]?.className ?? this.constructor.name;
3866
+ const rootNs = ctx.exports[rootClassName];
3867
+ if (!rootNs?.idFromName) {
3868
+ const minificationHint = /^_*[a-z][a-z0-9]{0,2}$/.test(rootClassName) ? ` The class name "${rootClassName}" looks minified — make sure your bundler preserves class names (e.g. esbuild's \`keepNames: true\`).` : "";
3869
+ throw new Error(`Sub-agent bootstrap requires the root agent class "${rootClassName}" to be available as a Durable Object namespace, but ctx.exports["${rootClassName}"] is missing or doesn't expose idFromName.${minificationHint} Make sure the root agent class is exported under that class name and registered in your wrangler.jsonc durable_objects.bindings.`);
3767
3870
  }
3768
- const facetId = parentNs.idFromName(name);
3871
+ const facetId = rootNs.idFromName(name);
3769
3872
  const stub = ctx.facets.get(facetKey, () => ({
3770
3873
  class: Cls,
3771
3874
  id: facetId