@tanstack/ai 0.33.0 → 0.34.1

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.
@@ -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;
@@ -1140,13 +1141,16 @@ class TextEngine {
1140
1141
  }
1141
1142
  }
1142
1143
  }
1144
+ let outboundChunk = chunk;
1143
1145
  if (chunk.type === EventType.CUSTOM && chunk.name === "structured-output.complete") {
1144
1146
  const parsed = readStructuredOutputCompleteValue(chunk.value);
1145
1147
  if (parsed) {
1146
- this.structuredOutputResult = {
1147
- data: parsed.object,
1148
- rawText: parsed.raw
1149
- };
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
+ }
1150
1154
  }
1151
1155
  }
1152
1156
  if (chunk.type === EventType.RUN_FINISHED && chunk.usage) {
@@ -1161,7 +1165,7 @@ class TextEngine {
1161
1165
  }
1162
1166
  const outputChunks = await this.middlewareRunner.runOnChunk(
1163
1167
  this.middlewareCtx,
1164
- chunk
1168
+ outboundChunk
1165
1169
  );
1166
1170
  if (this.finalStructuredOutput.yieldChunks) {
1167
1171
  for (const outputChunk of outputChunks) {
@@ -1267,7 +1271,8 @@ class TextEngine {
1267
1271
  } else {
1268
1272
  try {
1269
1273
  const parsed = JSON.parse(rawText);
1270
- this.structuredOutputResult = { data: parsed, rawText };
1274
+ const data = this.finalStructuredOutput.normalize ? this.finalStructuredOutput.normalize(parsed) : parsed;
1275
+ this.structuredOutputResult = { data, rawText };
1271
1276
  } catch (err) {
1272
1277
  const detail = rawText.slice(0, 200) + (rawText.length > 200 ? "..." : "");
1273
1278
  this.finalizationError = {
@@ -1508,12 +1513,11 @@ async function runAgenticStructuredOutput(options) {
1508
1513
  if (!outputSchema) {
1509
1514
  throw new Error("outputSchema is required for structured output");
1510
1515
  }
1511
- const jsonSchema = convertSchemaToJsonSchema(outputSchema, {
1512
- forStructuredOutput: true
1513
- });
1516
+ const { jsonSchema, nullWideningMap } = convertSchemaForStructuredOutput(outputSchema);
1514
1517
  if (!jsonSchema) {
1515
1518
  throw new Error("Failed to convert output schema to JSON Schema");
1516
1519
  }
1520
+ const normalize = (data) => undoNullWidening(data, nullWideningMap);
1517
1521
  const validate = isStandardSchema(outputSchema) ? (data) => parseWithStandardSchema(outputSchema, data) : void 0;
1518
1522
  const nativeCombined = adapter.supportsCombinedToolsAndSchema?.(options.modelOptions) === true;
1519
1523
  const mcpManager = MCPManager.from(mcp);
@@ -1530,6 +1534,7 @@ async function runAgenticStructuredOutput(options) {
1530
1534
  finalStructuredOutput: {
1531
1535
  jsonSchema,
1532
1536
  yieldChunks: false,
1537
+ normalize,
1533
1538
  ...validate ? { validate } : {},
1534
1539
  ...nativeCombined ? { nativeCombined: true } : {}
1535
1540
  }
@@ -1658,18 +1663,18 @@ function runStreamingStructuredOutput(options) {
1658
1663
  if (!outputSchema) {
1659
1664
  throw new Error("outputSchema is required for streaming structured output");
1660
1665
  }
1661
- const jsonSchema = convertSchemaToJsonSchema(outputSchema, {
1662
- forStructuredOutput: true
1663
- });
1666
+ const { jsonSchema, nullWideningMap } = convertSchemaForStructuredOutput(outputSchema);
1664
1667
  if (!jsonSchema) {
1665
1668
  throw new Error("Failed to convert output schema to JSON Schema");
1666
1669
  }
1670
+ const normalize = (data) => undoNullWidening(data, nullWideningMap);
1667
1671
  return runStreamingStructuredOutputImpl(
1668
1672
  options,
1669
- jsonSchema
1673
+ jsonSchema,
1674
+ normalize
1670
1675
  );
1671
1676
  }
1672
- async function* runStreamingStructuredOutputImpl(options, jsonSchema) {
1677
+ async function* runStreamingStructuredOutputImpl(options, jsonSchema, normalize) {
1673
1678
  const {
1674
1679
  adapter,
1675
1680
  outputSchema,
@@ -1696,6 +1701,7 @@ async function* runStreamingStructuredOutputImpl(options, jsonSchema) {
1696
1701
  finalStructuredOutput: {
1697
1702
  jsonSchema,
1698
1703
  yieldChunks: true,
1704
+ normalize,
1699
1705
  ...nativeCombined ? { nativeCombined: true } : {}
1700
1706
  }
1701
1707
  },