@tanstack/ai 0.45.1 → 0.46.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.
@@ -15,9 +15,10 @@ import { INTERRUPT_BINDING_METADATA_KEY, InterruptResumeValidationError, readUno
15
15
  import { normalizeToolResult } from "../../utilities/tool-result.js";
16
16
  import { isProviderExecutedToolCall } from "../../utilities/provider-executed.js";
17
17
  import { LazyToolManager } from "./tools/lazy-tool-manager.js";
18
+ import { assertUniqueToolNames } from "./tools/unique-tool-names.js";
18
19
  import { MiddlewareAbortError, ToolCallManager, executeToolCalls } from "./tools/tool-calls.js";
19
20
  import { maxIterations } from "./agent-loop-strategies.js";
20
- import { convertMessagesToModelMessages, generateMessageId } from "./messages.js";
21
+ import { convertMessagesToModelMessages, generateMessageId, modelMessageToUIMessage } from "./messages.js";
21
22
  import { MiddlewareRunner } from "./middleware/compose.js";
22
23
  import { provideSandboxRuntime } from "./middleware/sandbox-runtime.js";
23
24
  import { provideRunDisconnect } from "./middleware/run-disconnect.js";
@@ -148,6 +149,7 @@ var TextEngine = class {
148
149
  accumulatedThinking = [];
149
150
  currentThinkingContent = "";
150
151
  currentThinkingSignature = "";
152
+ hasSeenReasoningEvents = false;
151
153
  eventOptions;
152
154
  eventToolNames;
153
155
  finishedEvent = null;
@@ -202,6 +204,7 @@ var TextEngine = class {
202
204
  this.initialApprovals = approvals;
203
205
  this.initialClientToolResults = clientToolResults;
204
206
  this.messages = convertMessagesToModelMessages(config.params.messages);
207
+ assertUniqueToolNames(config.params.tools || []);
205
208
  this.lazyToolManager = new LazyToolManager(config.params.tools || [], this.messages, config.params.lazyToolsConfig);
206
209
  this.tools = this.lazyToolManager.getActiveTools();
207
210
  this.toolCallManager = new ToolCallManager(this.tools);
@@ -355,6 +358,7 @@ var TextEngine = class {
355
358
  duration: Date.now() - this.streamStartTime
356
359
  });
357
360
  } else {
361
+ this.addTerminalReasoningMessage();
358
362
  this.terminalHookCalled = true;
359
363
  await this.middlewareRunner.runOnFinish(this.middlewareCtx, {
360
364
  finishReason: this.lastFinishReason,
@@ -458,6 +462,7 @@ var TextEngine = class {
458
462
  this.accumulatedThinking = [];
459
463
  this.currentThinkingContent = "";
460
464
  this.currentThinkingSignature = "";
465
+ this.hasSeenReasoningEvents = false;
461
466
  this.finishedEvent = null;
462
467
  this.streamedToolErrorResults.clear();
463
468
  this.middlewareCtx.currentMessageId = this.currentMessageId;
@@ -593,7 +598,10 @@ var TextEngine = class {
593
598
  case "STEP_STARTED":
594
599
  this.handleStepStartedEvent();
595
600
  break;
596
- case "STEP_FINISHED": this.handleStepFinishedEvent(chunk);
601
+ case "STEP_FINISHED":
602
+ this.handleStepFinishedEvent(chunk);
603
+ break;
604
+ case "REASONING_MESSAGE_CONTENT": this.handleReasoningMessageContentEvent(chunk);
597
605
  }
598
606
  }
599
607
  handleTextMessageContentEvent(chunk) {
@@ -657,9 +665,19 @@ var TextEngine = class {
657
665
  this.finalizeCurrentThinkingStep();
658
666
  }
659
667
  handleStepFinishedEvent(chunk) {
660
- if (chunk.delta) this.currentThinkingContent += chunk.delta;
668
+ if (!this.hasSeenReasoningEvents) {
669
+ if (chunk.delta) this.currentThinkingContent += chunk.delta;
670
+ else if (chunk.content) {
671
+ if (chunk.content.startsWith(this.currentThinkingContent)) this.currentThinkingContent = chunk.content;
672
+ else if (!this.currentThinkingContent.startsWith(chunk.content)) this.currentThinkingContent += chunk.content;
673
+ }
674
+ }
661
675
  if (chunk.signature) this.currentThinkingSignature = chunk.signature;
662
676
  }
677
+ handleReasoningMessageContentEvent(chunk) {
678
+ this.hasSeenReasoningEvents = true;
679
+ this.currentThinkingContent += chunk.delta;
680
+ }
663
681
  /**
664
682
  * Tools available for execution this turn. The discovery tool is dropped
665
683
  * from the advertised set (`this.tools`) once every lazy tool is discovered,
@@ -871,6 +889,20 @@ var TextEngine = class {
871
889
  }];
872
890
  this.middlewareCtx.messages = this.messages;
873
891
  }
892
+ addTerminalReasoningMessage() {
893
+ this.finalizeCurrentThinkingStep();
894
+ if (this.accumulatedThinking.length === 0) return;
895
+ const messages = this.middlewareCtx.messages;
896
+ if (messages.some((message) => message.role === "assistant" && message.id === this.currentMessageId)) return;
897
+ this.messages = [...messages, {
898
+ role: "assistant",
899
+ content: this.accumulatedContent || null,
900
+ id: this.currentMessageId ?? void 0,
901
+ createdAt: this.currentMessageCreatedAt ?? void 0,
902
+ thinking: this.accumulatedThinking
903
+ }];
904
+ this.middlewareCtx.messages = this.messages;
905
+ }
874
906
  /**
875
907
  * Extract client state (approvals and client tool results) from original messages.
876
908
  * This is called in the constructor BEFORE converting to ModelMessage format,
@@ -980,10 +1012,13 @@ var TextEngine = class {
980
1012
  buildMessagesSnapshotChunk() {
981
1013
  const messages = this.messages.map((message, index) => {
982
1014
  const content = typeof message.content === "string" ? message.content : message.content === null ? void 0 : JSON.stringify(message.content);
1015
+ const id = message.id || `snapshot_${this.runIdOverride ?? this.requestId}_${index}`;
1016
+ const parts = message.role === "assistant" && message.thinking?.length ? modelMessageToUIMessage(message, id).parts : void 0;
983
1017
  return {
984
- id: message.id || `snapshot_${this.runIdOverride ?? this.requestId}_${index}`,
1018
+ id,
985
1019
  role: message.role,
986
1020
  ...content !== void 0 ? { content } : {},
1021
+ ...parts ? { parts } : {},
987
1022
  ..."toolCalls" in message && message.toolCalls ? { toolCalls: message.toolCalls } : {},
988
1023
  ..."toolCallId" in message && message.toolCallId ? { toolCallId: message.toolCallId } : {}
989
1024
  };
@@ -1755,6 +1790,7 @@ var TextEngine = class {
1755
1790
  this.applyResumeToolState(config.resumeToolState);
1756
1791
  this.messages = config.messages;
1757
1792
  this.systemPrompts = config.systemPrompts;
1793
+ assertUniqueToolNames(config.tools);
1758
1794
  this.tools = config.tools;
1759
1795
  this.params = {
1760
1796
  ...this.params,
@@ -1879,6 +1915,7 @@ var TextEngine = class {
1879
1915
  */
1880
1916
  function chat(options) {
1881
1917
  validateCapabilities(options.middleware ?? [], options.adapter);
1918
+ if (options.tools) assertUniqueToolNames(options.tools);
1882
1919
  const { outputSchema, stream } = options;
1883
1920
  if (outputSchema && stream === true) return runStreamingStructuredOutput({
1884
1921
  ...options,