@tanstack/ai 0.61.0 → 0.64.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 (104) hide show
  1. package/README.md +1 -0
  2. package/dist/esm/activities/chat/agents/define-agent.d.ts +17 -5
  3. package/dist/esm/activities/chat/agents/define-agent.js.map +1 -1
  4. package/dist/esm/activities/chat/agents/spawn.d.ts +2 -0
  5. package/dist/esm/activities/chat/agents/spawn.js +10 -33
  6. package/dist/esm/activities/chat/agents/spawn.js.map +1 -1
  7. package/dist/esm/activities/chat/index.d.ts +2 -0
  8. package/dist/esm/activities/chat/index.js +166 -60
  9. package/dist/esm/activities/chat/index.js.map +1 -1
  10. package/dist/esm/activities/chat/messages.js +43 -22
  11. package/dist/esm/activities/chat/messages.js.map +1 -1
  12. package/dist/esm/activities/chat/middleware/types.d.ts +1 -0
  13. package/dist/esm/activities/chat/middleware/types.js.map +1 -1
  14. package/dist/esm/activities/chat/stream/message-updaters.d.ts +2 -2
  15. package/dist/esm/activities/chat/stream/message-updaters.js +6 -2
  16. package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
  17. package/dist/esm/activities/chat/stream/processor.d.ts +11 -9
  18. package/dist/esm/activities/chat/stream/processor.js +38 -18
  19. package/dist/esm/activities/chat/stream/processor.js.map +1 -1
  20. package/dist/esm/activities/chat/tools/schema-converter.d.ts +8 -0
  21. package/dist/esm/activities/chat/tools/schema-converter.js +6 -5
  22. package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -1
  23. package/dist/esm/activities/chat/tools/tool-calls.d.ts +20 -3
  24. package/dist/esm/activities/chat/tools/tool-calls.js +126 -36
  25. package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
  26. package/dist/esm/activities/chat/tools/tool-definition.d.ts +4 -0
  27. package/dist/esm/activities/chat/tools/tool-definition.js +4 -0
  28. package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
  29. package/dist/esm/activities/evaluate/adapter.d.ts +4 -0
  30. package/dist/esm/activities/evaluate/adapter.js.map +1 -1
  31. package/dist/esm/activities/evaluate/index.d.ts +4 -0
  32. package/dist/esm/activities/evaluate/index.js +3 -1
  33. package/dist/esm/activities/evaluate/index.js.map +1 -1
  34. package/dist/esm/activities/generateSpeech/index.d.ts +1 -1
  35. package/dist/esm/activities/generateSpeech/index.js +1 -1
  36. package/dist/esm/activities/generateSpeech/index.js.map +1 -1
  37. package/dist/esm/activities/generateVideo/adapter.d.ts +14 -6
  38. package/dist/esm/activities/generateVideo/adapter.js +6 -3
  39. package/dist/esm/activities/generateVideo/adapter.js.map +1 -1
  40. package/dist/esm/activities/generateVideo/index.d.ts +5 -4
  41. package/dist/esm/activities/generateVideo/index.js.map +1 -1
  42. package/dist/esm/activities/generateVideo/snap.d.ts +12 -3
  43. package/dist/esm/activities/generateVideo/snap.js +47 -8
  44. package/dist/esm/activities/generateVideo/snap.js.map +1 -1
  45. package/dist/esm/activities/generateVoice/index.d.ts +1 -1
  46. package/dist/esm/activities/generateVoice/index.js +1 -1
  47. package/dist/esm/activities/generateVoice/index.js.map +1 -1
  48. package/dist/esm/activities/index.d.ts +2 -2
  49. package/dist/esm/activities/index.js +2 -2
  50. package/dist/esm/adapter-internals.d.ts +1 -0
  51. package/dist/esm/adapter-internals.js +2 -1
  52. package/dist/esm/client.d.ts +1 -1
  53. package/dist/esm/client.js.map +1 -1
  54. package/dist/esm/index.d.ts +1 -1
  55. package/dist/esm/index.js +2 -2
  56. package/dist/esm/interrupt-resume.js +29 -4
  57. package/dist/esm/interrupt-resume.js.map +1 -1
  58. package/dist/esm/middlewares/otel.d.ts +5 -2
  59. package/dist/esm/middlewares/otel.js +114 -0
  60. package/dist/esm/middlewares/otel.js.map +1 -1
  61. package/dist/esm/types.d.ts +70 -4
  62. package/dist/esm/utilities/ag-ui-wire.js +8 -4
  63. package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
  64. package/dist/esm/utilities/merge-streams.d.ts +6 -0
  65. package/dist/esm/utilities/merge-streams.js +37 -0
  66. package/dist/esm/utilities/merge-streams.js.map +1 -0
  67. package/dist/esm/utilities/reasoning-encrypted-value.d.ts +8 -0
  68. package/dist/esm/utilities/reasoning-encrypted-value.js +11 -1
  69. package/dist/esm/utilities/reasoning-encrypted-value.js.map +1 -1
  70. package/dist/esm/utilities/tool-result.d.ts +2 -1
  71. package/dist/esm/utilities/tool-result.js +4 -1
  72. package/dist/esm/utilities/tool-result.js.map +1 -1
  73. package/package.json +3 -3
  74. package/skills/ai-core/chat-experience/SKILL.md +120 -0
  75. package/skills/ai-core/media-generation/SKILL.md +3 -3
  76. package/skills/ai-core/tool-calling/SKILL.md +103 -0
  77. package/src/activities/chat/agents/define-agent.ts +20 -3
  78. package/src/activities/chat/agents/spawn.ts +22 -43
  79. package/src/activities/chat/index.ts +248 -65
  80. package/src/activities/chat/messages.ts +54 -7
  81. package/src/activities/chat/middleware/types.ts +1 -0
  82. package/src/activities/chat/stream/message-updaters.ts +8 -0
  83. package/src/activities/chat/stream/processor.ts +57 -27
  84. package/src/activities/chat/tools/schema-converter.ts +17 -5
  85. package/src/activities/chat/tools/tool-calls.ts +215 -68
  86. package/src/activities/chat/tools/tool-definition.ts +8 -0
  87. package/src/activities/evaluate/adapter.ts +4 -0
  88. package/src/activities/evaluate/index.ts +6 -0
  89. package/src/activities/generateSpeech/index.ts +1 -1
  90. package/src/activities/generateVideo/adapter.ts +21 -7
  91. package/src/activities/generateVideo/index.ts +5 -4
  92. package/src/activities/generateVideo/snap.ts +64 -6
  93. package/src/activities/generateVoice/index.ts +1 -1
  94. package/src/activities/index.ts +2 -1
  95. package/src/adapter-internals.ts +1 -0
  96. package/src/client.ts +1 -0
  97. package/src/index.ts +1 -0
  98. package/src/interrupt-resume.ts +55 -4
  99. package/src/middlewares/otel.ts +161 -3
  100. package/src/types.ts +66 -5
  101. package/src/utilities/ag-ui-wire.ts +17 -2
  102. package/src/utilities/merge-streams.ts +34 -0
  103. package/src/utilities/reasoning-encrypted-value.ts +12 -0
  104. package/src/utilities/tool-result.ts +7 -1
@@ -7,6 +7,7 @@ import { EventType } from "../../types.js";
7
7
  import { rebuildTokenUsage } from "../../utilities/ag-ui-usage.js";
8
8
  import { tanstackMetadata, withTanstackMetadata } from "../../utilities/merge-metadata.js";
9
9
  import { withDurabilityBatchHint } from "../../utilities/durability-batch.js";
10
+ import { isRedactedThinkingId } from "../../utilities/reasoning-encrypted-value.js";
10
11
  import { normalizeStreamChunk } from "../../utilities/normalize-stream-chunk.js";
11
12
  import { resolveDebugOption } from "../../logger/resolve.js";
12
13
  import { streamToText } from "../../stream-to-response.js";
@@ -149,6 +150,7 @@ var TextEngine = class {
149
150
  turnParts = [];
150
151
  currentThinkingContent = "";
151
152
  currentThinkingSignature = "";
153
+ currentThinkingRedacted = false;
152
154
  eventOptions;
153
155
  eventToolNames;
154
156
  finishedEvent = null;
@@ -163,8 +165,10 @@ var TextEngine = class {
163
165
  initialClientToolResults;
164
166
  resumeApprovals = /* @__PURE__ */ new Map();
165
167
  resumeClientToolResults = /* @__PURE__ */ new Map();
168
+ resumeClientToolErrors = /* @__PURE__ */ new Map();
166
169
  resumeDeniedToolResults = /* @__PURE__ */ new Map();
167
170
  resumeCancelledToolCallIds = /* @__PURE__ */ new Set();
171
+ resumeInputResponses = /* @__PURE__ */ new Map();
168
172
  resumeGenericInterrupts = /* @__PURE__ */ new Map();
169
173
  resumeGenericInterruptRequests = /* @__PURE__ */ new Map();
170
174
  threadId;
@@ -330,6 +334,33 @@ var TextEngine = class {
330
334
  getFinalizationError() {
331
335
  return this.finalizationError;
332
336
  }
337
+ async runTerminalHook() {
338
+ if (this.terminalHookCalled || this.isCancelled()) return;
339
+ this.terminalHookCalled = true;
340
+ if (this.finalizationError) {
341
+ const errForHook = new Error(this.finalizationError.message, this.finalizationError.cause !== void 0 ? { cause: this.finalizationError.cause } : void 0);
342
+ if (this.finalizationError.code !== void 0) Object.defineProperty(errForHook, "code", {
343
+ value: this.finalizationError.code,
344
+ enumerable: true
345
+ });
346
+ if (this.finalizationError.rawText !== void 0) Object.defineProperty(errForHook, "rawText", {
347
+ value: this.finalizationError.rawText,
348
+ enumerable: true
349
+ });
350
+ await this.middlewareRunner.runOnError(this.middlewareCtx, {
351
+ error: errForHook,
352
+ duration: Date.now() - this.streamStartTime
353
+ });
354
+ return;
355
+ }
356
+ this.addTerminalAssistantMessages();
357
+ await this.middlewareRunner.runOnFinish(this.middlewareCtx, {
358
+ finishReason: this.lastFinishReason,
359
+ duration: Date.now() - this.streamStartTime,
360
+ content: this.accumulatedContent,
361
+ usage: rebuildTokenUsage(this.finishedEvent?.usage, tanstackMetadata(this.finishedEvent ?? void 0)?.usage)
362
+ });
363
+ }
333
364
  async *run() {
334
365
  this.beforeRun();
335
366
  this.logger.agentLoop("run started", { threadId: this.middlewareCtx.threadId });
@@ -355,7 +386,11 @@ var TextEngine = class {
355
386
  }
356
387
  return;
357
388
  }
358
- if ((yield* this.checkForPendingToolCalls()) === "wait") return;
389
+ const pendingPhase = yield* this.checkForPendingToolCalls();
390
+ if (pendingPhase === "stop" || pendingPhase === "wait") {
391
+ await this.runTerminalHook();
392
+ return;
393
+ }
359
394
  if (!(!!this.finalStructuredOutput && this.tools.length === 0 && this.finalStructuredOutput.nativeCombined !== true)) do {
360
395
  if (this.earlyTermination) break;
361
396
  if (this.isCancelled()) return;
@@ -391,29 +426,7 @@ var TextEngine = class {
391
426
  if (!this.finalizationError && !this.isCancelled()) yield* this.flushDeferredModelRunFinishedChunks();
392
427
  } else yield* this.runStructuredFinalization();
393
428
  }
394
- if (!this.terminalHookCalled && this.toolPhase !== "wait" && !this.isCancelled()) {
395
- if (this.finalizationError) {
396
- this.terminalHookCalled = true;
397
- const errForHook = new Error(this.finalizationError.message, this.finalizationError.cause !== void 0 ? { cause: this.finalizationError.cause } : void 0);
398
- if (this.finalizationError.code !== void 0) Object.defineProperty(errForHook, "code", {
399
- value: this.finalizationError.code,
400
- enumerable: true
401
- });
402
- await this.middlewareRunner.runOnError(this.middlewareCtx, {
403
- error: errForHook,
404
- duration: Date.now() - this.streamStartTime
405
- });
406
- } else {
407
- this.addTerminalAssistantMessages();
408
- this.terminalHookCalled = true;
409
- await this.middlewareRunner.runOnFinish(this.middlewareCtx, {
410
- finishReason: this.lastFinishReason,
411
- duration: Date.now() - this.streamStartTime,
412
- content: this.accumulatedContent,
413
- usage: rebuildTokenUsage(this.finishedEvent?.usage, tanstackMetadata(this.finishedEvent ?? void 0)?.usage)
414
- });
415
- }
416
- }
429
+ await this.runTerminalHook();
417
430
  } catch (error) {
418
431
  if (error instanceof Error && error.name === "InterruptReplaySignal" && "continuationRunId" in error && typeof error.continuationRunId === "string") {
419
432
  this.terminalHookCalled = true;
@@ -508,6 +521,7 @@ var TextEngine = class {
508
521
  this.turnParts = [];
509
522
  this.currentThinkingContent = "";
510
523
  this.currentThinkingSignature = "";
524
+ this.currentThinkingRedacted = false;
511
525
  this.finishedEvent = null;
512
526
  this.streamedToolErrorResults.clear();
513
527
  this.middlewareCtx.currentMessageId = this.currentMessageId;
@@ -768,7 +782,8 @@ var TextEngine = class {
768
782
  if (this.currentThinkingContent || this.currentThinkingSignature) {
769
783
  this.accumulatedThinking.push({
770
784
  content: this.currentThinkingContent,
771
- ...this.currentThinkingSignature && { signature: this.currentThinkingSignature }
785
+ ...this.currentThinkingSignature && { signature: this.currentThinkingSignature },
786
+ ...this.currentThinkingRedacted && { redacted: true }
772
787
  });
773
788
  if (this.turnParts) {
774
789
  const placeholder = [...this.turnParts].reverse().find((part) => part.type === "thinking" && part.index === -1);
@@ -781,6 +796,7 @@ var TextEngine = class {
781
796
  }
782
797
  this.currentThinkingContent = "";
783
798
  this.currentThinkingSignature = "";
799
+ this.currentThinkingRedacted = false;
784
800
  }
785
801
  }
786
802
  /**
@@ -802,6 +818,7 @@ var TextEngine = class {
802
818
  if (typeof chunk.signature === "string" && chunk.signature !== "") {
803
819
  this.noteThinkingStepPosition();
804
820
  this.currentThinkingSignature = chunk.signature;
821
+ this.currentThinkingRedacted = isRedactedThinkingId(chunk.stepId);
805
822
  }
806
823
  }
807
824
  handleReasoningMessageContentEvent(chunk) {
@@ -819,6 +836,7 @@ var TextEngine = class {
819
836
  }
820
837
  this.noteThinkingStepPosition();
821
838
  this.currentThinkingSignature = chunk.encryptedValue;
839
+ this.currentThinkingRedacted = isRedactedThinkingId(chunk.entityId);
822
840
  }
823
841
  /**
824
842
  * Tools available for execution this turn. The discovery tool is dropped
@@ -885,9 +903,11 @@ var TextEngine = class {
885
903
  await this.middlewareRunner.runOnAfterToolCall(this.middlewareCtx, info);
886
904
  }
887
905
  }, this.middlewareCtx.context, this.toolAbortSignal, {
906
+ clientToolErrors: this.resumeClientToolErrors,
888
907
  deniedToolResults: this.resumeDeniedToolResults,
889
- cancelledToolCallIds: this.resumeCancelledToolCallIds
890
- });
908
+ cancelledToolCallIds: this.resumeCancelledToolCallIds,
909
+ inputResponses: this.resumeInputResponses
910
+ }, this.params.toolExecution);
891
911
  const executionResult = yield* this.drainToolCallGenerator(generator);
892
912
  if (this.isMiddlewareAborted()) {
893
913
  this.setToolPhase("stop");
@@ -900,10 +920,10 @@ var TextEngine = class {
900
920
  needsApproval: executionResult.needsApproval,
901
921
  needsClientExecution: executionResult.needsClientExecution
902
922
  }));
903
- if (executionResult.needsApproval.length > 0 || executionResult.needsClientExecution.length > 0 || executionResult.subagentInterrupts.length > 0) {
923
+ if (executionResult.needsApproval.length > 0 || executionResult.needsClientExecution.length > 0 || executionResult.inputRequired.length > 0 || executionResult.subagentInterrupts.length > 0) {
904
924
  this.discardDeferredToolCallRunFinishedChunks();
905
925
  if (allResults.length > 0) for (const chunk of this.buildToolResultChunks(allResults, finishEvent)) yield* this.pipeThroughMiddleware(chunk);
906
- const emitted = yield* this.emitActionableInterruptBoundary(finishEvent, executionResult.needsApproval, executionResult.needsClientExecution, [], executionResult.subagentInterrupts);
926
+ const emitted = yield* this.emitActionableInterruptBoundary(finishEvent, executionResult.needsApproval, executionResult.needsClientExecution, [], executionResult.inputRequired, executionResult.subagentInterrupts);
907
927
  this.setToolPhase(emitted ? "wait" : "stop");
908
928
  return emitted ? "wait" : "stop";
909
929
  }
@@ -977,9 +997,11 @@ var TextEngine = class {
977
997
  await this.middlewareRunner.runOnAfterToolCall(this.middlewareCtx, info);
978
998
  }
979
999
  }, this.middlewareCtx.context, this.toolAbortSignal, {
1000
+ clientToolErrors: this.resumeClientToolErrors,
980
1001
  deniedToolResults: this.resumeDeniedToolResults,
981
- cancelledToolCallIds: this.resumeCancelledToolCallIds
982
- });
1002
+ cancelledToolCallIds: this.resumeCancelledToolCallIds,
1003
+ inputResponses: this.resumeInputResponses
1004
+ }, this.params.toolExecution);
983
1005
  const executionResult = yield* this.drainToolCallGenerator(generator);
984
1006
  this.middlewareCtx.phase = "afterTools";
985
1007
  if (this.isMiddlewareAborted()) {
@@ -997,13 +1019,13 @@ var TextEngine = class {
997
1019
  const afterToolRequests = yield* this.runWhileYielding(this.middlewareRunner.runOnInterruptBoundary(this.middlewareCtx));
998
1020
  if (afterToolRequests.length > 0) {
999
1021
  for (const chunk of afterToolBoundaryChunks) yield* this.pipeThroughMiddleware(chunk);
1000
- yield* this.emitBoundaryInterrupts("afterTools", finishEvent, toolCalls, afterToolRequests);
1022
+ yield* this.emitBoundaryInterrupts("afterTools", finishEvent, toolCalls, afterToolRequests, executionResult.inputRequired);
1001
1023
  this.setToolPhase("wait");
1002
1024
  return;
1003
1025
  }
1004
- if (executionResult.needsApproval.length > 0 || executionResult.needsClientExecution.length > 0 || executionResult.subagentInterrupts.length > 0) {
1026
+ if (executionResult.needsApproval.length > 0 || executionResult.needsClientExecution.length > 0 || executionResult.inputRequired.length > 0 || executionResult.subagentInterrupts.length > 0) {
1005
1027
  if (allResults.length > 0) for (const chunk of afterToolBoundaryChunks) yield* this.pipeThroughMiddleware(chunk);
1006
- const emitted = yield* this.emitActionableInterruptBoundary(finishEvent, executionResult.needsApproval, executionResult.needsClientExecution, [], executionResult.subagentInterrupts);
1028
+ const emitted = yield* this.emitActionableInterruptBoundary(finishEvent, executionResult.needsApproval, executionResult.needsClientExecution, [], executionResult.inputRequired, executionResult.subagentInterrupts);
1007
1029
  this.setToolPhase(emitted ? "wait" : "stop");
1008
1030
  return;
1009
1031
  }
@@ -1230,7 +1252,7 @@ var TextEngine = class {
1230
1252
  genericInterruptId() {
1231
1253
  return this.createId("interrupt");
1232
1254
  }
1233
- buildActionableInterrupts(approvals, clientRequests, genericRequests = [], genericInterruptIds = [], childInterrupts = []) {
1255
+ buildActionableInterrupts(approvals, clientRequests, genericRequests = [], genericInterruptIds = [], inputRequired = [], childInterrupts = []) {
1234
1256
  const interrupts = [];
1235
1257
  for (const approval of approvals) {
1236
1258
  const tool = this.tools.find((candidate) => candidate.name === approval.toolName);
@@ -1311,6 +1333,27 @@ var TextEngine = class {
1311
1333
  }
1312
1334
  });
1313
1335
  }
1336
+ for (const pendingInput of inputRequired) {
1337
+ const id = `mcp_input_${pendingInput.toolCallId}`;
1338
+ interrupts.push({
1339
+ id,
1340
+ reason: "mcp_input",
1341
+ message: `Input required to run ${pendingInput.toolName}`,
1342
+ toolCallId: pendingInput.toolCallId,
1343
+ metadata: {
1344
+ toolName: pendingInput.toolName,
1345
+ [interruptBindingMetadataKey]: {
1346
+ v: 1,
1347
+ kind: "generic",
1348
+ interruptId: id
1349
+ },
1350
+ [INTERRUPT_PAYLOAD_METADATA_KEY]: {
1351
+ kind: pendingInput.kind,
1352
+ request: pendingInput.request
1353
+ }
1354
+ }
1355
+ });
1356
+ }
1314
1357
  interrupts.push(...childInterrupts);
1315
1358
  const ids = /* @__PURE__ */ new Set();
1316
1359
  for (const interrupt of interrupts) {
@@ -1319,13 +1362,13 @@ var TextEngine = class {
1319
1362
  }
1320
1363
  return interrupts;
1321
1364
  }
1322
- buildInterruptFinishedChunk(finishEvent, approvals, clientRequests, genericRequests = [], genericInterruptIds, childInterrupts) {
1365
+ buildInterruptFinishedChunk(finishEvent, approvals, clientRequests, genericRequests = [], genericInterruptIds, inputRequired = [], childInterrupts) {
1323
1366
  return {
1324
1367
  ...finishEvent,
1325
1368
  timestamp: Date.now(),
1326
1369
  outcome: {
1327
1370
  type: "interrupt",
1328
- interrupts: this.buildActionableInterrupts(approvals, clientRequests, genericRequests, genericInterruptIds, childInterrupts)
1371
+ interrupts: this.buildActionableInterrupts(approvals, clientRequests, genericRequests, genericInterruptIds, inputRequired, childInterrupts)
1329
1372
  }
1330
1373
  };
1331
1374
  }
@@ -1419,10 +1462,10 @@ var TextEngine = class {
1419
1462
  };
1420
1463
  yield* this.pipeThroughMiddleware(this.buildInterruptRunErrorChunk(error));
1421
1464
  }
1422
- async *emitActionableInterruptBoundary(finishEvent, approvals, clientRequests, genericRequests = [], childInterrupts = []) {
1465
+ async *emitActionableInterruptBoundary(finishEvent, approvals, clientRequests, genericRequests = [], inputRequired = [], childInterrupts = []) {
1423
1466
  yield* this.emitSyntheticRunStarted(finishEvent);
1424
1467
  const genericInterruptIds = genericRequests.map(() => this.genericInterruptId());
1425
- const terminal = this.completeEphemeralInterruptBindings(this.buildInterruptFinishedChunk(finishEvent, approvals, clientRequests, genericRequests, genericInterruptIds, childInterrupts));
1468
+ const terminal = this.completeEphemeralInterruptBindings(this.buildInterruptFinishedChunk(finishEvent, approvals, clientRequests, genericRequests, genericInterruptIds, inputRequired, childInterrupts));
1426
1469
  let terminalOutputs;
1427
1470
  try {
1428
1471
  terminalOutputs = [...this.emitPublicChunks(await this.middlewareRunner.runOnChunk(this.middlewareCtx, terminal))];
@@ -1439,7 +1482,7 @@ var TextEngine = class {
1439
1482
  for (const output of terminalOutputs) yield this.publicInterruptTerminal(output);
1440
1483
  return true;
1441
1484
  }
1442
- async *emitBoundaryInterrupts(phase, finishEvent, toolCalls = [], requests) {
1485
+ async *emitBoundaryInterrupts(phase, finishEvent, toolCalls = [], requests, inputRequired = []) {
1443
1486
  this.middlewareCtx.phase = phase;
1444
1487
  const boundaryRequests = requests ?? (yield* this.runWhileYielding(this.middlewareRunner.runOnInterruptBoundary(this.middlewareCtx)));
1445
1488
  if (boundaryRequests.length === 0) return false;
@@ -1449,7 +1492,7 @@ var TextEngine = class {
1449
1492
  else this.addAssistantTextMessageForInterrupt();
1450
1493
  }
1451
1494
  const actionable = this.getBoundaryActionableToolRequests(toolCalls);
1452
- yield* this.emitActionableInterruptBoundary(finishEvent, actionable.approvals, actionable.clientRequests, boundaryRequests);
1495
+ yield* this.emitActionableInterruptBoundary(finishEvent, actionable.approvals, actionable.clientRequests, boundaryRequests, inputRequired);
1453
1496
  return true;
1454
1497
  }
1455
1498
  addAssistantTextMessageForInterrupt() {
@@ -1482,7 +1525,7 @@ var TextEngine = class {
1482
1525
  input,
1483
1526
  approvalId
1484
1527
  });
1485
- else if (!tool.execute && !clientToolResults.has(toolCall.id) && !this.resumeCancelledToolCallIds.has(toolCall.id)) clientRequests.push({
1528
+ else if (!tool.execute && !clientToolResults.has(toolCall.id) && !this.resumeClientToolErrors.has(toolCall.id) && !this.resumeCancelledToolCallIds.has(toolCall.id)) clientRequests.push({
1486
1529
  toolCallId: toolCall.id,
1487
1530
  toolName: toolCall.function.name,
1488
1531
  input
@@ -1553,7 +1596,10 @@ var TextEngine = class {
1553
1596
  content: wireContent,
1554
1597
  role: "tool"
1555
1598
  };
1556
- chunks.push(result.state === "output-error" ? withTanstackMetadata(resultChunk, { state: result.state }) : resultChunk);
1599
+ chunks.push(result.state === "output-error" ? withTanstackMetadata(resultChunk, {
1600
+ state: result.state,
1601
+ ...result.outcome !== void 0 && { toolResultOutcome: result.outcome }
1602
+ }) : resultChunk);
1557
1603
  const placeholderIdx = this.messages.findIndex((m) => {
1558
1604
  if (m.role !== "tool" || m.toolCallId !== result.toolCallId) return false;
1559
1605
  if (typeof m.content !== "string") return false;
@@ -1563,18 +1609,31 @@ var TextEngine = class {
1563
1609
  return false;
1564
1610
  }
1565
1611
  });
1566
- const newToolMessage = {
1612
+ const isDeniedResult = result.outcome === "denied";
1613
+ const existingToolResultIdx = isDeniedResult ? this.messages.findIndex((message) => message.role === "tool" && message.toolCallId === result.toolCallId) : -1;
1614
+ const resultMessageIdx = existingToolResultIdx >= 0 ? existingToolResultIdx : placeholderIdx;
1615
+ const existingToolMessage = existingToolResultIdx >= 0 ? this.messages[existingToolResultIdx] : void 0;
1616
+ const errorField = result.state === "output-error" && { error: toolResultErrorText(parseToolOutput(wireContent)) };
1617
+ const replacementMessage = existingToolMessage?.role === "tool" ? {
1618
+ ...existingToolMessage,
1619
+ content,
1620
+ toolCallId: result.toolCallId,
1621
+ ...errorField
1622
+ } : {
1567
1623
  role: "tool",
1568
1624
  content,
1569
1625
  toolCallId: result.toolCallId,
1570
- ...result.state === "output-error" && { error: toolResultErrorText(parseToolOutput(wireContent)) }
1626
+ ...errorField
1571
1627
  };
1572
- if (placeholderIdx >= 0) this.messages = [
1573
- ...this.messages.slice(0, placeholderIdx),
1574
- newToolMessage,
1575
- ...this.messages.slice(placeholderIdx + 1)
1576
- ];
1577
- else this.messages = [...this.messages, newToolMessage];
1628
+ const newToolMessage = result.outcome !== void 0 ? withTanstackMetadata(replacementMessage, { toolResultOutcome: result.outcome }) : replacementMessage;
1629
+ if (resultMessageIdx >= 0) {
1630
+ const replacedMessages = [
1631
+ ...this.messages.slice(0, resultMessageIdx),
1632
+ newToolMessage,
1633
+ ...this.messages.slice(resultMessageIdx + 1)
1634
+ ];
1635
+ this.messages = isDeniedResult ? replacedMessages.filter((message, index) => index === resultMessageIdx || !(message.role === "tool" && message.toolCallId === result.toolCallId)) : replacedMessages;
1636
+ } else this.messages = [...this.messages, newToolMessage];
1578
1637
  this.middlewareCtx.messages = this.messages;
1579
1638
  }
1580
1639
  return chunks;
@@ -1586,7 +1645,7 @@ var TextEngine = class {
1586
1645
  if (typeof message.content === "string") try {
1587
1646
  if (JSON.parse(message.content).pendingExecution === true) hasPendingExecution = true;
1588
1647
  } catch {}
1589
- if (!hasPendingExecution) completedToolIds.add(message.toolCallId);
1648
+ if (!hasPendingExecution && !this.resumeDeniedToolResults.has(message.toolCallId)) completedToolIds.add(message.toolCallId);
1590
1649
  }
1591
1650
  const pending = [];
1592
1651
  for (const message of this.messages) if (message.role === "assistant" && message.toolCalls) for (const toolCall of message.toolCalls) {
@@ -1828,6 +1887,7 @@ var TextEngine = class {
1828
1887
  };
1829
1888
  const runChunkMiddleware = (synthChunk) => this.middlewareRunner.runOnChunk(this.middlewareCtx, synthChunk);
1830
1889
  let runErrorYielded = false;
1890
+ let rawText = "";
1831
1891
  for await (const raw of providerStream) {
1832
1892
  if (this.isCancelled()) break;
1833
1893
  {
@@ -1873,11 +1933,16 @@ var TextEngine = class {
1873
1933
  }
1874
1934
  }
1875
1935
  if (chunk.type === EventType.RUN_FINISHED) await this.runOnUsageFromChunk(chunk);
1876
- if (chunk.type === EventType.RUN_ERROR) this.finalizationError = {
1877
- message: chunk.message,
1878
- ...chunk.code ? { code: chunk.code } : {},
1879
- ...fallbackAdapterError !== void 0 ? { cause: fallbackAdapterError } : {}
1880
- };
1936
+ if (chunk.type === EventType.TEXT_MESSAGE_CONTENT) rawText += chunk.delta;
1937
+ if (chunk.type === EventType.RUN_ERROR) {
1938
+ const cause = fallbackAdapterError ?? chunk.rawEvent;
1939
+ this.finalizationError = {
1940
+ message: chunk.message,
1941
+ ...chunk.code ? { code: chunk.code } : {},
1942
+ ...cause !== void 0 ? { cause } : {},
1943
+ ...rawText ? { rawText } : {}
1944
+ };
1945
+ }
1881
1946
  const outputChunks = await this.middlewareRunner.runOnChunk(this.middlewareCtx, outboundChunk);
1882
1947
  if (this.finalStructuredOutput.yieldChunks) for (const spec of this.emitPublicChunks(outputChunks)) {
1883
1948
  if (spec.type === EventType.RUN_ERROR) runErrorYielded = true;
@@ -1967,7 +2032,8 @@ var TextEngine = class {
1967
2032
  this.finalizationError = {
1968
2033
  message: `Failed to parse structured output as JSON. Content: ${detail}`,
1969
2034
  code: "structured-output-parse-failed",
1970
- cause: err
2035
+ cause: err,
2036
+ rawText
1971
2037
  };
1972
2038
  }
1973
2039
  }
@@ -2029,6 +2095,7 @@ var TextEngine = class {
2029
2095
  resumeToolState: {
2030
2096
  approvals: this.resumeApprovals,
2031
2097
  clientToolResults: this.resumeClientToolResults,
2098
+ clientToolErrors: this.resumeClientToolErrors,
2032
2099
  deniedToolResults: this.resumeDeniedToolResults,
2033
2100
  cancelledToolCallIds: this.resumeCancelledToolCallIds
2034
2101
  },
@@ -2108,6 +2175,24 @@ var TextEngine = class {
2108
2175
  }] : [];
2109
2176
  });
2110
2177
  pending.push(...genericPending);
2178
+ const mcpInputCallIds = /* @__PURE__ */ new Map();
2179
+ for (const toolCall of pendingToolCalls) {
2180
+ const interruptId = `mcp_input_${toolCall.id}`;
2181
+ if (!resumeInterruptIds.has(interruptId)) continue;
2182
+ if (!toolsByCallId.get(toolCall.id)?.execute) continue;
2183
+ mcpInputCallIds.set(interruptId, toolCall.id);
2184
+ pending.push({
2185
+ interruptId,
2186
+ payload: { id: interruptId },
2187
+ binding: {
2188
+ v: 1,
2189
+ kind: "generic",
2190
+ interruptId,
2191
+ interruptedRunId,
2192
+ generation: 0
2193
+ }
2194
+ });
2195
+ }
2111
2196
  const validated = await validateInterruptResumeBatch({
2112
2197
  threadId: this.threadId,
2113
2198
  interruptedRunId,
@@ -2124,6 +2209,14 @@ var TextEngine = class {
2124
2209
  approvals
2125
2210
  });
2126
2211
  const genericResolutions = validated.resumeToolState.genericInterrupts;
2212
+ for (const [interruptId, toolCallId] of mcpInputCallIds) {
2213
+ const resolution = genericResolutions?.get(interruptId);
2214
+ if (!resolution) continue;
2215
+ this.resumeInputResponses.set(toolCallId, resolution.status === "resolved" ? {
2216
+ status: "resolved",
2217
+ payload: resolution.payload
2218
+ } : { status: "cancelled" });
2219
+ }
2127
2220
  if (genericPending.length > 0 && genericResolutions) {
2128
2221
  const resolutions = genericPending.sort((left, right) => {
2129
2222
  return (left.binding.kind === "generic" ? left.binding.batchIndex ?? 0 : 0) - (right.binding.kind === "generic" ? right.binding.batchIndex ?? 0 : 0);
@@ -2144,7 +2237,10 @@ var TextEngine = class {
2144
2237
  all: (...definitions) => definitions.length === 0 ? resolutions : resolutions.filter((resolution) => definitions.includes(resolution.request.definition))
2145
2238
  });
2146
2239
  if (policy.toolResume === "stop") this.earlyTermination = true;
2147
- else if (policy.toolResume === "cancel") for (const request of pendingToolCalls) this.resumeCancelledToolCallIds.add(request.id);
2240
+ else if (policy.toolResume === "cancel") for (const request of pendingToolCalls) {
2241
+ if (this.resumeDeniedToolResults.has(request.id)) continue;
2242
+ this.resumeCancelledToolCallIds.add(request.id);
2243
+ }
2148
2244
  }
2149
2245
  }
2150
2246
  getGenericContinuationPending(interruptedRunId) {
@@ -2216,6 +2312,7 @@ var TextEngine = class {
2216
2312
  applyResumeToolState(state) {
2217
2313
  if (state?.approvals) for (const [approvalId, resolution] of state.approvals) this.resumeApprovals.set(approvalId, resolution);
2218
2314
  if (state?.clientToolResults) for (const [toolCallId, result] of state.clientToolResults) this.resumeClientToolResults.set(toolCallId, result);
2315
+ if (state?.clientToolErrors) for (const [toolCallId, errorText] of state.clientToolErrors) this.resumeClientToolErrors.set(toolCallId, errorText);
2219
2316
  if (state?.deniedToolResults) for (const [toolCallId, result] of state.deniedToolResults) this.resumeDeniedToolResults.set(toolCallId, result);
2220
2317
  if (state?.cancelledToolCallIds) for (const toolCallId of state.cancelledToolCallIds) this.resumeCancelledToolCallIds.add(toolCallId);
2221
2318
  if (state?.genericInterrupts) for (const [interruptId, resolution] of state.genericInterrupts) this.resumeGenericInterrupts.set(interruptId, resolution);
@@ -2240,7 +2337,10 @@ var TextEngine = class {
2240
2337
  all: (...definitions) => definitions.length === 0 ? resolutions : resolutions.filter((resolution) => definitions.includes(resolution.request.definition))
2241
2338
  });
2242
2339
  if (policy.toolResume === "stop") this.earlyTermination = true;
2243
- else if (policy.toolResume === "cancel") for (const toolCall of this.getPendingToolCallsFromMessages()) this.resumeCancelledToolCallIds.add(toolCall.id);
2340
+ else if (policy.toolResume === "cancel") for (const toolCall of this.getPendingToolCallsFromMessages()) {
2341
+ if (this.resumeDeniedToolResults.has(toolCall.id)) continue;
2342
+ this.resumeCancelledToolCallIds.add(toolCall.id);
2343
+ }
2244
2344
  }
2245
2345
  applyMiddlewareConfig(config) {
2246
2346
  this.applyResumeToolState(config.resumeToolState);
@@ -2577,6 +2677,8 @@ async function* runRoutedSubagents(options, engineRef) {
2577
2677
  yield* runChatEngine(options, engineRef);
2578
2678
  return;
2579
2679
  }
2680
+ const withInput = bag.agents.find((agent) => agent.inputSchema !== void 0);
2681
+ if (withInput) throw new Error(`Subagent "${withInput.name}" has an inputSchema. inputSchema needs tool mode: remove subagents.router so the model writes the input.`);
2580
2682
  const threadId = options.threadId ?? `thread-${Date.now()}`;
2581
2683
  const runId = options.runId ?? `run-${Date.now()}`;
2582
2684
  const messages = options.messages ?? [];
@@ -2889,6 +2991,10 @@ async function runAgenticStructuredOutput(options) {
2889
2991
  value: finalizationError.code,
2890
2992
  enumerable: true
2891
2993
  });
2994
+ if (finalizationError.rawText !== void 0) Object.defineProperty(err, "rawText", {
2995
+ value: finalizationError.rawText,
2996
+ enumerable: true
2997
+ });
2892
2998
  throw err;
2893
2999
  }
2894
3000
  const validated = engine.getValidatedStructuredOutput();