ai 7.0.127 → 7.0.129

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 (100) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/index.d.ts +230 -155
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +386 -209
  5. package/dist/index.js.map +1 -1
  6. package/dist/internal/index.d.ts +288 -70
  7. package/dist/internal/index.d.ts.map +1 -1
  8. package/dist/internal/index.js +407 -76
  9. package/dist/internal/index.js.map +1 -1
  10. package/dist/test/index.d.ts +25 -17
  11. package/dist/test/index.d.ts.map +1 -1
  12. package/dist/test/index.js +27 -21
  13. package/dist/test/index.js.map +1 -1
  14. package/docs/02-foundations/06-provider-options.mdx +11 -10
  15. package/docs/02-getting-started/03-nextjs-pages-router.mdx +1 -1
  16. package/docs/02-getting-started/07-expo.mdx +1 -1
  17. package/docs/03-agents/02-building-agents.mdx +16 -11
  18. package/docs/03-agents/07-workflow-agent.mdx +83 -15
  19. package/docs/03-ai-sdk-core/16-mcp-tools.mdx +44 -0
  20. package/docs/03-ai-sdk-core/17-runtime-and-tool-context.mdx +18 -14
  21. package/docs/03-ai-sdk-core/25-settings.mdx +3 -2
  22. package/docs/03-ai-sdk-core/26-reasoning.mdx +12 -5
  23. package/docs/03-ai-sdk-core/{32-evaluation.mdx → 32-decisions.mdx} +64 -67
  24. package/docs/03-ai-sdk-core/35-image-generation.mdx +3 -1
  25. package/docs/03-ai-sdk-core/45-provider-management.mdx +8 -8
  26. package/docs/03-ai-sdk-core/60-telemetry.mdx +40 -31
  27. package/docs/03-ai-sdk-core/65-lifecycle-callbacks.mdx +21 -22
  28. package/docs/03-ai-sdk-harnesses/08-terminal-ui.mdx +2 -2
  29. package/docs/04-ai-sdk-ui/21-error-handling.mdx +28 -3
  30. package/docs/06-advanced/09-multistep-interfaces.mdx +1 -1
  31. package/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx +2 -2
  32. package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +2 -2
  33. package/docs/07-reference/01-ai-sdk-core/14-decide.mdx +74 -0
  34. package/docs/07-reference/01-ai-sdk-core/23-create-mcp-client.mdx +58 -4
  35. package/docs/07-reference/01-ai-sdk-core/40-provider-registry.mdx +11 -11
  36. package/docs/07-reference/01-ai-sdk-core/42-custom-provider.mdx +9 -9
  37. package/docs/07-reference/01-ai-sdk-core/66-extract-reasoning-middleware.mdx +24 -8
  38. package/docs/07-reference/02-ai-sdk-ui/32-prune-messages.mdx +1 -1
  39. package/docs/07-reference/03-ai-sdk-rsc/01-stream-ui.mdx +1 -0
  40. package/docs/07-reference/04-ai-sdk-workflow/01-workflow-agent.mdx +39 -2
  41. package/docs/07-reference/05-ai-sdk-errors/ai-decision-unsupported-question-type-error.mdx +31 -0
  42. package/docs/07-reference/05-ai-sdk-errors/ai-no-such-model-error.mdx +3 -3
  43. package/docs/07-reference/05-ai-sdk-errors/ai-no-such-provider-error.mdx +3 -3
  44. package/docs/08-migration-guides/23-migration-guide-7-0.mdx +1 -1
  45. package/docs/08-migration-guides/29-migration-guide-4-0.mdx +1 -1
  46. package/docs/09-troubleshooting/05-tool-invocation-missing-result.mdx +2 -2
  47. package/package.json +15 -15
  48. package/src/decide/decide-events.ts +129 -0
  49. package/src/{evaluate/evaluate.ts → decide/decide.ts} +36 -38
  50. package/src/decide/decision-provider.ts +11 -0
  51. package/src/decide/decision-result.ts +39 -0
  52. package/src/decide/index.ts +64 -0
  53. package/src/{evaluate → decide}/restricted-telemetry-dispatcher.ts +7 -7
  54. package/src/{evaluate/validate-evaluation.ts → decide/validate-decision.ts} +9 -9
  55. package/src/error/index.ts +10 -1
  56. package/src/generate-object/generate-object.ts +10 -0
  57. package/src/generate-object/stream-object.ts +10 -0
  58. package/src/generate-speech/generated-audio-file.ts +5 -4
  59. package/src/generate-speech/index.ts +13 -1
  60. package/src/generate-text/default-generate-text-result.ts +127 -0
  61. package/src/generate-text/generate-text.ts +5 -123
  62. package/src/generate-text/tool-approval-signature.ts +7 -4
  63. package/src/global.ts +3 -2
  64. package/src/index.ts +1 -1
  65. package/src/logger/deprecations.ts +72 -0
  66. package/src/logger/log-warnings.ts +25 -3
  67. package/src/middleware/extract-reasoning-middleware.ts +25 -6
  68. package/src/model/as-language-model-v3.ts +4 -0
  69. package/src/model/resolve-model.ts +45 -14
  70. package/src/prompt/convert-to-language-model-prompt.ts +7 -1
  71. package/src/realtime/encode-realtime-frame.ts +7 -2
  72. package/src/registry/custom-provider.ts +38 -26
  73. package/src/registry/index.ts +13 -1
  74. package/src/registry/no-such-provider-error.ts +2 -0
  75. package/src/registry/provider-registry.ts +56 -29
  76. package/src/telemetry/create-telemetry-dispatcher.ts +17 -5
  77. package/src/telemetry/telemetry.ts +35 -19
  78. package/src/telemetry/tracing-channel.ts +1 -1
  79. package/src/test/decision-mock-model-v4.ts +35 -0
  80. package/src/transcribe/index.ts +13 -1
  81. package/src/transcribe/transcribe.ts +1 -1
  82. package/src/types/index.ts +1 -0
  83. package/src/types/language-model.ts +9 -1
  84. package/src/types/usage.ts +21 -0
  85. package/src/ui/chat.ts +25 -9
  86. package/src/ui/convert-to-model-messages.ts +40 -8
  87. package/src/ui/http-chat-transport.ts +5 -3
  88. package/src/ui/process-text-stream.ts +5 -1
  89. package/src/ui/process-ui-message-stream.ts +21 -0
  90. package/src/ui/text-stream-chat-transport.ts +3 -1
  91. package/src/ui/ui-messages.ts +8 -0
  92. package/src/ui/unavailable-tool.ts +17 -0
  93. package/src/ui/validate-ui-messages.ts +10 -2
  94. package/docs/07-reference/01-ai-sdk-core/14-evaluate.mdx +0 -74
  95. package/docs/07-reference/05-ai-sdk-errors/ai-evaluation-unsupported-question-type-error.mdx +0 -31
  96. package/src/evaluate/evaluate-events.ts +0 -131
  97. package/src/evaluate/evaluation-provider.ts +0 -6
  98. package/src/evaluate/evaluation-result.ts +0 -39
  99. package/src/evaluate/index.ts +0 -13
  100. package/src/test/evaluation-mock-model-v4.ts +0 -27
@@ -0,0 +1,72 @@
1
+ // These codes are stable identifiers. Do not rename or reuse an existing code.
2
+ const deprecationCodes = new Map<string, string>([
3
+ ['generateObject', 'AISDK_DEP_GENERATE_OBJECT'],
4
+ ['streamObject', 'AISDK_DEP_STREAM_OBJECT'],
5
+ ['experimental_generateSpeech', 'AISDK_DEP_EXPERIMENTAL_GENERATE_SPEECH'],
6
+ ['experimental_transcribe', 'AISDK_DEP_EXPERIMENTAL_TRANSCRIBE'],
7
+ ['"image" content part', 'AISDK_DEP_IMAGE_CONTENT_PART'],
8
+ [
9
+ '"tool-result" content of type "file-data"',
10
+ 'AISDK_DEP_TOOL_RESULT_FILE_DATA',
11
+ ],
12
+ [
13
+ '"tool-result" content of type "file-url"',
14
+ 'AISDK_DEP_TOOL_RESULT_FILE_URL',
15
+ ],
16
+ ['"tool-result" content of type "file-id"', 'AISDK_DEP_TOOL_RESULT_FILE_ID'],
17
+ [
18
+ '"tool-result" content of type "file-reference"',
19
+ 'AISDK_DEP_TOOL_RESULT_FILE_REFERENCE',
20
+ ],
21
+ [
22
+ '"tool-result" content of type "image-data"',
23
+ 'AISDK_DEP_TOOL_RESULT_IMAGE_DATA',
24
+ ],
25
+ [
26
+ '"tool-result" content of type "image-url"',
27
+ 'AISDK_DEP_TOOL_RESULT_IMAGE_URL',
28
+ ],
29
+ [
30
+ '"tool-result" content of type "image-file-id"',
31
+ 'AISDK_DEP_TOOL_RESULT_IMAGE_FILE_ID',
32
+ ],
33
+ [
34
+ '"tool-result" content of type "image-file-reference"',
35
+ 'AISDK_DEP_TOOL_RESULT_IMAGE_FILE_REFERENCE',
36
+ ],
37
+ [
38
+ 'rawInput in output-error UI message parts',
39
+ 'AISDK_DEP_UI_MESSAGE_RAW_INPUT',
40
+ ],
41
+ ]);
42
+
43
+ /**
44
+ * Escape punctuation and UTF-16 code units without losing case or collapsing
45
+ * distinct settings. Underscores are escaped too, so `__` separates code parts.
46
+ */
47
+ function encodeCodePart(value: string): string {
48
+ return value.replace(
49
+ /[^a-zA-Z0-9]/g,
50
+ character =>
51
+ `_${character.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0')}`,
52
+ );
53
+ }
54
+
55
+ export function getDeprecationCode({
56
+ setting,
57
+ provider,
58
+ }: {
59
+ setting: string;
60
+ provider?: string;
61
+ }): string {
62
+ if (provider == null) {
63
+ return (
64
+ deprecationCodes.get(setting) ??
65
+ `AISDK_DEP_SETTING_${encodeCodePart(setting)}`
66
+ );
67
+ }
68
+
69
+ // Provider codes are scoped to the provider, but not to a particular model or
70
+ // message. This works for third-party providers without changing their spec.
71
+ return `AISDK_DEP_PROVIDER_${encodeCodePart(provider)}__${encodeCodePart(setting)}`;
72
+ }
@@ -1,4 +1,5 @@
1
1
  import type { Warning } from '../types';
2
+ import { getDeprecationCode } from './deprecations';
2
3
 
3
4
  /**
4
5
  * A function for logging warnings.
@@ -87,21 +88,24 @@ export const FIRST_WARNING_INFO_MESSAGE =
87
88
  'AI SDK Warning System: To turn off warning logging, set the AI_SDK_LOG_WARNINGS global to false.';
88
89
 
89
90
  let hasLoggedBefore = false;
91
+ const emittedDeprecationCodes = new Set<string>();
90
92
 
91
93
  function emitWarning({
92
94
  message,
93
95
  type,
96
+ code,
94
97
  }: {
95
98
  message: string;
96
99
  type: 'DeprecationWarning' | 'Warning';
100
+ code?: string;
97
101
  }) {
98
102
  if (
99
103
  typeof process !== 'undefined' &&
100
104
  typeof process.emitWarning === 'function'
101
105
  ) {
102
- process.emitWarning(message, { type });
106
+ process.emitWarning(message, code == null ? { type } : { type, code });
103
107
  } else {
104
- console.warn(message);
108
+ console.warn(code == null ? message : `[${code}] ${message}`);
105
109
  }
106
110
  }
107
111
 
@@ -111,7 +115,9 @@ function emitWarning({
111
115
  * The behavior can be customized via the `AI_SDK_LOG_WARNINGS` global variable:
112
116
  * - If set to `false`, warnings are suppressed.
113
117
  * - If set to a function, that function is called with the warnings.
114
- * - Otherwise, warnings are logged to the console using `console.warn`.
118
+ * - Otherwise, warnings use `process.emitWarning` when available, falling back
119
+ * to `console.warn`. Deprecations have stable codes and are emitted once per
120
+ * code by the default logger. Custom loggers receive every warning.
115
121
  *
116
122
  * @param options - The options containing warnings and context.
117
123
  * @param options.warnings - The warnings to log.
@@ -148,6 +154,20 @@ export const logWarnings: LogWarningsFunction = options => {
148
154
 
149
155
  // default behavior: log warnings via process.emitWarning if available, otherwise console.warn
150
156
  for (const warning of options.warnings) {
157
+ const code =
158
+ warning.type === 'deprecated'
159
+ ? getDeprecationCode({
160
+ setting: warning.setting,
161
+ provider: options.provider,
162
+ })
163
+ : undefined;
164
+ if (code != null) {
165
+ if (emittedDeprecationCodes.has(code)) {
166
+ continue;
167
+ }
168
+ emittedDeprecationCodes.add(code);
169
+ }
170
+
151
171
  const message = formatWarning({
152
172
  warning,
153
173
  provider: options.provider,
@@ -156,6 +176,7 @@ export const logWarnings: LogWarningsFunction = options => {
156
176
  emitWarning({
157
177
  message,
158
178
  type: warning.type === 'deprecated' ? 'DeprecationWarning' : 'Warning',
179
+ code,
159
180
  });
160
181
  }
161
182
  };
@@ -165,4 +186,5 @@ export const logWarnings: LogWarningsFunction = options => {
165
186
  */
166
187
  export const resetLogWarningsState = () => {
167
188
  hasLoggedBefore = false;
189
+ emittedDeprecationCodes.clear();
168
190
  };
@@ -3,14 +3,16 @@ import type {
3
3
  LanguageModelV4StreamPart,
4
4
  } from '@ai-sdk/provider';
5
5
  import type { LanguageModelMiddleware } from '../types/language-model-middleware';
6
+ import { InvalidArgumentError } from '../error/invalid-argument-error';
6
7
  import { createIdMap } from '../util/create-id-map';
7
8
  import { getPotentialStartIndex } from '../util/get-potential-start-index';
8
9
 
9
10
  /**
10
- * Extracts an XML-tagged reasoning section from the generated text and exposes it
11
+ * Extracts a delimited reasoning section from the generated text and exposes it
11
12
  * as a `reasoning` property on the result.
12
13
  *
13
- * @param tagName - The name of the XML tag to extract reasoning from.
14
+ * @param tagName - An XML tag name (without angle brackets), or literal opening
15
+ * and closing delimiters for formats such as Gemma's thought channel.
14
16
  * @param separator - The separator to use between reasoning and text sections.
15
17
  * @param startWithReasoning - Whether to start with reasoning tokens.
16
18
  */
@@ -19,12 +21,26 @@ export function extractReasoningMiddleware({
19
21
  separator = '\n',
20
22
  startWithReasoning = false,
21
23
  }: {
22
- tagName: string;
24
+ tagName: string | { opening: string; closing: string };
23
25
  separator?: string;
24
26
  startWithReasoning?: boolean;
25
27
  }): LanguageModelMiddleware {
26
- const openingTag = `<${tagName}>`;
27
- const closingTag = `</${tagName}>`;
28
+ const openingTag =
29
+ typeof tagName === 'string' ? `<${tagName}>` : tagName.opening;
30
+ const closingTag =
31
+ typeof tagName === 'string' ? `</${tagName}>` : tagName.closing;
32
+
33
+ if (openingTag.length === 0 || closingTag.length === 0) {
34
+ throw new InvalidArgumentError({
35
+ parameter: 'tagName',
36
+ value: tagName,
37
+ message: 'Reasoning delimiters must not be empty.',
38
+ });
39
+ }
40
+
41
+ // Delimiters are literal strings, including regex metacharacters such as `|`.
42
+ const escapedOpeningTag = openingTag.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
43
+ const escapedClosingTag = closingTag.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
28
44
 
29
45
  return {
30
46
  specificationVersion: 'v4',
@@ -40,7 +56,10 @@ export function extractReasoningMiddleware({
40
56
 
41
57
  const text = startWithReasoning ? openingTag + part.text : part.text;
42
58
 
43
- const regexp = new RegExp(`${openingTag}(.*?)${closingTag}`, 'gs');
59
+ const regexp = new RegExp(
60
+ `${escapedOpeningTag}(.*?)${escapedClosingTag}`,
61
+ 'gs',
62
+ );
44
63
  const matches = Array.from(text.matchAll(regexp));
45
64
 
46
65
  if (!matches.length) {
@@ -99,5 +99,9 @@ function convertV2UsageToV3(usage: LanguageModelV2Usage): LanguageModelV3Usage {
99
99
  text: undefined,
100
100
  reasoning: usage.reasoningTokens,
101
101
  },
102
+ raw:
103
+ usage.totalTokens == null
104
+ ? undefined
105
+ : { totalTokens: usage.totalTokens },
102
106
  };
103
107
  }
@@ -1,7 +1,7 @@
1
1
  import { gateway } from '@ai-sdk/gateway';
2
2
  import {
3
3
  NoSuchModelError,
4
- type Experimental_EvaluationModelV4 as EvaluationModelV4,
4
+ type Experimental_DecisionModelV4 as DecisionModelV4,
5
5
  type EmbeddingModelV4,
6
6
  type Experimental_SpeechTranslationModelV4,
7
7
  type Experimental_VideoModelV4,
@@ -12,8 +12,8 @@ import {
12
12
  type SpeechModelV4,
13
13
  type TranscriptionModelV4,
14
14
  } from '@ai-sdk/provider';
15
- import type { EvaluationModel } from '../evaluate/evaluation-result';
16
- import type { EvaluationProvider } from '../evaluate/evaluation-provider';
15
+ import type { DecisionModel } from '../decide/decision-result';
16
+ import type { DecisionProvider } from '../decide/decision-provider';
17
17
  import { UnsupportedModelVersionError } from '../error';
18
18
  import type { EmbeddingModel } from '../types/embedding-model';
19
19
  import type { LanguageModel } from '../types/language-model';
@@ -217,29 +217,30 @@ export function resolveRerankingModel(model: RerankingModel): RerankingModelV4 {
217
217
  return asRerankingModelV4(model);
218
218
  }
219
219
 
220
- export function resolveEvaluationModel(
221
- model: EvaluationModel,
222
- ): EvaluationModelV4 {
220
+ export function resolveDecisionModel(model: DecisionModel): DecisionModelV4 {
223
221
  if (typeof model === 'string') {
224
222
  // Use the original provider so experimental methods and their receiver survive.
225
223
  const provider = (globalThis.AI_SDK_DEFAULT_PROVIDER ??
226
- gateway) as EvaluationProvider;
224
+ gateway) as DecisionProvider;
227
225
 
228
- if (typeof provider?.evaluationModel !== 'function') {
226
+ const factory:
227
+ | ((modelId: string) => Exclude<DecisionModel, string>)
228
+ | undefined = provider.decisionModel ?? provider.evaluationModel;
229
+ if (typeof factory !== 'function') {
229
230
  throw new NoSuchModelError({
230
231
  modelId: model,
231
- modelType: 'evaluationModel',
232
+ modelType: 'decisionModel',
232
233
  message:
233
- 'The default provider does not support evaluation models. ' +
234
- 'Pass an evaluation model instance or configure AI_SDK_DEFAULT_PROVIDER with an evaluationModel method.',
234
+ 'The default provider does not support decision models. ' +
235
+ 'Pass a decision model instance or configure AI_SDK_DEFAULT_PROVIDER with a decisionModel method.',
235
236
  });
236
237
  }
237
238
 
238
- const resolvedModel = provider.evaluationModel(model);
239
+ const resolvedModel = factory.call(provider, model);
239
240
  if (resolvedModel == null) {
240
241
  throw new NoSuchModelError({
241
242
  modelId: model,
242
- modelType: 'evaluationModel',
243
+ modelType: 'decisionModel',
243
244
  });
244
245
  }
245
246
  model = resolvedModel;
@@ -253,10 +254,40 @@ export function resolveEvaluationModel(
253
254
  });
254
255
  }
255
256
 
256
- return model;
257
+ if ('doDecide' in model) {
258
+ return model;
259
+ }
260
+
261
+ const legacyModel = model;
262
+ return {
263
+ specificationVersion: legacyModel.specificationVersion,
264
+ provider: legacyModel.provider,
265
+ modelId: legacyModel.modelId,
266
+ supportedQuestionTypes: legacyModel.supportedQuestionTypes,
267
+ doDecide: options => legacyModel.doEvaluate(options),
268
+ };
257
269
  }
258
270
 
259
271
  function getGlobalProvider(): ProviderV4 {
260
272
  const provider = globalThis.AI_SDK_DEFAULT_PROVIDER ?? gateway;
261
273
  return asProviderV4(provider);
262
274
  }
275
+
276
+ /** Internal adapter for deprecated provider factories. */
277
+ export function asEvaluationModel(model: DecisionModelV4): DecisionModelV4 & {
278
+ doEvaluate: DecisionModelV4['doDecide'];
279
+ } {
280
+ if ('doEvaluate' in model && typeof model.doEvaluate === 'function') {
281
+ return model as DecisionModelV4 & {
282
+ doEvaluate: DecisionModelV4['doDecide'];
283
+ };
284
+ }
285
+ return {
286
+ specificationVersion: model.specificationVersion,
287
+ provider: model.provider,
288
+ modelId: model.modelId,
289
+ supportedQuestionTypes: model.supportedQuestionTypes,
290
+ doDecide: options => model.doDecide(options),
291
+ doEvaluate: options => model.doDecide(options),
292
+ };
293
+ }
@@ -123,7 +123,13 @@ export async function convertToLanguageModelPrompt({
123
123
  }
124
124
 
125
125
  lastCombinedMessage.content.push(...message.content);
126
- lastCombinedMessage.providerOptions = message.providerOptions;
126
+ lastCombinedMessage.providerOptions =
127
+ lastContentPart == null
128
+ ? mergeObjects(
129
+ lastCombinedMessage.providerOptions,
130
+ message.providerOptions,
131
+ )
132
+ : message.providerOptions;
127
133
  } else {
128
134
  combinedMessages.push(message);
129
135
  }
@@ -3,14 +3,19 @@ export const REALTIME_MAX_FRAME_BYTES = 128 * 1024;
3
3
  export const REALTIME_MAX_BUFFERED_BYTES = 128 * 1024;
4
4
 
5
5
  export type EncodedRealtimeFrame = {
6
- data: string | ArrayBuffer | ArrayBufferView | Blob;
6
+ data: string | ArrayBuffer | ArrayBufferView<ArrayBuffer> | Blob;
7
7
  byteLength: number;
8
8
  };
9
9
 
10
10
  /** Serialize once, measuring the exact payload passed to the browser. */
11
11
  export function encodeRealtimeFrame(value: unknown): EncodedRealtimeFrame {
12
- if (value instanceof ArrayBuffer || ArrayBuffer.isView(value))
12
+ if (value instanceof ArrayBuffer)
13
13
  return { data: value, byteLength: value.byteLength };
14
+ if (ArrayBuffer.isView(value))
15
+ return {
16
+ data: value as ArrayBufferView<ArrayBuffer>,
17
+ byteLength: value.byteLength,
18
+ };
14
19
  if (value instanceof Blob) return { data: value, byteLength: value.size };
15
20
  const data = typeof value === 'string' ? value : JSON.stringify(value);
16
21
  if (data === undefined)
@@ -1,5 +1,5 @@
1
1
  import {
2
- type Experimental_EvaluationModelV4 as EvaluationModelV4,
2
+ type Experimental_DecisionModelV4 as DecisionModelV4,
3
3
  type EmbeddingModelV4,
4
4
  type Experimental_VideoModelV3,
5
5
  type Experimental_VideoModelV4,
@@ -15,8 +15,8 @@ import {
15
15
  type SpeechModelV4,
16
16
  type TranscriptionModelV4,
17
17
  } from '@ai-sdk/provider';
18
- import type { EvaluationModel } from '../evaluate/evaluation-result';
19
- import type { EvaluationProvider } from '../evaluate/evaluation-provider';
18
+ import type { DecisionModel } from '../decide/decision-result';
19
+ import type { DecisionProvider } from '../decide/decision-provider';
20
20
  import { asProviderV4 } from '../model/as-provider-v4';
21
21
  import {
22
22
  resolveEmbeddingModel,
@@ -26,7 +26,8 @@ import {
26
26
  resolveSpeechModel,
27
27
  resolveTranscriptionModel,
28
28
  resolveVideoModel,
29
- resolveEvaluationModel,
29
+ resolveDecisionModel,
30
+ asEvaluationModel,
30
31
  } from '../model/resolve-model';
31
32
  import type { EmbeddingModel } from '../types/embedding-model';
32
33
  import type { ImageModel } from '../types/image-model';
@@ -53,7 +54,7 @@ type ProviderWithOptionalVideoModel = {
53
54
  * @param {Record<string, SpeechModel>} [options.speechModels] - A record of speech models, where keys are model IDs and values are speech model instances.
54
55
  * @param {Record<string, RerankingModel>} [options.rerankingModels] - A record of reranking models, where keys are model IDs and values are reranking model instances.
55
56
  * @param {Record<string, VideoModel>} [options.videoModels] - A record of video models, where keys are model IDs and values are video model instances.
56
- * @param {Record<string, EvaluationModel>} [options.evaluationModels] - Experimental evaluation models or default-provider model IDs, keyed by alias.
57
+ * @param {Record<string, DecisionModel>} [options.decisionModels] - Experimental decision models or default-provider model IDs, keyed by alias.
57
58
  * @param {FilesV4} [options.files] - A files interface for uploading files.
58
59
  * @param {SkillsV4} [options.skills] - A skills interface for uploading skills.
59
60
  * @param {ProviderV2 | ProviderV3 | ProviderV4} [options.fallbackProvider] - An optional fallback provider to use when a requested model is not found in the custom provider.
@@ -72,9 +73,9 @@ export function customProvider<
72
73
  FILES extends FilesV4 | undefined = undefined,
73
74
  SKILLS extends SkillsV4 | undefined = undefined,
74
75
  FALLBACK extends ProviderV2 | ProviderV3 | ProviderV4 | undefined = undefined,
75
- EVALUATION_MODELS extends Record<string, EvaluationModel> = Record<
76
+ DECISION_MODELS extends Record<string, DecisionModel> = Record<
76
77
  string,
77
- EvaluationModel
78
+ DecisionModel
78
79
  >,
79
80
  >({
80
81
  languageModels,
@@ -84,6 +85,7 @@ export function customProvider<
84
85
  speechModels,
85
86
  rerankingModels,
86
87
  videoModels,
88
+ decisionModels: decisionModelsArg,
87
89
  evaluationModels,
88
90
  files,
89
91
  skills,
@@ -96,7 +98,9 @@ export function customProvider<
96
98
  speechModels?: SPEECH_MODELS;
97
99
  rerankingModels?: RERANKING_MODELS;
98
100
  videoModels?: VIDEO_MODELS;
99
- evaluationModels?: EVALUATION_MODELS;
101
+ decisionModels?: DECISION_MODELS;
102
+ /** @deprecated Use `decisionModels` instead. When both are set, `decisionModels` takes precedence. */
103
+ evaluationModels?: DECISION_MODELS;
100
104
  files?: FILES;
101
105
  skills?: SKILLS;
102
106
  fallbackProvider?: FALLBACK;
@@ -110,9 +114,11 @@ export function customProvider<
110
114
  rerankingModel(modelId: ExtractModelId<RERANKING_MODELS>): RerankingModelV4;
111
115
  speechModel(modelId: ExtractModelId<SPEECH_MODELS>): SpeechModelV4;
112
116
  videoModel(modelId: ExtractModelId<VIDEO_MODELS>): Experimental_VideoModelV4;
113
- evaluationModel(
114
- modelId: ExtractModelId<EVALUATION_MODELS>,
115
- ): EvaluationModelV4;
117
+ decisionModel(modelId: ExtractModelId<DECISION_MODELS>): DecisionModelV4;
118
+ /** @deprecated Use `decisionModel` instead. */
119
+ evaluationModel(modelId: ExtractModelId<DECISION_MODELS>): DecisionModelV4 & {
120
+ doEvaluate: DecisionModelV4['doDecide'];
121
+ };
116
122
  } & (FILES extends FilesV4
117
123
  ? { files(): FilesV4 }
118
124
  : [FALLBACK] extends [{ files: () => FilesV4 }]
@@ -123,6 +129,7 @@ export function customProvider<
123
129
  : [FALLBACK] extends [{ skills: () => SkillsV4 }]
124
130
  ? { skills(): SkillsV4 }
125
131
  : { skills?(): SkillsV4 }) {
132
+ const decisionModels = decisionModelsArg ?? evaluationModels;
126
133
  const fallbackProvider =
127
134
  fallbackProviderArg == null ? undefined : asProviderV4(fallbackProviderArg);
128
135
 
@@ -138,9 +145,13 @@ export function customProvider<
138
145
  videoModel(
139
146
  modelId: ExtractModelId<VIDEO_MODELS>,
140
147
  ): Experimental_VideoModelV4;
148
+ decisionModel(modelId: ExtractModelId<DECISION_MODELS>): DecisionModelV4;
149
+ /** @deprecated Use `decisionModel` instead. */
141
150
  evaluationModel(
142
- modelId: ExtractModelId<EVALUATION_MODELS>,
143
- ): EvaluationModelV4;
151
+ modelId: ExtractModelId<DECISION_MODELS>,
152
+ ): DecisionModelV4 & {
153
+ doEvaluate: DecisionModelV4['doDecide'];
154
+ };
144
155
  } = {
145
156
  specificationVersion: 'v4',
146
157
  languageModel(modelId: ExtractModelId<LANGUAGE_MODELS>): LanguageModelV4 {
@@ -227,25 +238,26 @@ export function customProvider<
227
238
 
228
239
  throw new NoSuchModelError({ modelId, modelType: 'rerankingModel' });
229
240
  },
230
- evaluationModel(
231
- modelId: ExtractModelId<EVALUATION_MODELS>,
232
- ): EvaluationModelV4 {
233
- if (
234
- evaluationModels != null &&
235
- Object.hasOwn(evaluationModels, modelId)
236
- ) {
237
- return resolveEvaluationModel(evaluationModels[modelId]);
241
+ decisionModel(modelId: ExtractModelId<DECISION_MODELS>): DecisionModelV4 {
242
+ if (decisionModels != null && Object.hasOwn(decisionModels, modelId)) {
243
+ return resolveDecisionModel(decisionModels[modelId]);
238
244
  }
239
245
 
240
- const provider = fallbackProviderArg as EvaluationProvider | undefined;
241
- if (typeof provider?.evaluationModel === 'function') {
242
- const model = provider.evaluationModel(modelId);
246
+ const provider = fallbackProviderArg as DecisionProvider | undefined;
247
+ const factory:
248
+ | ((modelId: string) => Exclude<DecisionModel, string>)
249
+ | undefined = provider?.decisionModel ?? provider?.evaluationModel;
250
+ if (typeof factory === 'function') {
251
+ const model = factory.call(provider, modelId);
243
252
  if (model != null) {
244
- return resolveEvaluationModel(model);
253
+ return resolveDecisionModel(model);
245
254
  }
246
255
  }
247
256
 
248
- throw new NoSuchModelError({ modelId, modelType: 'evaluationModel' });
257
+ throw new NoSuchModelError({ modelId, modelType: 'decisionModel' });
258
+ },
259
+ evaluationModel(modelId: ExtractModelId<DECISION_MODELS>) {
260
+ return asEvaluationModel(this.decisionModel(modelId));
249
261
  },
250
262
  videoModel(
251
263
  modelId: ExtractModelId<VIDEO_MODELS>,
@@ -1,3 +1,6 @@
1
+ import type { ProviderV3, ProviderV4 } from '@ai-sdk/provider';
2
+ import type { DecisionProviderRegistry } from './provider-registry';
3
+
1
4
  export { customProvider } from './custom-provider';
2
5
  export { NoSuchProviderError } from './no-such-provider-error';
3
6
  export {
@@ -6,4 +9,13 @@ export {
6
9
  } from './provider-registry';
7
10
  export type { ProviderRegistryProvider } from './provider-registry';
8
11
 
9
- export type { EvaluationProviderRegistry as Experimental_EvaluationProviderRegistry } from './provider-registry';
12
+ export type { DecisionProviderRegistry as Experimental_DecisionProviderRegistry } from './provider-registry';
13
+
14
+ /** @deprecated Use `Experimental_DecisionProviderRegistry` instead. */
15
+ export type Experimental_EvaluationProviderRegistry<
16
+ PROVIDERS extends Record<string, ProviderV4 | ProviderV3> = Record<
17
+ string,
18
+ ProviderV4 | ProviderV3
19
+ >,
20
+ SEPARATOR extends string = ':',
21
+ > = DecisionProviderRegistry<PROVIDERS, SEPARATOR>;
@@ -26,6 +26,8 @@ export class NoSuchProviderError extends NoSuchModelError {
26
26
  | 'speechModel'
27
27
  | 'rerankingModel'
28
28
  | 'videoModel'
29
+ | 'decisionModel'
30
+ /** @deprecated Use `decisionModel` instead. */
29
31
  | 'evaluationModel';
30
32
  providerId: string;
31
33
  availableProviders: string[];