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
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  title: extractReasoningMiddleware
3
- description: Middleware that extracts XML-tagged reasoning sections from generated text
3
+ description: Middleware that extracts reasoning sections from generated text using configurable delimiters
4
4
  ---
5
5
 
6
6
  # `extractReasoningMiddleware()`
7
7
 
8
- `extractReasoningMiddleware` is a middleware function that extracts XML-tagged reasoning sections from generated text and exposes them separately from the main text content. This is particularly useful when you want to separate an AI model's reasoning process from its final output.
8
+ `extractReasoningMiddleware` is a middleware function that extracts delimited reasoning sections from generated text and exposes them separately from the main text content. This is particularly useful when you want to separate an AI model's reasoning process from its final output.
9
9
 
10
10
  ```ts
11
11
  import { extractReasoningMiddleware } from 'ai';
@@ -16,6 +16,22 @@ const middleware = extractReasoningMiddleware({
16
16
  });
17
17
  ```
18
18
 
19
+ For models that emit non-XML delimiters, pass literal `opening` and `closing`
20
+ strings. For example, Gemma 4's raw thought-channel output uses a newline in its
21
+ opening delimiter:
22
+
23
+ ```ts
24
+ const middleware = extractReasoningMiddleware({
25
+ tagName: { opening: '<|channel>thought\n', closing: '<channel|>' },
26
+ });
27
+ ```
28
+
29
+ Custom delimiters must be non-empty. They are matched literally, including
30
+ characters such as `|`, and can span multiple streaming chunks. Empty reasoning
31
+ blocks are removed from the answer text as well. Use this middleware when the
32
+ server returns these markers in text; providers that already return reasoning
33
+ separately do not need it.
34
+
19
35
  ## Import
20
36
 
21
37
  <Snippet
@@ -31,10 +47,10 @@ const middleware = extractReasoningMiddleware({
31
47
  content={[
32
48
  {
33
49
  name: 'tagName',
34
- type: 'string',
50
+ type: 'string | { opening: string; closing: string }',
35
51
  isOptional: false,
36
52
  description:
37
- 'The name of the XML tag to extract reasoning from (without angle brackets)',
53
+ 'An XML tag name without angle brackets (e.g. "think" for <think> / </think>), or an object containing non-empty literal opening and closing delimiters.',
38
54
  },
39
55
  {
40
56
  name: 'separator',
@@ -48,7 +64,7 @@ const middleware = extractReasoningMiddleware({
48
64
  type: 'boolean',
49
65
  isOptional: true,
50
66
  description:
51
- 'Starts with reasoning tokens. Set to true when the response always starts with reasoning and the initial tag is omitted. Defaults to false.',
67
+ 'Starts with reasoning tokens. Set to true when the response always starts with reasoning and the opening delimiter is omitted. Defaults to false.',
52
68
  },
53
69
  ]}
54
70
  />
@@ -58,9 +74,9 @@ const middleware = extractReasoningMiddleware({
58
74
  Returns a middleware object that:
59
75
 
60
76
  - Processes both streaming and non-streaming responses
61
- - Extracts content between specified XML tags as reasoning
62
- - Removes the XML tags and reasoning from the main text
63
- - Adds a `reasoning` property to the result containing the extracted content
77
+ - Extracts content between the specified delimiters as reasoning
78
+ - Removes the delimiters and reasoning from the main text
79
+ - Emits reasoning content parts separately from text content parts
64
80
  - Maintains proper separation between text sections using the specified separator
65
81
 
66
82
  ### Type Parameters
@@ -60,7 +60,7 @@ export async function POST(req: Request) {
60
60
  },
61
61
  {
62
62
  name: 'toolCalls',
63
- type: `'all' | 'before-last-message' | 'before-last-\${number}-messages' | 'none' | Array<{ type: 'all' | 'before-last-message' | 'before-last-\${number}-messages'; tools?: string[] }>`,
63
+ type: `'all' | 'before-last-message' | \`before-last-\${number}-messages\` | 'none' | Array<{ type: 'all' | 'before-last-message' | \`before-last-\${number}-messages\`; tools?: string[] }>`,
64
64
  description:
65
65
  'How to prune tool call/results/approval content. Can specify a strategy string or an array for per-tool fine control. Default: [] (empty array, equivalent to "none").',
66
66
  },
@@ -517,6 +517,7 @@ To see `streamUI` in action, check out [these examples](#examples).
517
517
  {
518
518
  name: 'response',
519
519
  type: 'Response',
520
+ isOptional: true,
520
521
  description: 'Optional response data.',
521
522
  properties: [
522
523
  {
@@ -99,7 +99,7 @@ To see `WorkflowAgent` in action, check out [these examples](#examples).
99
99
  type: 'StopCondition | StopCondition[]',
100
100
  isOptional: true,
101
101
  description:
102
- 'Default stop condition for the agent loop. When omitted, WorkflowAgent has no maximum step count and continues until natural completion. Use `isStepCount()` to bound execution. Per-stream values override this default.',
102
+ 'Default stop condition for the agent loop. When omitted, generate defaults to 20 steps, while stream has no maximum step count. Use `isStepCount()` to bound execution. Per-call values override this default.',
103
103
  },
104
104
  {
105
105
  name: 'activeTools',
@@ -478,6 +478,43 @@ To see `WorkflowAgent` in action, check out [these examples](#examples).
478
478
 
479
479
  ## Methods
480
480
 
481
+ ### `generate()`
482
+
483
+ Runs the durable agent loop using the model's non-streaming `doGenerate()` method. Model calls and tool execution use the same orchestration as `stream()`.
484
+
485
+ ```ts
486
+ const result = await agent.generate({ prompt: 'Summarize the findings.' });
487
+ console.log(result.text);
488
+ console.log(result.usage);
489
+ ```
490
+
491
+ Accepts `WorkflowAgentGenerateOptions`, sharing prompt/messages, instructions, generation settings, tools and runtime context, preparation, stopping, output, and lifecycle options with `stream()`. It does not accept `writable`, `includeRawChunks`, `experimental_transform`, `sendFinish`, or `preventClose`. Without a configured stop condition, generation stops after at most 20 steps. `stream()` retains its existing unbounded default.
492
+
493
+ The `include` option accepts `requestBody`, `responseBody`, and `requestMessages` booleans, all defaulting to `false`. Enable them only when the additional request/response data is needed. Response IDs, timestamps, model IDs, headers, and provider metadata are retained when supplied by the model.
494
+
495
+ #### Returns
496
+
497
+ Returns `Promise<WorkflowAgentGenerateResult>` with the core [`GenerateTextResult`](/docs/reference/ai-sdk-core/generate-text#returns) semantics:
498
+
499
+ - `text`, `finishReason`, `rawFinishReason`, and `finalStep` describe the final step.
500
+ - `content`, `files`, `sources`, `warnings`, tool calls, and tool results cover all steps.
501
+ - `usage` and `totalUsage` sum all steps while retaining token details and unknown counts.
502
+ - `responseMessages` includes generated messages, even when `prepareStep` replaces the input history.
503
+ - `output` defaults to text, or follows the constructor/per-call output specification. Reading it throws `NoOutputGeneratedError` when output is unavailable, such as a final `tool-calls` response.
504
+
505
+ Inside a workflow, `timeout` bounds model calls, including retries and dispatch after suspension. It does not cancel a hook that a tool is waiting on. Use the Workflow runtime’s `run.cancel()` to stop a suspended run. See [deadlines, cancellation, and replay](/docs/agents/workflow-agent#deadlines-cancellation-and-replay).
506
+
507
+ Generation failures reject. The end callback runs before complete-output parsing; a parsing failure can therefore reject after `onEnd` has run. Existing Workflow callback shapes and preparation precedence apply; they are not all identical to core's callback APIs.
508
+
509
+ <Note>
510
+ Use the result API inside workflow code and return selected serializable
511
+ fields (for example, `text` and `usage`) through `run.returnValue`. Returning
512
+ the whole result class is not supported. Performance data currently measures
513
+ the model response; complete tool/step timing is not yet reported.
514
+ </Note>
515
+
516
+ Approval requests appear in `content` and `responseMessages` without requiring a writable. To continue, append `responseMessages` to the original history and add a tool message containing the user's `tool-approval-response`. Preserve the request signature and tool-call input; use the same `experimental_toolApprovalSecret` environment-variable reference on continuation. Local approvals are validated before execution, and provider-executed approval responses are forwarded to the provider. See [approval round trips](/docs/agents/workflow-agent#approval-round-trips-without-streaming).
517
+
481
518
  ### `stream()`
482
519
 
483
520
  Runs the agent loop, streaming responses and executing tool calls as needed. Returns a promise resolving to a `WorkflowAgentStreamResult`.
@@ -549,7 +586,7 @@ const result = await agent.stream({
549
586
  name: 'timeout',
550
587
  type: 'number',
551
588
  isOptional: true,
552
- description: 'Timeout in milliseconds. Creates an AbortSignal that aborts the operation after the given time.',
589
+ description: 'Model-call deadline in milliseconds. Inside a workflow, the absolute deadline is checked at dispatch and retry and remains in effect across suspension. It does not cancel a tool waiting on a Workflow hook; use run.cancel() to stop the suspended run.',
553
590
  },
554
591
  {
555
592
  name: 'sendFinish',
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: AI_DecisionUnsupportedQuestionTypeError
3
+ description: Identify a decision question type that a model does not support.
4
+ ---
5
+
6
+ # AI_DecisionUnsupportedQuestionTypeError
7
+
8
+ This experimental error identifies a question whose type is unsupported by a
9
+ decision model. It is exported from `ai` and `@ai-sdk/provider` as
10
+ `Experimental_DecisionUnsupportedQuestionTypeError`.
11
+
12
+ ## Properties
13
+
14
+ - `questionId`: The ID of the unsupported question.
15
+ - `questionType`: The requested question type.
16
+ - `provider`: The provider of the decision model.
17
+ - `modelId`: The decision model ID.
18
+ - `message`: A description of the unsupported question and model. Providers can
19
+ supply a custom message.
20
+
21
+ ## Checking for this Error
22
+
23
+ Use the marker-based `isInstance` check, which works across package copies:
24
+
25
+ ```typescript
26
+ import { Experimental_DecisionUnsupportedQuestionTypeError as DecisionUnsupportedQuestionTypeError } from 'ai';
27
+
28
+ if (DecisionUnsupportedQuestionTypeError.isInstance(error)) {
29
+ console.log(error.questionId, error.questionType, error.modelId);
30
+ }
31
+ ```
@@ -25,6 +25,6 @@ if (NoSuchModelError.isInstance(error)) {
25
25
  }
26
26
  ```
27
27
 
28
- Experimental evaluation resolution uses `modelType: 'evaluationModel'`. This
29
- includes unavailable evaluation capabilities and unknown evaluation model or
30
- provider IDs. See [Evaluation](/docs/ai-sdk-core/evaluation#default-provider-strings).
28
+ Experimental decision resolution uses `modelType: 'decisionModel'`. This
29
+ includes unavailable decision capabilities and unknown decision model or
30
+ provider IDs. See [Decisions](/docs/ai-sdk-core/decisions#default-provider-strings).
@@ -27,6 +27,6 @@ if (NoSuchProviderError.isInstance(error)) {
27
27
  }
28
28
  ```
29
29
 
30
- Experimental evaluation resolution uses `modelType: 'evaluationModel'`. This
31
- includes unavailable evaluation capabilities and unknown evaluation model or
32
- provider IDs. See [Evaluation](/docs/ai-sdk-core/evaluation#default-provider-strings).
30
+ Experimental decision resolution uses `modelType: 'decisionModel'`. This
31
+ includes unavailable decision capabilities and unknown decision model or
32
+ provider IDs. See [Decisions](/docs/ai-sdk-core/decisions#default-provider-strings).
@@ -1385,7 +1385,7 @@ if (isToolUIPart(part)) {
1385
1385
 
1386
1386
  The deprecated tool result content part of `{ type: 'media' }` has been removed in AI SDK 7.
1387
1387
 
1388
- Use `{ type: 'file-data' }` for all inline file content, including images.
1388
+ Use `{ type: 'file', mediaType, data: { type: 'data', data } }` for inline tool-result file content, including images, as described below. The legacy `file-data` variant still works through runtime auto-migration, but is deprecated.
1389
1389
 
1390
1390
  #### Tool Result Content: Migrate Away From `image-*` and `file-*` variants to `file`
1391
1391
 
@@ -944,7 +944,7 @@ import { useAssistant } from '@ai-sdk/react';
944
944
  code manually.
945
945
  </Note>
946
946
 
947
- The `threadId` and `messageId` parameters have been removed from the `AssistantResponse` function.
947
+ The `threadId` and `messageId` properties have been removed from the argument passed to the `AssistantResponse` callback. The initial response options passed to `AssistantResponse` still require both IDs.
948
948
  Please use the `threadId` and `messageId` variables from the outer scope instead.
949
949
 
950
950
  ```ts filename="AI SDK 3.4"
@@ -57,14 +57,14 @@ const { messages, sendMessage, addToolOutput } = useChat({
57
57
  try {
58
58
  const result = await getLocationData();
59
59
 
60
- // Important: Don't await inside onToolCall to avoid deadlocks
60
+ // Important: Don't await addToolOutput inside onToolCall to avoid deadlocks
61
61
  addToolOutput({
62
62
  tool: 'getLocation',
63
63
  toolCallId: toolCall.toolCallId,
64
64
  output: result,
65
65
  });
66
66
  } catch (err) {
67
- // Important: Don't await inside onToolCall to avoid deadlocks
67
+ // Important: Don't await addToolOutput inside onToolCall to avoid deadlocks
68
68
  addToolOutput({
69
69
  tool: 'getLocation',
70
70
  toolCallId: toolCall.toolCallId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "7.0.127",
3
+ "version": "7.0.129",
4
4
  "type": "module",
5
5
  "description": "AI SDK by Vercel - build apps like ChatGPT, Claude, Gemini, and more with a single interface for any model using the Vercel AI Gateway or go direct to OpenAI, Anthropic, Google, or any other model provider.",
6
6
  "license": "Apache-2.0",
@@ -42,30 +42,30 @@
42
42
  }
43
43
  },
44
44
  "dependencies": {
45
- "@ai-sdk/gateway": "4.0.103",
46
- "@ai-sdk/provider": "4.0.21",
47
- "@ai-sdk/provider-utils": "5.0.53"
45
+ "@ai-sdk/gateway": "4.0.105",
46
+ "@ai-sdk/provider": "4.0.23",
47
+ "@ai-sdk/provider-utils": "5.0.55"
48
48
  },
49
49
  "devDependencies": {
50
- "@ai-sdk/amazon-bedrock": "5.0.105",
51
- "@ai-sdk/deepseek": "3.0.58",
52
- "@ai-sdk/google": "4.0.87",
53
- "@ai-sdk/groq": "4.0.54",
54
- "@ai-sdk/huggingface": "2.0.62",
55
- "@ai-sdk/moonshotai": "3.0.62",
56
- "@ai-sdk/openai": "4.0.83",
57
- "@ai-sdk/test-server": "2.0.3",
58
- "@ai-sdk/xai": "5.0.14",
50
+ "@ai-sdk/amazon-bedrock": "5.0.107",
51
+ "@ai-sdk/deepseek": "3.0.60",
52
+ "@ai-sdk/google": "4.0.89",
53
+ "@ai-sdk/groq": "4.0.56",
54
+ "@ai-sdk/huggingface": "2.0.64",
55
+ "@ai-sdk/moonshotai": "3.0.64",
56
+ "@ai-sdk/openai": "4.0.85",
57
+ "@ai-sdk/test-server": "2.0.4",
58
+ "@ai-sdk/xai": "5.0.16",
59
59
  "@edge-runtime/vm": "^5.0.0",
60
60
  "@smithy/eventstream-codec": "^4.3.3",
61
61
  "@smithy/util-utf8": "^4.3.3",
62
62
  "@types/json-schema": "7.0.15",
63
63
  "@types/node": "22.19.19",
64
64
  "@vercel/ai-tsconfig": "0.0.0",
65
- "esbuild": "^0.28.1",
65
+ "esbuild": "^0.28.2",
66
66
  "tsdown": "^0.23.0",
67
67
  "tsx": "4.23.12",
68
- "typescript": "5.8.3",
68
+ "typescript": "6.0.3",
69
69
  "zod": "3.25.76"
70
70
  },
71
71
  "peerDependencies": {
@@ -0,0 +1,129 @@
1
+ import type {
2
+ Experimental_DecisionModelV4CallOptions as DecisionModelV4CallOptions,
3
+ Experimental_DecisionModelV4Result as DecisionModelV4Result,
4
+ } from '@ai-sdk/provider';
5
+ import type { Context, ProviderOptions } from '@ai-sdk/provider-utils';
6
+ import type { DecisionQuestion, DecisionResult } from './decision-result';
7
+
8
+ /**
9
+ * Event passed to the `onStart` callback for decision operations.
10
+ *
11
+ * Called when the operation begins, before the decision model is called.
12
+ */
13
+ export type DecideStartEvent<RUNTIME_CONTEXT extends Context = Context> = {
14
+ /** User-defined runtime context. */
15
+ readonly runtimeContext: RUNTIME_CONTEXT;
16
+
17
+ /** Unique identifier for this decision call, used to correlate events. */
18
+ readonly callId: string;
19
+
20
+ /** Identifies the operation type (`ai.decide`). */
21
+ readonly operationId: 'ai.decide';
22
+
23
+ /** The provider identifier. */
24
+ readonly provider: string;
25
+
26
+ /** The decision model identifier. */
27
+ readonly modelId: string;
28
+
29
+ /** The shared state used to make decisions. */
30
+ readonly state: DecisionModelV4CallOptions['state'];
31
+
32
+ /** The questions to decide against the shared state. */
33
+ readonly questions: Readonly<Record<string, DecisionQuestion>>;
34
+
35
+ /** Maximum number of retries for the decision model call. */
36
+ readonly maxRetries: number;
37
+
38
+ /** Additional HTTP headers sent with the request. */
39
+ readonly headers: Record<string, string> | undefined;
40
+
41
+ /** Additional provider-specific options. */
42
+ readonly providerOptions: ProviderOptions;
43
+ };
44
+
45
+ /**
46
+ * Event passed to the `onEnd` callback for decision operations.
47
+ *
48
+ * Called when the operation completes successfully.
49
+ */
50
+ export type DecideEndEvent<RUNTIME_CONTEXT extends Context = Context> =
51
+ DecideStartEvent<RUNTIME_CONTEXT> & {
52
+ /** Exactly one typed answer per question ID. */
53
+ readonly answers: DecisionResult<
54
+ Record<string, DecisionQuestion>
55
+ >['answers'];
56
+
57
+ /** Token usage for the decision operation. */
58
+ readonly usage: DecisionResult<Record<string, DecisionQuestion>>['usage'];
59
+
60
+ /** Warnings from the decision model. */
61
+ readonly warnings: DecisionResult<
62
+ Record<string, DecisionQuestion>
63
+ >['warnings'];
64
+
65
+ /** Provider-declared decimal precision for probabilities and scores. */
66
+ readonly rounding: DecisionResult<
67
+ Record<string, DecisionQuestion>
68
+ >['rounding'];
69
+
70
+ /** Optional provider-specific metadata. */
71
+ readonly providerMetadata: DecisionResult<
72
+ Record<string, DecisionQuestion>
73
+ >['providerMetadata'];
74
+
75
+ /** Response metadata, including the resolved model ID and timestamp. */
76
+ readonly response: DecisionResult<
77
+ Record<string, DecisionQuestion>
78
+ >['response'];
79
+ };
80
+
81
+ /**
82
+ * Event fired when the decision model call begins.
83
+ *
84
+ * The logical model call includes any provider retries.
85
+ */
86
+ export type DecisionModelCallStartEvent = {
87
+ /** Unique identifier for the outer decision call. */
88
+ readonly callId: string;
89
+
90
+ /** Identifies the inner operation (`ai.decide.doDecide`). */
91
+ readonly operationId: 'ai.decide.doDecide';
92
+
93
+ /** The provider identifier. */
94
+ readonly provider: string;
95
+
96
+ /** The decision model identifier. */
97
+ readonly modelId: string;
98
+
99
+ /** The shared state used to make decisions. */
100
+ readonly state: DecisionModelV4CallOptions['state'];
101
+
102
+ /** The questions to decide against the shared state. */
103
+ readonly questions: Readonly<Record<string, DecisionQuestion>>;
104
+ };
105
+
106
+ /**
107
+ * Event fired after the decision model response has been validated.
108
+ *
109
+ * Contains the result of the logical model call, including any retries.
110
+ */
111
+ export type DecisionModelCallEndEvent = DecisionModelCallStartEvent & {
112
+ /** Exactly one answer per question ID. */
113
+ readonly answers: DecisionModelV4Result['answers'];
114
+
115
+ /** Token usage reported by the decision model. */
116
+ readonly usage?: DecisionModelV4Result['usage'];
117
+
118
+ /** Warnings from the decision model. */
119
+ readonly warnings: DecisionModelV4Result['warnings'];
120
+
121
+ /** Provider-declared decimal precision for probabilities and scores. */
122
+ readonly rounding?: DecisionModelV4Result['rounding'];
123
+
124
+ /** Optional provider-specific metadata. */
125
+ readonly providerMetadata?: DecisionModelV4Result['providerMetadata'];
126
+
127
+ /** Optional raw response metadata from the provider. */
128
+ readonly response?: DecisionModelV4Result['response'];
129
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
- Experimental_EvaluationUnsupportedQuestionTypeError as EvaluationUnsupportedQuestionTypeError,
3
- type Experimental_EvaluationModelV4CallOptions as EvaluationModelV4CallOptions,
2
+ Experimental_DecisionUnsupportedQuestionTypeError as DecisionUnsupportedQuestionTypeError,
3
+ type Experimental_DecisionModelV4CallOptions as DecisionModelV4CallOptions,
4
4
  } from '@ai-sdk/provider';
5
5
  import {
6
6
  createIdGenerator,
@@ -8,33 +8,33 @@ import {
8
8
  type Context,
9
9
  type ProviderOptions,
10
10
  } from '@ai-sdk/provider-utils';
11
- import { resolveEvaluationModel } from '../model/resolve-model';
11
+ import { resolveDecisionModel } from '../model/resolve-model';
12
12
  import { logWarnings } from '../logger/log-warnings';
13
13
  import type { TelemetryOptions } from '../telemetry/telemetry-options';
14
14
  import type { Callback } from '../util/callback';
15
15
  import { notify } from '../util/notify';
16
16
  import { prepareRetries } from '../util/prepare-retries';
17
17
  import { VERSION } from '../version';
18
- import type { EvaluateEndEvent, EvaluateStartEvent } from './evaluate-events';
18
+ import type { DecideEndEvent, DecideStartEvent } from './decide-events';
19
19
  import type {
20
- EvaluationModel,
21
- EvaluationQuestion,
22
- EvaluationResult,
23
- } from './evaluation-result';
20
+ DecisionModel,
21
+ DecisionQuestion,
22
+ DecisionResult,
23
+ } from './decision-result';
24
24
  import { createRestrictedTelemetryDispatcher } from './restricted-telemetry-dispatcher';
25
25
  import {
26
- validateEvaluationInput,
27
- validateEvaluationAnswers,
28
- } from './validate-evaluation';
26
+ validateDecisionInput,
27
+ validateDecisionAnswers,
28
+ } from './validate-decision';
29
29
 
30
30
  const originalGenerateCallId = createIdGenerator({
31
31
  prefix: 'call',
32
32
  size: 24,
33
33
  });
34
34
 
35
- /** Evaluate typed questions against one shared state. Experimental. */
36
- export async function evaluate<
37
- const QUESTIONS extends Record<string, EvaluationQuestion>,
35
+ /** Decide answers to typed questions against one shared state. Experimental. */
36
+ export async function decide<
37
+ const QUESTIONS extends Record<string, DecisionQuestion>,
38
38
  RUNTIME_CONTEXT extends Context = Context,
39
39
  >({
40
40
  model: modelArg,
@@ -50,9 +50,9 @@ export async function evaluate<
50
50
  onEnd,
51
51
  _internal: { generateCallId = originalGenerateCallId } = {},
52
52
  }: {
53
- /** An evaluation model instance or an ID resolved by the configured default provider. */
54
- model: EvaluationModel;
55
- state: EvaluationModelV4CallOptions['state'];
53
+ /** A decision model instance or an ID resolved by the configured default provider. */
54
+ model: DecisionModel;
55
+ state: DecisionModelV4CallOptions['state'];
56
56
  questions: QUESTIONS;
57
57
  /** Maximum retries for transient provider failures. Defaults to 2. */
58
58
  maxRetries?: number;
@@ -63,22 +63,22 @@ export async function evaluate<
63
63
  telemetry?: TelemetryOptions<RUNTIME_CONTEXT>;
64
64
  /** User-defined runtime context. Treat runtime context as immutable. */
65
65
  runtimeContext?: RUNTIME_CONTEXT;
66
- /** Called when the evaluate operation begins. */
67
- onStart?: Callback<EvaluateStartEvent<RUNTIME_CONTEXT>>;
68
- /** Called when the evaluate operation completes. */
69
- onEnd?: Callback<EvaluateEndEvent<RUNTIME_CONTEXT>>;
66
+ /** Called when the decide operation begins. */
67
+ onStart?: Callback<DecideStartEvent<RUNTIME_CONTEXT>>;
68
+ /** Called when the decide operation completes. */
69
+ onEnd?: Callback<DecideEndEvent<RUNTIME_CONTEXT>>;
70
70
  /** Internal. For test use only. May change without notice. */
71
71
  _internal?: {
72
72
  generateCallId?: () => string;
73
73
  };
74
- }): Promise<EvaluationResult<QUESTIONS>> {
75
- const model = resolveEvaluationModel(modelArg);
74
+ }): Promise<DecisionResult<QUESTIONS>> {
75
+ const model = resolveDecisionModel(modelArg);
76
76
 
77
- validateEvaluationInput({ state, questions });
77
+ validateDecisionInput({ state, questions });
78
78
 
79
79
  for (const [questionId, question] of Object.entries(questions)) {
80
80
  if (!model.supportedQuestionTypes.includes(question.type)) {
81
- throw new EvaluationUnsupportedQuestionTypeError({
81
+ throw new DecisionUnsupportedQuestionTypeError({
82
82
  questionId,
83
83
  questionType: question.type,
84
84
  provider: model.provider,
@@ -101,7 +101,7 @@ export async function evaluate<
101
101
  await execute());
102
102
  const startEvent = {
103
103
  callId,
104
- operationId: 'ai.evaluate' as const,
104
+ operationId: 'ai.decide' as const,
105
105
  runtimeContext,
106
106
  provider: model.provider,
107
107
  modelId: model.modelId,
@@ -112,7 +112,7 @@ export async function evaluate<
112
112
  providerOptions,
113
113
  };
114
114
  return await runInTracingChannelSpan({
115
- type: 'experimental_evaluate',
115
+ type: 'experimental_decide',
116
116
  event: startEvent,
117
117
  execute: async () => {
118
118
  await notify({
@@ -123,7 +123,7 @@ export async function evaluate<
123
123
  try {
124
124
  const modelCallEvent = {
125
125
  callId,
126
- operationId: 'ai.evaluate.doEvaluate' as const,
126
+ operationId: 'ai.decide.doDecide' as const,
127
127
  provider: model.provider,
128
128
  modelId: model.modelId,
129
129
  state,
@@ -132,12 +132,12 @@ export async function evaluate<
132
132
  await notify({
133
133
  event: modelCallEvent,
134
134
  callbacks: [
135
- telemetryDispatcher.experimental_onEvaluationModelCallStart,
135
+ telemetryDispatcher.experimental_onDecisionModelCallStart,
136
136
  ],
137
137
  });
138
138
  const result = await retry(async () => {
139
139
  abortSignal?.throwIfAborted();
140
- return await model.doEvaluate({
140
+ return await model.doDecide({
141
141
  state,
142
142
  questions,
143
143
  abortSignal,
@@ -147,16 +147,14 @@ export async function evaluate<
147
147
  });
148
148
 
149
149
  abortSignal?.throwIfAborted();
150
- validateEvaluationAnswers({
150
+ validateDecisionAnswers({
151
151
  questions,
152
152
  answers: result.answers,
153
153
  rounding: result.rounding,
154
154
  });
155
155
  await notify({
156
156
  event: { ...modelCallEvent, ...result },
157
- callbacks: [
158
- telemetryDispatcher.experimental_onEvaluationModelCallEnd,
159
- ],
157
+ callbacks: [telemetryDispatcher.experimental_onDecisionModelCallEnd],
160
158
  });
161
159
 
162
160
  logWarnings({
@@ -167,8 +165,8 @@ export async function evaluate<
167
165
 
168
166
  const inputTokens = result.usage?.inputTokens;
169
167
  const outputTokens = result.usage?.outputTokens;
170
- const evaluationResult: EvaluationResult<QUESTIONS> = {
171
- answers: result.answers as EvaluationResult<QUESTIONS>['answers'],
168
+ const decisionResult: DecisionResult<QUESTIONS> = {
169
+ answers: result.answers as DecisionResult<QUESTIONS>['answers'],
172
170
  usage: {
173
171
  inputTokens,
174
172
  outputTokens,
@@ -188,11 +186,11 @@ export async function evaluate<
188
186
  };
189
187
 
190
188
  await notify({
191
- event: { ...startEvent, ...evaluationResult },
189
+ event: { ...startEvent, ...decisionResult },
192
190
  callbacks: [onEnd, telemetryDispatcher.onEnd],
193
191
  });
194
192
 
195
- return evaluationResult;
193
+ return decisionResult;
196
194
  } catch (error) {
197
195
  await telemetryDispatcher.onError?.({ callId, error });
198
196
  throw error;
@@ -0,0 +1,11 @@
1
+ import type {
2
+ Experimental_DecisionModelV4 as DecisionModelV4,
3
+ Experimental_EvaluationModelV4 as EvaluationModelV4,
4
+ } from '@ai-sdk/provider';
5
+
6
+ /** Structural extension; decision is not part of the stable provider contract. */
7
+ export type DecisionProvider = {
8
+ decisionModel?: (modelId: string) => DecisionModelV4;
9
+ /** @deprecated Use `decisionModel` instead. */
10
+ evaluationModel?: (modelId: string) => EvaluationModelV4;
11
+ };