@tanstack/ai 0.32.0 → 0.34.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 (64) hide show
  1. package/dist/esm/activities/chat/index.js +47 -20
  2. package/dist/esm/activities/chat/index.js.map +1 -1
  3. package/dist/esm/activities/chat/middleware/types.d.ts +7 -0
  4. package/dist/esm/activities/chat/tools/lazy-tool-manager.d.ts +25 -1
  5. package/dist/esm/activities/chat/tools/lazy-tool-manager.js +26 -2
  6. package/dist/esm/activities/chat/tools/lazy-tool-manager.js.map +1 -1
  7. package/dist/esm/activities/chat/tools/schema-converter.d.ts +13 -0
  8. package/dist/esm/activities/chat/tools/schema-converter.js +61 -33
  9. package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -1
  10. package/dist/esm/activities/generateAudio/index.d.ts +7 -0
  11. package/dist/esm/activities/generateAudio/index.js +26 -1
  12. package/dist/esm/activities/generateAudio/index.js.map +1 -1
  13. package/dist/esm/activities/generateImage/index.d.ts +7 -0
  14. package/dist/esm/activities/generateImage/index.js +26 -1
  15. package/dist/esm/activities/generateImage/index.js.map +1 -1
  16. package/dist/esm/activities/generateSpeech/index.d.ts +7 -0
  17. package/dist/esm/activities/generateSpeech/index.js +26 -1
  18. package/dist/esm/activities/generateSpeech/index.js.map +1 -1
  19. package/dist/esm/activities/generateTranscription/index.d.ts +7 -0
  20. package/dist/esm/activities/generateTranscription/index.js +26 -1
  21. package/dist/esm/activities/generateTranscription/index.js.map +1 -1
  22. package/dist/esm/activities/generateVideo/index.d.ts +9 -0
  23. package/dist/esm/activities/generateVideo/index.js +52 -2
  24. package/dist/esm/activities/generateVideo/index.js.map +1 -1
  25. package/dist/esm/activities/middleware/index.d.ts +2 -0
  26. package/dist/esm/activities/middleware/run.d.ts +20 -0
  27. package/dist/esm/activities/middleware/run.js +42 -0
  28. package/dist/esm/activities/middleware/run.js.map +1 -0
  29. package/dist/esm/activities/middleware/types.d.ts +118 -0
  30. package/dist/esm/index.d.ts +2 -0
  31. package/dist/esm/index.js +2 -0
  32. package/dist/esm/index.js.map +1 -1
  33. package/dist/esm/middlewares/otel.d.ts +8 -2
  34. package/dist/esm/middlewares/otel.js +145 -95
  35. package/dist/esm/middlewares/otel.js.map +1 -1
  36. package/dist/esm/middlewares/usage-attributes.d.ts +24 -0
  37. package/dist/esm/middlewares/usage-attributes.js +43 -0
  38. package/dist/esm/middlewares/usage-attributes.js.map +1 -0
  39. package/dist/esm/types.d.ts +7 -7
  40. package/dist/esm/utilities/errors.d.ts +13 -0
  41. package/dist/esm/utilities/errors.js +22 -0
  42. package/dist/esm/utilities/errors.js.map +1 -0
  43. package/dist/esm/utilities/numbers.d.ts +8 -0
  44. package/dist/esm/utilities/numbers.js +12 -0
  45. package/dist/esm/utilities/numbers.js.map +1 -0
  46. package/package.json +3 -2
  47. package/src/activities/chat/index.ts +125 -35
  48. package/src/activities/chat/middleware/types.ts +7 -0
  49. package/src/activities/chat/tools/lazy-tool-manager.ts +46 -4
  50. package/src/activities/chat/tools/schema-converter.ts +146 -93
  51. package/src/activities/generateAudio/index.ts +42 -1
  52. package/src/activities/generateImage/index.ts +42 -1
  53. package/src/activities/generateSpeech/index.ts +42 -1
  54. package/src/activities/generateTranscription/index.ts +42 -1
  55. package/src/activities/generateVideo/index.ts +88 -2
  56. package/src/activities/middleware/index.ts +20 -0
  57. package/src/activities/middleware/run.ts +88 -0
  58. package/src/activities/middleware/types.ts +173 -0
  59. package/src/index.ts +19 -0
  60. package/src/middlewares/otel.ts +195 -120
  61. package/src/middlewares/usage-attributes.ts +65 -0
  62. package/src/types.ts +7 -7
  63. package/src/utilities/errors.ts +29 -0
  64. package/src/utilities/numbers.ts +15 -0
@@ -1,11 +1,12 @@
1
1
  import { devtoolsMiddleware } from "@tanstack/ai-event-client";
2
+ import { undoNullWidening } from "@tanstack/ai-utils";
2
3
  import { stripToSpecMiddleware } from "../../strip-to-spec-middleware.js";
3
4
  import { streamToText } from "../../stream-to-response.js";
4
5
  import { resolveDebugOption } from "../../logger/resolve.js";
5
6
  import { normalizeToolResult } from "../../utilities/tool-result.js";
6
7
  import { LazyToolManager } from "./tools/lazy-tool-manager.js";
7
8
  import { ToolCallManager, MiddlewareAbortError, executeToolCalls } from "./tools/tool-calls.js";
8
- import { convertSchemaToJsonSchema, isStandardSchema, parseWithStandardSchema } from "./tools/schema-converter.js";
9
+ import { convertSchemaForStructuredOutput, isStandardSchema, parseWithStandardSchema, convertSchemaToJsonSchema } from "./tools/schema-converter.js";
9
10
  import { maxIterations } from "./agent-loop-strategies.js";
10
11
  import { convertMessagesToModelMessages, generateMessageId } from "./messages.js";
11
12
  import { MiddlewareRunner } from "./middleware/compose.js";
@@ -90,8 +91,8 @@ class TextEngine {
90
91
  // to carry, so the client matches it to the streaming text deltas.
91
92
  combinedStructuredMessageId = null;
92
93
  // Holds the validated value when `finalStructuredOutput.validate` is provided
93
- // and succeeds. Distinct from `structuredOutputResult.data` (the raw,
94
- // unvalidated payload from the structured-output.complete chunk).
94
+ // and succeeds. Distinct from `structuredOutputResult.data` (the normalized
95
+ // but unvalidated payload from the structured-output.complete chunk).
95
96
  validatedStructuredOutput = void 0;
96
97
  hasValidatedStructuredOutput = false;
97
98
  finalizationError = null;
@@ -155,6 +156,7 @@ class TextEngine {
155
156
  this.deferredPromises.push(promise);
156
157
  },
157
158
  // Provider / adapter info
159
+ activity: "chat",
158
160
  provider: config.adapter.name,
159
161
  model: config.params.model,
160
162
  source: "server",
@@ -525,6 +527,20 @@ class TextEngine {
525
527
  this.currentThinkingSignature = chunk.signature;
526
528
  }
527
529
  }
530
+ /**
531
+ * Tools available for execution this turn. The discovery tool is dropped
532
+ * from the advertised set (`this.tools`) once every lazy tool is discovered,
533
+ * but a model may still re-request discovery; this widens execution lookup
534
+ * to include it so such calls don't fail with "Unknown tool". Centralised so
535
+ * both execution sites (`processToolCalls` and `checkForPendingToolCalls`)
536
+ * stay in sync.
537
+ */
538
+ resolveExecutableTools(toolCalls) {
539
+ return this.lazyToolManager.getExecutableTools(
540
+ this.tools,
541
+ toolCalls.map((tc) => tc.function.name)
542
+ );
543
+ }
528
544
  async *checkForPendingToolCalls() {
529
545
  const pendingToolCalls = this.getPendingToolCallsFromMessages();
530
546
  if (pendingToolCalls.length === 0) {
@@ -562,7 +578,7 @@ class TextEngine {
562
578
  const { approvals, clientToolResults } = this.collectClientState();
563
579
  const generator = executeToolCalls(
564
580
  executablePendingCalls,
565
- this.tools,
581
+ this.resolveExecutableTools(executablePendingCalls),
566
582
  approvals,
567
583
  clientToolResults,
568
584
  (eventName, data) => this.createCustomEventChunk(eventName, data),
@@ -694,7 +710,7 @@ class TextEngine {
694
710
  const { approvals, clientToolResults } = this.collectClientState();
695
711
  const generator = executeToolCalls(
696
712
  executableToolCalls,
697
- this.tools,
713
+ this.resolveExecutableTools(executableToolCalls),
698
714
  approvals,
699
715
  clientToolResults,
700
716
  (eventName, data) => this.createCustomEventChunk(eventName, data),
@@ -1125,13 +1141,16 @@ class TextEngine {
1125
1141
  }
1126
1142
  }
1127
1143
  }
1144
+ let outboundChunk = chunk;
1128
1145
  if (chunk.type === EventType.CUSTOM && chunk.name === "structured-output.complete") {
1129
1146
  const parsed = readStructuredOutputCompleteValue(chunk.value);
1130
1147
  if (parsed) {
1131
- this.structuredOutputResult = {
1132
- data: parsed.object,
1133
- rawText: parsed.raw
1134
- };
1148
+ const object = this.finalStructuredOutput.normalize ? this.finalStructuredOutput.normalize(parsed.object) : parsed.object;
1149
+ this.structuredOutputResult = { data: object, rawText: parsed.raw };
1150
+ const value = chunk.value;
1151
+ if (object !== parsed.object && value && typeof value === "object") {
1152
+ outboundChunk = { ...chunk, value: { ...value, object } };
1153
+ }
1135
1154
  }
1136
1155
  }
1137
1156
  if (chunk.type === EventType.RUN_FINISHED && chunk.usage) {
@@ -1146,7 +1165,7 @@ class TextEngine {
1146
1165
  }
1147
1166
  const outputChunks = await this.middlewareRunner.runOnChunk(
1148
1167
  this.middlewareCtx,
1149
- chunk
1168
+ outboundChunk
1150
1169
  );
1151
1170
  if (this.finalStructuredOutput.yieldChunks) {
1152
1171
  for (const outputChunk of outputChunks) {
@@ -1252,7 +1271,8 @@ class TextEngine {
1252
1271
  } else {
1253
1272
  try {
1254
1273
  const parsed = JSON.parse(rawText);
1255
- this.structuredOutputResult = { data: parsed, rawText };
1274
+ const data = this.finalStructuredOutput.normalize ? this.finalStructuredOutput.normalize(parsed) : parsed;
1275
+ this.structuredOutputResult = { data, rawText };
1256
1276
  } catch (err) {
1257
1277
  const detail = rawText.slice(0, 200) + (rawText.length > 200 ? "..." : "");
1258
1278
  this.finalizationError = {
@@ -1493,12 +1513,11 @@ async function runAgenticStructuredOutput(options) {
1493
1513
  if (!outputSchema) {
1494
1514
  throw new Error("outputSchema is required for structured output");
1495
1515
  }
1496
- const jsonSchema = convertSchemaToJsonSchema(outputSchema, {
1497
- forStructuredOutput: true
1498
- });
1516
+ const { jsonSchema, nullWideningMap } = convertSchemaForStructuredOutput(outputSchema);
1499
1517
  if (!jsonSchema) {
1500
1518
  throw new Error("Failed to convert output schema to JSON Schema");
1501
1519
  }
1520
+ const normalize = (data) => undoNullWidening(data, nullWideningMap);
1502
1521
  const validate = isStandardSchema(outputSchema) ? (data) => parseWithStandardSchema(outputSchema, data) : void 0;
1503
1522
  const nativeCombined = adapter.supportsCombinedToolsAndSchema?.(options.modelOptions) === true;
1504
1523
  const mcpManager = MCPManager.from(mcp);
@@ -1515,6 +1534,7 @@ async function runAgenticStructuredOutput(options) {
1515
1534
  finalStructuredOutput: {
1516
1535
  jsonSchema,
1517
1536
  yieldChunks: false,
1537
+ normalize,
1518
1538
  ...validate ? { validate } : {},
1519
1539
  ...nativeCombined ? { nativeCombined: true } : {}
1520
1540
  }
@@ -1629,7 +1649,13 @@ async function* fallbackStructuredOutputStream(adapter, options, onAdapterError)
1629
1649
  threadId,
1630
1650
  model,
1631
1651
  timestamp,
1632
- finishReason: "stop"
1652
+ finishReason: "stop",
1653
+ // Forward adapter-reported token usage so consumers reading
1654
+ // `RUN_FINISHED.usage` (and the engine's `runOnUsage` middleware hook) see
1655
+ // it on the fallback path, mirroring the native streaming path. The
1656
+ // conditional spread avoids emitting `usage: undefined` for adapters that
1657
+ // don't report it. See #758.
1658
+ ...result.usage ? { usage: result.usage } : {}
1633
1659
  };
1634
1660
  }
1635
1661
  function runStreamingStructuredOutput(options) {
@@ -1637,18 +1663,18 @@ function runStreamingStructuredOutput(options) {
1637
1663
  if (!outputSchema) {
1638
1664
  throw new Error("outputSchema is required for streaming structured output");
1639
1665
  }
1640
- const jsonSchema = convertSchemaToJsonSchema(outputSchema, {
1641
- forStructuredOutput: true
1642
- });
1666
+ const { jsonSchema, nullWideningMap } = convertSchemaForStructuredOutput(outputSchema);
1643
1667
  if (!jsonSchema) {
1644
1668
  throw new Error("Failed to convert output schema to JSON Schema");
1645
1669
  }
1670
+ const normalize = (data) => undoNullWidening(data, nullWideningMap);
1646
1671
  return runStreamingStructuredOutputImpl(
1647
1672
  options,
1648
- jsonSchema
1673
+ jsonSchema,
1674
+ normalize
1649
1675
  );
1650
1676
  }
1651
- async function* runStreamingStructuredOutputImpl(options, jsonSchema) {
1677
+ async function* runStreamingStructuredOutputImpl(options, jsonSchema, normalize) {
1652
1678
  const {
1653
1679
  adapter,
1654
1680
  outputSchema,
@@ -1675,6 +1701,7 @@ async function* runStreamingStructuredOutputImpl(options, jsonSchema) {
1675
1701
  finalStructuredOutput: {
1676
1702
  jsonSchema,
1677
1703
  yieldChunks: true,
1704
+ normalize,
1678
1705
  ...nativeCombined ? { nativeCombined: true } : {}
1679
1706
  }
1680
1707
  },