@tanstack/ai 0.59.0 → 0.63.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 (123) hide show
  1. package/README.md +1 -0
  2. package/dist/esm/activities/chat/adapter.d.ts +9 -0
  3. package/dist/esm/activities/chat/adapter.js +1 -0
  4. package/dist/esm/activities/chat/adapter.js.map +1 -1
  5. package/dist/esm/activities/chat/agents/define-agent.d.ts +17 -5
  6. package/dist/esm/activities/chat/agents/define-agent.js.map +1 -1
  7. package/dist/esm/activities/chat/agents/spawn.d.ts +2 -0
  8. package/dist/esm/activities/chat/agents/spawn.js +8 -5
  9. package/dist/esm/activities/chat/agents/spawn.js.map +1 -1
  10. package/dist/esm/activities/chat/index.js +289 -78
  11. package/dist/esm/activities/chat/index.js.map +1 -1
  12. package/dist/esm/activities/chat/messages.js +35 -19
  13. package/dist/esm/activities/chat/messages.js.map +1 -1
  14. package/dist/esm/activities/chat/middleware/types.d.ts +1 -0
  15. package/dist/esm/activities/chat/middleware/types.js.map +1 -1
  16. package/dist/esm/activities/chat/stream/message-updaters.d.ts +2 -2
  17. package/dist/esm/activities/chat/stream/message-updaters.js +11 -3
  18. package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
  19. package/dist/esm/activities/chat/stream/processor.d.ts +11 -10
  20. package/dist/esm/activities/chat/stream/processor.js +51 -28
  21. package/dist/esm/activities/chat/stream/processor.js.map +1 -1
  22. package/dist/esm/activities/chat/tools/tool-calls.d.ts +16 -2
  23. package/dist/esm/activities/chat/tools/tool-calls.js +57 -16
  24. package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
  25. package/dist/esm/activities/chat/tools/tool-definition.d.ts +4 -0
  26. package/dist/esm/activities/chat/tools/tool-definition.js +4 -0
  27. package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
  28. package/dist/esm/activities/embed/adapter.d.ts +7 -0
  29. package/dist/esm/activities/embed/adapter.js +1 -0
  30. package/dist/esm/activities/embed/adapter.js.map +1 -1
  31. package/dist/esm/activities/embed/index.js +2 -0
  32. package/dist/esm/activities/embed/index.js.map +1 -1
  33. package/dist/esm/activities/evaluate/adapter.d.ts +4 -0
  34. package/dist/esm/activities/evaluate/adapter.js.map +1 -1
  35. package/dist/esm/activities/evaluate/index.d.ts +4 -0
  36. package/dist/esm/activities/evaluate/index.js +3 -1
  37. package/dist/esm/activities/evaluate/index.js.map +1 -1
  38. package/dist/esm/activities/files/adapter.d.ts +97 -0
  39. package/dist/esm/activities/files/adapter.js +45 -0
  40. package/dist/esm/activities/files/adapter.js.map +1 -0
  41. package/dist/esm/activities/files/index.d.ts +66 -0
  42. package/dist/esm/activities/files/index.js +78 -0
  43. package/dist/esm/activities/files/index.js.map +1 -0
  44. package/dist/esm/activities/generateImage/adapter.d.ts +8 -0
  45. package/dist/esm/activities/generateImage/adapter.js +1 -0
  46. package/dist/esm/activities/generateImage/adapter.js.map +1 -1
  47. package/dist/esm/activities/generateImage/index.js +2 -0
  48. package/dist/esm/activities/generateImage/index.js.map +1 -1
  49. package/dist/esm/activities/generateVideo/adapter.d.ts +8 -0
  50. package/dist/esm/activities/generateVideo/adapter.js +1 -0
  51. package/dist/esm/activities/generateVideo/adapter.js.map +1 -1
  52. package/dist/esm/activities/generateVideo/index.js +3 -0
  53. package/dist/esm/activities/generateVideo/index.js.map +1 -1
  54. package/dist/esm/activities/generateWorld/adapter.d.ts +4 -2
  55. package/dist/esm/activities/generateWorld/adapter.js.map +1 -1
  56. package/dist/esm/activities/generateWorld/index.d.ts +4 -3
  57. package/dist/esm/activities/generateWorld/index.js +5 -4
  58. package/dist/esm/activities/generateWorld/index.js.map +1 -1
  59. package/dist/esm/activities/index.d.ts +6 -3
  60. package/dist/esm/activities/index.js +13 -11
  61. package/dist/esm/activities/summarize/chat-stream-summarize.d.ts +2 -0
  62. package/dist/esm/activities/summarize/chat-stream-summarize.js +8 -8
  63. package/dist/esm/activities/summarize/chat-stream-summarize.js.map +1 -1
  64. package/dist/esm/client.d.ts +3 -1
  65. package/dist/esm/client.js +2 -1
  66. package/dist/esm/client.js.map +1 -1
  67. package/dist/esm/index.d.ts +4 -3
  68. package/dist/esm/index.js +5 -3
  69. package/dist/esm/interrupt-resume.js +29 -4
  70. package/dist/esm/interrupt-resume.js.map +1 -1
  71. package/dist/esm/middlewares/otel.d.ts +5 -2
  72. package/dist/esm/middlewares/otel.js +114 -0
  73. package/dist/esm/middlewares/otel.js.map +1 -1
  74. package/dist/esm/types.d.ts +114 -14
  75. package/dist/esm/utilities/ag-ui-wire.js +39 -16
  76. package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
  77. package/dist/esm/utilities/content-source.d.ts +60 -0
  78. package/dist/esm/utilities/content-source.js +85 -0
  79. package/dist/esm/utilities/content-source.js.map +1 -0
  80. package/dist/esm/utilities/provider-executed.d.ts +7 -0
  81. package/dist/esm/utilities/provider-executed.js +10 -1
  82. package/dist/esm/utilities/provider-executed.js.map +1 -1
  83. package/dist/esm/utilities/tool-result.d.ts +14 -3
  84. package/dist/esm/utilities/tool-result.js +26 -3
  85. package/dist/esm/utilities/tool-result.js.map +1 -1
  86. package/package.json +4 -4
  87. package/skills/ai-core/adapter-configuration/SKILL.md +62 -0
  88. package/skills/ai-core/chat-experience/SKILL.md +134 -0
  89. package/skills/ai-core/media-generation/SKILL.md +8 -0
  90. package/skills/ai-core/tool-calling/SKILL.md +103 -0
  91. package/src/activities/chat/adapter.ts +10 -0
  92. package/src/activities/chat/agents/define-agent.ts +20 -3
  93. package/src/activities/chat/agents/spawn.ts +20 -12
  94. package/src/activities/chat/index.ts +458 -99
  95. package/src/activities/chat/messages.ts +52 -6
  96. package/src/activities/chat/middleware/types.ts +1 -0
  97. package/src/activities/chat/stream/message-updaters.ts +27 -2
  98. package/src/activities/chat/stream/processor.ts +81 -49
  99. package/src/activities/chat/tools/tool-calls.ts +104 -9
  100. package/src/activities/chat/tools/tool-definition.ts +8 -0
  101. package/src/activities/embed/adapter.ts +7 -0
  102. package/src/activities/embed/index.ts +5 -0
  103. package/src/activities/evaluate/adapter.ts +4 -0
  104. package/src/activities/evaluate/index.ts +6 -0
  105. package/src/activities/files/adapter.ts +120 -0
  106. package/src/activities/files/index.ts +113 -0
  107. package/src/activities/generateImage/adapter.ts +8 -0
  108. package/src/activities/generateImage/index.ts +4 -0
  109. package/src/activities/generateVideo/adapter.ts +8 -0
  110. package/src/activities/generateVideo/index.ts +7 -0
  111. package/src/activities/generateWorld/adapter.ts +4 -2
  112. package/src/activities/generateWorld/index.ts +7 -6
  113. package/src/activities/index.ts +25 -1
  114. package/src/activities/summarize/chat-stream-summarize.ts +22 -12
  115. package/src/client.ts +8 -0
  116. package/src/index.ts +17 -0
  117. package/src/interrupt-resume.ts +55 -4
  118. package/src/middlewares/otel.ts +161 -3
  119. package/src/types.ts +114 -14
  120. package/src/utilities/ag-ui-wire.ts +72 -17
  121. package/src/utilities/content-source.ts +138 -0
  122. package/src/utilities/provider-executed.ts +13 -0
  123. package/src/utilities/tool-result.ts +45 -3
@@ -17,12 +17,13 @@ import { hashSchemaInput, normalizeApprovalSchema } from "./tools/approval-schem
17
17
  import { INTERRUPT_BINDING_METADATA_KEY, InterruptResumeValidationError, readInterruptBinding, readUnopenedInterruptBinding, validateInterruptResumeBatch } from "../../interrupt-resume.js";
18
18
  import { INTERRUPT_PAYLOAD_METADATA_KEY, createInterruptBinding, rehydrateInterruptRequest } from "../../interrupt-definition.js";
19
19
  import { readGenericInterruptContinuation } from "../../generic-interrupt-continuation.js";
20
- import { normalizeToolResult } from "../../utilities/tool-result.js";
21
- import { subagentHostMessageId } from "../../utilities/subagent-wire.js";
22
20
  import { isProviderExecutedToolCall } from "../../utilities/provider-executed.js";
21
+ import { normalizeToolResult, parseToolOutput, toolResultErrorText } from "../../utilities/tool-result.js";
22
+ import { subagentHostMessageId } from "../../utilities/subagent-wire.js";
23
23
  import { appendUiResourceToModelMessages, convertMessagesToModelMessages, generateMessageId, modelMessagesToUIMessages, safeJsonStringify, uiResourcePartFromCustomValue } from "./messages.js";
24
24
  import { uiMessagesToWire } from "../../utilities/ag-ui-wire.js";
25
25
  import { restorePublicUsage } from "../../utilities/restore-inbound-chunk.js";
26
+ import { assertMessagesFileSourceSupport } from "../../utilities/content-source.js";
26
27
  import { LazyToolManager } from "./tools/lazy-tool-manager.js";
27
28
  import { assertUniqueToolNames } from "./tools/unique-tool-names.js";
28
29
  import { MiddlewareAbortError, ToolCallManager, executeToolCalls } from "./tools/tool-calls.js";
@@ -50,12 +51,6 @@ var kind = "text";
50
51
  var interruptBindingMetadataKey = INTERRUPT_BINDING_METADATA_KEY;
51
52
  /** Resume entries a subagent tool call owns. The parent run skips them. */
52
53
  var CHILD_RESUME_IDS = Symbol("tanstack.ai.childResumeIds");
53
- function assertNoFileSources(adapterName, messages) {
54
- for (const message of messages) {
55
- if (!Array.isArray(message.content)) continue;
56
- for (const part of message.content) if ("source" in part && part.source.type === "file") throw new Error(`${adapterName} does not support provider file-handle sources ({ type: 'file' }). Pass a data or url source.`);
57
- }
58
- }
59
54
  function isInterruptSubmissionError(value) {
60
55
  if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
61
56
  if (!("scope" in value) || !("code" in value) || !("message" in value) || !("source" in value) || !("retryable" in value) || !("threadId" in value) || !("interruptedRunId" in value) || !("generation" in value) || typeof value.code !== "string" || typeof value.message !== "string" || typeof value.retryable !== "boolean" || typeof value.threadId !== "string" || typeof value.interruptedRunId !== "string" || typeof value.generation !== "number") return false;
@@ -143,6 +138,15 @@ var TextEngine = class {
143
138
  streamIdentityCaptured = false;
144
139
  accumulatedContent = "";
145
140
  accumulatedThinking = [];
141
+ /**
142
+ * Arrival order of this iteration's thinking steps, text and tool calls.
143
+ * A ModelMessage keeps `thinking` apart from `content`/`toolCalls`, so a
144
+ * provider turn that thinks between provider-executed tools would otherwise
145
+ * be recorded as "all thinking, then text, then tools" and the provider
146
+ * rejects the replay (signed thinking must keep its position). `null` once
147
+ * the order could no longer be tracked (callers fall back to one message).
148
+ */
149
+ turnParts = [];
146
150
  currentThinkingContent = "";
147
151
  currentThinkingSignature = "";
148
152
  eventOptions;
@@ -159,8 +163,10 @@ var TextEngine = class {
159
163
  initialClientToolResults;
160
164
  resumeApprovals = /* @__PURE__ */ new Map();
161
165
  resumeClientToolResults = /* @__PURE__ */ new Map();
166
+ resumeClientToolErrors = /* @__PURE__ */ new Map();
162
167
  resumeDeniedToolResults = /* @__PURE__ */ new Map();
163
168
  resumeCancelledToolCallIds = /* @__PURE__ */ new Set();
169
+ resumeInputResponses = /* @__PURE__ */ new Map();
164
170
  resumeGenericInterrupts = /* @__PURE__ */ new Map();
165
171
  resumeGenericInterruptRequests = /* @__PURE__ */ new Map();
166
172
  threadId;
@@ -326,6 +332,33 @@ var TextEngine = class {
326
332
  getFinalizationError() {
327
333
  return this.finalizationError;
328
334
  }
335
+ async runTerminalHook() {
336
+ if (this.terminalHookCalled || this.isCancelled()) return;
337
+ this.terminalHookCalled = true;
338
+ if (this.finalizationError) {
339
+ const errForHook = new Error(this.finalizationError.message, this.finalizationError.cause !== void 0 ? { cause: this.finalizationError.cause } : void 0);
340
+ if (this.finalizationError.code !== void 0) Object.defineProperty(errForHook, "code", {
341
+ value: this.finalizationError.code,
342
+ enumerable: true
343
+ });
344
+ if (this.finalizationError.rawText !== void 0) Object.defineProperty(errForHook, "rawText", {
345
+ value: this.finalizationError.rawText,
346
+ enumerable: true
347
+ });
348
+ await this.middlewareRunner.runOnError(this.middlewareCtx, {
349
+ error: errForHook,
350
+ duration: Date.now() - this.streamStartTime
351
+ });
352
+ return;
353
+ }
354
+ this.addTerminalAssistantMessages();
355
+ await this.middlewareRunner.runOnFinish(this.middlewareCtx, {
356
+ finishReason: this.lastFinishReason,
357
+ duration: Date.now() - this.streamStartTime,
358
+ content: this.accumulatedContent,
359
+ usage: rebuildTokenUsage(this.finishedEvent?.usage, tanstackMetadata(this.finishedEvent ?? void 0)?.usage)
360
+ });
361
+ }
329
362
  async *run() {
330
363
  this.beforeRun();
331
364
  this.logger.agentLoop("run started", { threadId: this.middlewareCtx.threadId });
@@ -351,7 +384,11 @@ var TextEngine = class {
351
384
  }
352
385
  return;
353
386
  }
354
- if ((yield* this.checkForPendingToolCalls()) === "wait") return;
387
+ const pendingPhase = yield* this.checkForPendingToolCalls();
388
+ if (pendingPhase === "stop" || pendingPhase === "wait") {
389
+ await this.runTerminalHook();
390
+ return;
391
+ }
355
392
  if (!(!!this.finalStructuredOutput && this.tools.length === 0 && this.finalStructuredOutput.nativeCombined !== true)) do {
356
393
  if (this.earlyTermination) break;
357
394
  if (this.isCancelled()) return;
@@ -387,29 +424,7 @@ var TextEngine = class {
387
424
  if (!this.finalizationError && !this.isCancelled()) yield* this.flushDeferredModelRunFinishedChunks();
388
425
  } else yield* this.runStructuredFinalization();
389
426
  }
390
- if (!this.terminalHookCalled && this.toolPhase !== "wait" && !this.isCancelled()) {
391
- if (this.finalizationError) {
392
- this.terminalHookCalled = true;
393
- const errForHook = new Error(this.finalizationError.message, this.finalizationError.cause !== void 0 ? { cause: this.finalizationError.cause } : void 0);
394
- if (this.finalizationError.code !== void 0) Object.defineProperty(errForHook, "code", {
395
- value: this.finalizationError.code,
396
- enumerable: true
397
- });
398
- await this.middlewareRunner.runOnError(this.middlewareCtx, {
399
- error: errForHook,
400
- duration: Date.now() - this.streamStartTime
401
- });
402
- } else {
403
- this.addTerminalAssistantMessages();
404
- this.terminalHookCalled = true;
405
- await this.middlewareRunner.runOnFinish(this.middlewareCtx, {
406
- finishReason: this.lastFinishReason,
407
- duration: Date.now() - this.streamStartTime,
408
- content: this.accumulatedContent,
409
- usage: rebuildTokenUsage(this.finishedEvent?.usage, tanstackMetadata(this.finishedEvent ?? void 0)?.usage)
410
- });
411
- }
412
- }
427
+ await this.runTerminalHook();
413
428
  } catch (error) {
414
429
  if (error instanceof Error && error.name === "InterruptReplaySignal" && "continuationRunId" in error && typeof error.continuationRunId === "string") {
415
430
  this.terminalHookCalled = true;
@@ -501,6 +516,7 @@ var TextEngine = class {
501
516
  this.streamIdentityCaptured = false;
502
517
  this.accumulatedContent = "";
503
518
  this.accumulatedThinking = [];
519
+ this.turnParts = [];
504
520
  this.currentThinkingContent = "";
505
521
  this.currentThinkingSignature = "";
506
522
  this.finishedEvent = null;
@@ -531,7 +547,7 @@ var TextEngine = class {
531
547
  const { approvals } = this.collectClientState();
532
548
  const adapterApprovals = /* @__PURE__ */ new Map();
533
549
  for (const [approvalId, resolution] of approvals) adapterApprovals.set(approvalId, typeof resolution === "boolean" ? resolution : resolution.approved);
534
- assertNoFileSources(this.adapter.name, this.messages);
550
+ assertMessagesFileSourceSupport(this.adapter, this.messages);
535
551
  for await (const raw of this.adapter.chatStream({
536
552
  model: this.params.model,
537
553
  messages: this.providerMessages,
@@ -666,9 +682,23 @@ var TextEngine = class {
666
682
  }
667
683
  handleTextMessageContentEvent(chunk) {
668
684
  const extra = chunk;
685
+ const before = this.accumulatedContent;
669
686
  if (typeof extra.content === "string" && extra.content !== "") this.accumulatedContent = extra.content;
670
687
  else this.accumulatedContent += chunk.delta;
671
688
  this.middlewareCtx.accumulatedContent = this.accumulatedContent;
689
+ if (!this.turnParts) return;
690
+ if (!this.accumulatedContent.startsWith(before)) {
691
+ this.turnParts = null;
692
+ return;
693
+ }
694
+ const delta = this.accumulatedContent.slice(before.length);
695
+ if (delta === "") return;
696
+ const last = this.turnParts[this.turnParts.length - 1];
697
+ if (last && last.type === "text") last.content += delta;
698
+ else this.turnParts.push({
699
+ type: "text",
700
+ content: delta
701
+ });
672
702
  }
673
703
  captureStreamMessageIdentity(messageId) {
674
704
  this.currentMessageId = messageId;
@@ -685,6 +715,11 @@ var TextEngine = class {
685
715
  handleToolCallStartEvent(chunk) {
686
716
  if (typeof chunk.parentMessageId === "string" && chunk.parentMessageId !== "") this.captureStreamMessageIdentity(chunk.parentMessageId);
687
717
  this.toolCallManager.addToolCallStartEvent(chunk);
718
+ if (this.turnParts && !this.turnParts.some((part) => part.type === "call" && part.id === chunk.toolCallId)) this.turnParts.push({
719
+ type: "call",
720
+ id: chunk.toolCallId,
721
+ providerExecuted: isProviderExecutedToolCall({ metadata: chunk.metadata })
722
+ });
688
723
  const metadata = chunk.metadata;
689
724
  const thoughtSignature = metadata != null && typeof metadata === "object" && "thoughtSignature" in metadata && typeof metadata.thoughtSignature === "string" && metadata.thoughtSignature !== "" ? metadata.thoughtSignature : void 0;
690
725
  if (thoughtSignature === void 0) return;
@@ -746,17 +781,42 @@ var TextEngine = class {
746
781
  content: this.currentThinkingContent,
747
782
  ...this.currentThinkingSignature && { signature: this.currentThinkingSignature }
748
783
  });
784
+ if (this.turnParts) {
785
+ const placeholder = [...this.turnParts].reverse().find((part) => part.type === "thinking" && part.index === -1);
786
+ const index = this.accumulatedThinking.length - 1;
787
+ if (placeholder) placeholder.index = index;
788
+ else this.turnParts.push({
789
+ type: "thinking",
790
+ index
791
+ });
792
+ }
749
793
  this.currentThinkingContent = "";
750
794
  this.currentThinkingSignature = "";
751
795
  }
752
796
  }
797
+ /**
798
+ * Record where the current thinking step sits among this turn's parts. A
799
+ * step is finalized only when the next step starts (or the turn ends), by
800
+ * which time later tool calls have already arrived, so the position has to
801
+ * be noted when the step's first content or signature shows up.
802
+ */
803
+ noteThinkingStepPosition() {
804
+ if (this.turnParts && this.currentThinkingContent === "" && this.currentThinkingSignature === "") this.turnParts.push({
805
+ type: "thinking",
806
+ index: -1
807
+ });
808
+ }
753
809
  handleStepStartedEvent() {
754
810
  this.finalizeCurrentThinkingStep();
755
811
  }
756
812
  handleStepFinishedEvent(chunk) {
757
- if (typeof chunk.signature === "string" && chunk.signature !== "") this.currentThinkingSignature = chunk.signature;
813
+ if (typeof chunk.signature === "string" && chunk.signature !== "") {
814
+ this.noteThinkingStepPosition();
815
+ this.currentThinkingSignature = chunk.signature;
816
+ }
758
817
  }
759
818
  handleReasoningMessageContentEvent(chunk) {
819
+ this.noteThinkingStepPosition();
760
820
  this.currentThinkingContent += chunk.delta;
761
821
  }
762
822
  handleReasoningEncryptedValueEvent(chunk) {
@@ -768,6 +828,7 @@ var TextEngine = class {
768
828
  };
769
829
  return;
770
830
  }
831
+ this.noteThinkingStepPosition();
771
832
  this.currentThinkingSignature = chunk.encryptedValue;
772
833
  }
773
834
  /**
@@ -835,8 +896,10 @@ var TextEngine = class {
835
896
  await this.middlewareRunner.runOnAfterToolCall(this.middlewareCtx, info);
836
897
  }
837
898
  }, this.middlewareCtx.context, this.toolAbortSignal, {
899
+ clientToolErrors: this.resumeClientToolErrors,
838
900
  deniedToolResults: this.resumeDeniedToolResults,
839
- cancelledToolCallIds: this.resumeCancelledToolCallIds
901
+ cancelledToolCallIds: this.resumeCancelledToolCallIds,
902
+ inputResponses: this.resumeInputResponses
840
903
  });
841
904
  const executionResult = yield* this.drainToolCallGenerator(generator);
842
905
  if (this.isMiddlewareAborted()) {
@@ -850,10 +913,10 @@ var TextEngine = class {
850
913
  needsApproval: executionResult.needsApproval,
851
914
  needsClientExecution: executionResult.needsClientExecution
852
915
  }));
853
- if (executionResult.needsApproval.length > 0 || executionResult.needsClientExecution.length > 0 || executionResult.subagentInterrupts.length > 0) {
916
+ if (executionResult.needsApproval.length > 0 || executionResult.needsClientExecution.length > 0 || executionResult.inputRequired.length > 0 || executionResult.subagentInterrupts.length > 0) {
854
917
  this.discardDeferredToolCallRunFinishedChunks();
855
918
  if (allResults.length > 0) for (const chunk of this.buildToolResultChunks(allResults, finishEvent)) yield* this.pipeThroughMiddleware(chunk);
856
- const emitted = yield* this.emitActionableInterruptBoundary(finishEvent, executionResult.needsApproval, executionResult.needsClientExecution, [], executionResult.subagentInterrupts);
919
+ const emitted = yield* this.emitActionableInterruptBoundary(finishEvent, executionResult.needsApproval, executionResult.needsClientExecution, [], executionResult.inputRequired, executionResult.subagentInterrupts);
857
920
  this.setToolPhase(emitted ? "wait" : "stop");
858
921
  return emitted ? "wait" : "stop";
859
922
  }
@@ -927,8 +990,10 @@ var TextEngine = class {
927
990
  await this.middlewareRunner.runOnAfterToolCall(this.middlewareCtx, info);
928
991
  }
929
992
  }, this.middlewareCtx.context, this.toolAbortSignal, {
993
+ clientToolErrors: this.resumeClientToolErrors,
930
994
  deniedToolResults: this.resumeDeniedToolResults,
931
- cancelledToolCallIds: this.resumeCancelledToolCallIds
995
+ cancelledToolCallIds: this.resumeCancelledToolCallIds,
996
+ inputResponses: this.resumeInputResponses
932
997
  });
933
998
  const executionResult = yield* this.drainToolCallGenerator(generator);
934
999
  this.middlewareCtx.phase = "afterTools";
@@ -947,13 +1012,13 @@ var TextEngine = class {
947
1012
  const afterToolRequests = yield* this.runWhileYielding(this.middlewareRunner.runOnInterruptBoundary(this.middlewareCtx));
948
1013
  if (afterToolRequests.length > 0) {
949
1014
  for (const chunk of afterToolBoundaryChunks) yield* this.pipeThroughMiddleware(chunk);
950
- yield* this.emitBoundaryInterrupts("afterTools", finishEvent, toolCalls, afterToolRequests);
1015
+ yield* this.emitBoundaryInterrupts("afterTools", finishEvent, toolCalls, afterToolRequests, executionResult.inputRequired);
951
1016
  this.setToolPhase("wait");
952
1017
  return;
953
1018
  }
954
- if (executionResult.needsApproval.length > 0 || executionResult.needsClientExecution.length > 0 || executionResult.subagentInterrupts.length > 0) {
1019
+ if (executionResult.needsApproval.length > 0 || executionResult.needsClientExecution.length > 0 || executionResult.inputRequired.length > 0 || executionResult.subagentInterrupts.length > 0) {
955
1020
  if (allResults.length > 0) for (const chunk of afterToolBoundaryChunks) yield* this.pipeThroughMiddleware(chunk);
956
- const emitted = yield* this.emitActionableInterruptBoundary(finishEvent, executionResult.needsApproval, executionResult.needsClientExecution, [], executionResult.subagentInterrupts);
1021
+ const emitted = yield* this.emitActionableInterruptBoundary(finishEvent, executionResult.needsApproval, executionResult.needsClientExecution, [], executionResult.inputRequired, executionResult.subagentInterrupts);
957
1022
  this.setToolPhase(emitted ? "wait" : "stop");
958
1023
  return;
959
1024
  }
@@ -1013,16 +1078,67 @@ var TextEngine = class {
1013
1078
  shouldExecuteToolPhase() {
1014
1079
  return this.lastFinishReason === "tool_calls" && this.tools.length > 0 && this.toolCallManager.hasToolCalls();
1015
1080
  }
1081
+ /**
1082
+ * Split this iteration into assistant ModelMessages that keep the provider's
1083
+ * block order: a new segment starts at every thinking step that follows a
1084
+ * provider-executed tool call (the rule buildAssistantMessages applies to
1085
+ * UIMessages). Segments after the first get `${id}-segment-${n}` ids.
1086
+ * Returns null when no split is needed or the order could not be tracked,
1087
+ * so callers fall back to the single-message shape.
1088
+ */
1089
+ buildOrderedAssistantSegments(toolCalls, id, createdAt) {
1090
+ const parts = this.turnParts;
1091
+ if (!parts) return null;
1092
+ const providerCallIds = new Set(parts.flatMap((part) => part.type === "call" && part.providerExecuted ? [part.id] : []));
1093
+ let current = {
1094
+ thinking: [],
1095
+ text: "",
1096
+ callIds: []
1097
+ };
1098
+ const segments = [current];
1099
+ let split = false;
1100
+ for (const part of parts) if (part.type === "thinking") {
1101
+ const thinking = this.accumulatedThinking[part.index];
1102
+ if (!thinking) return null;
1103
+ if (current.callIds.some((callId) => providerCallIds.has(callId))) {
1104
+ current = {
1105
+ thinking: [thinking],
1106
+ text: "",
1107
+ callIds: []
1108
+ };
1109
+ segments.push(current);
1110
+ split = true;
1111
+ } else current.thinking.push(thinking);
1112
+ } else if (part.type === "text") current.text += part.content;
1113
+ else current.callIds.push(part.id);
1114
+ if (!split) return null;
1115
+ if (segments.map((segment) => segment.text).join("") !== this.accumulatedContent) return null;
1116
+ if (segments.reduce((n, segment) => n + segment.thinking.length, 0) !== this.accumulatedThinking.length) return null;
1117
+ const placed = new Set(segments.flatMap((segment) => segment.callIds));
1118
+ for (const toolCall of toolCalls) if (!placed.has(toolCall.id)) current.callIds.push(toolCall.id);
1119
+ return segments.map((segment, index) => {
1120
+ const segmentCalls = toolCalls.filter((toolCall) => segment.callIds.includes(toolCall.id));
1121
+ return {
1122
+ role: "assistant",
1123
+ content: segment.text || null,
1124
+ ...segmentCalls.length > 0 && { toolCalls: segmentCalls },
1125
+ id: id === void 0 ? void 0 : index === 0 ? id : `${id}-segment-${index}`,
1126
+ createdAt,
1127
+ ...segment.thinking.length > 0 && { thinking: segment.thinking }
1128
+ };
1129
+ });
1130
+ }
1016
1131
  addAssistantToolCallMessage(toolCalls) {
1017
1132
  this.finalizeCurrentThinkingStep();
1018
- this.messages = [...this.messages, {
1133
+ const segments = this.buildOrderedAssistantSegments(toolCalls, this.currentMessageId ?? void 0, this.currentMessageCreatedAt ?? void 0);
1134
+ this.messages = [...this.messages, ...segments ?? [{
1019
1135
  role: "assistant",
1020
1136
  content: this.accumulatedContent || null,
1021
1137
  toolCalls,
1022
1138
  id: this.currentMessageId ?? void 0,
1023
1139
  createdAt: this.currentMessageCreatedAt ?? void 0,
1024
1140
  ...this.accumulatedThinking.length > 0 && { thinking: this.accumulatedThinking }
1025
- }];
1141
+ }]];
1026
1142
  this.middlewareCtx.messages = this.messages;
1027
1143
  }
1028
1144
  addTerminalAssistantMessages() {
@@ -1063,13 +1179,17 @@ var TextEngine = class {
1063
1179
  ...thinking ? { thinking } : {}
1064
1180
  });
1065
1181
  } else {
1066
- if (!currentTurnAlreadyRecorded && (this.accumulatedContent !== "" || thinking)) messages.push({
1067
- role: "assistant",
1068
- content: this.accumulatedContent || null,
1069
- id: this.currentMessageId ?? this.createId("msg"),
1070
- createdAt: this.currentMessageCreatedAt ?? /* @__PURE__ */ new Date(),
1071
- ...thinking ? { thinking } : {}
1072
- });
1182
+ if (!currentTurnAlreadyRecorded && (this.accumulatedContent !== "" || thinking)) {
1183
+ const id = this.currentMessageId ?? this.createId("msg");
1184
+ const createdAt = this.currentMessageCreatedAt ?? /* @__PURE__ */ new Date();
1185
+ messages.push(...this.buildOrderedAssistantSegments(this.toolCallManager.getToolCalls(), id, createdAt) ?? [{
1186
+ role: "assistant",
1187
+ content: this.accumulatedContent || null,
1188
+ id,
1189
+ createdAt,
1190
+ ...thinking ? { thinking } : {}
1191
+ }]);
1192
+ }
1073
1193
  if (structuredOutput) messages.push({
1074
1194
  role: "assistant",
1075
1195
  content: raw || null,
@@ -1125,7 +1245,7 @@ var TextEngine = class {
1125
1245
  genericInterruptId() {
1126
1246
  return this.createId("interrupt");
1127
1247
  }
1128
- buildActionableInterrupts(approvals, clientRequests, genericRequests = [], genericInterruptIds = [], childInterrupts = []) {
1248
+ buildActionableInterrupts(approvals, clientRequests, genericRequests = [], genericInterruptIds = [], inputRequired = [], childInterrupts = []) {
1129
1249
  const interrupts = [];
1130
1250
  for (const approval of approvals) {
1131
1251
  const tool = this.tools.find((candidate) => candidate.name === approval.toolName);
@@ -1206,6 +1326,27 @@ var TextEngine = class {
1206
1326
  }
1207
1327
  });
1208
1328
  }
1329
+ for (const pendingInput of inputRequired) {
1330
+ const id = `mcp_input_${pendingInput.toolCallId}`;
1331
+ interrupts.push({
1332
+ id,
1333
+ reason: "mcp_input",
1334
+ message: `Input required to run ${pendingInput.toolName}`,
1335
+ toolCallId: pendingInput.toolCallId,
1336
+ metadata: {
1337
+ toolName: pendingInput.toolName,
1338
+ [interruptBindingMetadataKey]: {
1339
+ v: 1,
1340
+ kind: "generic",
1341
+ interruptId: id
1342
+ },
1343
+ [INTERRUPT_PAYLOAD_METADATA_KEY]: {
1344
+ kind: pendingInput.kind,
1345
+ request: pendingInput.request
1346
+ }
1347
+ }
1348
+ });
1349
+ }
1209
1350
  interrupts.push(...childInterrupts);
1210
1351
  const ids = /* @__PURE__ */ new Set();
1211
1352
  for (const interrupt of interrupts) {
@@ -1214,13 +1355,13 @@ var TextEngine = class {
1214
1355
  }
1215
1356
  return interrupts;
1216
1357
  }
1217
- buildInterruptFinishedChunk(finishEvent, approvals, clientRequests, genericRequests = [], genericInterruptIds, childInterrupts) {
1358
+ buildInterruptFinishedChunk(finishEvent, approvals, clientRequests, genericRequests = [], genericInterruptIds, inputRequired = [], childInterrupts) {
1218
1359
  return {
1219
1360
  ...finishEvent,
1220
1361
  timestamp: Date.now(),
1221
1362
  outcome: {
1222
1363
  type: "interrupt",
1223
- interrupts: this.buildActionableInterrupts(approvals, clientRequests, genericRequests, genericInterruptIds, childInterrupts)
1364
+ interrupts: this.buildActionableInterrupts(approvals, clientRequests, genericRequests, genericInterruptIds, inputRequired, childInterrupts)
1224
1365
  }
1225
1366
  };
1226
1367
  }
@@ -1314,10 +1455,10 @@ var TextEngine = class {
1314
1455
  };
1315
1456
  yield* this.pipeThroughMiddleware(this.buildInterruptRunErrorChunk(error));
1316
1457
  }
1317
- async *emitActionableInterruptBoundary(finishEvent, approvals, clientRequests, genericRequests = [], childInterrupts = []) {
1458
+ async *emitActionableInterruptBoundary(finishEvent, approvals, clientRequests, genericRequests = [], inputRequired = [], childInterrupts = []) {
1318
1459
  yield* this.emitSyntheticRunStarted(finishEvent);
1319
1460
  const genericInterruptIds = genericRequests.map(() => this.genericInterruptId());
1320
- const terminal = this.completeEphemeralInterruptBindings(this.buildInterruptFinishedChunk(finishEvent, approvals, clientRequests, genericRequests, genericInterruptIds, childInterrupts));
1461
+ const terminal = this.completeEphemeralInterruptBindings(this.buildInterruptFinishedChunk(finishEvent, approvals, clientRequests, genericRequests, genericInterruptIds, inputRequired, childInterrupts));
1321
1462
  let terminalOutputs;
1322
1463
  try {
1323
1464
  terminalOutputs = [...this.emitPublicChunks(await this.middlewareRunner.runOnChunk(this.middlewareCtx, terminal))];
@@ -1334,7 +1475,7 @@ var TextEngine = class {
1334
1475
  for (const output of terminalOutputs) yield this.publicInterruptTerminal(output);
1335
1476
  return true;
1336
1477
  }
1337
- async *emitBoundaryInterrupts(phase, finishEvent, toolCalls = [], requests) {
1478
+ async *emitBoundaryInterrupts(phase, finishEvent, toolCalls = [], requests, inputRequired = []) {
1338
1479
  this.middlewareCtx.phase = phase;
1339
1480
  const boundaryRequests = requests ?? (yield* this.runWhileYielding(this.middlewareRunner.runOnInterruptBoundary(this.middlewareCtx)));
1340
1481
  if (boundaryRequests.length === 0) return false;
@@ -1344,7 +1485,7 @@ var TextEngine = class {
1344
1485
  else this.addAssistantTextMessageForInterrupt();
1345
1486
  }
1346
1487
  const actionable = this.getBoundaryActionableToolRequests(toolCalls);
1347
- yield* this.emitActionableInterruptBoundary(finishEvent, actionable.approvals, actionable.clientRequests, boundaryRequests);
1488
+ yield* this.emitActionableInterruptBoundary(finishEvent, actionable.approvals, actionable.clientRequests, boundaryRequests, inputRequired);
1348
1489
  return true;
1349
1490
  }
1350
1491
  addAssistantTextMessageForInterrupt() {
@@ -1360,6 +1501,7 @@ var TextEngine = class {
1360
1501
  const approvalRequests = [];
1361
1502
  const clientRequests = [];
1362
1503
  for (const toolCall of toolCalls) {
1504
+ if (isProviderExecutedToolCall(toolCall)) continue;
1363
1505
  const tool = this.resolveExecutableTools([toolCall]).find((candidate) => candidate.name === toolCall.function.name);
1364
1506
  if (!tool) continue;
1365
1507
  let input = {};
@@ -1376,7 +1518,7 @@ var TextEngine = class {
1376
1518
  input,
1377
1519
  approvalId
1378
1520
  });
1379
- else if (!tool.execute && !clientToolResults.has(toolCall.id) && !this.resumeCancelledToolCallIds.has(toolCall.id)) clientRequests.push({
1521
+ else if (!tool.execute && !clientToolResults.has(toolCall.id) && !this.resumeClientToolErrors.has(toolCall.id) && !this.resumeCancelledToolCallIds.has(toolCall.id)) clientRequests.push({
1380
1522
  toolCallId: toolCall.id,
1381
1523
  toolName: toolCall.function.name,
1382
1524
  input
@@ -1447,7 +1589,10 @@ var TextEngine = class {
1447
1589
  content: wireContent,
1448
1590
  role: "tool"
1449
1591
  };
1450
- chunks.push(result.state === "output-error" ? withTanstackMetadata(resultChunk, { state: result.state }) : resultChunk);
1592
+ chunks.push(result.state === "output-error" ? withTanstackMetadata(resultChunk, {
1593
+ state: result.state,
1594
+ ...result.outcome !== void 0 && { toolResultOutcome: result.outcome }
1595
+ }) : resultChunk);
1451
1596
  const placeholderIdx = this.messages.findIndex((m) => {
1452
1597
  if (m.role !== "tool" || m.toolCallId !== result.toolCallId) return false;
1453
1598
  if (typeof m.content !== "string") return false;
@@ -1457,17 +1602,31 @@ var TextEngine = class {
1457
1602
  return false;
1458
1603
  }
1459
1604
  });
1460
- const newToolMessage = {
1605
+ const isDeniedResult = result.outcome === "denied";
1606
+ const existingToolResultIdx = isDeniedResult ? this.messages.findIndex((message) => message.role === "tool" && message.toolCallId === result.toolCallId) : -1;
1607
+ const resultMessageIdx = existingToolResultIdx >= 0 ? existingToolResultIdx : placeholderIdx;
1608
+ const existingToolMessage = existingToolResultIdx >= 0 ? this.messages[existingToolResultIdx] : void 0;
1609
+ const errorField = result.state === "output-error" && { error: toolResultErrorText(parseToolOutput(wireContent)) };
1610
+ const replacementMessage = existingToolMessage?.role === "tool" ? {
1611
+ ...existingToolMessage,
1612
+ content,
1613
+ toolCallId: result.toolCallId,
1614
+ ...errorField
1615
+ } : {
1461
1616
  role: "tool",
1462
1617
  content,
1463
- toolCallId: result.toolCallId
1618
+ toolCallId: result.toolCallId,
1619
+ ...errorField
1464
1620
  };
1465
- if (placeholderIdx >= 0) this.messages = [
1466
- ...this.messages.slice(0, placeholderIdx),
1467
- newToolMessage,
1468
- ...this.messages.slice(placeholderIdx + 1)
1469
- ];
1470
- else this.messages = [...this.messages, newToolMessage];
1621
+ const newToolMessage = result.outcome !== void 0 ? withTanstackMetadata(replacementMessage, { toolResultOutcome: result.outcome }) : replacementMessage;
1622
+ if (resultMessageIdx >= 0) {
1623
+ const replacedMessages = [
1624
+ ...this.messages.slice(0, resultMessageIdx),
1625
+ newToolMessage,
1626
+ ...this.messages.slice(resultMessageIdx + 1)
1627
+ ];
1628
+ this.messages = isDeniedResult ? replacedMessages.filter((message, index) => index === resultMessageIdx || !(message.role === "tool" && message.toolCallId === result.toolCallId)) : replacedMessages;
1629
+ } else this.messages = [...this.messages, newToolMessage];
1471
1630
  this.middlewareCtx.messages = this.messages;
1472
1631
  }
1473
1632
  return chunks;
@@ -1479,7 +1638,7 @@ var TextEngine = class {
1479
1638
  if (typeof message.content === "string") try {
1480
1639
  if (JSON.parse(message.content).pendingExecution === true) hasPendingExecution = true;
1481
1640
  } catch {}
1482
- if (!hasPendingExecution) completedToolIds.add(message.toolCallId);
1641
+ if (!hasPendingExecution && !this.resumeDeniedToolResults.has(message.toolCallId)) completedToolIds.add(message.toolCallId);
1483
1642
  }
1484
1643
  const pending = [];
1485
1644
  for (const message of this.messages) if (message.role === "assistant" && message.toolCalls) for (const toolCall of message.toolCalls) {
@@ -1682,7 +1841,7 @@ var TextEngine = class {
1682
1841
  tools: baseConfig.tools
1683
1842
  }));
1684
1843
  this.applyMiddlewareConfig(postOnConfig);
1685
- assertNoFileSources(this.adapter.name, this.messages);
1844
+ assertMessagesFileSourceSupport(this.adapter, this.messages);
1686
1845
  const structuredCallOptions = {
1687
1846
  chatOptions: {
1688
1847
  model: this.params.model,
@@ -1721,6 +1880,7 @@ var TextEngine = class {
1721
1880
  };
1722
1881
  const runChunkMiddleware = (synthChunk) => this.middlewareRunner.runOnChunk(this.middlewareCtx, synthChunk);
1723
1882
  let runErrorYielded = false;
1883
+ let rawText = "";
1724
1884
  for await (const raw of providerStream) {
1725
1885
  if (this.isCancelled()) break;
1726
1886
  {
@@ -1766,11 +1926,16 @@ var TextEngine = class {
1766
1926
  }
1767
1927
  }
1768
1928
  if (chunk.type === EventType.RUN_FINISHED) await this.runOnUsageFromChunk(chunk);
1769
- if (chunk.type === EventType.RUN_ERROR) this.finalizationError = {
1770
- message: chunk.message,
1771
- ...chunk.code ? { code: chunk.code } : {},
1772
- ...fallbackAdapterError !== void 0 ? { cause: fallbackAdapterError } : {}
1773
- };
1929
+ if (chunk.type === EventType.TEXT_MESSAGE_CONTENT) rawText += chunk.delta;
1930
+ if (chunk.type === EventType.RUN_ERROR) {
1931
+ const cause = fallbackAdapterError ?? chunk.rawEvent;
1932
+ this.finalizationError = {
1933
+ message: chunk.message,
1934
+ ...chunk.code ? { code: chunk.code } : {},
1935
+ ...cause !== void 0 ? { cause } : {},
1936
+ ...rawText ? { rawText } : {}
1937
+ };
1938
+ }
1774
1939
  const outputChunks = await this.middlewareRunner.runOnChunk(this.middlewareCtx, outboundChunk);
1775
1940
  if (this.finalStructuredOutput.yieldChunks) for (const spec of this.emitPublicChunks(outputChunks)) {
1776
1941
  if (spec.type === EventType.RUN_ERROR) runErrorYielded = true;
@@ -1832,7 +1997,12 @@ var TextEngine = class {
1832
1997
  async *harvestCombinedStructuredOutput() {
1833
1998
  if (!this.finalStructuredOutput) throw new Error("harvestCombinedStructuredOutput called without finalStructuredOutput config");
1834
1999
  const yieldChunks = this.finalStructuredOutput.yieldChunks;
1835
- if ((this.finalStructuredOutput.source ?? "text") === "event") {
2000
+ const source = this.finalStructuredOutput.source ?? "text";
2001
+ if (this.lastFinishReason === "length") this.finalizationError = {
2002
+ message: "The response was cut off because the maximum token limit was reached (finish_reason=length); raise the output token limit.",
2003
+ code: "max_tokens"
2004
+ };
2005
+ else if (source === "event") {
1836
2006
  if (!this.structuredOutputResult) this.finalizationError = {
1837
2007
  message: "missing structured result",
1838
2008
  code: "structured-output-missing-result"
@@ -1855,7 +2025,8 @@ var TextEngine = class {
1855
2025
  this.finalizationError = {
1856
2026
  message: `Failed to parse structured output as JSON. Content: ${detail}`,
1857
2027
  code: "structured-output-parse-failed",
1858
- cause: err
2028
+ cause: err,
2029
+ rawText
1859
2030
  };
1860
2031
  }
1861
2032
  }
@@ -1917,6 +2088,7 @@ var TextEngine = class {
1917
2088
  resumeToolState: {
1918
2089
  approvals: this.resumeApprovals,
1919
2090
  clientToolResults: this.resumeClientToolResults,
2091
+ clientToolErrors: this.resumeClientToolErrors,
1920
2092
  deniedToolResults: this.resumeDeniedToolResults,
1921
2093
  cancelledToolCallIds: this.resumeCancelledToolCallIds
1922
2094
  },
@@ -1996,6 +2168,24 @@ var TextEngine = class {
1996
2168
  }] : [];
1997
2169
  });
1998
2170
  pending.push(...genericPending);
2171
+ const mcpInputCallIds = /* @__PURE__ */ new Map();
2172
+ for (const toolCall of pendingToolCalls) {
2173
+ const interruptId = `mcp_input_${toolCall.id}`;
2174
+ if (!resumeInterruptIds.has(interruptId)) continue;
2175
+ if (!toolsByCallId.get(toolCall.id)?.execute) continue;
2176
+ mcpInputCallIds.set(interruptId, toolCall.id);
2177
+ pending.push({
2178
+ interruptId,
2179
+ payload: { id: interruptId },
2180
+ binding: {
2181
+ v: 1,
2182
+ kind: "generic",
2183
+ interruptId,
2184
+ interruptedRunId,
2185
+ generation: 0
2186
+ }
2187
+ });
2188
+ }
1999
2189
  const validated = await validateInterruptResumeBatch({
2000
2190
  threadId: this.threadId,
2001
2191
  interruptedRunId,
@@ -2012,6 +2202,14 @@ var TextEngine = class {
2012
2202
  approvals
2013
2203
  });
2014
2204
  const genericResolutions = validated.resumeToolState.genericInterrupts;
2205
+ for (const [interruptId, toolCallId] of mcpInputCallIds) {
2206
+ const resolution = genericResolutions?.get(interruptId);
2207
+ if (!resolution) continue;
2208
+ this.resumeInputResponses.set(toolCallId, resolution.status === "resolved" ? {
2209
+ status: "resolved",
2210
+ payload: resolution.payload
2211
+ } : { status: "cancelled" });
2212
+ }
2015
2213
  if (genericPending.length > 0 && genericResolutions) {
2016
2214
  const resolutions = genericPending.sort((left, right) => {
2017
2215
  return (left.binding.kind === "generic" ? left.binding.batchIndex ?? 0 : 0) - (right.binding.kind === "generic" ? right.binding.batchIndex ?? 0 : 0);
@@ -2032,7 +2230,10 @@ var TextEngine = class {
2032
2230
  all: (...definitions) => definitions.length === 0 ? resolutions : resolutions.filter((resolution) => definitions.includes(resolution.request.definition))
2033
2231
  });
2034
2232
  if (policy.toolResume === "stop") this.earlyTermination = true;
2035
- else if (policy.toolResume === "cancel") for (const request of pendingToolCalls) this.resumeCancelledToolCallIds.add(request.id);
2233
+ else if (policy.toolResume === "cancel") for (const request of pendingToolCalls) {
2234
+ if (this.resumeDeniedToolResults.has(request.id)) continue;
2235
+ this.resumeCancelledToolCallIds.add(request.id);
2236
+ }
2036
2237
  }
2037
2238
  }
2038
2239
  getGenericContinuationPending(interruptedRunId) {
@@ -2104,6 +2305,7 @@ var TextEngine = class {
2104
2305
  applyResumeToolState(state) {
2105
2306
  if (state?.approvals) for (const [approvalId, resolution] of state.approvals) this.resumeApprovals.set(approvalId, resolution);
2106
2307
  if (state?.clientToolResults) for (const [toolCallId, result] of state.clientToolResults) this.resumeClientToolResults.set(toolCallId, result);
2308
+ if (state?.clientToolErrors) for (const [toolCallId, errorText] of state.clientToolErrors) this.resumeClientToolErrors.set(toolCallId, errorText);
2107
2309
  if (state?.deniedToolResults) for (const [toolCallId, result] of state.deniedToolResults) this.resumeDeniedToolResults.set(toolCallId, result);
2108
2310
  if (state?.cancelledToolCallIds) for (const toolCallId of state.cancelledToolCallIds) this.resumeCancelledToolCallIds.add(toolCallId);
2109
2311
  if (state?.genericInterrupts) for (const [interruptId, resolution] of state.genericInterrupts) this.resumeGenericInterrupts.set(interruptId, resolution);
@@ -2128,7 +2330,10 @@ var TextEngine = class {
2128
2330
  all: (...definitions) => definitions.length === 0 ? resolutions : resolutions.filter((resolution) => definitions.includes(resolution.request.definition))
2129
2331
  });
2130
2332
  if (policy.toolResume === "stop") this.earlyTermination = true;
2131
- else if (policy.toolResume === "cancel") for (const toolCall of this.getPendingToolCallsFromMessages()) this.resumeCancelledToolCallIds.add(toolCall.id);
2333
+ else if (policy.toolResume === "cancel") for (const toolCall of this.getPendingToolCallsFromMessages()) {
2334
+ if (this.resumeDeniedToolResults.has(toolCall.id)) continue;
2335
+ this.resumeCancelledToolCallIds.add(toolCall.id);
2336
+ }
2132
2337
  }
2133
2338
  applyMiddlewareConfig(config) {
2134
2339
  this.applyResumeToolState(config.resumeToolState);
@@ -2465,6 +2670,8 @@ async function* runRoutedSubagents(options, engineRef) {
2465
2670
  yield* runChatEngine(options, engineRef);
2466
2671
  return;
2467
2672
  }
2673
+ const withInput = bag.agents.find((agent) => agent.inputSchema !== void 0);
2674
+ if (withInput) throw new Error(`Subagent "${withInput.name}" has an inputSchema. inputSchema needs tool mode: remove subagents.router so the model writes the input.`);
2468
2675
  const threadId = options.threadId ?? `thread-${Date.now()}`;
2469
2676
  const runId = options.runId ?? `run-${Date.now()}`;
2470
2677
  const messages = options.messages ?? [];
@@ -2777,6 +2984,10 @@ async function runAgenticStructuredOutput(options) {
2777
2984
  value: finalizationError.code,
2778
2985
  enumerable: true
2779
2986
  });
2987
+ if (finalizationError.rawText !== void 0) Object.defineProperty(err, "rawText", {
2988
+ value: finalizationError.rawText,
2989
+ enumerable: true
2990
+ });
2780
2991
  throw err;
2781
2992
  }
2782
2993
  const validated = engine.getValidatedStructuredOutput();