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,18 +1,29 @@
1
- import { o as isPlatformFailure } from "../retries-D9B2UCq3.js";
1
+ import {
2
+ i as isDurableObjectResetError,
3
+ s as isPlatformFailure
4
+ } from "../retries-CV6AkXmQ.js";
2
5
  import {
3
6
  I as AgentToolEvent,
4
- J as AgentToolRunState,
5
- L as AgentToolEventMessage,
6
- R as AgentToolEventState,
7
- _ as FiberRecoveryContext$1
8
- } from "../agent-routing-B2XLNMxq.js";
9
- import { _ as TaskStep, m as TaskRunOptions } from "../tasks-V2lCT8ZV.js";
7
+ R as AgentToolEventMessage,
8
+ Y as AgentToolRunState,
9
+ _ as FiberRecoveryContext$1,
10
+ at as isPositionlessAgentToolChunk,
11
+ z as AgentToolEventState
12
+ } from "../agent-routing-0DR0Tk2v.js";
13
+ import { _ as TaskStep, m as TaskRunOptions } from "../tasks-9YxYtByh.js";
10
14
  import {
11
- n as ClientToolSchema,
12
- r as createToolsFromClientSchemas,
13
- t as ClientToolExecutor
14
- } from "../client-tools-aIBO0Fk7.js";
15
- import { n as Streams } from "../streams-BcE8JP2X.js";
15
+ a as CHAT_MESSAGE_TYPES,
16
+ c as ClientToolExecutor,
17
+ i as OutgoingMessage,
18
+ l as ClientToolSchema,
19
+ n as IncomingMessage,
20
+ o as STREAM_RESUME_NONE_REASONS,
21
+ r as MessageType,
22
+ s as StreamResumeNoneReason,
23
+ t as ChatTurnOutcome,
24
+ u as createToolsFromClientSchemas
25
+ } from "../wire-types-CrjKvDyi.js";
26
+ import { n as Streams } from "../streams-Cmkj9QfW.js";
16
27
  import {
17
28
  a as applyAgentToolEvent,
18
29
  i as AgentToolProgressEmitter,
@@ -21,9 +32,9 @@ import {
21
32
  r as AgentToolProgressEmitResult,
22
33
  s as interceptAgentToolBroadcast,
23
34
  t as AgentToolBroadcastHooks
24
- } from "../agent-tools-Dj5Mzlw7.js";
35
+ } from "../agent-tools-YrATZJu2.js";
25
36
  import { l as SessionMessage } from "../types-B7LojTe4.js";
26
- import { JSONSchema7, UIMessage } from "ai";
37
+ import { ModelMessage, UIMessage } from "ai";
27
38
  import { Connection, FiberRecoveryContext } from "agents";
28
39
 
29
40
  //#region src/chat/message-builder.d.ts
@@ -90,6 +101,44 @@ declare function normalizeToolInput(raw: unknown): {
90
101
  input: unknown;
91
102
  changed: boolean;
92
103
  };
104
+ /**
105
+ * Whether `chunk` is a `tool-input-available` for a tool part that has
106
+ * already reached an approval state. Stream builders apply it server-side
107
+ * (see {@link applyLateToolInput}) but must not forward it: the AI SDK client
108
+ * would move its part back to `input-available` and drop the approval UI.
109
+ */
110
+ declare function isLateToolInputChunk(
111
+ parts: MessagePart[],
112
+ chunk: StreamChunkData
113
+ ): boolean;
114
+ /**
115
+ * Fill an approval part's input from a `tool-input-available` that arrived
116
+ * after its `tool-approval-request`, without changing the approval state.
117
+ * Only replaces input that is missing or was reconstructed from deltas, so
118
+ * a complete input the user has already seen is never swapped out.
119
+ *
120
+ * @returns `true` when the part's input changed.
121
+ */
122
+ declare function applyLateToolInput(
123
+ parts: MessagePart[],
124
+ chunk: StreamChunkData
125
+ ): boolean;
126
+ /**
127
+ * The chunks a stream builder forwards and stores for a late
128
+ * `tool-input-available` (see {@link isLateToolInputChunk}) so clients and
129
+ * stream replay see the input without losing the approval: the input chunk,
130
+ * then the part's approval request again. The AI SDK client moves the part
131
+ * to `input-available` on the first and back to `approval-requested` on the
132
+ * second.
133
+ *
134
+ * Returns `[]` unless the part is still awaiting approval: once the user has
135
+ * responded, re-sending the request would reopen it.
136
+ */
137
+ declare function lateToolInputForwardChunks(
138
+ parts: MessagePart[],
139
+ chunk: StreamChunkData,
140
+ approvalRequest?: StreamChunkData
141
+ ): StreamChunkData[];
93
142
  /**
94
143
  * Applies a stream chunk to a mutable parts array, building up the message
95
144
  * incrementally. Returns true if the chunk was handled, false if it was
@@ -329,6 +378,23 @@ declare class TurnQueue {
329
378
  private _decrementCount;
330
379
  }
331
380
  //#endregion
381
+ //#region src/chat/origin-message-ids.d.ts
382
+ /**
383
+ * IDs of the user messages a chat request originated from: the trailing run of
384
+ * user messages in its `messages` (one for a plain send or a regenerate,
385
+ * several when queued sends arrive together). Terminal response frames echo
386
+ * them as `messageIds` (#2280).
387
+ */
388
+ declare function originMessageIds$1(messages: unknown): string[] | undefined;
389
+ /**
390
+ * Return `frame` with `messageIds` added when it is a terminal
391
+ * (`done` or `error`) frame that does not already carry them.
392
+ */
393
+ declare function withOriginMessageIds<T extends object>(
394
+ frame: T,
395
+ messageIds: string[] | undefined
396
+ ): T;
397
+ //#endregion
332
398
  //#region src/chat/text-segment-joiner.d.ts
333
399
  /** @internal A parsed structured-stream chunk accepted by the joiner. */
334
400
  interface TextSegmentChunk {
@@ -380,6 +446,11 @@ type ChatResponseResult = {
380
446
  | "error"
381
447
  | "aborted" /** Error message when `status` is `"error"`. */;
382
448
  error?: string;
449
+ /**
450
+ * `true` when the hook is delivered by recovery after a restart, because
451
+ * the turn's message was persisted but the hook had not run yet.
452
+ */
453
+ recovered?: boolean;
383
454
  /**
384
455
  * Advisory reply attachments recorded during the turn (best-effort,
385
456
  * producing-attempt only — not re-applied on a ledger replay).
@@ -534,10 +605,11 @@ type ChatRecoveryProgressContext = {
534
605
  maxAttempts: number;
535
606
  recoveryKind: "retry" | "continue";
536
607
  /**
537
- * Recovery work units produced since this incident began — a durable,
538
- * monotonic, reconnect-immune count of produced content/tool segments (not
539
- * tokens). The signal that distinguishes a healthy long turn from a runaway
540
- * loop.
608
+ * Recovery work produced since this incident began — a durable, monotonic,
609
+ * reconnect-immune count of flushed stream segments (roughly ten packed
610
+ * streaming chunks, one settled tool result, or one forwarded sub-agent
611
+ * credit each; not tokens). The signal that distinguishes a healthy long turn
612
+ * from a runaway loop, in the same unit as `maxRecoveryWork`.
541
613
  */
542
614
  work: number /** Wall-clock ms since the incident's first interruption. */;
543
615
  ageMs: number;
@@ -573,9 +645,9 @@ type ChatRecoveryConfig =
573
645
  */
574
646
  noProgressTimeoutMs?: number;
575
647
  /**
576
- * Runaway-loop guard. Maximum recovery WORK — produced content/tool units
577
- * since the incident began — before a still-progressing turn is sealed
578
- * with `reason="work_budget_exceeded"`. Defaults to `1000`: a generous
648
+ * Runaway-loop guard. Maximum recovery WORK since the incident began
649
+ * before a still-progressing turn is sealed with
650
+ * `reason="work_budget_exceeded"`. Defaults to `10000`: a generous
579
651
  * backstop that bounds wasted re-run cost when a turn keeps emitting a
580
652
  * little content but never converges (e.g. an isolate that OOMs mid-stream
581
653
  * on every recovery — #1825 — which otherwise resets the attempt cap and
@@ -585,6 +657,14 @@ type ChatRecoveryConfig =
585
657
  * that legitimately needs more can raise this (or set `Infinity` to
586
658
  * disable the framework cap and bound the runaway via `shouldKeepRecovering`
587
659
  * instead).
660
+ *
661
+ * The unit is one durably flushed stream segment: roughly ten packed
662
+ * streaming chunks, one settled tool result (flushed on its own), or one
663
+ * explicit credit for forwarded sub-agent output. It is not tokens,
664
+ * messages, or chunks. The unit changed from "credited chunk" in #2223
665
+ * (and the default moved from `1000` to `10000`); an explicit value
666
+ * carried over from an earlier release is not recalibrated, so measure
667
+ * `ctx.work` for a healthy interrupted turn before choosing a cap.
588
668
  */
589
669
  maxRecoveryWork?: number;
590
670
  /**
@@ -800,6 +880,12 @@ declare class ResumableStream {
800
880
  * restored from SQLite after hibernation in restore().
801
881
  */
802
882
  private _activeIsContinuation;
883
+ /**
884
+ * Index the next stored chunk of the active stream gets, which is also its
885
+ * position in a replay. `null` for a stream restored from SQLite, whose
886
+ * count is not tracked.
887
+ */
888
+ private _nextChunkSeq;
803
889
  private _chunkBuffer;
804
890
  private _chunkBufferBytes;
805
891
  private _isFlushingChunks;
@@ -809,6 +895,8 @@ declare class ResumableStream {
809
895
  * write, or {@link finalizePending} it when there is nothing to persist.
810
896
  */
811
897
  private _pendingCutover;
898
+ /** The stream most recently closed by complete, finish, or markError. */
899
+ private _lastClosedStreamId;
812
900
  private readonly ops;
813
901
  constructor(
814
902
  streams: Streams,
@@ -911,9 +999,13 @@ declare class ResumableStream {
911
999
  requestId: string,
912
1000
  options?: {
913
1001
  messageId?: string;
1002
+ parentMessageId?: string;
914
1003
  continuation?: boolean;
1004
+ originMessageIds?: string[];
915
1005
  }
916
1006
  ): string;
1007
+ private _nextSeqForRequest;
1008
+ private _seqBase;
917
1009
  /**
918
1010
  * The assistant message id an orphaned stream was producing — the same id the
919
1011
  * live path persists under, so recovery re-associates reconstructed chunks
@@ -921,11 +1013,36 @@ declare class ResumableStream {
921
1013
  * predates message-id tracking.
922
1014
  */
923
1015
  getStreamMessageId(streamId: string): string | null;
1016
+ /**
1017
+ * The message an orphaned stream's assistant message is a child of, or null
1018
+ * when the stream appends to the latest leaf or predates parent tracking.
1019
+ */
1020
+ getStreamParentMessageId(streamId: string): string | null;
1021
+ /**
1022
+ * The user message ids the request's latest chat stream was started for
1023
+ * (#2280), or undefined when no stream recorded them.
1024
+ */
1025
+ getOriginMessageIds(requestId: string): string[] | undefined;
1026
+ /**
1027
+ * How the request's latest chat stream ended (recorded by {@link complete}
1028
+ * or {@link finish}), or undefined for a normal completion.
1029
+ */
1030
+ getOutcome(requestId: string): ChatTurnOutcome | undefined;
1031
+ /**
1032
+ * Origin ids and outcome of recently deleted streams (cutover, reclaim),
1033
+ * so a resume ACK that arrives after the rows are gone still gets them on
1034
+ * its replay terminal.
1035
+ */
1036
+ private readonly _deletedTerminals;
1037
+ private _rememberDeleted;
1038
+ private _recordOutcome;
924
1039
  /**
925
1040
  * Mark a stream as completed and flush any pending chunks.
926
1041
  * @param streamId - The stream to mark as completed
1042
+ * @param outcome - How the request ended, when not a normal completion.
1043
+ * Defaults to `aborted` for a stream restored without a live reader.
927
1044
  */
928
- complete(streamId: string): void;
1045
+ complete(streamId: string, outcome?: ChatTurnOutcome): void;
929
1046
  /**
930
1047
  * The producer finished, but leave the row `streaming` for the cutover:
931
1048
  * the host persists the message and settles the stream in one
@@ -933,7 +1050,7 @@ declare class ResumableStream {
933
1050
  * live — exactly the evidence recovery rebuilds the message from. The
934
1051
  * host MUST follow with {@link cutover} or {@link finalizePending}.
935
1052
  */
936
- finish(streamId: string): void;
1053
+ finish(streamId: string, outcome?: ChatTurnOutcome): void;
937
1054
  /** The stream {@link finish}ed and awaiting its cutover, if any. */
938
1055
  get pendingCutoverId(): string | null;
939
1056
  /**
@@ -972,8 +1089,11 @@ declare class ResumableStream {
972
1089
  * but will be missing from replay on reconnection.
973
1090
  * @param streamId - The stream this chunk belongs to
974
1091
  * @param body - The serialized chunk body
1092
+ * @returns The chunk's index in a replay of the stream, for the live
1093
+ * broadcast to carry as `seq`; `undefined` when the chunk is not stored
1094
+ * or the stream's count is not tracked.
975
1095
  */
976
- storeChunk(streamId: string, body: string): void;
1096
+ storeChunk(streamId: string, body: string): number | undefined;
977
1097
  /**
978
1098
  * Flush the buffered chunks to storage as a single packed segment.
979
1099
  * Uses a lock to prevent concurrent flush operations.
@@ -1025,6 +1145,15 @@ declare class ResumableStream {
1025
1145
  connection: Connection,
1026
1146
  requestId: string
1027
1147
  ): boolean;
1148
+ /**
1149
+ * Replay the request's just-closed stream (finished and awaiting its
1150
+ * cutover, completed for a recovery, or errored), ending in
1151
+ * `replayComplete` rather than `done`: the host has not sent the request's
1152
+ * terminal frame yet and delivers it live once the message is persisted.
1153
+ * After the cutover deleted the rows, only the `replayComplete` is sent.
1154
+ * @returns False when the connection closed mid-replay.
1155
+ */
1156
+ replayClosedStreamChunks(connection: Connection, requestId: string): boolean;
1028
1157
  /**
1029
1158
  * Replay the stored chunks of an errored stream for a request, WITHOUT a
1030
1159
  * terminal frame — the caller follows up with the `done: true, error: true`
@@ -1192,7 +1321,8 @@ type ChatFiberSnapshot<Kind extends string = string> = {
1192
1321
  latestUserMessageId?: string;
1193
1322
  startedAt: number;
1194
1323
  lastBody?: Record<string, unknown>;
1195
- lastClientTools?: ClientToolSchema[];
1324
+ lastClientTools?: ClientToolSchema[] /** User message ids the turn's request originated from, if any. */;
1325
+ originMessageIds?: string[];
1196
1326
  };
1197
1327
  declare function createChatFiberSnapshot<Kind extends string>({
1198
1328
  kind,
@@ -1201,7 +1331,8 @@ declare function createChatFiberSnapshot<Kind extends string>({
1201
1331
  continuation,
1202
1332
  messages,
1203
1333
  lastBody,
1204
- lastClientTools
1334
+ lastClientTools,
1335
+ originMessageIds
1205
1336
  }: {
1206
1337
  kind: Kind;
1207
1338
  requestId: string;
@@ -1210,6 +1341,7 @@ declare function createChatFiberSnapshot<Kind extends string>({
1210
1341
  messages: ReadonlyArray<SnapshotMessage>;
1211
1342
  lastBody?: Record<string, unknown>;
1212
1343
  lastClientTools?: ClientToolSchema[];
1344
+ originMessageIds?: string[];
1213
1345
  }): ChatFiberSnapshot<Kind>;
1214
1346
  declare function wrapChatFiberSnapshot<Kind extends string>(
1215
1347
  key: string,
@@ -1293,6 +1425,14 @@ type ChatRecoveryIncident = {
1293
1425
  * incident with `reason="out_of_memory"` (#1825). Optional for backward-compat.
1294
1426
  */
1295
1427
  oomAttempts?: number;
1428
+ /**
1429
+ * Recoveries scheduled for this incident after a transient or rate-limited
1430
+ * stream error. Drives the retry backoff and is capped by `maxAttempts`.
1431
+ * Unlike `attempt`, it is not debounced and does not reset on progress: a
1432
+ * provider that fails every retry within seconds must still back off and
1433
+ * run out of attempts. Bumped by `ChatRecoveryEngine.recordTransientRetry`.
1434
+ */
1435
+ transientRetries?: number;
1296
1436
  };
1297
1437
  declare const CHAT_RECOVERY_INCIDENT_KEY_PREFIX = "cf:chat-recovery:incident:";
1298
1438
  /**
@@ -1327,7 +1467,7 @@ declare const CHAT_LAST_TERMINAL_KEY = "cf:chat:last-terminal";
1327
1467
  declare const DEFAULT_CHAT_RECOVERY_MAX_ATTEMPTS = 10;
1328
1468
  /**
1329
1469
  * Runaway-loop guard default — the framework-imposed backstop on cumulative
1330
- * recovery WORK (produced content/tool units) since an incident opened.
1470
+ * recovery WORK (durable stream segments, see below) since an incident opened.
1331
1471
  *
1332
1472
  * Originally `Infinity` (rfc-chat-recovery-work-budget): the SDK shipped the
1333
1473
  * *mechanism* but no default cap, so a progressing turn was never terminated on
@@ -1510,7 +1650,8 @@ declare class StreamProgressCreditThrottle {
1510
1650
  /** Durable record of the last turn that ended in a terminal error (#1645). */
1511
1651
  type ChatTerminalRecord = {
1512
1652
  requestId: string;
1513
- body: string;
1653
+ body: string /** The request's originating user message ids (#2280). */;
1654
+ messageIds?: string[];
1514
1655
  };
1515
1656
  /**
1516
1657
  * Persist a durable record of the last terminal turn so a client that
@@ -1521,7 +1662,8 @@ type ChatTerminalRecord = {
1521
1662
  declare function recordChatTerminal(
1522
1663
  storage: Pick<DurableObjectStorage, "put">,
1523
1664
  requestId: string,
1524
- body: string
1665
+ body: string,
1666
+ messageIds?: string[]
1525
1667
  ): Promise<void>;
1526
1668
  /** Clear the durable terminal record once a later turn supersedes it (#1645). */
1527
1669
  declare function clearChatTerminal(
@@ -1639,8 +1781,15 @@ type ChatRecoveryScheduleCallback =
1639
1781
  * settles only AFTER the callback returns, so an idempotent reschedule would
1640
1782
  * dedup onto the doomed attempt and settle with it — the retry would never
1641
1783
  * fire. A fresh (non-idempotent) delayed attempt survives.
1784
+ *
1785
+ * - `"chained_retry"` — the next attempt, scheduled from inside an executing
1786
+ * recovery attempt that was interrupted again. Non-idempotent for the same
1787
+ * reason as `"stable_timeout_retry"`.
1642
1788
  */
1643
- type ChatRecoveryScheduleReason = "initial" | "stable_timeout_retry";
1789
+ type ChatRecoveryScheduleReason =
1790
+ | "initial"
1791
+ | "stable_timeout_retry"
1792
+ | "chained_retry";
1644
1793
  /**
1645
1794
  * A reconstructed orphaned-stream partial. The engine seam is deliberately
1646
1795
  * **wire-vocabulary-agnostic**: `text` is the accumulated assistant text and
@@ -1719,6 +1868,12 @@ interface ChatRecoveryAdapter {
1719
1868
  * fixture) omits it and the engine treats the turn as never parked (`false`).
1720
1869
  */
1721
1870
  isAwaitingClientInteraction?(): boolean;
1871
+ /**
1872
+ * Optional: list the live (not yet terminalized) incidents. Required for
1873
+ * {@link ChatRecoveryEngine.cancelScheduledRecovery}; a host that omits it
1874
+ * cannot cancel a scheduled recovery.
1875
+ */
1876
+ listActiveIncidents?(): Promise<ChatRecoveryIncident[]>;
1722
1877
  /** Persist the evaluated incident under `key`. */
1723
1878
  putIncident(key: string, incident: ChatRecoveryIncident): Promise<void>;
1724
1879
  /**
@@ -1771,7 +1926,13 @@ interface ChatRecoveryAdapter {
1771
1926
  config: ResolvedChatRecoveryConfig,
1772
1927
  partial: RecoveryPartial,
1773
1928
  streamId: string,
1774
- createdAt: number
1929
+ createdAt: number,
1930
+ /**
1931
+ * The fiber snapshot's origin ids (#2280). A restored pre-stream turn has
1932
+ * no stream row or live request to recover them from otherwise.
1933
+ */
1934
+
1935
+ originMessageIds?: string[]
1775
1936
  ): Promise<void>;
1776
1937
  /**
1777
1938
  * Resolve the orphaned stream identity for a (recovery-root) request id —
@@ -2016,6 +2177,7 @@ declare class ChatRecoveryEngine {
2016
2177
  callback: ChatRecoveryScheduleCallback;
2017
2178
  data: Record<string, unknown>;
2018
2179
  reason?: ChatRecoveryScheduleReason;
2180
+ delaySeconds?: number;
2019
2181
  }): Promise<void>;
2020
2182
  /**
2021
2183
  * Reschedule a recovery continuation/retry that timed out waiting for stable
@@ -2041,6 +2203,24 @@ declare class ChatRecoveryEngine {
2041
2203
  data: Record<string, unknown> | undefined;
2042
2204
  fallbackMaxAttempts: number;
2043
2205
  }): Promise<boolean>;
2206
+ /**
2207
+ * Bump the incident's durable `transientRetries` counter before scheduling a
2208
+ * recovery for a transient or rate-limited stream error, and return the new
2209
+ * count so the caller can derive its backoff. Returns `1` when the incident
2210
+ * record is gone.
2211
+ */
2212
+ recordTransientRetry(incidentId: string): Promise<number>;
2213
+ /**
2214
+ * The user cancelled `requestId` while its recovery was scheduled but not
2215
+ * yet running (e.g. during a transient-error backoff). Marks every
2216
+ * `scheduled` incident whose recovery root or current attempt is
2217
+ * `requestId` as `skipped` with {@link CHAT_RECOVERY_CANCELLED_REASON}, so
2218
+ * the queued callback bails when it fires (see {@link isRecoveryCancelled}).
2219
+ * Returns whether any incident was cancelled.
2220
+ */
2221
+ cancelScheduledRecovery(requestId: string): Promise<boolean>;
2222
+ /** Whether the user cancelled this incident's scheduled recovery. */
2223
+ isRecoveryCancelled(incidentId: string | undefined): Promise<boolean>;
2044
2224
  /**
2045
2225
  * Record that a recovery callback observed a Durable Object memory-limit reset
2046
2226
  * (the isolate exceeded its 128 MB limit — `isDurableObjectMemoryLimitReset`)
@@ -2138,6 +2318,28 @@ declare class ChatRecoveryEngine {
2138
2318
  reason?: string
2139
2319
  ): Promise<void>;
2140
2320
  }
2321
+ /** `incident.reason` for a scheduled recovery the user cancelled. */
2322
+ declare const CHAT_RECOVERY_CANCELLED_REASON = "user_cancelled";
2323
+ /**
2324
+ * Delay before the `retries`-th transient-error recovery: exponential backoff
2325
+ * capped at {@link CHAT_RECOVERY_MAX_BACKOFF_SECONDS}. A provider
2326
+ * `retryAfterSeconds` (rate limits) extends it, capped at
2327
+ * {@link CHAT_RECOVERY_MAX_RETRY_AFTER_SECONDS}.
2328
+ */
2329
+ declare function chatRecoveryBackoffSeconds(
2330
+ retries: number,
2331
+ retryAfterSeconds?: number
2332
+ ): number;
2333
+ /**
2334
+ * The `Retry-After` an error carries, in whole seconds. Reads
2335
+ * `responseHeaders` (AI SDK `APICallError`) or `headers` on the error or its
2336
+ * `cause` chain; accepts delta-seconds or an HTTP date. `undefined` when absent
2337
+ * or unparseable.
2338
+ */
2339
+ declare function retryAfterSeconds(
2340
+ error: unknown,
2341
+ now?: number
2342
+ ): number | undefined;
2141
2343
  /**
2142
2344
  * The complete give-up choreography from a single call: build the exhausted
2143
2345
  * context, fire the shared notification ({@link notifyChatRecoveryExhausted}),
@@ -2193,7 +2395,11 @@ type ChatRecoveryTaskInput = {
2193
2395
  readonly delaySeconds: number;
2194
2396
  };
2195
2397
  /** Why a recovery attempt is being enqueued. */
2196
- type ChatRecoveryTaskReason = "initial" | "stable_timeout_retry" | "redefer";
2398
+ type ChatRecoveryTaskReason =
2399
+ | "initial"
2400
+ | "stable_timeout_retry"
2401
+ | "chained_retry"
2402
+ | "redefer";
2197
2403
  /** The host's bounded entry point for each continuation callback. */
2198
2404
  type ChatRecoveryTaskHooks = Record<
2199
2405
  ChatRecoveryScheduleCallback,
@@ -2286,202 +2492,6 @@ declare function buildInClauseStrings(
2286
2492
  count: number
2287
2493
  ): TemplateStringsArray;
2288
2494
  //#endregion
2289
- //#region src/chat/protocol.d.ts
2290
- /**
2291
- * Wire protocol message type constants for the cf_agent_chat_* protocol.
2292
- *
2293
- * These are the string values used on the wire between agent servers and
2294
- * clients. Both @cloudflare/ai-chat (via its MessageType enum) and
2295
- * @cloudflare/think use these values.
2296
- */
2297
- declare const STREAM_RESUME_NONE_REASONS: {
2298
- /** No active, pending, or terminal stream exists for this agent. */ readonly IDLE: "idle" /** An active tool continuation is owned by another live connection. */;
2299
- readonly CONTINUATION_OWNED: "continuation-owned";
2300
- };
2301
- type StreamResumeNoneReason =
2302
- (typeof STREAM_RESUME_NONE_REASONS)[keyof typeof STREAM_RESUME_NONE_REASONS];
2303
- declare const CHAT_MESSAGE_TYPES: {
2304
- readonly CHAT_MESSAGES: "cf_agent_chat_messages";
2305
- readonly USE_CHAT_REQUEST: "cf_agent_use_chat_request";
2306
- readonly USE_CHAT_RESPONSE: "cf_agent_use_chat_response";
2307
- readonly CHAT_CLEAR: "cf_agent_chat_clear";
2308
- readonly CHAT_REQUEST_CANCEL: "cf_agent_chat_request_cancel";
2309
- readonly STREAM_RESUMING: "cf_agent_stream_resuming";
2310
- readonly STREAM_RESUME_ACK: "cf_agent_stream_resume_ack";
2311
- readonly STREAM_RESUME_REQUEST: "cf_agent_stream_resume_request";
2312
- readonly STREAM_RESUME_NONE: "cf_agent_stream_resume_none";
2313
- readonly STREAM_PENDING: "cf_agent_stream_pending";
2314
- readonly TOOL_RESULT: "cf_agent_tool_result";
2315
- readonly TOOL_APPROVAL: "cf_agent_tool_approval";
2316
- readonly MESSAGE_UPDATED: "cf_agent_message_updated";
2317
- readonly CHAT_RECOVERING: "cf_agent_chat_recovering";
2318
- };
2319
- //#endregion
2320
- //#region src/chat/wire-types.d.ts
2321
- /**
2322
- * Enum for message types to improve type safety and maintainability
2323
- */
2324
- declare enum MessageType {
2325
- CF_AGENT_CHAT_MESSAGES = "cf_agent_chat_messages",
2326
- CF_AGENT_USE_CHAT_REQUEST = "cf_agent_use_chat_request",
2327
- CF_AGENT_USE_CHAT_RESPONSE = "cf_agent_use_chat_response",
2328
- CF_AGENT_CHAT_CLEAR = "cf_agent_chat_clear",
2329
- CF_AGENT_CHAT_REQUEST_CANCEL = "cf_agent_chat_request_cancel",
2330
- /** Sent by server when client connects and there's an active stream to resume */
2331
- CF_AGENT_STREAM_RESUMING = "cf_agent_stream_resuming",
2332
- /** Sent by client to acknowledge stream resuming notification and request chunks */
2333
- CF_AGENT_STREAM_RESUME_ACK = "cf_agent_stream_resume_ack",
2334
- /** Sent by client after message handler is ready, requesting stream resume check */
2335
- CF_AGENT_STREAM_RESUME_REQUEST = "cf_agent_stream_resume_request",
2336
- /** Sent by server when client requests resume but no active stream exists */
2337
- CF_AGENT_STREAM_RESUME_NONE = "cf_agent_stream_resume_none",
2338
- /**
2339
- * Sent by server when a turn is accepted but its resumable stream has not
2340
- * started yet (queued / debouncing / waiting on MCP / async setup). Tells a
2341
- * reconnecting client to keep waiting rather than resolve its resume probe to
2342
- * "no stream". Resolved by a later `CF_AGENT_STREAM_RESUMING` (stream started)
2343
- * or `CF_AGENT_STREAM_RESUME_NONE` (settled without streaming). See #1784.
2344
- */
2345
- CF_AGENT_STREAM_PENDING = "cf_agent_stream_pending",
2346
- /** Client sends tool result to server (for client-side tools) */
2347
- CF_AGENT_TOOL_RESULT = "cf_agent_tool_result",
2348
- /** Server notifies client that a message was updated (e.g., tool result applied) */
2349
- CF_AGENT_MESSAGE_UPDATED = "cf_agent_message_updated",
2350
- /** Client sends tool approval response to server (for tools with needsApproval) */
2351
- CF_AGENT_TOOL_APPROVAL = "cf_agent_tool_approval",
2352
- /**
2353
- * Server→client progress hint: a durable chat turn is being recovered
2354
- * (interrupted by a deploy/eviction or a stream-stall watchdog abort and now
2355
- * resuming). Sent when a recovery continuation is scheduled and cleared on
2356
- * every terminal outcome. (`@cloudflare/think` also replays it on connect;
2357
- * `@cloudflare/ai-chat` broadcasts the live signal only — see #1645.)
2358
- * Backward-compatible — clients that don't understand it ignore it. See #1620.
2359
- */
2360
- CF_AGENT_CHAT_RECOVERING = "cf_agent_chat_recovering"
2361
- }
2362
- /**
2363
- * Types of messages sent from the Agent to clients
2364
- */
2365
- type OutgoingMessage<ChatMessage extends UIMessage = UIMessage> =
2366
- | {
2367
- /** Indicates this message is a command to clear chat history */ type: MessageType.CF_AGENT_CHAT_CLEAR;
2368
- }
2369
- | {
2370
- /** Indicates this message contains updated chat messages */ type: MessageType.CF_AGENT_CHAT_MESSAGES /** Array of chat messages */;
2371
- messages: readonly ChatMessage[];
2372
- }
2373
- | {
2374
- /** Indicates this message is a response to a chat request */ type: MessageType.CF_AGENT_USE_CHAT_RESPONSE /** Unique ID of the request this response corresponds to */;
2375
- id: string /** Content body of the response */;
2376
- body: string /** Whether this is the final chunk of the response */;
2377
- done: boolean /** Whether this response contains an error */;
2378
- error?: boolean /** Whether this is a continuation (append to last assistant message) */;
2379
- continuation?: boolean /** Whether this chunk is being replayed from storage (stream resumption) */;
2380
- replay?: boolean /** Signals that replay of stored chunks is complete (stream is still active) */;
2381
- replayComplete?: boolean;
2382
- }
2383
- | {
2384
- /** Indicates the server is resuming an active stream */ type: MessageType.CF_AGENT_STREAM_RESUMING /** The request ID of the stream being resumed */;
2385
- id: string /** Present when this offer directly answers a client resume probe. */;
2386
- probeId?: string;
2387
- }
2388
- | {
2389
- /** Server notifies client that a message was updated (e.g., tool result applied) */ type: MessageType.CF_AGENT_MESSAGE_UPDATED /** The updated message */;
2390
- message: ChatMessage;
2391
- }
2392
- | {
2393
- /** Server responds to a resume request with no stream for this client. */ type: MessageType.CF_AGENT_STREAM_RESUME_NONE;
2394
- /**
2395
- * Why no stream was offered. Only `idle` proves global inactivity;
2396
- * omitted by older servers and by non-authoritative delayed releases.
2397
- */
2398
- reason?: StreamResumeNoneReason /** Correlates an authoritative response to its client resume probe. */;
2399
- probeId?: string;
2400
- }
2401
- | {
2402
- /**
2403
- * Server signals an accepted turn whose resumable stream has not started
2404
- * yet — the client should keep waiting for `STREAM_RESUMING` (or a later
2405
- * `STREAM_RESUME_NONE`) rather than give up. See #1784.
2406
- */
2407
- type: MessageType.CF_AGENT_STREAM_PENDING /** The accepted request id, when known. */;
2408
- id?: string /** Correlates a direct keep-waiting response to its client probe. */;
2409
- probeId?: string;
2410
- }
2411
- | {
2412
- /**
2413
- * Progress hint: a durable chat turn is being recovered (`recovering:
2414
- * true`) or recovery has resolved (`recovering: false`). Purely advisory;
2415
- * a client renders a "recovering…" indicator while true.
2416
- */
2417
- type: MessageType.CF_AGENT_CHAT_RECOVERING /** Whether recovery is in progress (true) or has resolved (false). */;
2418
- recovering: boolean /** The recovery-root request id of the turn being recovered, if known. */;
2419
- id?: string;
2420
- };
2421
- /**
2422
- * Types of messages sent from clients to the Agent
2423
- */
2424
- type IncomingMessage<ChatMessage extends UIMessage = UIMessage> =
2425
- | {
2426
- /** Indicates this message is a command to clear chat history */ type: MessageType.CF_AGENT_CHAT_CLEAR;
2427
- }
2428
- | {
2429
- /** Indicates this message is a request to the chat API */ type: MessageType.CF_AGENT_USE_CHAT_REQUEST /** Unique ID for this request */;
2430
- id: string /** Request initialization options */;
2431
- init: Pick<
2432
- RequestInit,
2433
- | "method"
2434
- | "keepalive"
2435
- | "headers"
2436
- | "body"
2437
- | "redirect"
2438
- | "integrity"
2439
- | "credentials"
2440
- | "mode"
2441
- | "referrer"
2442
- | "referrerPolicy"
2443
- | "window"
2444
- >;
2445
- }
2446
- | {
2447
- /** Indicates this message contains updated chat messages */ type: MessageType.CF_AGENT_CHAT_MESSAGES /** Array of chat messages */;
2448
- messages: ChatMessage[];
2449
- }
2450
- | {
2451
- /** Indicates the user wants to stop generation of this message */ type: MessageType.CF_AGENT_CHAT_REQUEST_CANCEL;
2452
- id: string;
2453
- }
2454
- | {
2455
- /** Client acknowledges stream resuming notification and is ready to receive chunks */ type: MessageType.CF_AGENT_STREAM_RESUME_ACK /** The request ID of the stream being resumed */;
2456
- id: string;
2457
- }
2458
- | {
2459
- /** Client requests stream resume check after message handler is registered */ type: MessageType.CF_AGENT_STREAM_RESUME_REQUEST /** Opaque correlation id echoed by direct server responses. */;
2460
- probeId?: string;
2461
- }
2462
- | {
2463
- /** Client sends tool result to server (for client-side tools) */ type: MessageType.CF_AGENT_TOOL_RESULT /** The tool call ID this result is for */;
2464
- toolCallId: string /** The name of the tool */;
2465
- toolName: string /** The output from the tool execution */;
2466
- output: unknown /** Override the tool part state (e.g. "output-error" for custom denial) */;
2467
- state?:
2468
- | "output-available"
2469
- | "output-error" /** Error message when state is "output-error" */;
2470
- errorText?: string /** Whether server should auto-continue the conversation after applying result */;
2471
- autoContinue?: boolean /** Client tool schemas for continuation (client is source of truth) */;
2472
- clientTools?: Array<{
2473
- name: string;
2474
- description?: string;
2475
- parameters?: JSONSchema7;
2476
- }>;
2477
- }
2478
- | {
2479
- /** Client sends tool approval response to server (for tools with needsApproval) */ type: MessageType.CF_AGENT_TOOL_APPROVAL /** The tool call ID this approval is for */;
2480
- toolCallId: string /** Whether the tool execution was approved */;
2481
- approved: boolean /** Whether server should auto-continue the conversation after applying approval */;
2482
- autoContinue?: boolean;
2483
- };
2484
- //#endregion
2485
2495
  //#region src/chat/connection.d.ts
2486
2496
  /**
2487
2497
  * Connection I/O — shared WebSocket send guard for chat agents.
@@ -3131,14 +3141,22 @@ declare function parseProtocolMessage(raw: string): ChatProtocolEvent | null;
3131
3141
  /**
3132
3142
  * Reconcile incoming client messages against server state.
3133
3143
  *
3134
- * 1. Merges server-known tool outputs into incoming messages that still
3135
- * show stale states (input-available, approval-requested, approval-responded)
3136
- * 2. Reconciles assistant IDs: exact match → content-key match → toolCallId match
3144
+ * 1. Reconciles assistant IDs: exact match → same tool call → content-key
3145
+ * match. Each server row is claimed at most once, and a tool-call match
3146
+ * requires the same toolCallId, tool and input, since providers may reuse
3147
+ * toolCallIds across turns.
3148
+ * 2. Merges server-known tool outputs into incoming messages that still
3149
+ * show stale states (input-available, approval-requested, approval-responded).
3150
+ * Outputs come only from the server row the message resolved to.
3151
+ * 3. Drops a stale copy of an assistant the same submit also echoes under its
3152
+ * stored ID (see {@link dropStaleToolCopies}).
3137
3153
  *
3138
3154
  * @param incoming - Messages from the client
3139
3155
  * @param serverMessages - Current server-side messages (source of truth)
3140
3156
  * @param sanitizeForContentKey - Function to sanitize a message before computing
3141
- * its content key (typically strips ephemeral provider metadata)
3157
+ * its content key or comparing its tool calls against stored rows
3158
+ * (typically the host's persistence sanitizer, so a tool input the host
3159
+ * truncates on write compares equal to its stored form)
3142
3160
  * @returns Reconciled messages ready for persistence
3143
3161
  */
3144
3162
  declare function reconcileMessages(
@@ -3149,7 +3167,13 @@ declare function reconcileMessages(
3149
3167
  /**
3150
3168
  * For a single message, resolve its ID by matching toolCallId against server state.
3151
3169
  * Prevents duplicate DB rows when client IDs differ from server IDs.
3152
- * Tool call IDs are unique per conversation, so matching is safe regardless of state.
3170
+ *
3171
+ * @deprecated Unsafe when a provider reuses a toolCallId across turns. This
3172
+ * scans the whole conversation and claims nothing, so a later assistant can
3173
+ * adopt an earlier row's ID and overwrite it on upsert (#1992). Use
3174
+ * {@link reconcileMessages}, which claims server rows one-to-one over the
3175
+ * whole transcript. Retained only for backwards compatibility; no longer used
3176
+ * by `@cloudflare/ai-chat` or `@cloudflare/think`.
3153
3177
  */
3154
3178
  declare function resolveToolMergeId(
3155
3179
  message: UIMessage,
@@ -3237,6 +3261,16 @@ interface RepairInterruptedToolPartsOptions {
3237
3261
  * with an error. Skipped parts are not counted in `removedToolCalls`.
3238
3262
  */
3239
3263
  shouldRepair?: (part: UIMessage["parts"][number]) => boolean;
3264
+ /**
3265
+ * Also repair `approval-responded` parts in any message a later message
3266
+ * follows. Pass `true` only when no continuation will execute them: a turn
3267
+ * that is not itself a continuation, with no continuation waiting to run.
3268
+ * Parts in the last message are always kept, because the AI SDK executes a
3269
+ * trailing approval response when the transcript is submitted as-is. A
3270
+ * denied approval settles as `output-denied`; an approved one is handed to
3271
+ * `repairPart`. Defaults to `false`.
3272
+ */
3273
+ repairApprovalResponded?: boolean;
3240
3274
  }
3241
3275
  interface RepairInterruptedToolPartsResult {
3242
3276
  /** A new messages array; unchanged messages keep their original reference. */
@@ -3255,7 +3289,7 @@ interface RepairInterruptedToolPartsResult {
3255
3289
  *
3256
3290
  * - a tool part with NO settled result and state `approval-responded` is kept
3257
3291
  * verbatim (an approved server tool waiting for its continuation to run
3258
- * `execute()` — not abandoned);
3292
+ * `execute()` — not abandoned), unless `repairApprovalResponded` is set;
3259
3293
  * - a tool part with NO settled result for which `shouldRepair` returns false
3260
3294
  * is kept verbatim (a part still awaiting a CLIENT interaction; see option);
3261
3295
  * - any other tool part with no settled result is normalized then handed to
@@ -3327,6 +3361,22 @@ declare function persistReconstructedOrphan<
3327
3361
  ): Promise<boolean>;
3328
3362
  //#endregion
3329
3363
  //#region src/chat/recovery-codec.d.ts
3364
+ /**
3365
+ * Whether a reconstructed AI SDK `UIMessage` parts array carries any settled
3366
+ * (provider-accepted) tool result — the completed, often non-idempotent work
3367
+ * that a `{ persist: false }` recovery return would otherwise silently discard
3368
+ * (#1631). A part counts as settled when it is a tool part (`tool-*` /
3369
+ * `dynamic-tool`) carrying an `output`/`result`, or whose state reached a
3370
+ * terminal `output-{available,error,denied}`.
3371
+ *
3372
+ * This is the AI SDK codec's implementation of the per-vocabulary "did this
3373
+ * partial settle a tool?" question. It lives with {@link AISDKRecoveryCodec}
3374
+ * (not in the engine) because the codec owns the part vocabulary — the engine
3375
+ * only ever reads the precomputed `RecoveryPartial.hasSettledToolResults`
3376
+ * boolean and never names a part type. Foreign codecs (e.g. AG-UI) compute the
3377
+ * same boolean from their own chunk vocabulary without producing AI SDK parts.
3378
+ */
3379
+ declare function partialHasSettledToolResults(parts: MessagePart[]): boolean;
3330
3380
  /**
3331
3381
  * Reconstructs the partial assistant state of an interrupted turn from its
3332
3382
  * stored `ResumableStream` chunk bodies (oldest-first).
@@ -3409,6 +3459,7 @@ declare const aiSdkRecoveryCodec: AISDKRecoveryCodec;
3409
3459
  interface PendingChatTerminal {
3410
3460
  requestId: string;
3411
3461
  body: string;
3462
+ messageIds?: string[];
3412
3463
  }
3413
3464
  /**
3414
3465
  * The host-owned surface the resume handshake threads. `pendingResumeConnections`
@@ -3446,6 +3497,14 @@ interface ResumeHandshakeHost {
3446
3497
  * resumed by the replacement connection (#1784).
3447
3498
  */
3448
3499
  isConnectionPresent?(connectionId: string): boolean;
3500
+ /**
3501
+ * Whether the host still holds the request's terminal frames and will
3502
+ * broadcast them once its message is persisted. Optional: hosts that send
3503
+ * the terminal frame with the stream's end omit it. While true, a resume
3504
+ * ACK gets the stored chunks without a terminal, so the connection learns
3505
+ * the outcome from the live frame that follows the transcript.
3506
+ */
3507
+ holdsTerminalFrames?(requestId: string): boolean;
3449
3508
  }
3450
3509
  /**
3451
3510
  * Drives the server side of the stream-resume protocol over a
@@ -3551,6 +3610,12 @@ interface TruncateOptions {
3551
3610
  maxToolOutputChars?: number;
3552
3611
  /** Max chars for text parts in older messages (default: 10000) */
3553
3612
  maxTextChars?: number;
3613
+ /**
3614
+ * Truncate tool outputs in older messages (default: true). Set to `false`
3615
+ * to leave them intact and truncate the converted model messages with
3616
+ * {@link truncateOlderToolResults} instead.
3617
+ */
3618
+ toolOutputs?: boolean;
3554
3619
  }
3555
3620
  /**
3556
3621
  * Truncate tool outputs and long text in older messages.
@@ -3559,6 +3624,8 @@ interface TruncateOptions {
3559
3624
  * Recent messages (last `keepRecent`) are left intact.
3560
3625
  * Older messages get tool outputs and long text truncated. Structured tool
3561
3626
  * outputs are truncated in place instead of being replaced by raw strings.
3627
+ * Provider-executed tool outputs are never truncated: the provider parses
3628
+ * them against its own schema when they are replayed.
3562
3629
  *
3563
3630
  * Use in assembleContext() before sending to the LLM:
3564
3631
  * ```typescript
@@ -3573,6 +3640,31 @@ declare function truncateOlderMessages(
3573
3640
  messages: SessionMessage[],
3574
3641
  options?: TruncateOptions
3575
3642
  ): SessionMessage[];
3643
+ interface TruncateToolResultsOptions {
3644
+ /** Number of recent UI messages whose tool results stay intact (default: 4) */
3645
+ keepRecent?: number;
3646
+ /** Max chars for each older tool result (default: 500) */
3647
+ maxToolOutputChars?: number;
3648
+ }
3649
+ /**
3650
+ * Truncate the tool results of older messages after `convertToModelMessages`.
3651
+ * `messages` are the UI messages that were converted, so "older" means the
3652
+ * same messages {@link truncateOlderMessages} treats as older.
3653
+ *
3654
+ * The converted result is what the model reads, after any `toModelOutput`, so
3655
+ * no tool schema applies to it. Provider-executed results are left intact.
3656
+ * Inline file and image bytes in an older `content` result are replaced by a
3657
+ * short text marker.
3658
+ *
3659
+ * Tool call ids are not unique across turns, so each converted result is
3660
+ * matched to the UI tool part it came from by order: the Nth result for an id
3661
+ * belongs to the Nth UI part with that id that converts to a tool result.
3662
+ */
3663
+ declare function truncateOlderToolResults<M extends ModelMessage>(
3664
+ modelMessages: M[],
3665
+ messages: readonly SessionMessage[],
3666
+ options?: TruncateToolResultsOptions
3667
+ ): M[];
3576
3668
  //#endregion
3577
3669
  export {
3578
3670
  AGENT_TOOL_STREAM_PROGRESS_BUMP_THROTTLE_MS,
@@ -3598,6 +3690,7 @@ export {
3598
3690
  CHAT_RECOVERING_FLAG_TTL_MS,
3599
3691
  CHAT_RECOVERING_KEY,
3600
3692
  CHAT_RECOVERY_ALARM_DEBOUNCE_MS,
3693
+ CHAT_RECOVERY_CANCELLED_REASON,
3601
3694
  CHAT_RECOVERY_INCIDENT_KEY_PREFIX,
3602
3695
  CHAT_RECOVERY_INCIDENT_TTL_MS,
3603
3696
  CHAT_RECOVERY_PROGRESS_KEY,
@@ -3630,6 +3723,7 @@ export {
3630
3723
  type ChatStreamStatus,
3631
3724
  type ChatTerminalRecord,
3632
3725
  type ChatTurnClosureEntry,
3726
+ type ChatTurnOutcome,
3633
3727
  type ChatTurnTaskHooks,
3634
3728
  type ChunkAction,
3635
3729
  type ChunkResult,
@@ -3696,11 +3790,13 @@ export {
3696
3790
  TextSegmentJoiner,
3697
3791
  type ToolPartUpdate,
3698
3792
  type TruncateOptions,
3793
+ type TruncateToolResultsOptions,
3699
3794
  TurnQueue,
3700
3795
  type TurnResult,
3701
3796
  aiSdkRecoveryCodec,
3702
3797
  applyAgentToolEvent,
3703
3798
  applyChunkToParts,
3799
+ applyLateToolInput,
3704
3800
  applyToolUpdate,
3705
3801
  awaitWithDeadline,
3706
3802
  transition as broadcastTransition,
@@ -3708,6 +3804,7 @@ export {
3708
3804
  buildInClauseStrings,
3709
3805
  bumpChatRecoveryProgress,
3710
3806
  byteLength,
3807
+ chatRecoveryBackoffSeconds,
3711
3808
  chatRecoveryTaskRunOptions,
3712
3809
  classifyAgentToolChildRecovery,
3713
3810
  clearChatTerminal,
@@ -3724,13 +3821,19 @@ export {
3724
3821
  enforceRowSizeLimit,
3725
3822
  hasIncompleteToolBatch,
3726
3823
  interceptAgentToolBroadcast,
3824
+ isDurableObjectResetError,
3825
+ isLateToolInputChunk,
3727
3826
  isPlatformFailure,
3827
+ isPositionlessAgentToolChunk,
3728
3828
  isReplayChunk,
3729
3829
  iterateWithStallWatchdog,
3830
+ lateToolInputForwardChunks,
3730
3831
  listActiveChatRecoveryIncidents,
3731
3832
  normalizeToolInput,
3833
+ originMessageIds$1 as originMessageIds,
3732
3834
  parseProtocolMessage,
3733
3835
  partAwaitsClientInteraction,
3836
+ partialHasSettledToolResults,
3734
3837
  pausedExecutionUpdate,
3735
3838
  pendingChatTerminal,
3736
3839
  persistReconstructedOrphan,
@@ -3741,6 +3844,7 @@ export {
3741
3844
  repairInterruptedToolParts,
3742
3845
  resolveChatRecoveryConfig,
3743
3846
  resolveToolMergeId,
3847
+ retryAfterSeconds,
3744
3848
  runChatRecoveryExhaustion,
3745
3849
  sanitizeMessage,
3746
3850
  sendIfOpen,
@@ -3751,7 +3855,9 @@ export {
3751
3855
  toolPartHasSettledResult,
3752
3856
  toolResultUpdate,
3753
3857
  truncateOlderMessages,
3858
+ truncateOlderToolResults,
3754
3859
  unwrapChatFiberSnapshot,
3860
+ withOriginMessageIds,
3755
3861
  wrapChatFiberSnapshot
3756
3862
  };
3757
3863
  //# sourceMappingURL=index.d.ts.map