@ai-sdk/provider-utils 5.0.0-beta.2 → 5.0.0-beta.21

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 (49) hide show
  1. package/CHANGELOG.md +226 -0
  2. package/dist/index.d.ts +433 -174
  3. package/dist/index.js +322 -284
  4. package/dist/index.js.map +1 -1
  5. package/dist/test/index.js +2 -35
  6. package/dist/test/index.js.map +1 -1
  7. package/package.json +8 -10
  8. package/src/convert-image-model-file-to-data-uri.ts +3 -3
  9. package/src/create-tool-name-mapping.ts +5 -21
  10. package/src/get-error-message.ts +1 -15
  11. package/src/has-required-key.ts +6 -0
  12. package/src/index.ts +17 -7
  13. package/src/inject-json-instruction.ts +5 -5
  14. package/src/is-json-serializable.ts +29 -0
  15. package/src/is-provider-reference.ts +18 -0
  16. package/src/load-api-key.ts +1 -1
  17. package/src/load-setting.ts +1 -1
  18. package/src/map-reasoning-to-provider.ts +105 -0
  19. package/src/provider-tool-factory.ts +43 -32
  20. package/src/resolve-provider-reference.ts +27 -0
  21. package/src/resolve.ts +15 -0
  22. package/src/response-handler.ts +1 -1
  23. package/src/secure-json-parse.ts +1 -1
  24. package/src/serialize-model-options.ts +63 -0
  25. package/src/to-json-schema/zod3-to-json-schema/parsers/date.ts +1 -1
  26. package/src/to-json-schema/zod3-to-json-schema/parsers/intersection.ts +1 -1
  27. package/src/to-json-schema/zod3-to-json-schema/parsers/record.ts +2 -2
  28. package/src/types/assistant-model-message.ts +4 -0
  29. package/src/types/content-part.ts +98 -14
  30. package/src/types/context.ts +4 -0
  31. package/src/types/executable-tool.ts +17 -0
  32. package/src/types/execute-tool.ts +28 -9
  33. package/src/types/index.ts +11 -9
  34. package/src/types/infer-tool-context.ts +12 -0
  35. package/src/types/infer-tool-input.ts +7 -0
  36. package/src/types/infer-tool-output.ts +7 -0
  37. package/src/types/infer-tool-set-context.ts +17 -0
  38. package/src/types/provider-options.ts +2 -2
  39. package/src/types/provider-reference.ts +10 -0
  40. package/src/types/tool-set.ts +22 -0
  41. package/src/types/tool.ts +74 -40
  42. package/src/types/union-to-intersection.ts +17 -0
  43. package/src/validate-download-url.ts +7 -2
  44. package/dist/index.d.mts +0 -1433
  45. package/dist/index.mjs +0 -2759
  46. package/dist/index.mjs.map +0 -1
  47. package/dist/test/index.d.mts +0 -17
  48. package/dist/test/index.mjs +0 -77
  49. package/dist/test/index.mjs.map +0 -1
@@ -64,7 +64,7 @@ export const createJsonErrorResponseHandler =
64
64
  isRetryable: isRetryable?.(response, parsedError),
65
65
  }),
66
66
  };
67
- } catch (parseError) {
67
+ } catch {
68
68
  return {
69
69
  responseHeaders,
70
70
  value: new APICallError({
@@ -83,7 +83,7 @@ export function secureJsonParse(text: string) {
83
83
  try {
84
84
  // Performance optimization, see https://github.com/fastify/secure-json-parse/pull/90
85
85
  Error.stackTraceLimit = 0;
86
- } catch (e) {
86
+ } catch {
87
87
  // Fallback in case Error is immutable (v8 readonly)
88
88
  return _parse(text);
89
89
  }
@@ -0,0 +1,63 @@
1
+ import { JSONObject } from '@ai-sdk/provider';
2
+ import { isJSONSerializable } from './is-json-serializable';
3
+ import { Resolvable } from './resolve';
4
+
5
+ /**
6
+ * Serializes a model instance for workflow step boundaries.
7
+ * Returns the `modelId` plus the JSON-serializable config properties.
8
+ *
9
+ * Non-serializable values are omitted. As a special case, a
10
+ * function-valued `headers` property is resolved during serialization
11
+ * and included if the returned value is JSON-serializable.
12
+ *
13
+ * Used as the body of `static [WORKFLOW_SERIALIZE]` in provider models.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * static [WORKFLOW_SERIALIZE](model: MyLanguageModel) {
18
+ * return serializeModelOptions({
19
+ * modelId: model.modelId,
20
+ * config: model.config,
21
+ * });
22
+ * }
23
+ * ```
24
+ */
25
+ export function serializeModelOptions<
26
+ CONFIG extends {
27
+ headers?: Resolvable<Record<string, string | undefined>>;
28
+ },
29
+ >(options: {
30
+ modelId: string;
31
+ config: CONFIG;
32
+ }): {
33
+ modelId: string;
34
+ config: JSONObject;
35
+ } {
36
+ const serializableConfig: JSONObject = {};
37
+ for (const [key, value] of Object.entries(options.config)) {
38
+ if (key === 'headers') {
39
+ const resolvedHeaders = resolveSync(value);
40
+ if (isJSONSerializable(resolvedHeaders)) {
41
+ serializableConfig[key] = resolvedHeaders;
42
+ }
43
+ } else if (isJSONSerializable(value)) {
44
+ serializableConfig[key] = value;
45
+ }
46
+ }
47
+ return { modelId: options.modelId, config: serializableConfig };
48
+ }
49
+
50
+ function resolveSync<T>(value: Resolvable<T>): T {
51
+ let next: unknown = value;
52
+ if (typeof value === 'function') {
53
+ next = (value as () => unknown)();
54
+ }
55
+
56
+ // the serialization for workflows currently only supports synchronous values
57
+ // TODO introduce SerializationError
58
+ if (next instanceof Promise) {
59
+ throw new Error('Promise returned from resolveSync');
60
+ }
61
+
62
+ return next as T;
63
+ }
@@ -22,7 +22,7 @@ export function parseDateDef(
22
22
 
23
23
  if (Array.isArray(strategy)) {
24
24
  return {
25
- anyOf: strategy.map((item, i) => parseDateDef(def, refs, item)),
25
+ anyOf: strategy.map(item => parseDateDef(def, refs, item)),
26
26
  };
27
27
  }
28
28
 
@@ -42,7 +42,7 @@ export function parseIntersectionDef(
42
42
  'additionalProperties' in schema &&
43
43
  schema.additionalProperties === false
44
44
  ) {
45
- const { additionalProperties, ...rest } = schema;
45
+ const { additionalProperties: _additionalProperties, ...rest } = schema;
46
46
  nestedSchema = rest;
47
47
  }
48
48
  mergedAllOf.push(nestedSchema);
@@ -38,7 +38,7 @@ export function parseRecordDef(
38
38
  def.keyType?._def.typeName === ZodFirstPartyTypeKind.ZodString &&
39
39
  def.keyType._def.checks?.length
40
40
  ) {
41
- const { type, ...keyType } = parseStringDef(def.keyType._def, refs);
41
+ const { type: _type, ...keyType } = parseStringDef(def.keyType._def, refs);
42
42
 
43
43
  return {
44
44
  ...schema,
@@ -56,7 +56,7 @@ export function parseRecordDef(
56
56
  def.keyType._def.type._def.typeName === ZodFirstPartyTypeKind.ZodString &&
57
57
  def.keyType._def.type._def.checks?.length
58
58
  ) {
59
- const { type, ...keyType } = parseBrandedDef(
59
+ const { type: _type, ...keyType } = parseBrandedDef(
60
60
  def.keyType._def,
61
61
  refs,
62
62
  ) as JsonSchema7StringType;
@@ -1,5 +1,7 @@
1
1
  import {
2
+ CustomPart,
2
3
  FilePart,
4
+ ReasoningFilePart,
3
5
  ReasoningPart,
4
6
  TextPart,
5
7
  ToolCallPart,
@@ -31,8 +33,10 @@ export type AssistantContent =
31
33
  | string
32
34
  | Array<
33
35
  | TextPart
36
+ | CustomPart
34
37
  | FilePart
35
38
  | ReasoningPart
39
+ | ReasoningFilePart
36
40
  | ToolCallPart
37
41
  | ToolResultPart
38
42
  | ToolApprovalRequest
@@ -1,6 +1,7 @@
1
1
  import { JSONValue } from '@ai-sdk/provider';
2
2
  import { DataContent } from './data-content';
3
3
  import { ProviderOptions } from './provider-options';
4
+ import { ProviderReference } from './provider-reference';
4
5
 
5
6
  /**
6
7
  * Text content part of a prompt. It contains a string of text.
@@ -32,8 +33,9 @@ export interface ImagePart {
32
33
  *
33
34
  * - data: a base64-encoded string, a Uint8Array, an ArrayBuffer, or a Buffer
34
35
  * - URL: a URL that points to the image
36
+ * - ProviderReference: a provider reference from `uploadFile`
35
37
  */
36
- image: DataContent | URL;
38
+ image: DataContent | URL | ProviderReference;
37
39
 
38
40
  /**
39
41
  * Optional IANA media type of the image.
@@ -60,9 +62,10 @@ export interface FilePart {
60
62
  * File data. Can either be:
61
63
  *
62
64
  * - data: a base64-encoded string, a Uint8Array, an ArrayBuffer, or a Buffer
63
- * - URL: a URL that points to the image
65
+ * - URL: a URL that points to the file
66
+ * - ProviderReference: a provider reference from `uploadFile`
64
67
  */
65
- data: DataContent | URL;
68
+ data: DataContent | URL | ProviderReference;
66
69
 
67
70
  /**
68
71
  * Optional filename of the file.
@@ -103,6 +106,55 @@ export interface ReasoningPart {
103
106
  providerOptions?: ProviderOptions;
104
107
  }
105
108
 
109
+ /**
110
+ * Custom content part of a prompt. It contains no standardized payload beyond
111
+ * provider-specific options.
112
+ */
113
+ export interface CustomPart {
114
+ type: 'custom';
115
+
116
+ /**
117
+ * The kind of custom content, in the format `{provider}.{provider-type}`.
118
+ */
119
+ kind: `${string}.${string}`;
120
+
121
+ /**
122
+ * Additional provider-specific metadata. They are passed through
123
+ * to the provider from the AI SDK and enable provider-specific
124
+ * functionality that can be fully encapsulated in the provider.
125
+ */
126
+ providerOptions?: ProviderOptions;
127
+ }
128
+
129
+ /**
130
+ * Reasoning file content part of a prompt. It contains a file generated as part of reasoning.
131
+ */
132
+ export interface ReasoningFilePart {
133
+ type: 'reasoning-file';
134
+
135
+ /**
136
+ * File data. Can either be:
137
+ *
138
+ * - data: a base64-encoded string, a Uint8Array, an ArrayBuffer, or a Buffer
139
+ * - URL: a URL that points to the file
140
+ */
141
+ data: DataContent | URL;
142
+
143
+ /**
144
+ * IANA media type of the file.
145
+ *
146
+ * @see https://www.iana.org/assignments/media-types/media-types.xhtml
147
+ */
148
+ mediaType: string;
149
+
150
+ /**
151
+ * Additional provider-specific metadata. They are passed through
152
+ * to the provider from the AI SDK and enable provider-specific
153
+ * functionality that can be fully encapsulated in the provider.
154
+ */
155
+ providerOptions?: ProviderOptions;
156
+ }
157
+
106
158
  /**
107
159
  * Tool call content part of a prompt. It contains a tool call (usually generated by the AI model).
108
160
  */
@@ -241,14 +293,6 @@ export type ToolResultOutput =
241
293
  */
242
294
  providerOptions?: ProviderOptions;
243
295
  }
244
- | {
245
- /**
246
- * @deprecated Use image-data or file-data instead.
247
- */
248
- type: 'media';
249
- data: string;
250
- mediaType: string;
251
- }
252
296
  | {
253
297
  type: 'file-data';
254
298
 
@@ -281,12 +325,21 @@ export type ToolResultOutput =
281
325
  */
282
326
  url: string;
283
327
 
328
+ /**
329
+ * IANA media type.
330
+ * @see https://www.iana.org/assignments/media-types/media-types.xhtml
331
+ */
332
+ mediaType?: string; // Temporarily optional. TODO: make required in v8, after migration period.
333
+
284
334
  /**
285
335
  * Provider-specific options.
286
336
  */
287
337
  providerOptions?: ProviderOptions;
288
338
  }
289
339
  | {
340
+ /**
341
+ * @deprecated Use file-reference instead.
342
+ */
290
343
  type: 'file-id';
291
344
 
292
345
  /**
@@ -299,6 +352,20 @@ export type ToolResultOutput =
299
352
  */
300
353
  fileId: string | Record<string, string>;
301
354
 
355
+ /**
356
+ * Provider-specific options.
357
+ */
358
+ providerOptions?: ProviderOptions;
359
+ }
360
+ | {
361
+ type: 'file-reference';
362
+
363
+ /**
364
+ * Provider-specific references for the file.
365
+ * The key is the provider name, e.g. 'openai' or 'anthropic'.
366
+ */
367
+ providerReference: ProviderReference;
368
+
302
369
  /**
303
370
  * Provider-specific options.
304
371
  */
@@ -306,7 +373,7 @@ export type ToolResultOutput =
306
373
  }
307
374
  | {
308
375
  /**
309
- * Images that are referenced using base64 encoded data.
376
+ * @deprecated Use file-data instead.
310
377
  */
311
378
  type: 'image-data';
312
379
 
@@ -328,7 +395,7 @@ export type ToolResultOutput =
328
395
  }
329
396
  | {
330
397
  /**
331
- * Images that are referenced using a URL.
398
+ * @deprecated Use file-url instead.
332
399
  */
333
400
  type: 'image-url';
334
401
 
@@ -344,7 +411,7 @@ export type ToolResultOutput =
344
411
  }
345
412
  | {
346
413
  /**
347
- * Images that are referenced using a provider file id.
414
+ * @deprecated Use file-reference instead.
348
415
  */
349
416
  type: 'image-file-id';
350
417
 
@@ -358,6 +425,23 @@ export type ToolResultOutput =
358
425
  */
359
426
  fileId: string | Record<string, string>;
360
427
 
428
+ /**
429
+ * Provider-specific options.
430
+ */
431
+ providerOptions?: ProviderOptions;
432
+ }
433
+ | {
434
+ /**
435
+ * @deprecated Use file-reference instead.
436
+ */
437
+ type: 'image-file-reference';
438
+
439
+ /**
440
+ * Provider-specific references for the image file.
441
+ * The key is the provider name, e.g. 'openai' or 'anthropic'.
442
+ */
443
+ providerReference: ProviderReference;
444
+
361
445
  /**
362
446
  * Provider-specific options.
363
447
  */
@@ -0,0 +1,4 @@
1
+ /**
2
+ * A context object that is passed into tool execution.
3
+ */
4
+ export type Context = Record<string, unknown>;
@@ -0,0 +1,17 @@
1
+ import { Tool } from './tool';
2
+
3
+ /**
4
+ * A tool that is guaranteed to expose an execute function.
5
+ */
6
+ export type ExecutableTool<TOOL extends Tool = Tool> = TOOL & {
7
+ execute: NonNullable<TOOL['execute']>;
8
+ };
9
+
10
+ /**
11
+ * Checks whether a tool exposes an execute function.
12
+ */
13
+ export function isExecutableTool<TOOL extends Tool>(
14
+ tool: TOOL | undefined,
15
+ ): tool is ExecutableTool<TOOL> {
16
+ return tool != null && typeof tool.execute === 'function';
17
+ }
@@ -1,21 +1,40 @@
1
1
  import { isAsyncIterable } from '../is-async-iterable';
2
- import { ToolExecutionOptions, ToolExecuteFunction } from './tool';
2
+ import { ExecutableTool } from './executable-tool';
3
+ import { InferToolContext } from './infer-tool-context';
4
+ import { InferToolInput } from './infer-tool-input';
5
+ import { InferToolOutput } from './infer-tool-output';
6
+ import { Tool, ToolExecutionOptions } from './tool';
3
7
 
4
- export async function* executeTool<INPUT, OUTPUT>({
5
- execute,
8
+ /**
9
+ * Executes a tool function and normalizes its results into a stream of outputs.
10
+ *
11
+ * - If the tool's `execute` function returns an `AsyncIterable`, each yielded value is emitted as
12
+ * `{ type: "preliminary", output }`. After iteration completes, the last yielded value is emitted
13
+ * again as `{ type: "final", output }`.
14
+ * - If the tool returns a direct value or Promise, a single `{ type: "final", output }` is yielded.
15
+ *
16
+ * @param params.tool The tool whose `execute` function should be invoked.
17
+ * @param params.input The input value to pass to the tool.
18
+ * @param params.options Additional options for tool execution.
19
+ * @yields A preliminary output for each streamed value, followed by a final output, or a single final
20
+ * output for non-streaming tools.
21
+ */
22
+ export async function* executeTool<TOOL extends Tool>({
23
+ tool,
6
24
  input,
7
25
  options,
8
26
  }: {
9
- execute: ToolExecuteFunction<INPUT, OUTPUT>;
10
- input: INPUT;
11
- options: ToolExecutionOptions;
27
+ tool: ExecutableTool<TOOL>;
28
+ input: InferToolInput<TOOL>;
29
+ options: ToolExecutionOptions<InferToolContext<TOOL>>;
12
30
  }): AsyncGenerator<
13
- { type: 'preliminary'; output: OUTPUT } | { type: 'final'; output: OUTPUT }
31
+ | { type: 'preliminary'; output: InferToolOutput<TOOL> }
32
+ | { type: 'final'; output: InferToolOutput<TOOL> }
14
33
  > {
15
- const result = execute(input, options);
34
+ const result = tool.execute(input, options);
16
35
 
17
36
  if (isAsyncIterable(result)) {
18
- let lastOutput: OUTPUT | undefined;
37
+ let lastOutput: InferToolOutput<TOOL> | undefined;
19
38
  for await (const output of result) {
20
39
  lastOutput = output;
21
40
  yield { type: 'preliminary', output };
@@ -3,38 +3,40 @@ export type {
3
3
  AssistantModelMessage,
4
4
  } from './assistant-model-message';
5
5
  export type {
6
+ CustomPart,
6
7
  FilePart,
7
8
  ImagePart,
9
+ ReasoningFilePart,
8
10
  ReasoningPart,
9
11
  TextPart,
10
12
  ToolCallPart,
11
13
  ToolResultOutput,
12
14
  ToolResultPart,
13
15
  } from './content-part';
16
+ export type { Context } from './context';
14
17
  export type { DataContent } from './data-content';
15
18
  export { executeTool } from './execute-tool';
19
+ export { isExecutableTool, type ExecutableTool } from './executable-tool';
20
+ export type { InferToolContext } from './infer-tool-context';
21
+ export type { InferToolInput } from './infer-tool-input';
22
+ export type { InferToolOutput } from './infer-tool-output';
23
+ export type { InferToolSetContext } from './infer-tool-set-context';
16
24
  export type { ModelMessage } from './model-message';
17
25
  export type { ProviderOptions } from './provider-options';
26
+ export type { ProviderReference } from './provider-reference';
18
27
  export type { SystemModelMessage } from './system-model-message';
19
28
  export {
20
29
  dynamicTool,
21
30
  tool,
22
- type InferToolInput,
23
- type InferToolOutput,
24
31
  type Tool,
25
- type ToolExecutionOptions,
26
32
  type ToolExecuteFunction,
33
+ type ToolExecutionOptions,
27
34
  type ToolNeedsApprovalFunction,
28
35
  } from './tool';
36
+ export type { ToolSet } from './tool-set';
29
37
  export type { ToolApprovalRequest } from './tool-approval-request';
30
38
  export type { ToolApprovalResponse } from './tool-approval-response';
31
39
  export type { ToolCall } from './tool-call';
32
40
  export type { ToolContent, ToolModelMessage } from './tool-model-message';
33
41
  export type { ToolResult } from './tool-result';
34
42
  export type { UserContent, UserModelMessage } from './user-model-message';
35
- import type { ToolExecutionOptions } from './tool';
36
-
37
- /**
38
- * @deprecated Use ToolExecutionOptions instead.
39
- */
40
- export type ToolCallOptions = ToolExecutionOptions;
@@ -0,0 +1,12 @@
1
+ import { HasRequiredKey } from '../has-required-key';
2
+ import type { Tool } from './tool';
3
+
4
+ /**
5
+ * Infer the context type of a tool.
6
+ */
7
+ export type InferToolContext<TOOL extends Tool> =
8
+ TOOL extends Tool<any, any, infer CONTEXT>
9
+ ? HasRequiredKey<CONTEXT> extends true
10
+ ? CONTEXT
11
+ : never
12
+ : never;
@@ -0,0 +1,7 @@
1
+ import type { Tool } from './tool';
2
+
3
+ /**
4
+ * Infer the input type of a tool.
5
+ */
6
+ export type InferToolInput<TOOL extends Tool<any, any, any>> =
7
+ TOOL extends Tool<infer INPUT, any, any> ? INPUT : never;
@@ -0,0 +1,7 @@
1
+ import type { Tool } from './tool';
2
+
3
+ /**
4
+ * Infer the output type of a tool.
5
+ */
6
+ export type InferToolOutput<TOOL extends Tool<any, any, any>> =
7
+ TOOL extends Tool<any, infer OUTPUT, any> ? OUTPUT : never;
@@ -0,0 +1,17 @@
1
+ import type { InferToolContext } from './infer-tool-context';
2
+ import type { ToolSet } from './tool-set';
3
+ import type { UnionToIntersection } from './union-to-intersection';
4
+
5
+ /**
6
+ * Infer the context type for a tool set.
7
+ *
8
+ * The inferred type contains all properties required by the contexts of the
9
+ * tools in the set.
10
+ *
11
+ * If there are incompatible properties, they will be of type `never`.
12
+ */
13
+ export type InferToolSetContext<TOOLS extends ToolSet> = UnionToIntersection<
14
+ {
15
+ [K in keyof TOOLS]: InferToolContext<NoInfer<TOOLS[K]>>;
16
+ }[keyof TOOLS]
17
+ >;
@@ -1,4 +1,4 @@
1
- import { SharedV3ProviderOptions } from '@ai-sdk/provider';
1
+ import { SharedV4ProviderOptions } from '@ai-sdk/provider';
2
2
 
3
3
  /**
4
4
  * Additional provider-specific options.
@@ -6,4 +6,4 @@ import { SharedV3ProviderOptions } from '@ai-sdk/provider';
6
6
  * They are passed through to the provider from the AI SDK and enable
7
7
  * provider-specific functionality that can be fully encapsulated in the provider.
8
8
  */
9
- export type ProviderOptions = SharedV3ProviderOptions;
9
+ export type ProviderOptions = SharedV4ProviderOptions;
@@ -0,0 +1,10 @@
1
+ import { SharedV4ProviderReference } from '@ai-sdk/provider';
2
+
3
+ /**
4
+ * A mapping of provider names to provider-specific file identifiers.
5
+ *
6
+ * Provider references allow files to be identified across different
7
+ * providers without re-uploading, by storing each provider's own
8
+ * identifier for the same logical file.
9
+ */
10
+ export type ProviderReference = SharedV4ProviderReference;
@@ -0,0 +1,22 @@
1
+ import type { Tool } from './tool';
2
+
3
+ /**
4
+ * A mapping of tool names to tool definitions.
5
+ */
6
+ export type ToolSet = Record<
7
+ string,
8
+ (
9
+ | Tool<never, never, any>
10
+ | Tool<any, any, any>
11
+ | Tool<any, never, any>
12
+ | Tool<never, any, any>
13
+ ) &
14
+ Pick<
15
+ Tool<any, any, any>,
16
+ | 'execute'
17
+ | 'onInputAvailable'
18
+ | 'onInputStart'
19
+ | 'onInputDelta'
20
+ | 'needsApproval'
21
+ >
22
+ >;