agents 0.28.1 → 0.30.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 (115) hide show
  1. package/dist/{agent-routing-BMvWTFEp.d.ts → agent-routing-CDbpVjYq.d.ts} +7 -8
  2. package/dist/agent-routing.d.ts +1 -1
  3. package/dist/agent-tool-types.d.ts +1 -1
  4. package/dist/{agent-tools-ohoewW-B.d.ts → agent-tools-C8DH8Yii.d.ts} +2 -2
  5. package/dist/agent-tools.d.ts +1 -1
  6. package/dist/{ai-ahruGw7e.d.ts → ai-iXw0uOGj.d.ts} +3 -3
  7. package/dist/{ai-sdk-C2iTAwUd.js → ai-sdk-DRPh2rRa.js} +185 -125
  8. package/dist/ai-sdk-DRPh2rRa.js.map +1 -0
  9. package/dist/browser/ai.d.ts +1 -1
  10. package/dist/browser/ai.js +2 -2
  11. package/dist/browser/index.d.ts +8 -8
  12. package/dist/browser/index.js +3 -3
  13. package/dist/browser/tools/ai-sdk.d.ts +2 -2
  14. package/dist/browser/tools/ai-sdk.js +1 -1
  15. package/dist/browser/tools/pi.d.ts +7 -3
  16. package/dist/browser/tools/pi.js +9 -5
  17. package/dist/browser/tools/pi.js.map +1 -1
  18. package/dist/browser/tools/tanstack-ai.d.ts +2 -2
  19. package/dist/browser/tools/tanstack-ai.js +1 -1
  20. package/dist/{browser-CEdNlsaD.js → browser-DccPw_wW.js} +130 -79
  21. package/dist/browser-DccPw_wW.js.map +1 -0
  22. package/dist/{browser-D30VlpcA.d.ts → browser-DlXhSAdf.d.ts} +41 -37
  23. package/dist/{browser-tool-4iomavs_.js → browser-tool-B1mhifin.js} +3 -3
  24. package/dist/{browser-tool-4iomavs_.js.map → browser-tool-B1mhifin.js.map} +1 -1
  25. package/dist/{browser-tool-vtrPOV8e.d.ts → browser-tool-Cxjk5sgG.d.ts} +2 -2
  26. package/dist/chat/index.d.ts +143 -71
  27. package/dist/chat/index.js +269 -110
  28. package/dist/chat/index.js.map +1 -1
  29. package/dist/chat-sdk/index.d.ts +1 -1
  30. package/dist/chat-sdk/index.js +1 -1
  31. package/dist/cli.js +53 -52
  32. package/dist/{client-Bp-JwL3p.d.ts → client-C27CtRZr.d.ts} +2 -2
  33. package/dist/client.d.ts +1 -1
  34. package/dist/{connector-DEXzVoaY.d.ts → connector-20DJ6p4k.d.ts} +2 -2
  35. package/dist/{connector-CtZylXdk.js → connector-DAXBOIIi.js} +2 -2
  36. package/dist/{connector-CtZylXdk.js.map → connector-DAXBOIIi.js.map} +1 -1
  37. package/dist/experimental/channels/web/index.js +1 -1
  38. package/dist/harness/container/index.js +1 -1
  39. package/dist/harness/container/index.js.map +1 -1
  40. package/dist/harness/opencode/index.js +1 -1
  41. package/dist/harness/pi/index.d.ts +70 -40
  42. package/dist/harness/pi/index.js +266 -330
  43. package/dist/harness/pi/index.js.map +1 -1
  44. package/dist/{images-C4hiIexM.js → images-xaDv2Fqe.js} +636 -168
  45. package/dist/images-xaDv2Fqe.js.map +1 -0
  46. package/dist/index-DCxk3OSJ.d.ts +378 -0
  47. package/dist/{index-kbSUIer3.d.ts → index-iv9FTXX9.d.ts} +80 -112
  48. package/dist/index.d.ts +1 -1
  49. package/dist/index.js +1 -1
  50. package/dist/{input-schema-xBofjBKC.js → input-schema-B0Etuo-o.js} +2 -2
  51. package/dist/{input-schema-xBofjBKC.js.map → input-schema-B0Etuo-o.js.map} +1 -1
  52. package/dist/lifecycle/index.js +1 -1
  53. package/dist/{lifecycle-DGorpAmA.js → lifecycle-v1rKHV2C.js} +67 -19
  54. package/dist/lifecycle-v1rKHV2C.js.map +1 -0
  55. package/dist/mcp/client/index.d.ts +1 -1
  56. package/dist/mcp/index.d.ts +1 -1
  57. package/dist/mcp/index.js +1 -1
  58. package/dist/models/ai-sdk/index.d.ts +29 -352
  59. package/dist/models/ai-sdk/index.js +1 -1
  60. package/dist/models/opencode/index.d.ts +25 -13
  61. package/dist/models/opencode/index.js +16 -11
  62. package/dist/models/opencode/index.js.map +1 -1
  63. package/dist/models/pi-ai/index.d.ts +13 -14
  64. package/dist/models/pi-ai/index.js +87 -34
  65. package/dist/models/pi-ai/index.js.map +1 -1
  66. package/dist/react.d.ts +2 -2
  67. package/dist/routing/index.d.ts +1 -1
  68. package/dist/serializable.d.ts +1 -1
  69. package/dist/{session-store-DoPY12xM.d.ts → session-store-_IK6dV-w.d.ts} +14 -2
  70. package/dist/{session-store-Do4xkDcf.js → session-store-yvwq1f9x.js} +55 -2
  71. package/dist/session-store-yvwq1f9x.js.map +1 -0
  72. package/dist/{settings-BjAiPd6Z.js → settings-Dk2il2Hf.js} +4 -1
  73. package/dist/settings-Dk2il2Hf.js.map +1 -0
  74. package/dist/skills/index.d.ts +22 -28
  75. package/dist/skills/index.js +183 -143
  76. package/dist/skills/index.js.map +1 -1
  77. package/dist/{src-CQxJFv4l.js → src-DfLzdwlK.js} +3 -3
  78. package/dist/src-DfLzdwlK.js.map +1 -0
  79. package/dist/sub-routing.d.ts +1 -1
  80. package/dist/{tool-VF0qiO7q.js → tool-DkT_DJBm.js} +2 -2
  81. package/dist/tool-DkT_DJBm.js.map +1 -0
  82. package/dist/transport-CPh7YGiw.d.ts +623 -0
  83. package/dist/voice/index.d.ts +1 -1
  84. package/dist/web/fetch/tools/pi.d.ts +10 -6
  85. package/dist/web/fetch/tools/pi.js +12 -8
  86. package/dist/web/fetch/tools/pi.js.map +1 -1
  87. package/dist/web/search/index.js +1 -1
  88. package/dist/web/search/tools/ai-sdk.js +2 -2
  89. package/dist/web/search/tools/pi.d.ts +10 -6
  90. package/dist/web/search/tools/pi.js +13 -9
  91. package/dist/web/search/tools/pi.js.map +1 -1
  92. package/dist/web/search/tools/tanstack-ai.js +2 -2
  93. package/dist/websockets/index.js +1 -1
  94. package/dist/{websockets-C3zy8YR0.js → websockets-CyoeosdO.js} +2 -2
  95. package/dist/{websockets-C3zy8YR0.js.map → websockets-CyoeosdO.js.map} +1 -1
  96. package/dist/workflow-types.d.ts +1 -1
  97. package/dist/workflows.d.ts +1 -1
  98. package/dist/workflows.js +1 -1
  99. package/docs/browse-the-web.md +1 -1
  100. package/docs/chat-agents.md +19 -18
  101. package/docs/harnesses/pi.md +101 -38
  102. package/docs/lifecycle.md +7 -1
  103. package/docs/models-pi-ai.md +66 -20
  104. package/docs/models.md +197 -172
  105. package/package.json +12 -7
  106. package/dist/ai-sdk-C2iTAwUd.js.map +0 -1
  107. package/dist/browser-CEdNlsaD.js.map +0 -1
  108. package/dist/images-C4hiIexM.js.map +0 -1
  109. package/dist/lifecycle-DGorpAmA.js.map +0 -1
  110. package/dist/session-store-Do4xkDcf.js.map +0 -1
  111. package/dist/settings-BjAiPd6Z.js.map +0 -1
  112. package/dist/settings-DnD__xuE.d.ts +0 -349
  113. package/dist/src-CQxJFv4l.js.map +0 -1
  114. package/dist/tool-VF0qiO7q.js.map +0 -1
  115. package/dist/transport-DCyarnwm.d.ts +0 -200
@@ -9,7 +9,7 @@ import {
9
9
  _ as FiberRecoveryContext$1,
10
10
  at as isPositionlessAgentToolChunk,
11
11
  z as AgentToolEventState
12
- } from "../agent-routing-BMvWTFEp.js";
12
+ } from "../agent-routing-CDbpVjYq.js";
13
13
  import { _ as TaskStep, m as TaskRunOptions } from "../tasks-E89KdwkS.js";
14
14
  import {
15
15
  n as ClientToolSchema,
@@ -34,7 +34,7 @@ import {
34
34
  r as AgentToolProgressEmitResult,
35
35
  s as interceptAgentToolBroadcast,
36
36
  t as AgentToolBroadcastHooks
37
- } from "../agent-tools-ohoewW-B.js";
37
+ } from "../agent-tools-C8DH8Yii.js";
38
38
  import { l as SessionMessage } from "../types-B7LojTe4.js";
39
39
  import { ModelMessage, UIMessage } from "ai";
40
40
  import { Connection, FiberRecoveryContext } from "agents";
@@ -578,9 +578,11 @@ type ChatRecoveryExhaustedContext = Pick<
578
578
  * - `work_budget_exceeded` — the turn kept producing content but exceeded the
579
579
  * configured `maxRecoveryWork` runaway-loop budget.
580
580
  * - `recovery_aborted` — the caller's `shouldKeepRecovering` hook returned `false`.
581
- * - `out_of_memory` — recovery attempts kept hitting a Durable Object
582
- * memory-limit reset (the isolate exceeded its 128 MB limit) until the
583
- * tight `maxOomRetries` budget drained (#1825).
581
+ * - `interrupted_attempts_exceeded` — the turn's attempts kept dying before
582
+ * they finished (an isolate reset such as a memory-limit reset or a
583
+ * deploy) until `maxInterruptedAttempts` of them had been interrupted.
584
+ * - `out_of_memory` — the alarm memory-limit circuit breaker sealed the
585
+ * recovery after repeated Durable Object memory-limit resets (#1825).
584
586
  * - `stable_timeout` — a recovery attempt kept timing out waiting for the
585
587
  * isolate to reach stable state until the budget drained (extreme churn).
586
588
  * - `max_recovery_window_exceeded` — DEPRECATED. The old absolute incident-age
@@ -620,7 +622,8 @@ type ChatRecoveryProgressContext = {
620
622
  * Configuration for durable chat recovery, which is always enabled for chat
621
623
  * turns. `true` uses these defaults: `maxAttempts: 10`,
622
624
  * `stableTimeoutMs: 10_000`, `noProgressTimeoutMs: 300_000` (5 min),
623
- * `maxRecoveryWork: 10000`, and a generic terminal message. Assign an object to
625
+ * `maxRecoveryWork: 10000`, `maxInterruptedAttempts: 5`, and a generic
626
+ * terminal message. Assign an object to
624
627
  * tune recovery without disabling its durable bookkeeping.
625
628
  *
626
629
  * **Apply this as a class field or in the constructor — never assign it in
@@ -642,8 +645,10 @@ type ChatRecoveryConfig =
642
645
  * How long an incident may go WITHOUT forward progress before it is
643
646
  * sealed with `reason="no_progress_timeout"`. This is the primary
644
647
  * stuck-turn bound. It **resets on every progress-bearing attempt**, so a
645
- * turn that keeps producing content survives unbounded interruption while
646
- * a genuinely idle turn is sealed within the window. Defaults to 5 min.
648
+ * turn that keeps producing content is never sealed by this bound, while
649
+ * a genuinely idle turn is sealed within the window. Repeated
650
+ * interruption is bounded separately by `maxInterruptedAttempts`.
651
+ * Defaults to 5 min.
647
652
  */
648
653
  noProgressTimeoutMs?: number;
649
654
  /**
@@ -670,16 +675,29 @@ type ChatRecoveryConfig =
670
675
  */
671
676
  maxRecoveryWork?: number;
672
677
  /**
673
- * Tight retry budget for the specific case of a Durable Object isolate
674
- * exceeding its memory limit and being reset mid-turn. An OOM is usually
675
- * deterministic (the turn's working set no longer fits in 128 MB), so
676
- * re-running re-OOMs; but a single OOM can be a transient spike, so
677
- * recovery retries this many times before sealing with
678
- * `reason="out_of_memory"`. Counts only attempts that ended in an OOM (not
679
- * total attempts), so a turn interrupted by deploys is unaffected.
680
- * Defaults to `3`. Set `0` to seal on the first OOM. Much tighter than
681
- * `maxRecoveryWork` because an OOM is attributable and each re-run is
682
- * expensive (it re-runs the model).
678
+ * How many of one turn's attempts may be interrupted before recovery
679
+ * gives up with `reason="interrupted_attempts_exceeded"`. An attempt is
680
+ * interrupted when its isolate dies before the attempt finishes: a
681
+ * Durable Object memory-limit reset, a deploy, or any other reset. The
682
+ * original turn counts, so the default of `5` runs the model at most five
683
+ * times for a turn that dies every time.
684
+ *
685
+ * Each attempt records itself before it runs anything heavy, and the
686
+ * next attempt counts a record left by an isolate that died, because
687
+ * the isolate that died cannot record anything. Streamed output never
688
+ * resets the count: a turn that re-runs and dies again produces output
689
+ * too (#2613). A memory-limit reset and a
690
+ * deploy look the same from the next isolate, so a turn interrupted by
691
+ * this many deploys in a row is also sealed. Values below `1` are read
692
+ * as `1`; `Infinity` disables the bound.
693
+ */
694
+ maxInterruptedAttempts?: number;
695
+ /**
696
+ * @deprecated Use `maxInterruptedAttempts`. When that is unset, this is
697
+ * read as `maxInterruptedAttempts: maxOomRetries + 1`, which keeps the
698
+ * old number of retries. The budget now counts every interrupted
699
+ * attempt, not only the ones that ended in an observed memory-limit
700
+ * reset, because a reset isolate cannot record what killed it.
683
701
  */
684
702
  maxOomRetries?: number;
685
703
  /**
@@ -709,7 +727,7 @@ type ResolvedChatRecoveryConfig = {
709
727
  terminalMessage: string;
710
728
  noProgressTimeoutMs: number;
711
729
  maxRecoveryWork: number;
712
- maxOomRetries: number;
730
+ maxInterruptedAttempts: number;
713
731
  shouldKeepRecovering?: (
714
732
  ctx: ChatRecoveryProgressContext
715
733
  ) => boolean | Promise<boolean>;
@@ -1366,6 +1384,36 @@ declare function unwrapChatFiberSnapshot<Kind extends string>(
1366
1384
  * {@link chatRecoveryIncidentId}).
1367
1385
  */
1368
1386
  type ChatRecoveryKind = "retry" | "continue";
1387
+ /**
1388
+ * One recovery attempt in flight, recorded on the incident before the attempt
1389
+ * does anything heavy. `isolate` identifies the object instance that started
1390
+ * it; `token` identifies the attempt. An isolate killed by a memory-limit
1391
+ * reset cannot write anything, so it cannot clear this record: a later
1392
+ * isolate that finds a record it did not write knows that attempt died
1393
+ * (#2613).
1394
+ */
1395
+ type ChatRecoveryAttempt = {
1396
+ readonly isolate: string;
1397
+ readonly token: string;
1398
+ };
1399
+ /**
1400
+ * Why an incident evaluation is running.
1401
+ *
1402
+ * - `interrupted`: a later isolate is replaying a turn run whose isolate died
1403
+ * before the run finished. The replay is itself an attempt, recorded as
1404
+ * `attempt`.
1405
+ * - `stalled`: a live isolate caught a stalled or failed stream. Nothing
1406
+ * died, so nothing is counted; transient retries are bounded by
1407
+ * `transientRetries` instead.
1408
+ */
1409
+ type ChatRecoveryTrigger =
1410
+ | {
1411
+ readonly kind: "interrupted";
1412
+ readonly attempt: ChatRecoveryAttempt;
1413
+ }
1414
+ | {
1415
+ readonly kind: "stalled";
1416
+ };
1369
1417
  /**
1370
1418
  * Durable per-incident recovery record.
1371
1419
  *
@@ -1416,17 +1464,25 @@ type ChatRecoveryIncident = {
1416
1464
  */
1417
1465
  workBaseline?: number;
1418
1466
  /**
1419
- * Count of recovery attempts for this incident that ended in a Durable Object
1420
- * memory-limit reset (the isolate exceeded its 128 MB limit — see
1421
- * `isDurableObjectMemoryLimitReset`). An OOM is a poison signal: re-running the
1422
- * same memory-heavy turn deterministically re-OOMs, so unlike a deploy/eviction
1423
- * it must NOT credit forward progress and must be bounded by a tight,
1424
- * OOM-specific budget (`maxOomRetries`) rather than the generic attempt cap
1425
- * (which resets on progress). Bumped by `ChatRecoveryEngine.recordOomAndDecide`
1426
- * when a recovery callback observes an OOM; exceeding `maxOomRetries` seals the
1427
- * incident with `reason="out_of_memory"` (#1825). Optional for backward-compat.
1467
+ * How many of this turn's attempts were interrupted: their isolate died
1468
+ * before they finished. The original turn's death is counted when its run
1469
+ * is first replayed; every later death is found through the
1470
+ * `attemptsInFlight` entries it left behind. Never counted on the failure
1471
+ * path, because an isolate killed by a memory-limit reset cannot write
1472
+ * (#2613), and never reset by progress, because a turn that re-runs and
1473
+ * dies again streams output too. Reaching `maxInterruptedAttempts` seals the
1474
+ * incident with `reason="interrupted_attempts_exceeded"`. Optional for
1475
+ * backward-compat.
1476
+ */
1477
+ interruptedAttempts?: number;
1478
+ /**
1479
+ * The recovery attempts currently running for this turn. Each is written
1480
+ * and confirmed before it does any heavy work and removed when it
1481
+ * finishes, so a replay and a callback that overlap are tracked apart. An
1482
+ * entry written by another isolate means that isolate died mid-attempt;
1483
+ * however many entries it left, it counts as one interruption.
1428
1484
  */
1429
- oomAttempts?: number;
1485
+ attemptsInFlight?: ChatRecoveryAttempt[];
1430
1486
  /**
1431
1487
  * Recoveries scheduled for this incident after a transient or rate-limited
1432
1488
  * stream error. Drives the retry backoff and is capped by `maxAttempts`.
@@ -1501,18 +1557,14 @@ declare const DEFAULT_CHAT_RECOVERY_MAX_ATTEMPTS = 10;
1501
1557
  */
1502
1558
  declare const DEFAULT_CHAT_RECOVERY_MAX_WORK = 10000;
1503
1559
  /**
1504
- * Tight, OOM-specific retry budget (#1825). A Durable Object memory-limit reset
1505
- * (`isDurableObjectMemoryLimitReset`) is usually deterministic — the turn's
1506
- * working set no longer fits in the isolate's 128 MB — so re-running it re-OOMs.
1507
- * But a single OOM CAN be a transient spike (the isolate's 128 MB is shared
1508
- * across the global scope / noisy neighbors), so recovery retries a small number
1509
- * of times before sealing with `reason="out_of_memory"` rather than abandoning a
1510
- * turn that one more attempt might have completed. Far tighter than the generic
1511
- * `maxRecoveryWork` backstop because an OOM is attributable and re-running it is
1512
- * expensive (it re-runs the model). Counts attempts that ended in an OOM, not
1513
- * total attempts, so a turn interrupted by deploys (no OOM) is unaffected.
1514
- */
1515
- declare const DEFAULT_CHAT_RECOVERY_MAX_OOM_RETRIES = 3;
1560
+ * Default number of interrupted attempts a turn may accumulate before recovery
1561
+ * seals it with `reason="interrupted_attempts_exceeded"` (#2613). The original
1562
+ * turn counts, so a turn that dies every time runs the model at most five
1563
+ * times. A deterministic memory-limit reset dies every time; a deploy rarely
1564
+ * lands on the same turn five times in a row, so five tolerates churn while
1565
+ * still bounding a crash loop.
1566
+ */
1567
+ declare const DEFAULT_CHAT_RECOVERY_MAX_INTERRUPTED_ATTEMPTS = 5;
1516
1568
  declare const DEFAULT_CHAT_RECOVERY_STABLE_TIMEOUT_MS = 10000;
1517
1569
  /**
1518
1570
  * Delay before retrying a recovery that timed out waiting for stable state.
@@ -1739,7 +1791,8 @@ type EvaluateChatRecoveryIncidentInput = {
1739
1791
  recoveryRootRequestId?: string | null;
1740
1792
  latestUserMessageId?: string | null;
1741
1793
  recoveryKind: ChatRecoveryKind;
1742
- } /** Fully-resolved recovery config. */;
1794
+ } /** Why this evaluation is running; decides whether it counts an interruption. */;
1795
+ trigger: ChatRecoveryTrigger /** Fully-resolved recovery config. */;
1743
1796
  config: ResolvedChatRecoveryConfig /** The existing incident for this identity, or `null` if this is fresh. */;
1744
1797
  existing: ChatRecoveryIncident | null /** Current value of the durable monotonic progress counter. */;
1745
1798
  currentProgress: number;
@@ -1817,6 +1870,13 @@ interface BeginChatRecoveryIncidentInput {
1817
1870
  recoveryRootRequestId?: string | null;
1818
1871
  latestUserMessageId?: string | null;
1819
1872
  recoveryKind: ChatRecoveryKind;
1873
+ /**
1874
+ * Why the incident is being opened: the replay of a turn run whose isolate
1875
+ * died (`interrupted`), or a stall a live isolate caught (`stalled`). Only
1876
+ * a replay can count against `maxInterruptedAttempts`, and only a replay
1877
+ * records itself as the attempt in flight.
1878
+ */
1879
+ trigger: "interrupted" | "stalled";
1820
1880
  /** Test-only clock injection for deterministic debounce/window timing. */
1821
1881
  nowMs?: number;
1822
1882
  }
@@ -1824,6 +1884,12 @@ interface BeginChatRecoveryIncidentResult {
1824
1884
  incident: ChatRecoveryIncident;
1825
1885
  config: ResolvedChatRecoveryConfig;
1826
1886
  exhausted: boolean;
1887
+ /**
1888
+ * The attempt this opening recorded as in flight (an `interrupted` trigger
1889
+ * on an incident that is not sealed), for the caller to finish. `null`
1890
+ * when nothing was recorded.
1891
+ */
1892
+ attempt: ChatRecoveryAttempt | null;
1827
1893
  }
1828
1894
  /**
1829
1895
  * Package-specific host operations the engine drives during incident
@@ -1878,6 +1944,14 @@ interface ChatRecoveryAdapter {
1878
1944
  listActiveIncidents?(): Promise<ChatRecoveryIncident[]>;
1879
1945
  /** Persist the evaluated incident under `key`. */
1880
1946
  putIncident(key: string, incident: ChatRecoveryIncident): Promise<void>;
1947
+ /**
1948
+ * Resolve once every write issued so far is durably confirmed (Durable
1949
+ * Object `storage.sync()`). {@link ChatRecoveryEngine.beginIncident} waits
1950
+ * on it before returning: the attempt that follows can run in the same
1951
+ * invocation, and a memory-limit reset discards writes that were not yet
1952
+ * confirmed, which would lose the interruption count (#2613).
1953
+ */
1954
+ syncStorage(): Promise<void>;
1881
1955
  /**
1882
1956
  * Delete the incident record under `key`. The engine calls this on the
1883
1957
  * terminal `completed` transition (a completed recovery is never retried, so
@@ -2098,8 +2172,32 @@ interface ChatFiberWakeHooks<TClassify> {
2098
2172
  * this class owns the surrounding sequence and its ordering invariants.
2099
2173
  */
2100
2174
  declare class ChatRecoveryEngine {
2175
+ #private;
2101
2176
  private readonly adapter;
2102
2177
  constructor(adapter: ChatRecoveryAdapter);
2178
+ /**
2179
+ * Run one recovery attempt under the interruption budget (#2613): a
2180
+ * `_chatRecoveryContinue` / `_chatRecoveryRetry` callback and the turn it
2181
+ * starts. Before `run` does anything heavy, the attempt counts any earlier
2182
+ * attempt that died (entries another isolate left in `attemptsInFlight`)
2183
+ * and records itself, confirmed with `syncStorage`. Once
2184
+ * `maxInterruptedAttempts` attempts have died the turn is sealed with
2185
+ * `interrupted_attempts_exceeded` and `run` is never called. The entry is
2186
+ * removed when `run` settles, whatever its outcome.
2187
+ *
2188
+ * This catches deaths the replay of an interrupted turn run cannot see, such
2189
+ * as a reset before the callback starts its turn, which leaves no turn run
2190
+ * to replay. A callback for a sealed incident does nothing: the turn was
2191
+ * already terminalized, and running it would re-run the model. A payload
2192
+ * without an incident, or one whose incident is gone, runs untracked.
2193
+ *
2194
+ * @param input - The callback being run, its payload, and the work.
2195
+ */
2196
+ runRecoveryAttempt(input: {
2197
+ callback: ChatRecoveryScheduleCallback;
2198
+ data: Record<string, unknown> | undefined;
2199
+ run: () => Promise<void>;
2200
+ }): Promise<void>;
2103
2201
  /**
2104
2202
  * Open or re-evaluate the recovery incident for `input`, persist the result,
2105
2203
  * and broadcast its lifecycle events. Returns the incident, the resolved
@@ -2223,34 +2321,6 @@ declare class ChatRecoveryEngine {
2223
2321
  cancelScheduledRecovery(requestId: string): Promise<boolean>;
2224
2322
  /** Whether the user cancelled this incident's scheduled recovery. */
2225
2323
  isRecoveryCancelled(incidentId: string | undefined): Promise<boolean>;
2226
- /**
2227
- * Record that a recovery callback observed a Durable Object memory-limit reset
2228
- * (the isolate exceeded its 128 MB limit — `isDurableObjectMemoryLimitReset`)
2229
- * and decide what to do next (#1825).
2230
- *
2231
- * Bumps the incident's durable `oomAttempts` counter, then:
2232
- * - if it is still within `maxOomRetries`, issues a delayed, NON-idempotent
2233
- * reschedule of the SAME callback (same machinery as
2234
- * {@link rescheduleAfterStableTimeout}: the executing attempt settles
2235
- * only after the callback returns, so an idempotent reschedule would
2236
- * dedup onto that doomed attempt) and returns `"rescheduled"`. The small
2237
- * delay lets a transient memory spike clear before the re-run;
2238
- * - otherwise leaves the incremented count persisted (so a begin-path
2239
- * re-evaluation agrees) and returns `"exhausted"` — the caller then
2240
- * terminalizes via the give-up path with `reason="out_of_memory"`.
2241
- *
2242
- * Returns `"exhausted"` when there is no incident to track against (no id /
2243
- * record gone): an OOM we cannot bound must seal rather than loop. Unlike a
2244
- * stable-state retry this is gated by the OOM-specific budget, NOT the generic
2245
- * attempt cap — re-running an OOM streams a little "progress" that would
2246
- * otherwise reset the attempt cap forever (the #1825 loop).
2247
- */
2248
- recordOomAndDecide(input: {
2249
- incidentId: string | undefined;
2250
- callback: ChatRecoveryScheduleCallback;
2251
- data: Record<string, unknown> | undefined;
2252
- maxOomRetries: number;
2253
- }): Promise<"rescheduled" | "exhausted">;
2254
2324
  /**
2255
2325
  * Give up on a recovery turn whose retry budget drained, terminalizing it so
2256
2326
  * it can never become an eternal spinner (#1645). The shared spine both
@@ -3704,6 +3774,7 @@ export {
3704
3774
  type ChatFiberWakeHooks,
3705
3775
  type ChatProtocolEvent,
3706
3776
  type ChatRecoveryAdapter,
3777
+ type ChatRecoveryAttempt,
3707
3778
  type ChatRecoveryCodec,
3708
3779
  type ChatRecoveryConfig,
3709
3780
  type ChatRecoveryContext,
@@ -3720,6 +3791,7 @@ export {
3720
3791
  type ChatRecoveryTaskHooks,
3721
3792
  type ChatRecoveryTaskInput,
3722
3793
  type ChatRecoveryTaskReason,
3794
+ type ChatRecoveryTrigger,
3723
3795
  type ChatResponseResult,
3724
3796
  ChatStreamStalledError,
3725
3797
  type ChatStreamStatus,
@@ -3738,7 +3810,7 @@ export {
3738
3810
  type ContinuationSpec,
3739
3811
  ContinuationState,
3740
3812
  DEFAULT_CHAT_RECOVERY_MAX_ATTEMPTS,
3741
- DEFAULT_CHAT_RECOVERY_MAX_OOM_RETRIES,
3813
+ DEFAULT_CHAT_RECOVERY_MAX_INTERRUPTED_ATTEMPTS,
3742
3814
  DEFAULT_CHAT_RECOVERY_MAX_WORK,
3743
3815
  DEFAULT_CHAT_RECOVERY_NO_PROGRESS_TIMEOUT_MS,
3744
3816
  DEFAULT_CHAT_RECOVERY_STABLE_TIMEOUT_MS,