ai 7.0.127 → 7.0.128

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 (72) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/index.d.ts +213 -153
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +239 -178
  5. package/dist/index.js.map +1 -1
  6. package/dist/internal/index.d.ts +278 -68
  7. package/dist/internal/index.d.ts.map +1 -1
  8. package/dist/internal/index.js +340 -61
  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-getting-started/03-nextjs-pages-router.mdx +1 -1
  15. package/docs/02-getting-started/07-expo.mdx +1 -1
  16. package/docs/03-agents/07-workflow-agent.mdx +80 -12
  17. package/docs/03-ai-sdk-core/16-mcp-tools.mdx +44 -0
  18. package/docs/03-ai-sdk-core/{32-evaluation.mdx → 32-decisions.mdx} +49 -49
  19. package/docs/03-ai-sdk-core/35-image-generation.mdx +1 -1
  20. package/docs/03-ai-sdk-core/45-provider-management.mdx +8 -8
  21. package/docs/03-ai-sdk-core/60-telemetry.mdx +40 -31
  22. package/docs/03-ai-sdk-core/65-lifecycle-callbacks.mdx +21 -22
  23. package/docs/03-ai-sdk-harnesses/08-terminal-ui.mdx +2 -2
  24. package/docs/06-advanced/09-multistep-interfaces.mdx +1 -1
  25. package/docs/07-reference/01-ai-sdk-core/14-decide.mdx +74 -0
  26. package/docs/07-reference/01-ai-sdk-core/23-create-mcp-client.mdx +58 -4
  27. package/docs/07-reference/01-ai-sdk-core/40-provider-registry.mdx +11 -11
  28. package/docs/07-reference/01-ai-sdk-core/42-custom-provider.mdx +9 -9
  29. package/docs/07-reference/01-ai-sdk-core/66-extract-reasoning-middleware.mdx +24 -8
  30. package/docs/07-reference/02-ai-sdk-ui/32-prune-messages.mdx +1 -1
  31. package/docs/07-reference/03-ai-sdk-rsc/01-stream-ui.mdx +1 -0
  32. package/docs/07-reference/04-ai-sdk-workflow/01-workflow-agent.mdx +39 -2
  33. package/docs/07-reference/05-ai-sdk-errors/ai-decision-unsupported-question-type-error.mdx +31 -0
  34. package/docs/07-reference/05-ai-sdk-errors/ai-no-such-model-error.mdx +3 -3
  35. package/docs/07-reference/05-ai-sdk-errors/ai-no-such-provider-error.mdx +3 -3
  36. package/docs/08-migration-guides/23-migration-guide-7-0.mdx +1 -1
  37. package/docs/08-migration-guides/29-migration-guide-4-0.mdx +1 -1
  38. package/docs/09-troubleshooting/05-tool-invocation-missing-result.mdx +2 -2
  39. package/package.json +12 -12
  40. package/src/decide/decide-events.ts +129 -0
  41. package/src/{evaluate/evaluate.ts → decide/decide.ts} +36 -38
  42. package/src/decide/decision-provider.ts +11 -0
  43. package/src/decide/decision-result.ts +39 -0
  44. package/src/decide/index.ts +64 -0
  45. package/src/{evaluate → decide}/restricted-telemetry-dispatcher.ts +7 -7
  46. package/src/{evaluate/validate-evaluation.ts → decide/validate-decision.ts} +9 -9
  47. package/src/error/index.ts +10 -1
  48. package/src/generate-speech/generated-audio-file.ts +5 -4
  49. package/src/generate-text/default-generate-text-result.ts +127 -0
  50. package/src/generate-text/generate-text.ts +2 -122
  51. package/src/global.ts +1 -1
  52. package/src/index.ts +1 -1
  53. package/src/middleware/extract-reasoning-middleware.ts +25 -6
  54. package/src/model/resolve-model.ts +45 -14
  55. package/src/registry/custom-provider.ts +38 -26
  56. package/src/registry/index.ts +13 -1
  57. package/src/registry/no-such-provider-error.ts +2 -0
  58. package/src/registry/provider-registry.ts +56 -29
  59. package/src/telemetry/create-telemetry-dispatcher.ts +17 -5
  60. package/src/telemetry/telemetry.ts +35 -19
  61. package/src/telemetry/tracing-channel.ts +1 -1
  62. package/src/test/decision-mock-model-v4.ts +35 -0
  63. package/src/transcribe/transcribe.ts +1 -1
  64. package/src/ui/chat.ts +9 -1
  65. package/src/ui/process-ui-message-stream.ts +21 -0
  66. package/docs/07-reference/01-ai-sdk-core/14-evaluate.mdx +0 -74
  67. package/docs/07-reference/05-ai-sdk-errors/ai-evaluation-unsupported-question-type-error.mdx +0 -31
  68. package/src/evaluate/evaluate-events.ts +0 -131
  69. package/src/evaluate/evaluation-provider.ts +0 -6
  70. package/src/evaluate/evaluation-result.ts +0 -39
  71. package/src/evaluate/index.ts +0 -13
  72. package/src/test/evaluation-mock-model-v4.ts +0 -27
@@ -15,7 +15,7 @@ import {
15
15
  type ProviderOptions,
16
16
  type ToolSet,
17
17
  } from '@ai-sdk/provider-utils';
18
- import { NoOutputGeneratedError, ToolChoiceViolationError } from '../error';
18
+ import { ToolChoiceViolationError } from '../error';
19
19
  import { logWarnings } from '../logger/log-warnings';
20
20
  import { resolveLanguageModel } from '../model/resolve-model';
21
21
  import type { ModelMessage } from '../prompt';
@@ -76,6 +76,7 @@ import type {
76
76
  GenerateTextOnStepFinishCallback,
77
77
  GenerateTextOnStepStartCallback,
78
78
  } from './generate-text-events';
79
+ import { DefaultGenerateTextResult } from './default-generate-text-result';
79
80
  import type { GenerateTextResult } from './generate-text-result';
80
81
  import { isToolExecutionAllowedFinishReason } from './is-tool-execution-allowed-finish-reason';
81
82
  import type {
@@ -83,11 +84,9 @@ import type {
83
84
  OnLanguageModelCallStartCallback,
84
85
  } from './language-model-events';
85
86
  import { text, type Output } from './output';
86
- import type { InferCompleteOutput } from './output-utils';
87
87
  import { parseToolCall } from './parse-tool-call';
88
88
  import type { PrepareStepFunction } from './prepare-step';
89
89
  import { prepareStepCallSettings } from './prepare-step-call-settings';
90
- import { convertToReasoningOutputs } from './reasoning-output';
91
90
  import { resolveToolApproval } from './resolve-tool-approval';
92
91
  import type { ResponseMessage } from './response-message';
93
92
  import { createRestrictedTelemetryDispatcher } from './restricted-telemetry-dispatcher';
@@ -1687,122 +1686,3 @@ async function executeTools<TOOLS extends ToolSet>({
1687
1686
  (result): result is NonNullable<typeof result> => result != null,
1688
1687
  );
1689
1688
  }
1690
-
1691
- class DefaultGenerateTextResult<
1692
- TOOLS extends ToolSet,
1693
- RUNTIME_CONTEXT extends Context,
1694
- OUTPUT extends Output,
1695
- > implements GenerateTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT> {
1696
- readonly steps: GenerateTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>['steps'];
1697
- readonly totalUsage: LanguageModelUsage;
1698
- private readonly _output: InferCompleteOutput<OUTPUT> | undefined;
1699
-
1700
- constructor(options: {
1701
- initialResponseMessages: Array<ResponseMessage>;
1702
- steps: GenerateTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>['steps'];
1703
- output: InferCompleteOutput<OUTPUT> | undefined;
1704
- totalUsage: LanguageModelUsage;
1705
- }) {
1706
- this.initialResponseMessages = options.initialResponseMessages;
1707
- this.steps = options.steps;
1708
- this._output = options.output;
1709
- this.totalUsage = options.totalUsage;
1710
- }
1711
-
1712
- private readonly initialResponseMessages: Array<ResponseMessage>;
1713
-
1714
- get finalStep() {
1715
- return this.steps.at(-1)!;
1716
- }
1717
-
1718
- get content() {
1719
- return this.steps.flatMap(step => step.content);
1720
- }
1721
-
1722
- get text() {
1723
- return this.finalStep.text;
1724
- }
1725
-
1726
- get files() {
1727
- return this.steps.flatMap(step => step.files);
1728
- }
1729
-
1730
- get reasoningText() {
1731
- return this.finalStep.reasoningText;
1732
- }
1733
-
1734
- get reasoning() {
1735
- return convertToReasoningOutputs(this.finalStep.reasoning);
1736
- }
1737
-
1738
- get toolCalls() {
1739
- return this.steps.flatMap(step => step.toolCalls);
1740
- }
1741
-
1742
- get staticToolCalls() {
1743
- return this.steps.flatMap(step => step.staticToolCalls);
1744
- }
1745
-
1746
- get dynamicToolCalls() {
1747
- return this.steps.flatMap(step => step.dynamicToolCalls);
1748
- }
1749
-
1750
- get toolResults() {
1751
- return this.steps.flatMap(step => step.toolResults);
1752
- }
1753
-
1754
- get staticToolResults() {
1755
- return this.steps.flatMap(step => step.staticToolResults);
1756
- }
1757
-
1758
- get dynamicToolResults() {
1759
- return this.steps.flatMap(step => step.dynamicToolResults);
1760
- }
1761
-
1762
- get sources() {
1763
- return this.steps.flatMap(step => step.sources);
1764
- }
1765
-
1766
- get finishReason() {
1767
- return this.finalStep.finishReason;
1768
- }
1769
-
1770
- get rawFinishReason() {
1771
- return this.finalStep.rawFinishReason;
1772
- }
1773
-
1774
- get warnings() {
1775
- return this.steps.flatMap(step => step.warnings ?? []);
1776
- }
1777
-
1778
- get providerMetadata() {
1779
- return this.finalStep.providerMetadata;
1780
- }
1781
-
1782
- get response() {
1783
- return this.finalStep.response;
1784
- }
1785
-
1786
- get responseMessages() {
1787
- return [
1788
- ...this.initialResponseMessages,
1789
- ...this.steps.flatMap(step => step.response.messages),
1790
- ];
1791
- }
1792
-
1793
- get request() {
1794
- return this.finalStep.request;
1795
- }
1796
-
1797
- get usage() {
1798
- return this.totalUsage;
1799
- }
1800
-
1801
- get output() {
1802
- if (this._output == null) {
1803
- throw new NoOutputGeneratedError();
1804
- }
1805
-
1806
- return this._output;
1807
- }
1808
- }
package/src/global.ts CHANGED
@@ -9,7 +9,7 @@ declare global {
9
9
  * String model ids are resolved to the default provider and model id.
10
10
  *
11
11
  * If not set, the default provider is the Vercel AI gateway provider.
12
- * Experimental evaluation requires an explicitly configured evaluation-capable provider.
12
+ * An explicitly configured provider must support decision models to use experimental_decide.
13
13
  *
14
14
  * @see https://ai-sdk.dev/docs/ai-sdk-core/provider-management#global-provider-configuration
15
15
  */
package/src/index.ts CHANGED
@@ -41,7 +41,7 @@ export * from './agent';
41
41
  export * from './batch';
42
42
  export * from './embed';
43
43
  export * from './error';
44
- export * from './evaluate';
44
+ export * from './decide';
45
45
  export * from './generate-image';
46
46
  export * from './generate-object';
47
47
  export * from './generate-speech';
@@ -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) {
@@ -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
+ }
@@ -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[];