@ai-sdk/provider-utils 5.0.0-beta.9 → 5.0.0-canary.32

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 (105) hide show
  1. package/CHANGELOG.md +184 -0
  2. package/dist/index.d.ts +1346 -878
  3. package/dist/index.js +813 -325
  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 -11
  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 +1 -1
  12. package/src/convert-inline-file-data-to-uint8-array.ts +30 -0
  13. package/src/create-tool-name-mapping.ts +1 -1
  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 +39 -14
  20. package/src/inject-json-instruction.ts +1 -1
  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 +4 -1
  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-tool-factory.ts → provider-defined-tool-factory.ts} +22 -29
  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 +3 -3
  79. package/src/types/content-part.ts +138 -19
  80. package/src/types/executable-tool.ts +17 -0
  81. package/src/types/execute-tool.ts +23 -23
  82. package/src/types/file-data.ts +48 -0
  83. package/src/types/index.ts +19 -3
  84. package/src/types/infer-tool-context.ts +7 -2
  85. package/src/types/infer-tool-set-context.ts +7 -9
  86. package/src/types/model-message.ts +4 -4
  87. package/src/types/never-optional.ts +7 -0
  88. package/src/types/provider-options.ts +1 -1
  89. package/src/types/provider-reference.ts +10 -0
  90. package/src/types/sensitive-context.ts +9 -0
  91. package/src/types/system-model-message.ts +1 -1
  92. package/src/types/tool-approval-request.ts +7 -0
  93. package/src/types/tool-execute-function.ts +50 -0
  94. package/src/types/tool-model-message.ts +3 -3
  95. package/src/types/tool-needs-approval-function.ts +39 -0
  96. package/src/types/tool.ts +236 -223
  97. package/src/types/user-model-message.ts +2 -2
  98. package/src/validate-types.ts +5 -3
  99. package/dist/index.d.mts +0 -1578
  100. package/dist/index.mjs +0 -2817
  101. package/dist/index.mjs.map +0 -1
  102. package/dist/test/index.d.mts +0 -17
  103. package/dist/test/index.mjs +0 -77
  104. package/dist/test/index.mjs.map +0 -1
  105. package/src/types/union-to-intersection.ts +0 -17
@@ -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.9",
3
+ "version": "5.0.0-canary.32",
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.5"
36
+ "@workflow/serde": "4.1.0",
37
+ "eventsource-parser": "^3.0.8",
38
+ "@ai-sdk/provider": "4.0.0-canary.16"
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"
@@ -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,4 +1,4 @@
1
- import { ImageModelV4File } from '@ai-sdk/provider';
1
+ import type { ImageModelV4File } from '@ai-sdk/provider';
2
2
  import { convertUint8ArrayToBase64 } from './uint8-utils';
3
3
 
4
4
  /**
@@ -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,4 +1,4 @@
1
- import {
1
+ import type {
2
2
  LanguageModelV4FunctionTool,
3
3
  LanguageModelV4ProviderTool,
4
4
  } from '@ai-sdk/provider';
@@ -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;