agents 0.17.0 → 0.17.3

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.
@@ -2,7 +2,7 @@ import {
2
2
  O as Agent,
3
3
  ct as SubAgentClass,
4
4
  lt as SubAgentStub
5
- } from "../agent-tool-types-Cd1TZPfB.js";
5
+ } from "../agent-tool-types-CNyE1iz_.js";
6
6
  import { Lock, QueueEntry, StateAdapter } from "chat";
7
7
 
8
8
  //#region src/chat-sdk/agent.d.ts
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { O as Agent } from "./agent-tool-types-Cd1TZPfB.js";
1
+ import { O as Agent } from "./agent-tool-types-CNyE1iz_.js";
2
2
  import {
3
3
  ClientParameters,
4
4
  Method,
@@ -176,6 +176,15 @@ type AgentObservabilityEvent =
176
176
  type: string;
177
177
  }
178
178
  >
179
+ | BaseEvent<
180
+ "alarm:memory_limit_reset",
181
+ {
182
+ strikes: number;
183
+ limit: number;
184
+ sealed: boolean;
185
+ error: string;
186
+ }
187
+ >
179
188
  | BaseEvent<
180
189
  "queue:create",
181
190
  {
@@ -935,4 +944,4 @@ export {
935
944
  MCPObservabilityEvent as s,
936
945
  ChannelEventMap as t
937
946
  };
938
- //# sourceMappingURL=index-CcbnKkNh.d.ts.map
947
+ //# sourceMappingURL=index-BRnybD6X.d.ts.map
package/dist/index.d.ts CHANGED
@@ -81,13 +81,14 @@ import {
81
81
  x as ChatCapableAgentClass,
82
82
  y as AgentToolStoredChunk,
83
83
  z as EmailRoutingOptions
84
- } from "./agent-tool-types-Cd1TZPfB.js";
84
+ } from "./agent-tool-types-CNyE1iz_.js";
85
85
  import { n as camelCaseToKebabCase } from "./utils-CGtGDSgA.js";
86
86
  import {
87
- i as isPlatformTransientError,
87
+ a as isPlatformTransientError,
88
88
  n as isDurableObjectCodeUpdateReset,
89
+ r as isDurableObjectMemoryLimitReset,
89
90
  t as RetryOptions
90
- } from "./retries-CwlpAGet.js";
91
+ } from "./retries-CvHJwSuh.js";
91
92
  import {
92
93
  n as AgentsOAuthProvider,
93
94
  r as DurableObjectOAuthClientProvider,
@@ -179,6 +180,7 @@ export {
179
180
  getCurrentAgent,
180
181
  getSubAgentByName,
181
182
  isDurableObjectCodeUpdateReset,
183
+ isDurableObjectMemoryLimitReset,
182
184
  isPlatformTransientError,
183
185
  normalizeServerId,
184
186
  parseSubAgentPath,
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { camelCaseToKebabCase, isInternalJsStubProp } from "./utils.js";
5
5
  import { createHeaderBasedEmailResolver, signAgentHeaders } from "./email.js";
6
6
  import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, t as _classPrivateFieldGet2 } from "./classPrivateFieldGet2-DZBYAB34.js";
7
7
  import { SUB_PREFIX, getSubAgentByName, parseSubAgentPath, routeSubAgentRequest } from "./sub-routing.js";
8
- import { isDurableObjectCodeUpdateReset, isErrorRetryable, isPlatformTransientError, tryN, validateRetryOptions } from "./retries.js";
8
+ import { isDurableObjectCodeUpdateReset, isDurableObjectMemoryLimitReset, isErrorRetryable, isPlatformTransientError, tryN, validateRetryOptions } from "./retries.js";
9
9
  import { a as MCPConnectionState, c as RPC_DO_PREFIX, i as normalizeServerId, l as DisposableStore, n as MCP_SERVER_ID_MAX_LENGTH, t as MCPClientManager } from "./client-BZ-B3NhC.js";
10
10
  import { DurableObjectOAuthClientProvider } from "./mcp/do-oauth-client-provider.js";
11
11
  import { genericObservability } from "./observability/index.js";
@@ -327,7 +327,16 @@ const DEFAULT_AGENT_STATIC_OPTIONS = {
327
327
  */
328
328
  agentToolReattachMaxWindowMs: DEFAULT_AGENT_TOOL_REATTACH_MAX_WINDOW_MS,
329
329
  detachedMaxBudgetMs: DEFAULT_DETACHED_MAX_BUDGET_MS,
330
- detachedNoProgressBudgetMs: DEFAULT_DETACHED_NO_PROGRESS_BUDGET_MS
330
+ detachedNoProgressBudgetMs: DEFAULT_DETACHED_NO_PROGRESS_BUDGET_MS,
331
+ /**
332
+ * Consecutive alarm invocations that may end in a Durable Object memory-limit
333
+ * reset (the isolate exceeded its 128 MB limit) before the alarm-boundary
334
+ * circuit breaker stops the platform's auto-retry loop and seals the looping
335
+ * work (#1825). A small budget tolerates a genuinely transient memory spike;
336
+ * a deterministic OOM (the work's footprint, not the platform, is the cause)
337
+ * is bounded here regardless of whether the in-DO recovery budgets could run.
338
+ */
339
+ maxAlarmMemoryLimitStrikes: 3
331
340
  };
332
341
  /**
333
342
  * Parse the raw `retry_options` TEXT column from a SQLite row into a
@@ -454,7 +463,8 @@ var Agent = class Agent extends Server {
454
463
  agentToolReattachNoProgressTimeoutMs: ctor.options?.agentToolReattachNoProgressTimeoutMs ?? DEFAULT_AGENT_STATIC_OPTIONS.agentToolReattachNoProgressTimeoutMs,
455
464
  agentToolReattachMaxWindowMs: ctor.options?.agentToolReattachMaxWindowMs ?? DEFAULT_AGENT_STATIC_OPTIONS.agentToolReattachMaxWindowMs,
456
465
  detachedMaxBudgetMs: ctor.options?.detachedMaxBudgetMs ?? DEFAULT_AGENT_STATIC_OPTIONS.detachedMaxBudgetMs,
457
- detachedNoProgressBudgetMs: ctor.options?.detachedNoProgressBudgetMs ?? DEFAULT_AGENT_STATIC_OPTIONS.detachedNoProgressBudgetMs
466
+ detachedNoProgressBudgetMs: ctor.options?.detachedNoProgressBudgetMs ?? DEFAULT_AGENT_STATIC_OPTIONS.detachedNoProgressBudgetMs,
467
+ maxAlarmMemoryLimitStrikes: ctor.options?.maxAlarmMemoryLimitStrikes ?? DEFAULT_AGENT_STATIC_OPTIONS.maxAlarmMemoryLimitStrikes
458
468
  };
459
469
  return this._cachedOptions;
460
470
  }
@@ -3248,6 +3258,7 @@ var Agent = class Agent extends Server {
3248
3258
  const isOneShotSchedule = row.type === "delayed" || row.type === "scheduled";
3249
3259
  const shouldDeferReset = (error) => isOneShotSchedule && isDurableObjectCodeUpdateReset(error);
3250
3260
  const shouldDeferOnExhaustion = (error) => isOneShotSchedule && isPlatformTransientError(error);
3261
+ const shouldDeferMemoryLimit = (error) => isOneShotSchedule && isDurableObjectMemoryLimitReset(error);
3251
3262
  try {
3252
3263
  this._emit("schedule:execute", {
3253
3264
  callback: row.callback,
@@ -3275,6 +3286,10 @@ var Agent = class Agent extends Server {
3275
3286
  console.warn(`Deferring scheduled callback "${row.callback}" after exhausting in-process retries on a transient platform error; the one-shot row is preserved and the alarm will re-run once the platform recovers.`);
3276
3287
  throw e;
3277
3288
  }
3289
+ if (shouldDeferMemoryLimit(e)) {
3290
+ console.warn(`Deferring scheduled callback "${row.callback}" to the alarm memory-limit circuit breaker after a Durable Object memory-limit reset; the one-shot row is preserved so the breaker can bound the retry loop and seal it (#1825).`);
3291
+ throw e;
3292
+ }
3278
3293
  console.error(`error executing callback "${row.callback}" after ${maxAttempts} attempts`, e);
3279
3294
  this._emit("schedule:error", {
3280
3295
  callback: row.callback,
@@ -3386,6 +3401,20 @@ var Agent = class Agent extends Server {
3386
3401
  await this.destroy();
3387
3402
  return;
3388
3403
  }
3404
+ try {
3405
+ await this._cf_runAlarmBody();
3406
+ await this._cf_clearAlarmMemoryLimitStrikes();
3407
+ } catch (error) {
3408
+ if (!isDurableObjectMemoryLimitReset(error)) throw error;
3409
+ await this._cf_handleAlarmMemoryLimitReset(error);
3410
+ }
3411
+ }
3412
+ /**
3413
+ * The alarm body: PartyServer init + due-schedule processing + housekeeping +
3414
+ * next-alarm arm. Extracted from {@link alarm} so the memory-limit circuit
3415
+ * breaker can wrap it at the outermost frame (see {@link alarm}).
3416
+ */
3417
+ async _cf_runAlarmBody() {
3389
3418
  await super.alarm();
3390
3419
  const now = Math.floor(Date.now() / 1e3);
3391
3420
  const result = this.sql`
@@ -3436,7 +3465,9 @@ var Agent = class Agent extends Server {
3436
3465
  continue;
3437
3466
  }
3438
3467
  else {
3468
+ this._cf_executingScheduleRowId = row.id;
3439
3469
  await this._executeScheduleCallback(row);
3470
+ this._cf_executingScheduleRowId = void 0;
3440
3471
  executed = true;
3441
3472
  }
3442
3473
  if (this._destroyed) return;
@@ -3462,6 +3493,105 @@ var Agent = class Agent extends Server {
3462
3493
  await this._scheduleNextAlarm();
3463
3494
  }
3464
3495
  /**
3496
+ * The schedule-callback names whose alarm rows drive a recovery loop that can
3497
+ * deterministically OOM. The base agent has none; chat hosts (`Think`,
3498
+ * `AIChatAgent`) override this to return their recovery continuation callbacks
3499
+ * so the circuit breaker can surgically back them off / purge them WITHOUT
3500
+ * disturbing unrelated scheduled tasks. See {@link _cf_handleAlarmMemoryLimitReset}.
3501
+ */
3502
+ _cf_recoveryAlarmCallbacks() {
3503
+ return [];
3504
+ }
3505
+ /**
3506
+ * Hook for a host to terminalize ("seal") any in-flight recovery work as an
3507
+ * out-of-memory exhaustion when the alarm circuit breaker trips at its strike
3508
+ * budget (#1825). Runs at the outermost alarm frame (post-unwind, so writes
3509
+ * can land). Default: no-op. Chat hosts override to fire `onExhausted` + the
3510
+ * terminal banner and persist the sealed incident.
3511
+ */
3512
+ async _cf_sealMemoryLimitedRecovery() {}
3513
+ /**
3514
+ * Clear the durable memory-limit strike counter after a clean alarm so the
3515
+ * circuit breaker counts CONSECUTIVE resets rather than lifetime ones
3516
+ * (#1825). Reads first (cheap, usually cached) and only writes when a strike
3517
+ * is actually recorded, so the common no-strike path costs no write.
3518
+ * Best-effort: a stale strike only costs one extra tolerated spike later.
3519
+ */
3520
+ async _cf_clearAlarmMemoryLimitStrikes() {
3521
+ try {
3522
+ const prior = await this.ctx.storage.get(Agent._CF_OOM_ALARM_STRIKES_KEY);
3523
+ if (typeof prior === "number" && prior > 0) await this.ctx.storage.delete(Agent._CF_OOM_ALARM_STRIKES_KEY);
3524
+ } catch {}
3525
+ }
3526
+ /**
3527
+ * Alarm-boundary circuit breaker for Durable Object memory-limit resets
3528
+ * (#1825). The in-DO recovery budgets (`chatRecovery.maxOomRetries` /
3529
+ * `maxRecoveryWork`) only engage if their code runs AND its writes land; a
3530
+ * severe OOM can defeat both — thrown before the budget runs (boot hydration),
3531
+ * or its own small writes also OOM under memory pressure. In that case the
3532
+ * error reaches {@link alarm} and, unhandled, the platform auto-retries the
3533
+ * alarm indefinitely (re-running the doomed, billable turn each cycle).
3534
+ *
3535
+ * This runs at the OUTERMOST frame: the heavy turn has unwound and GC has
3536
+ * reclaimed its footprint, so the small writes here can land where mid-turn
3537
+ * ones (e.g. give-up's incident read) OOMed. A durable strike counter tolerates
3538
+ * a few resets (a transient spike may clear), backing off the recovery rows so
3539
+ * the retry is not a hot loop. At the `maxAlarmMemoryLimitStrikes` budget it
3540
+ * seals the recovery work and purges the looping rows so the loop — and the
3541
+ * bill — stops. Each step is best-effort: even these tiny writes can OOM, but
3542
+ * swallowing (not re-throwing) still halts the platform's auto-retry, and a
3543
+ * later wake re-arms legitimate schedules.
3544
+ */
3545
+ async _cf_handleAlarmMemoryLimitReset(error) {
3546
+ const key = Agent._CF_OOM_ALARM_STRIKES_KEY;
3547
+ let strikes = 1;
3548
+ try {
3549
+ const prior = await this.ctx.storage.get(key);
3550
+ strikes = (typeof prior === "number" ? prior : 0) + 1;
3551
+ await this.ctx.storage.put(key, strikes);
3552
+ } catch {}
3553
+ const limit = this._resolvedOptions.maxAlarmMemoryLimitStrikes;
3554
+ const sealed = strikes >= limit;
3555
+ const recoveryCallbacks = this._cf_recoveryAlarmCallbacks();
3556
+ const executingRowId = this._cf_executingScheduleRowId;
3557
+ this._cf_executingScheduleRowId = void 0;
3558
+ console.error(`Alarm hit a Durable Object memory-limit reset (strike ${strikes}/${limit}${sealed ? ", sealing recovery" : ", will retry with backoff"}). Breaking the platform alarm-retry loop (#1825).`, error instanceof Error ? error.message : String(error));
3559
+ if (sealed) {
3560
+ for (const cb of recoveryCallbacks) try {
3561
+ this.sql`DELETE FROM cf_agents_schedules WHERE callback = ${cb}`;
3562
+ } catch {}
3563
+ if (executingRowId) try {
3564
+ this.sql`DELETE FROM cf_agents_schedules WHERE id = ${executingRowId}`;
3565
+ } catch {}
3566
+ try {
3567
+ await this._cf_sealMemoryLimitedRecovery();
3568
+ } catch {}
3569
+ try {
3570
+ await this.ctx.storage.delete(key);
3571
+ } catch {}
3572
+ } else {
3573
+ const backoffSeconds = Math.min(300, 30 * strikes);
3574
+ const nextTime = Math.floor(Date.now() / 1e3) + backoffSeconds;
3575
+ for (const cb of recoveryCallbacks) try {
3576
+ this.sql`UPDATE cf_agents_schedules SET time = ${nextTime} WHERE callback = ${cb} AND time <= ${nextTime}`;
3577
+ } catch {}
3578
+ if (executingRowId) try {
3579
+ this.sql`UPDATE cf_agents_schedules SET time = ${nextTime} WHERE id = ${executingRowId} AND time <= ${nextTime}`;
3580
+ } catch {}
3581
+ }
3582
+ try {
3583
+ this._emit("alarm:memory_limit_reset", {
3584
+ strikes,
3585
+ limit,
3586
+ sealed,
3587
+ error: error instanceof Error ? error.message : String(error)
3588
+ });
3589
+ } catch {}
3590
+ try {
3591
+ await this._scheduleNextAlarm();
3592
+ } catch {}
3593
+ }
3594
+ /**
3465
3595
  * Intercept incoming HTTP/WS requests whose URL contains a
3466
3596
  * `/sub/{child-class}/{child-name}` marker and forward them to
3467
3597
  * the facet. The `onBeforeSubAgent` hook fires first (authorize,
@@ -6808,6 +6938,7 @@ var Agent = class Agent extends Server {
6808
6938
  }
6809
6939
  };
6810
6940
  Agent.options = { hibernate: true };
6941
+ Agent._CF_OOM_ALARM_STRIKES_KEY = "cf_agents:oom_alarm_strikes";
6811
6942
  const wrappedClasses = /* @__PURE__ */ new Set();
6812
6943
  /**
6813
6944
  * Route a request to the appropriate Agent
@@ -6986,6 +7117,6 @@ var StreamingResponse = class {
6986
7117
  }
6987
7118
  };
6988
7119
  //#endregion
6989
- export { AGENT_TOOL_MILESTONE_PART, AGENT_TOOL_PROGRESS_PART, Agent, DEFAULT_AGENT_STATIC_OPTIONS, DurableObjectOAuthClientProvider, MCP_SERVER_ID_MAX_LENGTH, MessageType, SUB_PREFIX, SqlError, StreamingResponse, __DO_NOT_USE_WILL_BREAK__agentContext, callable, camelCaseToKebabCase, createHeaderBasedEmailResolver, getAgentByName, getCurrentAgent, getSubAgentByName, isDurableObjectCodeUpdateReset, isPlatformTransientError, normalizeServerId, parseSubAgentPath, routeAgentEmail, routeAgentRequest, routeSubAgentRequest, unstable_callable };
7120
+ export { AGENT_TOOL_MILESTONE_PART, AGENT_TOOL_PROGRESS_PART, Agent, DEFAULT_AGENT_STATIC_OPTIONS, DurableObjectOAuthClientProvider, MCP_SERVER_ID_MAX_LENGTH, MessageType, SUB_PREFIX, SqlError, StreamingResponse, __DO_NOT_USE_WILL_BREAK__agentContext, callable, camelCaseToKebabCase, createHeaderBasedEmailResolver, getAgentByName, getCurrentAgent, getSubAgentByName, isDurableObjectCodeUpdateReset, isDurableObjectMemoryLimitReset, isPlatformTransientError, normalizeServerId, parseSubAgentPath, routeAgentEmail, routeAgentRequest, routeSubAgentRequest, unstable_callable };
6990
7121
 
6991
7122
  //# sourceMappingURL=index.js.map