@ai-sdk/provider-utils 5.0.0-beta.4 → 5.0.0-beta.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/provider-utils",
3
- "version": "5.0.0-beta.4",
3
+ "version": "5.0.0-beta.6",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -35,7 +35,7 @@
35
35
  "dependencies": {
36
36
  "@standard-schema/spec": "^1.1.0",
37
37
  "eventsource-parser": "^3.0.6",
38
- "@ai-sdk/provider": "4.0.0-beta.2"
38
+ "@ai-sdk/provider": "4.0.0-beta.4"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "20.17.24",
@@ -69,9 +69,7 @@
69
69
  "build": "pnpm clean && tsup --tsconfig tsconfig.build.json",
70
70
  "build:watch": "pnpm clean && tsup --watch",
71
71
  "clean": "del-cli dist *.tsbuildinfo",
72
- "lint": "eslint \"./**/*.ts*\"",
73
72
  "type-check": "tsc --build",
74
- "prettier-check": "prettier --check \"./**/*.ts*\"",
75
73
  "test": "pnpm test:node && pnpm test:edge",
76
74
  "test:update": "pnpm test:node -u",
77
75
  "test:watch": "vitest --config vitest.node.config.js",
package/src/index.ts CHANGED
@@ -25,6 +25,11 @@ export * from './is-abort-error';
25
25
  export { isNonNullable } from './is-non-nullable';
26
26
  export { isUrlSupported } from './is-url-supported';
27
27
  export * from './load-api-key';
28
+ export {
29
+ isCustomReasoning,
30
+ mapReasoningToProviderBudget,
31
+ mapReasoningToProviderEffort,
32
+ } from './map-reasoning-to-provider';
28
33
  export { loadOptionalSetting } from './load-optional-setting';
29
34
  export { loadSetting } from './load-setting';
30
35
  export { type MaybePromiseLike } from './maybe-promise-like';
@@ -0,0 +1,105 @@
1
+ import { LanguageModelV4CallOptions, SharedV4Warning } from '@ai-sdk/provider';
2
+
3
+ export type ReasoningLevel = Exclude<
4
+ LanguageModelV4CallOptions['reasoning'],
5
+ 'none' | 'provider-default' | undefined
6
+ >;
7
+
8
+ export function isCustomReasoning(
9
+ reasoning: LanguageModelV4CallOptions['reasoning'],
10
+ ): reasoning is Exclude<
11
+ LanguageModelV4CallOptions['reasoning'],
12
+ 'provider-default' | undefined
13
+ > {
14
+ return reasoning !== undefined && reasoning !== 'provider-default';
15
+ }
16
+
17
+ /**
18
+ * Maps a top-level reasoning level to a provider-specific effort string using
19
+ * the given effort map. Pushes a compatibility warning if the reasoning level
20
+ * maps to a different string, or an unsupported warning if the level is not
21
+ * present in the map.
22
+ *
23
+ * @returns The mapped effort string, or `undefined` if the level is not
24
+ * supported.
25
+ */
26
+ export function mapReasoningToProviderEffort<T extends string>({
27
+ reasoning,
28
+ effortMap,
29
+ warnings,
30
+ }: {
31
+ reasoning: ReasoningLevel;
32
+ effortMap: Partial<Record<ReasoningLevel, T>>;
33
+ warnings: SharedV4Warning[];
34
+ }): T | undefined {
35
+ const mapped = effortMap[reasoning];
36
+
37
+ if (mapped == null) {
38
+ warnings.push({
39
+ type: 'unsupported',
40
+ feature: 'reasoning',
41
+ details: `reasoning "${reasoning}" is not supported by this model.`,
42
+ });
43
+ return undefined;
44
+ }
45
+
46
+ if (mapped !== reasoning) {
47
+ warnings.push({
48
+ type: 'compatibility',
49
+ feature: 'reasoning',
50
+ details: `reasoning "${reasoning}" is not directly supported by this model. mapped to effort "${mapped}".`,
51
+ });
52
+ }
53
+
54
+ return mapped;
55
+ }
56
+
57
+ const DEFAULT_REASONING_BUDGET_PERCENTAGES: Record<ReasoningLevel, number> = {
58
+ minimal: 0.02,
59
+ low: 0.1,
60
+ medium: 0.3,
61
+ high: 0.6,
62
+ xhigh: 0.9,
63
+ };
64
+
65
+ /**
66
+ * Maps a top-level reasoning level to an absolute token budget by multiplying
67
+ * the model's max output tokens by a percentage from the budget percentages
68
+ * map. The result is clamped between `minReasoningBudget` (default 1024) and
69
+ * `maxReasoningBudget`. Pushes an unsupported warning if the level is not
70
+ * present in the budget percentages map.
71
+ *
72
+ * @returns The computed token budget, or `undefined` if the level is not
73
+ * supported.
74
+ */
75
+ export function mapReasoningToProviderBudget({
76
+ reasoning,
77
+ maxOutputTokens,
78
+ maxReasoningBudget,
79
+ minReasoningBudget = 1024,
80
+ budgetPercentages = DEFAULT_REASONING_BUDGET_PERCENTAGES,
81
+ warnings,
82
+ }: {
83
+ reasoning: ReasoningLevel;
84
+ maxOutputTokens: number;
85
+ maxReasoningBudget: number;
86
+ minReasoningBudget?: number;
87
+ budgetPercentages?: Partial<Record<ReasoningLevel, number>>;
88
+ warnings: SharedV4Warning[];
89
+ }): number | undefined {
90
+ const pct = budgetPercentages[reasoning];
91
+
92
+ if (pct == null) {
93
+ warnings.push({
94
+ type: 'unsupported',
95
+ feature: 'reasoning',
96
+ details: `reasoning "${reasoning}" is not supported by this model.`,
97
+ });
98
+ return undefined;
99
+ }
100
+
101
+ return Math.min(
102
+ maxReasoningBudget,
103
+ Math.max(minReasoningBudget, Math.round(maxOutputTokens * pct)),
104
+ );
105
+ }
@@ -1,4 +1,5 @@
1
1
  import {
2
+ CustomPart,
2
3
  FilePart,
3
4
  ReasoningFilePart,
4
5
  ReasoningPart,
@@ -32,6 +33,7 @@ export type AssistantContent =
32
33
  | string
33
34
  | Array<
34
35
  | TextPart
36
+ | CustomPart
35
37
  | FilePart
36
38
  | ReasoningPart
37
39
  | ReasoningFilePart
@@ -103,6 +103,26 @@ export interface ReasoningPart {
103
103
  providerOptions?: ProviderOptions;
104
104
  }
105
105
 
106
+ /**
107
+ * Custom content part of a prompt. It contains no standardized payload beyond
108
+ * provider-specific options.
109
+ */
110
+ export interface CustomPart {
111
+ type: 'custom';
112
+
113
+ /**
114
+ * The kind of custom content, in the format `{provider}-{provider-type}`.
115
+ */
116
+ kind: string;
117
+
118
+ /**
119
+ * Additional provider-specific metadata. They are passed through
120
+ * to the provider from the AI SDK and enable provider-specific
121
+ * functionality that can be fully encapsulated in the provider.
122
+ */
123
+ providerOptions?: ProviderOptions;
124
+ }
125
+
106
126
  /**
107
127
  * Reasoning file content part of a prompt. It contains a file generated as part of reasoning.
108
128
  */
@@ -3,6 +3,7 @@ export type {
3
3
  AssistantModelMessage,
4
4
  } from './assistant-model-message';
5
5
  export type {
6
+ CustomPart,
6
7
  FilePart,
7
8
  ImagePart,
8
9
  ReasoningFilePart,
@@ -18,11 +18,16 @@ export function validateDownloadUrl(url: string): void {
18
18
  });
19
19
  }
20
20
 
21
- // Only allow http and https protocols
21
+ // data: URLs are inline content, so they do not trigger a network fetch or SSRF risk.
22
+ if (parsed.protocol === 'data:') {
23
+ return;
24
+ }
25
+
26
+ // Only allow http and https network protocols
22
27
  if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
23
28
  throw new DownloadError({
24
29
  url,
25
- message: `URL scheme must be http or https, got ${parsed.protocol}`,
30
+ message: `URL scheme must be http, https, or data, got ${parsed.protocol}`,
26
31
  });
27
32
  }
28
33