@ai-sdk/provider-utils 5.0.0-beta.3 → 5.0.0-beta.30

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 (110) hide show
  1. package/CHANGELOG.md +284 -0
  2. package/dist/index.d.ts +1339 -813
  3. package/dist/index.js +837 -288
  4. package/dist/index.js.map +1 -1
  5. package/dist/test/index.d.ts +2 -1
  6. package/dist/test/index.js +18 -37
  7. package/dist/test/index.js.map +1 -1
  8. package/package.json +13 -13
  9. package/src/add-additional-properties-to-json-schema.ts +1 -1
  10. package/src/as-array.ts +12 -0
  11. package/src/convert-image-model-file-to-data-uri.ts +3 -3
  12. package/src/convert-inline-file-data-to-uint8-array.ts +30 -0
  13. package/src/create-tool-name-mapping.ts +6 -22
  14. package/src/detect-media-type.ts +312 -0
  15. package/src/filter-nullable.ts +11 -0
  16. package/src/get-error-message.ts +1 -15
  17. package/src/get-from-api.ts +2 -2
  18. package/src/has-required-key.ts +6 -0
  19. package/src/index.ts +42 -12
  20. package/src/inject-json-instruction.ts +6 -6
  21. package/src/is-buffer.ts +9 -0
  22. package/src/is-json-serializable.ts +29 -0
  23. package/src/is-provider-reference.ts +21 -0
  24. package/src/is-url-supported.ts +17 -2
  25. package/src/load-api-key.ts +1 -1
  26. package/src/load-setting.ts +1 -1
  27. package/src/map-reasoning-to-provider.ts +108 -0
  28. package/src/maybe-promise-like.ts +3 -0
  29. package/src/parse-json-event-stream.ts +3 -3
  30. package/src/parse-json.ts +3 -3
  31. package/src/parse-provider-options.ts +1 -1
  32. package/src/post-to-api.ts +4 -4
  33. package/src/provider-defined-tool-factory.ts +129 -0
  34. package/src/provider-executed-tool-factory.ts +69 -0
  35. package/src/resolve-full-media-type.ts +49 -0
  36. package/src/resolve-provider-reference.ts +26 -0
  37. package/src/resolve.ts +16 -1
  38. package/src/response-handler.ts +3 -3
  39. package/src/schema.ts +6 -3
  40. package/src/secure-json-parse.ts +1 -1
  41. package/src/serialize-model-options.ts +63 -0
  42. package/src/streaming-tool-call-tracker.ts +241 -0
  43. package/src/test/convert-response-stream-to-array.ts +1 -1
  44. package/src/test/is-node-version.ts +22 -1
  45. package/src/to-json-schema/zod3-to-json-schema/options.ts +3 -3
  46. package/src/to-json-schema/zod3-to-json-schema/parse-def.ts +3 -3
  47. package/src/to-json-schema/zod3-to-json-schema/parse-types.ts +22 -22
  48. package/src/to-json-schema/zod3-to-json-schema/parsers/array.ts +3 -3
  49. package/src/to-json-schema/zod3-to-json-schema/parsers/bigint.ts +1 -1
  50. package/src/to-json-schema/zod3-to-json-schema/parsers/branded.ts +2 -2
  51. package/src/to-json-schema/zod3-to-json-schema/parsers/catch.ts +2 -2
  52. package/src/to-json-schema/zod3-to-json-schema/parsers/date.ts +4 -4
  53. package/src/to-json-schema/zod3-to-json-schema/parsers/default.ts +3 -3
  54. package/src/to-json-schema/zod3-to-json-schema/parsers/effects.ts +3 -3
  55. package/src/to-json-schema/zod3-to-json-schema/parsers/enum.ts +1 -1
  56. package/src/to-json-schema/zod3-to-json-schema/parsers/intersection.ts +5 -5
  57. package/src/to-json-schema/zod3-to-json-schema/parsers/literal.ts +1 -1
  58. package/src/to-json-schema/zod3-to-json-schema/parsers/map.ts +4 -5
  59. package/src/to-json-schema/zod3-to-json-schema/parsers/native-enum.ts +1 -1
  60. package/src/to-json-schema/zod3-to-json-schema/parsers/never.ts +1 -2
  61. package/src/to-json-schema/zod3-to-json-schema/parsers/nullable.ts +4 -4
  62. package/src/to-json-schema/zod3-to-json-schema/parsers/number.ts +1 -1
  63. package/src/to-json-schema/zod3-to-json-schema/parsers/object.ts +3 -3
  64. package/src/to-json-schema/zod3-to-json-schema/parsers/optional.ts +3 -3
  65. package/src/to-json-schema/zod3-to-json-schema/parsers/pipeline.ts +4 -4
  66. package/src/to-json-schema/zod3-to-json-schema/parsers/promise.ts +3 -3
  67. package/src/to-json-schema/zod3-to-json-schema/parsers/readonly.ts +2 -2
  68. package/src/to-json-schema/zod3-to-json-schema/parsers/record.ts +9 -10
  69. package/src/to-json-schema/zod3-to-json-schema/parsers/set.ts +3 -3
  70. package/src/to-json-schema/zod3-to-json-schema/parsers/string.ts +2 -2
  71. package/src/to-json-schema/zod3-to-json-schema/parsers/tuple.ts +3 -3
  72. package/src/to-json-schema/zod3-to-json-schema/parsers/undefined.ts +1 -2
  73. package/src/to-json-schema/zod3-to-json-schema/parsers/union.ts +3 -3
  74. package/src/to-json-schema/zod3-to-json-schema/parsers/unknown.ts +1 -2
  75. package/src/to-json-schema/zod3-to-json-schema/refs.ts +3 -3
  76. package/src/to-json-schema/zod3-to-json-schema/select-parser.ts +2 -2
  77. package/src/to-json-schema/zod3-to-json-schema/zod3-to-json-schema.ts +3 -3
  78. package/src/types/assistant-model-message.ts +5 -3
  79. package/src/types/content-part.ts +102 -24
  80. package/src/types/context.ts +4 -0
  81. package/src/types/executable-tool.ts +17 -0
  82. package/src/types/execute-tool.ts +29 -9
  83. package/src/types/file-data.ts +48 -0
  84. package/src/types/index.ts +26 -11
  85. package/src/types/infer-tool-context.ts +12 -0
  86. package/src/types/infer-tool-input.ts +7 -0
  87. package/src/types/infer-tool-output.ts +7 -0
  88. package/src/types/infer-tool-set-context.ts +15 -0
  89. package/src/types/model-message.ts +4 -4
  90. package/src/types/never-optional.ts +7 -0
  91. package/src/types/provider-options.ts +2 -2
  92. package/src/types/provider-reference.ts +10 -0
  93. package/src/types/sensitive-context.ts +9 -0
  94. package/src/types/system-model-message.ts +1 -1
  95. package/src/types/tool-approval-request.ts +7 -0
  96. package/src/types/tool-execute-function.ts +50 -0
  97. package/src/types/tool-model-message.ts +3 -3
  98. package/src/types/tool-needs-approval-function.ts +39 -0
  99. package/src/types/tool-set.ts +22 -0
  100. package/src/types/tool.ts +251 -222
  101. package/src/types/user-model-message.ts +2 -2
  102. package/src/validate-download-url.ts +7 -2
  103. package/src/validate-types.ts +5 -3
  104. package/dist/index.d.mts +0 -1458
  105. package/dist/index.mjs +0 -2759
  106. package/dist/index.mjs.map +0 -1
  107. package/dist/test/index.d.mts +0 -17
  108. package/dist/test/index.mjs +0 -77
  109. package/dist/test/index.mjs.map +0 -1
  110. package/src/provider-tool-factory.ts +0 -125
@@ -9,9 +9,10 @@ declare function convertReadableStreamToArray<T>(stream: ReadableStream<T>): Pro
9
9
  declare function convertResponseStreamToArray(response: Response): Promise<string[]>;
10
10
 
11
11
  declare function isNodeVersion(version: number): boolean;
12
+ declare function isNodeVersionAtLeast(major: number, minor?: number, patch?: number): boolean;
12
13
 
13
14
  declare function mockId({ prefix, }?: {
14
15
  prefix?: string;
15
16
  }): () => string;
16
17
 
17
- export { convertArrayToAsyncIterable, convertArrayToReadableStream, convertAsyncIterableToArray, convertReadableStreamToArray, convertResponseStreamToArray, isNodeVersion, mockId };
18
+ export { convertArrayToAsyncIterable, convertArrayToReadableStream, convertAsyncIterableToArray, convertReadableStreamToArray, convertResponseStreamToArray, isNodeVersion, isNodeVersionAtLeast, mockId };
@@ -1,35 +1,3 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/test/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- convertArrayToAsyncIterable: () => convertArrayToAsyncIterable,
24
- convertArrayToReadableStream: () => convertArrayToReadableStream,
25
- convertAsyncIterableToArray: () => convertAsyncIterableToArray,
26
- convertReadableStreamToArray: () => convertReadableStreamToArray,
27
- convertResponseStreamToArray: () => convertResponseStreamToArray,
28
- isNodeVersion: () => isNodeVersion,
29
- mockId: () => mockId
30
- });
31
- module.exports = __toCommonJS(index_exports);
32
-
33
1
  // src/test/convert-array-to-async-iterable.ts
34
2
  function convertArrayToAsyncIterable(values) {
35
3
  return {
@@ -79,16 +47,29 @@ async function convertReadableStreamToArray(stream) {
79
47
 
80
48
  // src/test/convert-response-stream-to-array.ts
81
49
  async function convertResponseStreamToArray(response) {
82
- return convertReadableStreamToArray(
50
+ return await convertReadableStreamToArray(
83
51
  response.body.pipeThrough(new TextDecoderStream())
84
52
  );
85
53
  }
86
54
 
87
55
  // src/test/is-node-version.ts
56
+ function getNodeVersionParts() {
57
+ return process.versions.node.split(".").map((version) => Number.parseInt(version, 10));
58
+ }
88
59
  function isNodeVersion(version) {
89
- const nodeMajorVersion = parseInt(process.version.slice(1).split(".")[0], 10);
60
+ const [nodeMajorVersion] = getNodeVersionParts();
90
61
  return nodeMajorVersion === version;
91
62
  }
63
+ function isNodeVersionAtLeast(major, minor = 0, patch = 0) {
64
+ const [nodeMajorVersion, nodeMinorVersion, nodePatchVersion] = getNodeVersionParts();
65
+ if (nodeMajorVersion !== major) {
66
+ return nodeMajorVersion > major;
67
+ }
68
+ if (nodeMinorVersion !== minor) {
69
+ return nodeMinorVersion > minor;
70
+ }
71
+ return nodePatchVersion >= patch;
72
+ }
92
73
 
93
74
  // src/test/mock-id.ts
94
75
  function mockId({
@@ -97,14 +78,14 @@ function mockId({
97
78
  let counter = 0;
98
79
  return () => `${prefix}-${counter++}`;
99
80
  }
100
- // Annotate the CommonJS export names for ESM import in node:
101
- 0 && (module.exports = {
81
+ export {
102
82
  convertArrayToAsyncIterable,
103
83
  convertArrayToReadableStream,
104
84
  convertAsyncIterableToArray,
105
85
  convertReadableStreamToArray,
106
86
  convertResponseStreamToArray,
107
87
  isNodeVersion,
88
+ isNodeVersionAtLeast,
108
89
  mockId
109
- });
90
+ };
110
91
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/test/index.ts","../../src/test/convert-array-to-async-iterable.ts","../../src/test/convert-array-to-readable-stream.ts","../../src/test/convert-async-iterable-to-array.ts","../../src/test/convert-readable-stream-to-array.ts","../../src/test/convert-response-stream-to-array.ts","../../src/test/is-node-version.ts","../../src/test/mock-id.ts"],"sourcesContent":["export * from './convert-array-to-async-iterable';\nexport * from './convert-array-to-readable-stream';\nexport * from './convert-async-iterable-to-array';\nexport * from './convert-readable-stream-to-array';\nexport * from './convert-response-stream-to-array';\nexport * from './is-node-version';\nexport * from './mock-id';\n","export function convertArrayToAsyncIterable<T>(values: T[]): AsyncIterable<T> {\n return {\n async *[Symbol.asyncIterator]() {\n for (const value of values) {\n yield value;\n }\n },\n };\n}\n","export function convertArrayToReadableStream<T>(\n values: T[],\n): ReadableStream<T> {\n return new ReadableStream({\n start(controller) {\n try {\n for (const value of values) {\n controller.enqueue(value);\n }\n } finally {\n controller.close();\n }\n },\n });\n}\n","export async function convertAsyncIterableToArray<T>(\n iterable: AsyncIterable<T>,\n): Promise<T[]> {\n const result: T[] = [];\n for await (const item of iterable) {\n result.push(item);\n }\n return result;\n}\n","export async function convertReadableStreamToArray<T>(\n stream: ReadableStream<T>,\n): Promise<T[]> {\n const reader = stream.getReader();\n const result: T[] = [];\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n result.push(value);\n }\n\n return result;\n}\n","import { convertReadableStreamToArray } from './convert-readable-stream-to-array';\n\nexport async function convertResponseStreamToArray(\n response: Response,\n): Promise<string[]> {\n return convertReadableStreamToArray(\n response.body!.pipeThrough(new TextDecoderStream()),\n );\n}\n","export function isNodeVersion(version: number) {\n const nodeMajorVersion = parseInt(process.version.slice(1).split('.')[0], 10);\n return nodeMajorVersion === version;\n}\n","export function mockId({\n prefix = 'id',\n}: {\n prefix?: string;\n} = {}): () => string {\n let counter = 0;\n return () => `${prefix}-${counter++}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,SAAS,4BAA+B,QAA+B;AAC5E,SAAO;AAAA,IACL,QAAQ,OAAO,aAAa,IAAI;AAC9B,iBAAW,SAAS,QAAQ;AAC1B,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;;;ACRO,SAAS,6BACd,QACmB;AACnB,SAAO,IAAI,eAAe;AAAA,IACxB,MAAM,YAAY;AAChB,UAAI;AACF,mBAAW,SAAS,QAAQ;AAC1B,qBAAW,QAAQ,KAAK;AAAA,QAC1B;AAAA,MACF,UAAE;AACA,mBAAW,MAAM;AAAA,MACnB;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;ACdA,eAAsB,4BACpB,UACc;AACd,QAAM,SAAc,CAAC;AACrB,mBAAiB,QAAQ,UAAU;AACjC,WAAO,KAAK,IAAI;AAAA,EAClB;AACA,SAAO;AACT;;;ACRA,eAAsB,6BACpB,QACc;AACd,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,SAAc,CAAC;AAErB,SAAO,MAAM;AACX,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,QAAI,KAAM;AACV,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,SAAO;AACT;;;ACXA,eAAsB,6BACpB,UACmB;AACnB,SAAO;AAAA,IACL,SAAS,KAAM,YAAY,IAAI,kBAAkB,CAAC;AAAA,EACpD;AACF;;;ACRO,SAAS,cAAc,SAAiB;AAC7C,QAAM,mBAAmB,SAAS,QAAQ,QAAQ,MAAM,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE;AAC5E,SAAO,qBAAqB;AAC9B;;;ACHO,SAAS,OAAO;AAAA,EACrB,SAAS;AACX,IAEI,CAAC,GAAiB;AACpB,MAAI,UAAU;AACd,SAAO,MAAM,GAAG,MAAM,IAAI,SAAS;AACrC;","names":[]}
1
+ {"version":3,"sources":["../../src/test/convert-array-to-async-iterable.ts","../../src/test/convert-array-to-readable-stream.ts","../../src/test/convert-async-iterable-to-array.ts","../../src/test/convert-readable-stream-to-array.ts","../../src/test/convert-response-stream-to-array.ts","../../src/test/is-node-version.ts","../../src/test/mock-id.ts"],"sourcesContent":["export function convertArrayToAsyncIterable<T>(values: T[]): AsyncIterable<T> {\n return {\n async *[Symbol.asyncIterator]() {\n for (const value of values) {\n yield value;\n }\n },\n };\n}\n","export function convertArrayToReadableStream<T>(\n values: T[],\n): ReadableStream<T> {\n return new ReadableStream({\n start(controller) {\n try {\n for (const value of values) {\n controller.enqueue(value);\n }\n } finally {\n controller.close();\n }\n },\n });\n}\n","export async function convertAsyncIterableToArray<T>(\n iterable: AsyncIterable<T>,\n): Promise<T[]> {\n const result: T[] = [];\n for await (const item of iterable) {\n result.push(item);\n }\n return result;\n}\n","export async function convertReadableStreamToArray<T>(\n stream: ReadableStream<T>,\n): Promise<T[]> {\n const reader = stream.getReader();\n const result: T[] = [];\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n result.push(value);\n }\n\n return result;\n}\n","import { convertReadableStreamToArray } from './convert-readable-stream-to-array';\n\nexport async function convertResponseStreamToArray(\n response: Response,\n): Promise<string[]> {\n return await convertReadableStreamToArray(\n response.body!.pipeThrough(new TextDecoderStream()),\n );\n}\n","function getNodeVersionParts() {\n return process.versions.node\n .split('.')\n .map(version => Number.parseInt(version, 10));\n}\n\nexport function isNodeVersion(version: number) {\n const [nodeMajorVersion] = getNodeVersionParts();\n return nodeMajorVersion === version;\n}\n\nexport function isNodeVersionAtLeast(major: number, minor = 0, patch = 0) {\n const [nodeMajorVersion, nodeMinorVersion, nodePatchVersion] =\n getNodeVersionParts();\n\n if (nodeMajorVersion !== major) {\n return nodeMajorVersion > major;\n }\n\n if (nodeMinorVersion !== minor) {\n return nodeMinorVersion > minor;\n }\n\n return nodePatchVersion >= patch;\n}\n","export function mockId({\n prefix = 'id',\n}: {\n prefix?: string;\n} = {}): () => string {\n let counter = 0;\n return () => `${prefix}-${counter++}`;\n}\n"],"mappings":";AAAO,SAAS,4BAA+B,QAA+B;AAC5E,SAAO;AAAA,IACL,QAAQ,OAAO,aAAa,IAAI;AAC9B,iBAAW,SAAS,QAAQ;AAC1B,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;;;ACRO,SAAS,6BACd,QACmB;AACnB,SAAO,IAAI,eAAe;AAAA,IACxB,MAAM,YAAY;AAChB,UAAI;AACF,mBAAW,SAAS,QAAQ;AAC1B,qBAAW,QAAQ,KAAK;AAAA,QAC1B;AAAA,MACF,UAAE;AACA,mBAAW,MAAM;AAAA,MACnB;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;ACdA,eAAsB,4BACpB,UACc;AACd,QAAM,SAAc,CAAC;AACrB,mBAAiB,QAAQ,UAAU;AACjC,WAAO,KAAK,IAAI;AAAA,EAClB;AACA,SAAO;AACT;;;ACRA,eAAsB,6BACpB,QACc;AACd,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,SAAc,CAAC;AAErB,SAAO,MAAM;AACX,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,QAAI,KAAM;AACV,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,SAAO;AACT;;;ACXA,eAAsB,6BACpB,UACmB;AACnB,SAAO,MAAM;AAAA,IACX,SAAS,KAAM,YAAY,IAAI,kBAAkB,CAAC;AAAA,EACpD;AACF;;;ACRA,SAAS,sBAAsB;AAC7B,SAAO,QAAQ,SAAS,KACrB,MAAM,GAAG,EACT,IAAI,aAAW,OAAO,SAAS,SAAS,EAAE,CAAC;AAChD;AAEO,SAAS,cAAc,SAAiB;AAC7C,QAAM,CAAC,gBAAgB,IAAI,oBAAoB;AAC/C,SAAO,qBAAqB;AAC9B;AAEO,SAAS,qBAAqB,OAAe,QAAQ,GAAG,QAAQ,GAAG;AACxE,QAAM,CAAC,kBAAkB,kBAAkB,gBAAgB,IACzD,oBAAoB;AAEtB,MAAI,qBAAqB,OAAO;AAC9B,WAAO,mBAAmB;AAAA,EAC5B;AAEA,MAAI,qBAAqB,OAAO;AAC9B,WAAO,mBAAmB;AAAA,EAC5B;AAEA,SAAO,oBAAoB;AAC7B;;;ACxBO,SAAS,OAAO;AAAA,EACrB,SAAS;AACX,IAEI,CAAC,GAAiB;AACpB,MAAI,UAAU;AACd,SAAO,MAAM,GAAG,MAAM,IAAI,SAAS;AACrC;","names":[]}
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@ai-sdk/provider-utils",
3
- "version": "5.0.0-beta.3",
3
+ "version": "5.0.0-beta.30",
4
+ "type": "module",
4
5
  "license": "Apache-2.0",
5
6
  "sideEffects": false,
6
7
  "main": "./dist/index.js",
7
- "module": "./dist/index.mjs",
8
8
  "types": "./dist/index.d.ts",
9
9
  "source": "./src/index.ts",
10
10
  "files": [
@@ -22,20 +22,20 @@
22
22
  "./package.json": "./package.json",
23
23
  ".": {
24
24
  "types": "./dist/index.d.ts",
25
- "import": "./dist/index.mjs",
26
- "require": "./dist/index.js"
25
+ "import": "./dist/index.js",
26
+ "default": "./dist/index.js"
27
27
  },
28
28
  "./test": {
29
29
  "types": "./dist/test/index.d.ts",
30
- "import": "./dist/test/index.mjs",
31
- "module": "./dist/test/index.mjs",
32
- "require": "./dist/test/index.js"
30
+ "import": "./dist/test/index.js",
31
+ "default": "./dist/test/index.js"
33
32
  }
34
33
  },
35
34
  "dependencies": {
36
35
  "@standard-schema/spec": "^1.1.0",
37
- "eventsource-parser": "^3.0.6",
38
- "@ai-sdk/provider": "4.0.0-beta.2"
36
+ "@workflow/serde": "4.1.0",
37
+ "eventsource-parser": "^3.0.8",
38
+ "@ai-sdk/provider": "4.0.0-beta.14"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "20.17.24",
@@ -52,12 +52,14 @@
52
52
  "node": ">=18"
53
53
  },
54
54
  "publishConfig": {
55
- "access": "public"
55
+ "access": "public",
56
+ "provenance": true
56
57
  },
57
58
  "homepage": "https://ai-sdk.dev/docs",
58
59
  "repository": {
59
60
  "type": "git",
60
- "url": "git+https://github.com/vercel/ai.git"
61
+ "url": "https://github.com/vercel/ai",
62
+ "directory": "packages/provider-utils"
61
63
  },
62
64
  "bugs": {
63
65
  "url": "https://github.com/vercel/ai/issues"
@@ -69,9 +71,7 @@
69
71
  "build": "pnpm clean && tsup --tsconfig tsconfig.build.json",
70
72
  "build:watch": "pnpm clean && tsup --watch",
71
73
  "clean": "del-cli dist *.tsbuildinfo",
72
- "lint": "eslint \"./**/*.ts*\"",
73
74
  "type-check": "tsc --build",
74
- "prettier-check": "prettier --check \"./**/*.ts*\"",
75
75
  "test": "pnpm test:node && pnpm test:edge",
76
76
  "test:update": "pnpm test:node -u",
77
77
  "test:watch": "vitest --config vitest.node.config.js",
@@ -1,4 +1,4 @@
1
- import { JSONSchema7, JSONSchema7Definition } from '@ai-sdk/provider';
1
+ import type { JSONSchema7, JSONSchema7Definition } from '@ai-sdk/provider';
2
2
 
3
3
  /**
4
4
  * Recursively adds additionalProperties: false to the JSON schema. This is necessary because some providers (e.g. OpenAI) do not support additionalProperties: true.
@@ -0,0 +1,12 @@
1
+ /**
2
+ * A value that can be provided either as a single item, an array of items,
3
+ * or be left undefined.
4
+ */
5
+ export type Arrayable<T> = T | T[] | undefined;
6
+
7
+ /**
8
+ * Normalizes a possibly undefined or non-array value into an array.
9
+ */
10
+ export function asArray<T>(value: Arrayable<T>): T[] {
11
+ return value === undefined ? [] : Array.isArray(value) ? value : [value];
12
+ }
@@ -1,14 +1,14 @@
1
- import { ImageModelV3File } from '@ai-sdk/provider';
1
+ import type { ImageModelV4File } from '@ai-sdk/provider';
2
2
  import { convertUint8ArrayToBase64 } from './uint8-utils';
3
3
 
4
4
  /**
5
- * Convert an ImageModelV3File to a URL or data URI string.
5
+ * Convert an ImageModelV4File to a URL or data URI string.
6
6
  *
7
7
  * If the file is a URL, it returns the URL as-is.
8
8
  * If the file is base64 data, it returns a data URI with the base64 data.
9
9
  * If the file is a Uint8Array, it converts it to base64 and returns a data URI.
10
10
  */
11
- export function convertImageModelFileToDataUri(file: ImageModelV3File): string {
11
+ export function convertImageModelFileToDataUri(file: ImageModelV4File): string {
12
12
  if (file.type === 'url') return file.url;
13
13
 
14
14
  return `data:${file.mediaType};base64,${
@@ -0,0 +1,30 @@
1
+ import type { FilePart } from './types/content-part';
2
+ import { convertBase64ToUint8Array } from './uint8-utils';
3
+
4
+ type InlineFileData = Extract<
5
+ FilePart['data'],
6
+ { type: 'data' } | { type: 'text' }
7
+ >;
8
+
9
+ /**
10
+ * Converts inline file data (a tagged `data` or `text` shape) into raw bytes.
11
+ *
12
+ * - `{ type: 'text', text }` → UTF-8 encoded bytes
13
+ * - `{ type: 'data', data: Uint8Array | Buffer }` → returned as-is
14
+ * - `{ type: 'data', data: ArrayBuffer }` → wrapped in a `Uint8Array`
15
+ * - `{ type: 'data', data: string }` → decoded as base64
16
+ */
17
+ export function convertInlineFileDataToUint8Array(
18
+ data: InlineFileData,
19
+ ): Uint8Array {
20
+ if (data.type === 'text') {
21
+ return new TextEncoder().encode(data.text);
22
+ }
23
+ if (data.data instanceof Uint8Array) {
24
+ return data.data;
25
+ }
26
+ if (data.data instanceof ArrayBuffer) {
27
+ return new Uint8Array(data.data);
28
+ }
29
+ return convertBase64ToUint8Array(data.data);
30
+ }
@@ -1,6 +1,6 @@
1
- import {
2
- LanguageModelV3FunctionTool,
3
- LanguageModelV3ProviderTool,
1
+ import type {
2
+ LanguageModelV4FunctionTool,
3
+ LanguageModelV4ProviderTool,
4
4
  } from '@ai-sdk/provider';
5
5
 
6
6
  /**
@@ -33,41 +33,25 @@ export interface ToolNameMapping {
33
33
  export function createToolNameMapping({
34
34
  tools = [],
35
35
  providerToolNames,
36
- resolveProviderToolName,
37
36
  }: {
38
37
  /**
39
38
  * Tools that were passed to the language model.
40
39
  */
41
40
  tools:
42
- | Array<LanguageModelV3FunctionTool | LanguageModelV3ProviderTool>
41
+ | Array<LanguageModelV4FunctionTool | LanguageModelV4ProviderTool>
43
42
  | undefined;
44
43
 
45
44
  /**
46
45
  * Maps the provider tool ids to the provider tool names.
47
46
  */
48
47
  providerToolNames: Record<`${string}.${string}`, string>;
49
-
50
- /**
51
- * Optional resolver for provider tool names that cannot be represented as
52
- * static id -> name mappings (e.g. dynamic provider names).
53
- */
54
- resolveProviderToolName?: (
55
- tool: LanguageModelV3ProviderTool,
56
- ) => string | undefined;
57
48
  }): ToolNameMapping {
58
49
  const customToolNameToProviderToolName: Record<string, string> = {};
59
50
  const providerToolNameToCustomToolName: Record<string, string> = {};
60
51
 
61
52
  for (const tool of tools) {
62
- if (tool.type === 'provider') {
63
- const providerToolName =
64
- resolveProviderToolName?.(tool) ??
65
- (tool.id in providerToolNames ? providerToolNames[tool.id] : undefined);
66
-
67
- if (providerToolName == null) {
68
- continue;
69
- }
70
-
53
+ if (tool.type === 'provider' && tool.id in providerToolNames) {
54
+ const providerToolName = providerToolNames[tool.id];
71
55
  customToolNameToProviderToolName[tool.name] = providerToolName;
72
56
  providerToolNameToCustomToolName[providerToolName] = tool.name;
73
57
  }
@@ -0,0 +1,312 @@
1
+ import { convertBase64ToUint8Array } from './uint8-utils';
2
+
3
+ const imageMediaTypeSignatures = [
4
+ {
5
+ mediaType: 'image/gif' as const,
6
+ bytesPrefix: [0x47, 0x49, 0x46], // GIF
7
+ },
8
+ {
9
+ mediaType: 'image/png' as const,
10
+ bytesPrefix: [0x89, 0x50, 0x4e, 0x47], // PNG
11
+ },
12
+ {
13
+ mediaType: 'image/jpeg' as const,
14
+ bytesPrefix: [0xff, 0xd8], // JPEG
15
+ },
16
+ {
17
+ mediaType: 'image/webp' as const,
18
+ bytesPrefix: [
19
+ 0x52,
20
+ 0x49,
21
+ 0x46,
22
+ 0x46, // "RIFF"
23
+ null,
24
+ null,
25
+ null,
26
+ null, // file size (variable)
27
+ 0x57,
28
+ 0x45,
29
+ 0x42,
30
+ 0x50, // "WEBP"
31
+ ],
32
+ },
33
+ {
34
+ mediaType: 'image/bmp' as const,
35
+ bytesPrefix: [0x42, 0x4d],
36
+ },
37
+ {
38
+ mediaType: 'image/tiff' as const,
39
+ bytesPrefix: [0x49, 0x49, 0x2a, 0x00],
40
+ },
41
+ {
42
+ mediaType: 'image/tiff' as const,
43
+ bytesPrefix: [0x4d, 0x4d, 0x00, 0x2a],
44
+ },
45
+ {
46
+ mediaType: 'image/avif' as const,
47
+ bytesPrefix: [
48
+ 0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70, 0x61, 0x76, 0x69, 0x66,
49
+ ],
50
+ },
51
+ {
52
+ mediaType: 'image/heic' as const,
53
+ bytesPrefix: [
54
+ 0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70, 0x68, 0x65, 0x69, 0x63,
55
+ ],
56
+ },
57
+ ] as const;
58
+
59
+ const documentMediaTypeSignatures = [
60
+ {
61
+ mediaType: 'application/pdf' as const,
62
+ bytesPrefix: [0x25, 0x50, 0x44, 0x46], // %PDF
63
+ },
64
+ ] as const;
65
+
66
+ const audioMediaTypeSignatures = [
67
+ {
68
+ mediaType: 'audio/mpeg' as const,
69
+ bytesPrefix: [0xff, 0xfb],
70
+ },
71
+ {
72
+ mediaType: 'audio/mpeg' as const,
73
+ bytesPrefix: [0xff, 0xfa],
74
+ },
75
+ {
76
+ mediaType: 'audio/mpeg' as const,
77
+ bytesPrefix: [0xff, 0xf3],
78
+ },
79
+ {
80
+ mediaType: 'audio/mpeg' as const,
81
+ bytesPrefix: [0xff, 0xf2],
82
+ },
83
+ {
84
+ mediaType: 'audio/mpeg' as const,
85
+ bytesPrefix: [0xff, 0xe3],
86
+ },
87
+ {
88
+ mediaType: 'audio/mpeg' as const,
89
+ bytesPrefix: [0xff, 0xe2],
90
+ },
91
+ {
92
+ mediaType: 'audio/wav' as const,
93
+ bytesPrefix: [
94
+ 0x52, // R
95
+ 0x49, // I
96
+ 0x46, // F
97
+ 0x46, // F
98
+ null,
99
+ null,
100
+ null,
101
+ null,
102
+ 0x57, // W
103
+ 0x41, // A
104
+ 0x56, // V
105
+ 0x45, // E
106
+ ],
107
+ },
108
+ {
109
+ mediaType: 'audio/ogg' as const,
110
+ bytesPrefix: [0x4f, 0x67, 0x67, 0x53],
111
+ },
112
+ {
113
+ mediaType: 'audio/flac' as const,
114
+ bytesPrefix: [0x66, 0x4c, 0x61, 0x43],
115
+ },
116
+ {
117
+ mediaType: 'audio/aac' as const,
118
+ bytesPrefix: [0x40, 0x15, 0x00, 0x00],
119
+ },
120
+ {
121
+ mediaType: 'audio/mp4' as const,
122
+ bytesPrefix: [0x66, 0x74, 0x79, 0x70],
123
+ },
124
+ {
125
+ mediaType: 'audio/webm',
126
+ bytesPrefix: [0x1a, 0x45, 0xdf, 0xa3],
127
+ },
128
+ ] as const;
129
+
130
+ const videoMediaTypeSignatures = [
131
+ {
132
+ mediaType: 'video/mp4' as const,
133
+ bytesPrefix: [
134
+ 0x00,
135
+ 0x00,
136
+ 0x00,
137
+ null,
138
+ 0x66,
139
+ 0x74,
140
+ 0x79,
141
+ 0x70, // ftyp
142
+ ],
143
+ },
144
+ {
145
+ mediaType: 'video/webm' as const,
146
+ bytesPrefix: [0x1a, 0x45, 0xdf, 0xa3], // EBML
147
+ },
148
+ {
149
+ mediaType: 'video/quicktime' as const,
150
+ bytesPrefix: [
151
+ 0x00,
152
+ 0x00,
153
+ 0x00,
154
+ 0x14,
155
+ 0x66,
156
+ 0x74,
157
+ 0x79,
158
+ 0x70,
159
+ 0x71,
160
+ 0x74, // ftypqt
161
+ ],
162
+ },
163
+ {
164
+ mediaType: 'video/x-msvideo' as const,
165
+ bytesPrefix: [0x52, 0x49, 0x46, 0x46], // RIFF (AVI)
166
+ },
167
+ ] as const;
168
+
169
+ const stripID3 = (data: Uint8Array | string) => {
170
+ const bytes =
171
+ typeof data === 'string' ? convertBase64ToUint8Array(data) : data;
172
+ const id3Size =
173
+ ((bytes[6] & 0x7f) << 21) |
174
+ ((bytes[7] & 0x7f) << 14) |
175
+ ((bytes[8] & 0x7f) << 7) |
176
+ (bytes[9] & 0x7f);
177
+
178
+ // The raw MP3 starts here
179
+ return bytes.slice(id3Size + 10);
180
+ };
181
+
182
+ function stripID3TagsIfPresent(data: Uint8Array | string): Uint8Array | string {
183
+ const hasId3 =
184
+ (typeof data === 'string' && data.startsWith('SUQz')) ||
185
+ (typeof data !== 'string' &&
186
+ data.length > 10 &&
187
+ data[0] === 0x49 && // 'I'
188
+ data[1] === 0x44 && // 'D'
189
+ data[2] === 0x33); // '3'
190
+
191
+ return hasId3 ? stripID3(data) : data;
192
+ }
193
+
194
+ type MediaTypeSignatures = ReadonlyArray<{
195
+ readonly mediaType: string;
196
+ readonly bytesPrefix: ReadonlyArray<number | null>;
197
+ }>;
198
+
199
+ function detectMediaTypeBySignatures<T extends MediaTypeSignatures>({
200
+ data,
201
+ signatures,
202
+ }: {
203
+ data: Uint8Array | string;
204
+ signatures: T;
205
+ }): T[number]['mediaType'] | undefined {
206
+ const processedData = stripID3TagsIfPresent(data);
207
+
208
+ // Convert the first ~18 bytes (24 base64 chars) for consistent detection logic:
209
+ const bytes =
210
+ typeof processedData === 'string'
211
+ ? convertBase64ToUint8Array(
212
+ processedData.substring(0, Math.min(processedData.length, 24)),
213
+ )
214
+ : processedData;
215
+
216
+ for (const signature of signatures) {
217
+ if (
218
+ bytes.length >= signature.bytesPrefix.length &&
219
+ signature.bytesPrefix.every(
220
+ (byte, index) => byte === null || bytes[index] === byte,
221
+ )
222
+ ) {
223
+ return signature.mediaType;
224
+ }
225
+ }
226
+
227
+ return undefined;
228
+ }
229
+
230
+ const topLevelSignatureTables = {
231
+ image: imageMediaTypeSignatures,
232
+ audio: audioMediaTypeSignatures,
233
+ video: videoMediaTypeSignatures,
234
+ application: documentMediaTypeSignatures,
235
+ } as const;
236
+
237
+ type TopLevelMediaType = keyof typeof topLevelSignatureTables;
238
+
239
+ /**
240
+ * Detect the IANA media type of a file from its raw bytes or base64 string.
241
+ *
242
+ * - When `topLevelType` is omitted, every known signature is considered
243
+ * (image, audio, video, and application). Returns `undefined` when the
244
+ * bytes do not match any known signature.
245
+ * - When `topLevelType` is provided, only signatures for that top-level
246
+ * segment are considered. Returns `undefined` for unsupported segments
247
+ * (e.g. `"text"`) or when no signature matches.
248
+ */
249
+ export function detectMediaType({
250
+ data,
251
+ topLevelType,
252
+ }: {
253
+ data: Uint8Array | string;
254
+ topLevelType?: string;
255
+ }): string | undefined {
256
+ if (topLevelType === undefined) {
257
+ return detectMediaTypeBySignatures({
258
+ data,
259
+ signatures: [
260
+ ...imageMediaTypeSignatures,
261
+ ...documentMediaTypeSignatures,
262
+ ...audioMediaTypeSignatures,
263
+ ...videoMediaTypeSignatures,
264
+ ],
265
+ });
266
+ }
267
+
268
+ const signatures = topLevelSignatureTables[topLevelType as TopLevelMediaType];
269
+
270
+ if (signatures === undefined) {
271
+ return undefined;
272
+ }
273
+
274
+ return detectMediaTypeBySignatures({ data, signatures });
275
+ }
276
+
277
+ /**
278
+ * Returns the top-level segment of a media type (the portion before `/`).
279
+ *
280
+ * Examples:
281
+ * - `"image/png"` -> `"image"`
282
+ * - `"image/*"` -> `"image"`
283
+ * - `"image"` -> `"image"`
284
+ * - `"image/"` -> `"image"`
285
+ * - `""` -> `""`
286
+ * - `"/"` -> `""`
287
+ */
288
+ export function getTopLevelMediaType(mediaType: string): string {
289
+ const slashIndex = mediaType.indexOf('/');
290
+ return slashIndex === -1 ? mediaType : mediaType.substring(0, slashIndex);
291
+ }
292
+
293
+ /**
294
+ * Returns `true` only when the given media type has a non-empty, non-wildcard
295
+ * subtype (i.e. matches the form `type/subtype`, and `subtype` is not `*`).
296
+ *
297
+ * Examples:
298
+ * - `"image/png"` -> `true`
299
+ * - `"image/*"` -> `false`
300
+ * - `"image"` -> `false`
301
+ * - `"image/"` -> `false`
302
+ * - `""` -> `false`
303
+ * - `"/"` -> `false`
304
+ */
305
+ export function isFullMediaType(mediaType: string): boolean {
306
+ const slashIndex = mediaType.indexOf('/');
307
+ if (slashIndex === -1) {
308
+ return false;
309
+ }
310
+ const subtype = mediaType.substring(slashIndex + 1);
311
+ return subtype.length > 0 && subtype !== '*';
312
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Filters `null` and `undefined` values out of a list of values.
3
+ *
4
+ * @param values - The values to filter.
5
+ * @returns A new array containing only non-nullish values.
6
+ */
7
+ export function filterNullable<T>(
8
+ ...values: Array<T | undefined | null>
9
+ ): Array<T> {
10
+ return values.filter((value): value is NonNullable<T> => value != null);
11
+ }
@@ -1,15 +1 @@
1
- export function getErrorMessage(error: unknown | undefined) {
2
- if (error == null) {
3
- return 'unknown error';
4
- }
5
-
6
- if (typeof error === 'string') {
7
- return error;
8
- }
9
-
10
- if (error instanceof Error) {
11
- return error.message;
12
- }
13
-
14
- return JSON.stringify(error);
15
- }
1
+ export { getErrorMessage } from '@ai-sdk/provider';
@@ -1,9 +1,9 @@
1
1
  import { APICallError } from '@ai-sdk/provider';
2
2
  import { extractResponseHeaders } from './extract-response-headers';
3
- import { FetchFunction } from './fetch-function';
3
+ import type { FetchFunction } from './fetch-function';
4
4
  import { handleFetchError } from './handle-fetch-error';
5
5
  import { isAbortError } from './is-abort-error';
6
- import { ResponseHandler } from './response-handler';
6
+ import type { ResponseHandler } from './response-handler';
7
7
  import { getRuntimeEnvironmentUserAgent } from './get-runtime-environment-user-agent';
8
8
  import { withUserAgentSuffix } from './with-user-agent-suffix';
9
9
  import { VERSION } from './version';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Checks if an object has required keys.
3
+ * @param OBJECT - The object to check.
4
+ * @returns True if the object has required keys, false otherwise.
5
+ */
6
+ export type HasRequiredKey<OBJECT> = {} extends OBJECT ? false : true;