@ai-sdk/provider-utils 5.0.0-beta.22 → 5.0.0-beta.24

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @ai-sdk/provider-utils
2
2
 
3
+ ## 5.0.0-beta.24
4
+
5
+ ### Patch Changes
6
+
7
+ - f807e45: Extract shared `StreamingToolCallTracker` class into `@ai-sdk/provider-utils` to deduplicate streaming tool call handling across OpenAI-compatible providers. Also adds missing `generateId()` fallback for `toolCallId` in Alibaba's `doGenerate` path and ensures all providers finalize unfinished tool calls during stream flush.
8
+
9
+ ## 5.0.0-beta.23
10
+
11
+ ### Patch Changes
12
+
13
+ - 350ea38: refactoring: introduce Arrayable type
14
+
3
15
  ## 5.0.0-beta.22
4
16
 
5
17
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ImageModelV4File, LanguageModelV4FunctionTool, LanguageModelV4ProviderTool, AISDKError, JSONSchema7, JSONParseError, TypeValidationError, JSONValue, APICallError, LanguageModelV4Prompt, LanguageModelV4FilePart, SharedV4ProviderReference, LanguageModelV4CallOptions, SharedV4Warning, SharedV4ProviderOptions, JSONObject, TypeValidationContext } from '@ai-sdk/provider';
1
+ import { ImageModelV4File, LanguageModelV4FunctionTool, LanguageModelV4ProviderTool, AISDKError, JSONSchema7, JSONParseError, TypeValidationError, JSONValue, APICallError, LanguageModelV4Prompt, LanguageModelV4FilePart, SharedV4ProviderReference, LanguageModelV4CallOptions, SharedV4Warning, SharedV4ProviderOptions, JSONObject, SharedV4ProviderMetadata, LanguageModelV4StreamPart, TypeValidationContext } from '@ai-sdk/provider';
2
2
  export { getErrorMessage } from '@ai-sdk/provider';
3
3
  import { StandardSchemaV1, StandardJSONSchemaV1 } from '@standard-schema/spec';
4
4
  export * from '@standard-schema/spec';
@@ -7,6 +7,16 @@ import * as z4 from 'zod/v4';
7
7
  export { WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE } from '@workflow/serde';
8
8
  export { EventSourceMessage, EventSourceParserStream } from 'eventsource-parser/stream';
9
9
 
10
+ /**
11
+ * A value that can be provided either as a single item, an array of items,
12
+ * or be left undefined.
13
+ */
14
+ type Arrayable<T> = T | T[] | undefined;
15
+ /**
16
+ * Normalizes a possibly undefined or non-array value into an array.
17
+ */
18
+ declare function asArray<T>(value: Arrayable<T>): T[];
19
+
10
20
  declare function combineHeaders(...headers: Array<Record<string, string | undefined> | undefined>): Record<string, string | undefined>;
11
21
 
12
22
  /**
@@ -1469,6 +1479,76 @@ declare function serializeModelOptions<CONFIG extends {
1469
1479
  config: JSONObject;
1470
1480
  };
1471
1481
 
1482
+ /**
1483
+ * Minimal interface for a streaming tool call delta from an OpenAI-compatible API.
1484
+ */
1485
+ interface StreamingToolCallDelta {
1486
+ index?: number | null;
1487
+ id?: string | null;
1488
+ type?: string | null;
1489
+ function?: {
1490
+ name?: string | null;
1491
+ arguments?: string | null;
1492
+ } | null;
1493
+ }
1494
+ interface StreamingToolCallTrackerOptions {
1495
+ /**
1496
+ * ID generator function for tool call IDs.
1497
+ * Defaults to the standard generateId.
1498
+ */
1499
+ generateId?: () => string;
1500
+ /**
1501
+ * How to validate the `type` field on new tool call deltas.
1502
+ * - `'none'`: no validation (default)
1503
+ * - `'if-present'`: throw if type is present and not `'function'`
1504
+ * - `'required'`: throw if type is not exactly `'function'`
1505
+ */
1506
+ typeValidation?: 'none' | 'if-present' | 'required';
1507
+ /**
1508
+ * Extract provider-specific metadata from a tool call delta.
1509
+ * Called once when a new tool call is detected.
1510
+ * The returned metadata is stored on the tool call and passed to
1511
+ * `buildToolCallProviderMetadata` when the tool call is finalized.
1512
+ */
1513
+ extractMetadata?: (delta: StreamingToolCallDelta) => SharedV4ProviderMetadata | undefined;
1514
+ /**
1515
+ * Build the `providerMetadata` object for a `tool-call` event.
1516
+ * Receives the metadata previously extracted via `extractMetadata`.
1517
+ * If `undefined` is returned, no `providerMetadata` is included in the event.
1518
+ */
1519
+ buildToolCallProviderMetadata?: (metadata: SharedV4ProviderMetadata | undefined) => SharedV4ProviderMetadata | undefined;
1520
+ }
1521
+ /**
1522
+ * Tracks streaming tool call state across multiple deltas from an
1523
+ * OpenAI-compatible chat completion stream. Handles argument accumulation,
1524
+ * emits tool-input-start/delta/end and tool-call events, and finalizes
1525
+ * unfinished tool calls on flush.
1526
+ *
1527
+ * Used by openai, openai-compatible, groq, deepseek, and alibaba providers.
1528
+ */
1529
+ declare class StreamingToolCallTracker {
1530
+ private toolCalls;
1531
+ private readonly _generateId;
1532
+ private readonly typeValidation;
1533
+ private readonly extractMetadata?;
1534
+ private readonly buildToolCallProviderMetadata?;
1535
+ constructor(options?: StreamingToolCallTrackerOptions);
1536
+ /**
1537
+ * Process a tool call delta from a streaming response chunk.
1538
+ * Emits tool-input-start, tool-input-delta, tool-input-end, and tool-call
1539
+ * events as appropriate.
1540
+ */
1541
+ processDelta(toolCallDelta: StreamingToolCallDelta, enqueue: (part: LanguageModelV4StreamPart) => void): void;
1542
+ /**
1543
+ * Finalize any unfinished tool calls. Should be called during the stream's
1544
+ * flush handler to ensure all tool calls are properly completed.
1545
+ */
1546
+ flush(enqueue: (part: LanguageModelV4StreamPart) => void): void;
1547
+ private processNewToolCall;
1548
+ private processExistingToolCall;
1549
+ private finishToolCall;
1550
+ }
1551
+
1472
1552
  /**
1473
1553
  * Strips file extension segments from a filename.
1474
1554
  *
@@ -1674,4 +1754,4 @@ interface ToolResult<NAME extends string, INPUT, OUTPUT> {
1674
1754
  dynamic?: boolean;
1675
1755
  }
1676
1756
 
1677
- export { type AssistantContent, type AssistantModelMessage, type Context, type CustomPart, DEFAULT_MAX_DOWNLOAD_SIZE, type DataContent, DelayedPromise, DownloadError, type ExecutableTool, type FetchFunction, type FilePart, type FlexibleSchema, type HasRequiredKey, type IdGenerator, type ImagePart, type InferSchema, type InferToolContext, type InferToolInput, type InferToolOutput, type InferToolSetContext, type LazySchema, type MaybePromiseLike, type ModelMessage, type ParseResult, type ProviderOptions, type ProviderReference, type ProviderToolFactory, type ProviderToolFactoryWithOutputSchema, type ReasoningFilePart, type ReasoningPart, type Resolvable, type ResponseHandler, type Schema, type SystemModelMessage, type TextPart, type Tool, type ToolApprovalRequest, type ToolApprovalResponse, type ToolCall, type ToolCallPart, type ToolContent, type ToolExecuteFunction, type ToolExecutionOptions, type ToolModelMessage, type ToolNameMapping, type ToolNeedsApprovalFunction, type ToolResult, type ToolResultOutput, type ToolResultPart, type ToolSet, type UserContent, type UserModelMessage, VERSION, type ValidationResult, asSchema, combineHeaders, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertImageModelFileToDataUri, convertToBase64, convertToFormData, convertUint8ArrayToBase64, createBinaryResponseHandler, createEventSourceResponseHandler, createIdGenerator, createJsonErrorResponseHandler, createJsonResponseHandler, createProviderToolFactory, createProviderToolFactoryWithOutputSchema, createStatusCodeErrorResponseHandler, createToolNameMapping, delay, downloadBlob, dynamicTool, executeTool, extractResponseHeaders, generateId, getFromApi, getRuntimeEnvironmentUserAgent, injectJsonInstructionIntoMessages, isAbortError, isCustomReasoning, isExecutableTool, isNonNullable, isParsableJson, isProviderReference, isUrlSupported, jsonSchema, lazySchema, loadApiKey, loadOptionalSetting, loadSetting, mapReasoningToProviderBudget, mapReasoningToProviderEffort, mediaTypeToExtension, normalizeHeaders, parseJSON, parseJsonEventStream, parseProviderOptions, postFormDataToApi, postJsonToApi, postToApi, readResponseWithSizeLimit, removeUndefinedEntries, resolve, resolveProviderReference, safeParseJSON, safeValidateTypes, serializeModelOptions, stripFileExtension, tool, validateDownloadUrl, validateTypes, withUserAgentSuffix, withoutTrailingSlash, zodSchema };
1757
+ export { type Arrayable, type AssistantContent, type AssistantModelMessage, type Context, type CustomPart, DEFAULT_MAX_DOWNLOAD_SIZE, type DataContent, DelayedPromise, DownloadError, type ExecutableTool, type FetchFunction, type FilePart, type FlexibleSchema, type HasRequiredKey, type IdGenerator, type ImagePart, type InferSchema, type InferToolContext, type InferToolInput, type InferToolOutput, type InferToolSetContext, type LazySchema, type MaybePromiseLike, type ModelMessage, type ParseResult, type ProviderOptions, type ProviderReference, type ProviderToolFactory, type ProviderToolFactoryWithOutputSchema, type ReasoningFilePart, type ReasoningPart, type Resolvable, type ResponseHandler, type Schema, type StreamingToolCallDelta, StreamingToolCallTracker, type StreamingToolCallTrackerOptions, type SystemModelMessage, type TextPart, type Tool, type ToolApprovalRequest, type ToolApprovalResponse, type ToolCall, type ToolCallPart, type ToolContent, type ToolExecuteFunction, type ToolExecutionOptions, type ToolModelMessage, type ToolNameMapping, type ToolNeedsApprovalFunction, type ToolResult, type ToolResultOutput, type ToolResultPart, type ToolSet, type UserContent, type UserModelMessage, VERSION, type ValidationResult, asArray, asSchema, combineHeaders, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertImageModelFileToDataUri, convertToBase64, convertToFormData, convertUint8ArrayToBase64, createBinaryResponseHandler, createEventSourceResponseHandler, createIdGenerator, createJsonErrorResponseHandler, createJsonResponseHandler, createProviderToolFactory, createProviderToolFactoryWithOutputSchema, createStatusCodeErrorResponseHandler, createToolNameMapping, delay, downloadBlob, dynamicTool, executeTool, extractResponseHeaders, generateId, getFromApi, getRuntimeEnvironmentUserAgent, injectJsonInstructionIntoMessages, isAbortError, isCustomReasoning, isExecutableTool, isNonNullable, isParsableJson, isProviderReference, isUrlSupported, jsonSchema, lazySchema, loadApiKey, loadOptionalSetting, loadSetting, mapReasoningToProviderBudget, mapReasoningToProviderEffort, mediaTypeToExtension, normalizeHeaders, parseJSON, parseJsonEventStream, parseProviderOptions, postFormDataToApi, postJsonToApi, postToApi, readResponseWithSizeLimit, removeUndefinedEntries, resolve, resolveProviderReference, safeParseJSON, safeValidateTypes, serializeModelOptions, stripFileExtension, tool, validateDownloadUrl, validateTypes, withUserAgentSuffix, withoutTrailingSlash, zodSchema };
package/dist/index.js CHANGED
@@ -1,3 +1,8 @@
1
+ // src/as-array.ts
2
+ function asArray(value) {
3
+ return value === void 0 ? [] : Array.isArray(value) ? value : [value];
4
+ }
5
+
1
6
  // src/combine-headers.ts
2
7
  function combineHeaders(...headers) {
3
8
  return headers.reduce(
@@ -566,7 +571,7 @@ function withUserAgentSuffix(headers, ...userAgentSuffixParts) {
566
571
  }
567
572
 
568
573
  // src/version.ts
569
- var VERSION = true ? "5.0.0-beta.22" : "0.0.0-test";
574
+ var VERSION = true ? "5.0.0-beta.24" : "0.0.0-test";
570
575
 
571
576
  // src/get-from-api.ts
572
577
  var getOriginalFetch = () => globalThis.fetch;
@@ -2765,6 +2770,140 @@ function resolveSync(value) {
2765
2770
  return next;
2766
2771
  }
2767
2772
 
2773
+ // src/streaming-tool-call-tracker.ts
2774
+ import {
2775
+ InvalidResponseDataError
2776
+ } from "@ai-sdk/provider";
2777
+ var StreamingToolCallTracker = class {
2778
+ constructor(options = {}) {
2779
+ this.toolCalls = [];
2780
+ var _a2, _b2;
2781
+ this._generateId = (_a2 = options.generateId) != null ? _a2 : generateId;
2782
+ this.typeValidation = (_b2 = options.typeValidation) != null ? _b2 : "none";
2783
+ this.extractMetadata = options.extractMetadata;
2784
+ this.buildToolCallProviderMetadata = options.buildToolCallProviderMetadata;
2785
+ }
2786
+ /**
2787
+ * Process a tool call delta from a streaming response chunk.
2788
+ * Emits tool-input-start, tool-input-delta, tool-input-end, and tool-call
2789
+ * events as appropriate.
2790
+ */
2791
+ processDelta(toolCallDelta, enqueue) {
2792
+ var _a2;
2793
+ const index = (_a2 = toolCallDelta.index) != null ? _a2 : this.toolCalls.length;
2794
+ if (this.toolCalls[index] == null) {
2795
+ this.processNewToolCall(index, toolCallDelta, enqueue);
2796
+ } else {
2797
+ this.processExistingToolCall(index, toolCallDelta, enqueue);
2798
+ }
2799
+ }
2800
+ /**
2801
+ * Finalize any unfinished tool calls. Should be called during the stream's
2802
+ * flush handler to ensure all tool calls are properly completed.
2803
+ */
2804
+ flush(enqueue) {
2805
+ for (const toolCall of this.toolCalls) {
2806
+ if (!toolCall.hasFinished) {
2807
+ this.finishToolCall(toolCall, enqueue);
2808
+ }
2809
+ }
2810
+ }
2811
+ processNewToolCall(index, toolCallDelta, enqueue) {
2812
+ var _a2, _b2, _c;
2813
+ if (this.typeValidation === "required") {
2814
+ if (toolCallDelta.type !== "function") {
2815
+ throw new InvalidResponseDataError({
2816
+ data: toolCallDelta,
2817
+ message: `Expected 'function' type.`
2818
+ });
2819
+ }
2820
+ } else if (this.typeValidation === "if-present") {
2821
+ if (toolCallDelta.type != null && toolCallDelta.type !== "function") {
2822
+ throw new InvalidResponseDataError({
2823
+ data: toolCallDelta,
2824
+ message: `Expected 'function' type.`
2825
+ });
2826
+ }
2827
+ }
2828
+ if (toolCallDelta.id == null) {
2829
+ throw new InvalidResponseDataError({
2830
+ data: toolCallDelta,
2831
+ message: `Expected 'id' to be a string.`
2832
+ });
2833
+ }
2834
+ if (((_a2 = toolCallDelta.function) == null ? void 0 : _a2.name) == null) {
2835
+ throw new InvalidResponseDataError({
2836
+ data: toolCallDelta,
2837
+ message: `Expected 'function.name' to be a string.`
2838
+ });
2839
+ }
2840
+ enqueue({
2841
+ type: "tool-input-start",
2842
+ id: toolCallDelta.id,
2843
+ toolName: toolCallDelta.function.name
2844
+ });
2845
+ const metadata = (_b2 = this.extractMetadata) == null ? void 0 : _b2.call(this, toolCallDelta);
2846
+ this.toolCalls[index] = {
2847
+ id: toolCallDelta.id,
2848
+ type: "function",
2849
+ function: {
2850
+ name: toolCallDelta.function.name,
2851
+ arguments: (_c = toolCallDelta.function.arguments) != null ? _c : ""
2852
+ },
2853
+ hasFinished: false,
2854
+ metadata
2855
+ };
2856
+ const toolCall = this.toolCalls[index];
2857
+ if (toolCall.function.arguments.length > 0) {
2858
+ enqueue({
2859
+ type: "tool-input-delta",
2860
+ id: toolCall.id,
2861
+ delta: toolCall.function.arguments
2862
+ });
2863
+ }
2864
+ if (isParsableJson(toolCall.function.arguments)) {
2865
+ this.finishToolCall(toolCall, enqueue);
2866
+ }
2867
+ }
2868
+ processExistingToolCall(index, toolCallDelta, enqueue) {
2869
+ var _a2;
2870
+ const toolCall = this.toolCalls[index];
2871
+ if (toolCall.hasFinished) {
2872
+ return;
2873
+ }
2874
+ if (((_a2 = toolCallDelta.function) == null ? void 0 : _a2.arguments) != null) {
2875
+ toolCall.function.arguments += toolCallDelta.function.arguments;
2876
+ enqueue({
2877
+ type: "tool-input-delta",
2878
+ id: toolCall.id,
2879
+ delta: toolCallDelta.function.arguments
2880
+ });
2881
+ }
2882
+ if (isParsableJson(toolCall.function.arguments)) {
2883
+ this.finishToolCall(toolCall, enqueue);
2884
+ }
2885
+ }
2886
+ finishToolCall(toolCall, enqueue) {
2887
+ var _a2, _b2;
2888
+ enqueue({
2889
+ type: "tool-input-end",
2890
+ id: toolCall.id
2891
+ });
2892
+ const providerMetadata = (_a2 = this.buildToolCallProviderMetadata) == null ? void 0 : _a2.call(
2893
+ this,
2894
+ toolCall.metadata
2895
+ );
2896
+ enqueue({
2897
+ type: "tool-call",
2898
+ toolCallId: (_b2 = toolCall.id) != null ? _b2 : this._generateId(),
2899
+ toolName: toolCall.function.name,
2900
+ input: toolCall.function.arguments,
2901
+ ...providerMetadata ? { providerMetadata } : {}
2902
+ });
2903
+ toolCall.hasFinished = true;
2904
+ }
2905
+ };
2906
+
2768
2907
  // src/strip-file-extension.ts
2769
2908
  function stripFileExtension(filename) {
2770
2909
  const firstDotIndex = filename.indexOf(".");
@@ -2815,9 +2954,11 @@ export {
2815
2954
  DelayedPromise,
2816
2955
  DownloadError,
2817
2956
  EventSourceParserStream2 as EventSourceParserStream,
2957
+ StreamingToolCallTracker,
2818
2958
  VERSION,
2819
2959
  WORKFLOW_DESERIALIZE,
2820
2960
  WORKFLOW_SERIALIZE,
2961
+ asArray,
2821
2962
  asSchema,
2822
2963
  combineHeaders,
2823
2964
  convertAsyncIteratorToReadableStream,