ai 7.0.124 → 7.0.126

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.
@@ -111,7 +111,7 @@ function asAsyncIterableStream(stream) {
111
111
  }
112
112
  //#endregion
113
113
  //#region src/version.ts
114
- const VERSION = "7.0.124";
114
+ const VERSION = "7.0.126";
115
115
  //#endregion
116
116
  //#region src/util/download/download.ts
117
117
  /**
@@ -178,6 +178,31 @@ transports by providing an `authProvider`.
178
178
 
179
179
  </Note>
180
180
 
181
+ ### Shared OAuth Credential Storage
182
+
183
+ When multiple MCP clients or replicas share OAuth credentials, a rotating refresh
184
+ token can be used concurrently. One refresh may save new tokens while another
185
+ receives `invalid_grant` for the old refresh token.
186
+
187
+ The optional `OAuthClientProvider.invalidateCredentials` method receives a
188
+ second argument identifying the tokens used by a failed refresh:
189
+
190
+ ```typescript
191
+ invalidateCredentials(
192
+ scope: 'all' | 'client' | 'tokens' | 'verifier',
193
+ context?: { tokens: OAuthTokens },
194
+ ): void | Promise<void>;
195
+ ```
196
+
197
+ For `scope === 'tokens'` with a context, delete the credential only if the stored
198
+ access and refresh tokens still match `context.tokens`. The comparison and
199
+ deletion must be atomic, using a conditional database operation or a transaction.
200
+ If they no longer match, leave the newer tokens in storage. The SDK retries
201
+ authorization and reads the stored tokens again.
202
+
203
+ The SDK also provides this context when invalidating stored tokens that lack an
204
+ authorization server pin. Other invalidations can omit the context.
205
+
181
206
  ### OAuth Authorization Server Validation
182
207
 
183
208
  When using MCP OAuth in server-side applications, the MCP server can advertise
@@ -343,7 +343,8 @@ try {
343
343
  | [Groq](/providers/ai-sdk-providers/groq#transcription-models) | `whisper-large-v3` |
344
344
  | [Mistral](/providers/ai-sdk-providers/mistral#transcription-models) | `voxtral-mini-latest` |
345
345
  | [Azure OpenAI](/providers/ai-sdk-providers/azure#transcription-models) | `whisper-1` |
346
- | [Azure Speech](/providers/ai-sdk-providers/azure#mai-transcribe-2) | `mai-transcribe-2` |
346
+ | [Azure Speech](/providers/ai-sdk-providers/azure#mai-transcribe) | `mai-transcribe-2` |
347
+ | [Azure Speech](/providers/ai-sdk-providers/azure#mai-transcribe) | `mai-transcribe-1.5` |
347
348
  | [Azure OpenAI](/providers/ai-sdk-providers/azure#transcription-models) | `gpt-4o-transcribe` |
348
349
  | [Azure OpenAI](/providers/ai-sdk-providers/azure#transcription-models) | `gpt-4o-mini-transcribe` |
349
350
  | [Rev.ai](/providers/ai-sdk-providers/revai#transcription-models) | `machine` |
@@ -158,6 +158,8 @@ try {
158
158
  | [OpenAI](/providers/ai-sdk-providers/openai#speech-models) | `tts-1-hd` |
159
159
  | [OpenAI](/providers/ai-sdk-providers/openai#speech-models) | `gpt-4o-mini-tts` |
160
160
  | [Mistral](/providers/ai-sdk-providers/mistral#speech-models) | `voxtral-mini-tts-2603` |
161
+ | [Azure Speech](/providers/ai-sdk-providers/azure#mai-voice) | `mai-voice-2-flash` |
162
+ | [Azure Speech](/providers/ai-sdk-providers/azure#mai-voice) | `mai-voice-2` |
161
163
  | [ElevenLabs](/providers/ai-sdk-providers/elevenlabs#speech-models) | `eleven_v3` |
162
164
  | [ElevenLabs](/providers/ai-sdk-providers/elevenlabs#speech-models) | `eleven_multilingual_v2` |
163
165
  | [ElevenLabs](/providers/ai-sdk-providers/elevenlabs#speech-models) | `eleven_flash_v2_5` |
@@ -59,6 +59,13 @@ export async function* streamAgent(
59
59
  description:
60
60
  'Array of input UI message objects (e.g., user/assistant/chat history). These will be validated and converted for the agent.',
61
61
  },
62
+ {
63
+ name: 'convertDataPart',
64
+ type: '(part: DataUIPart) => TextPart | FilePart | undefined',
65
+ isRequired: false,
66
+ description:
67
+ 'Converts custom UI data parts into text or file parts for the model. Data parts are ignored when this callback is omitted or returns undefined.',
68
+ },
62
69
  {
63
70
  name: 'abortSignal',
64
71
  type: 'AbortSignal',
@@ -57,6 +57,13 @@ export async function POST(request: Request) {
57
57
  description:
58
58
  'Array of input UI messages provided to the agent (e.g., user and assistant messages).',
59
59
  },
60
+ {
61
+ name: 'convertDataPart',
62
+ type: '(part: DataUIPart) => TextPart | FilePart | undefined',
63
+ isRequired: false,
64
+ description:
65
+ 'Converts custom UI data parts into text or file parts for the model. Data parts are ignored when this callback is omitted or returns undefined.',
66
+ },
60
67
  {
61
68
  name: 'abortSignal',
62
69
  type: 'AbortSignal',
@@ -61,6 +61,13 @@ export async function handler(req, res) {
61
61
  description:
62
62
  'Array of input UI messages sent to the agent (such as user/assistant message objects).',
63
63
  },
64
+ {
65
+ name: 'convertDataPart',
66
+ type: '(part: DataUIPart) => TextPart | FilePart | undefined',
67
+ isRequired: false,
68
+ description:
69
+ 'Converts custom UI data parts into text or file parts for the model. Data parts are ignored when this callback is omitted or returns undefined.',
70
+ },
64
71
  {
65
72
  name: 'abortSignal',
66
73
  type: 'AbortSignal',
@@ -120,7 +120,7 @@ To see `WorkflowAgent` in action, check out [these examples](#examples).
120
120
  type: 'ToolCallRepairFunction',
121
121
  isOptional: true,
122
122
  description:
123
- 'Default function to repair tool calls that fail to parse. Per-stream values override this default.',
123
+ "Default function to repair tool calls that fail to parse. Mark the function with 'use step' when used in a workflow. Per-stream values override this default.",
124
124
  },
125
125
  {
126
126
  name: 'experimental_download',
@@ -573,13 +573,13 @@ const result = await agent.stream({
573
573
  name: 'repairToolCall',
574
574
  type: 'ToolCallRepairFunction',
575
575
  isOptional: true,
576
- description: 'Callback to attempt automatic recovery when a tool call cannot be parsed.',
576
+ description: "Callback to attempt automatic recovery when a tool call cannot be parsed. Mark the function with 'use step' when used in a workflow.",
577
577
  },
578
578
  {
579
579
  name: 'experimental_transform',
580
580
  type: 'StreamTextTransform | Array<StreamTextTransform>',
581
581
  isOptional: true,
582
- description: 'Stream transformations applied in order. Must maintain the stream structure.',
582
+ description: "Factories for stream transformations, applied in order to raw provider events before model processing and writable output. Each factory must return a TransformStream synchronously and maintain the stream structure. Mark each factory with 'use step' when used in a workflow.",
583
583
  },
584
584
  {
585
585
  name: 'experimental_download',
@@ -750,6 +750,63 @@ Returns a `Promise<WorkflowAgentStreamResult>` with the following properties:
750
750
  ]}
751
751
  />
752
752
 
753
+ ### `repairToolCall` in a workflow
754
+
755
+ `repairToolCall` runs inside the model step. When you use it in a workflow,
756
+ define the callback as a function with a `'use step'` directive. You can set
757
+ it on the constructor or pass it to `stream()`.
758
+
759
+ Workflow saves a reference to the registered function and loads its
760
+ implementation inside the model step. Keep any values captured by the
761
+ function serializable. An ordinary inline callback causes a serialization
762
+ error when it crosses this step boundary.
763
+
764
+ The callback can be asynchronous. Return the repaired tool call, or `null`
765
+ if the repair cannot be completed. See [tool call repair](/docs/ai-sdk-core/tools-and-tool-calling#tool-call-repair)
766
+ for repair strategies.
767
+
768
+ ### `experimental_transform` in a workflow
769
+
770
+ Pass a transform factory, or an array of factories, to `stream()`.
771
+ Mark each factory with `'use step'` so Workflow can load it inside the model
772
+ step. The factory must return a `TransformStream` synchronously. Keep any
773
+ captured values serializable.
774
+
775
+ ```ts
776
+ import type { LanguageModelV4StreamPart } from '@ai-sdk/provider';
777
+ import { WorkflowAgent } from '@ai-sdk/workflow';
778
+ import { getWritable } from 'workflow';
779
+
780
+ function uppercaseText() {
781
+ 'use step';
782
+
783
+ return new TransformStream<
784
+ LanguageModelV4StreamPart,
785
+ LanguageModelV4StreamPart
786
+ >({
787
+ transform(part, controller) {
788
+ controller.enqueue(
789
+ part.type === 'text-delta'
790
+ ? { ...part, delta: part.delta.toUpperCase() }
791
+ : part,
792
+ );
793
+ },
794
+ });
795
+ }
796
+
797
+ export async function uppercaseWorkflow() {
798
+ 'use workflow';
799
+
800
+ const agent = new WorkflowAgent({ model: 'openai/gpt-5' });
801
+
802
+ return agent.stream({
803
+ messages: [{ role: 'user', content: 'Write a short greeting.' }],
804
+ writable: getWritable(),
805
+ experimental_transform: uppercaseText,
806
+ });
807
+ }
808
+ ```
809
+
753
810
  ## Utilities
754
811
 
755
812
  ### `createModelCallToUIChunkTransform(options?)`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "7.0.124",
3
+ "version": "7.0.126",
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",
@@ -47,11 +47,11 @@
47
47
  "@ai-sdk/provider-utils": "5.0.53"
48
48
  },
49
49
  "devDependencies": {
50
- "@ai-sdk/amazon-bedrock": "5.0.103",
50
+ "@ai-sdk/amazon-bedrock": "5.0.104",
51
51
  "@ai-sdk/deepseek": "3.0.58",
52
52
  "@ai-sdk/google": "4.0.87",
53
53
  "@ai-sdk/groq": "4.0.54",
54
- "@ai-sdk/huggingface": "2.0.61",
54
+ "@ai-sdk/huggingface": "2.0.62",
55
55
  "@ai-sdk/moonshotai": "3.0.62",
56
56
  "@ai-sdk/openai": "4.0.83",
57
57
  "@ai-sdk/test-server": "2.0.3",
@@ -14,8 +14,9 @@ import type { UIMessageStreamOptions } from '../generate-text/stream-text-result
14
14
  import type { TimeoutConfiguration } from '../prompt/request-options';
15
15
  import { createUIMessageStreamResponse } from '../ui-message-stream';
16
16
  import type { UIMessageStreamResponseInit } from '../ui-message-stream/ui-message-stream-response-init';
17
- import type { InferUITools, UIMessage } from '../ui/ui-messages';
17
+ import type { InferUITools, UIMessage, UIDataTypes } from '../ui/ui-messages';
18
18
  import type { Agent } from './agent';
19
+ import type { convertToModelMessages } from '../ui/convert-to-model-messages';
19
20
  import { createAgentUIStream } from './create-agent-ui-stream';
20
21
 
21
22
  /**
@@ -23,6 +24,7 @@ import { createAgentUIStream } from './create-agent-ui-stream';
23
24
  *
24
25
  * @param agent - The agent to run.
25
26
  * @param uiMessages - The input UI messages.
27
+ * @param convertDataPart - Optional function to convert custom data parts to text or file model message parts.
26
28
  * @param abortSignal - Abort signal. Optional.
27
29
  * @param timeout - Timeout in milliseconds. Optional.
28
30
  * @param experimental_sandbox - The sandbox environment that is passed through to tool execution. Optional.
@@ -44,6 +46,11 @@ export async function createAgentUIStreamResponse<
44
46
  RUNTIME_CONTEXT extends Context = Context,
45
47
  OUTPUT extends Output = never,
46
48
  MESSAGE_METADATA = unknown,
49
+ UI_MESSAGE extends UIMessage<
50
+ MESSAGE_METADATA,
51
+ UIDataTypes,
52
+ InferUITools<TOOLS>
53
+ > = UIMessage<MESSAGE_METADATA, UIDataTypes, InferUITools<TOOLS>>,
47
54
  >({
48
55
  headers,
49
56
  status,
@@ -54,6 +61,13 @@ export async function createAgentUIStreamResponse<
54
61
  }: {
55
62
  agent: Agent<CALL_OPTIONS, TOOLS, RUNTIME_CONTEXT, OUTPUT>;
56
63
  uiMessages: unknown[];
64
+ /**
65
+ * Converts custom UI data parts to text or file model message parts.
66
+ * Data parts are ignored when omitted or when the callback returns undefined.
67
+ */
68
+ convertDataPart?: NonNullable<
69
+ Parameters<typeof convertToModelMessages<UI_MESSAGE>>[1]
70
+ >['convertDataPart'];
57
71
  abortSignal?: AbortSignal;
58
72
  timeout?: TimeoutConfiguration<TOOLS>;
59
73
  experimental_sandbox?: SandboxSession;
@@ -63,9 +77,7 @@ export async function createAgentUIStreamResponse<
63
77
  /** @deprecated Use `onStepEnd` instead. */
64
78
  onStepFinish?: GenerateTextOnStepFinishCallback<TOOLS>;
65
79
  } & UIMessageStreamResponseInit &
66
- UIMessageStreamOptions<
67
- UIMessage<MESSAGE_METADATA, never, InferUITools<TOOLS>>
68
- >): Promise<Response> {
80
+ UIMessageStreamOptions<UI_MESSAGE>): Promise<Response> {
69
81
  return createUIMessageStreamResponse({
70
82
  headers,
71
83
  status,
@@ -20,6 +20,7 @@ import type {
20
20
  InferUIMessageTools,
21
21
  InferUITools,
22
22
  UIMessage,
23
+ UIDataTypes,
23
24
  } from '../ui/ui-messages';
24
25
  import { validateUIMessagesForAgent } from '../ui/validate-ui-messages';
25
26
  import {
@@ -33,6 +34,7 @@ import type { Agent } from './agent';
33
34
  *
34
35
  * @param agent - The agent to run.
35
36
  * @param uiMessages - The input UI messages.
37
+ * @param convertDataPart - Optional function to convert custom data parts to text or file model message parts.
36
38
  * @param abortSignal - The abort signal. Optional.
37
39
  * @param timeout - Timeout in milliseconds. Optional.
38
40
  * @param experimental_sandbox - The sandbox environment that is passed through to tool execution. Optional.
@@ -49,11 +51,15 @@ export async function createAgentUIStream<
49
51
  RUNTIME_CONTEXT extends Context = Context,
50
52
  OUTPUT extends Output = never,
51
53
  MESSAGE_METADATA = unknown,
52
- UI_MESSAGE extends UIMessage<MESSAGE_METADATA, never, InferUITools<TOOLS>> =
53
- UIMessage<MESSAGE_METADATA, never, InferUITools<TOOLS>>,
54
+ UI_MESSAGE extends UIMessage<
55
+ MESSAGE_METADATA,
56
+ UIDataTypes,
57
+ InferUITools<TOOLS>
58
+ > = UIMessage<MESSAGE_METADATA, UIDataTypes, InferUITools<TOOLS>>,
54
59
  >({
55
60
  agent,
56
61
  uiMessages,
62
+ convertDataPart,
57
63
  options,
58
64
  abortSignal,
59
65
  timeout,
@@ -65,6 +71,13 @@ export async function createAgentUIStream<
65
71
  }: {
66
72
  agent: Agent<CALL_OPTIONS, TOOLS, RUNTIME_CONTEXT, OUTPUT>;
67
73
  uiMessages: unknown[];
74
+ /**
75
+ * Converts custom UI data parts to text or file model message parts.
76
+ * Data parts are ignored when omitted or when the callback returns undefined.
77
+ */
78
+ convertDataPart?: NonNullable<
79
+ Parameters<typeof convertToModelMessages<UI_MESSAGE>>[1]
80
+ >['convertDataPart'];
68
81
  abortSignal?: AbortSignal;
69
82
  timeout?: TimeoutConfiguration<TOOLS>;
70
83
  experimental_sandbox?: SandboxSession;
@@ -91,6 +104,7 @@ export async function createAgentUIStream<
91
104
 
92
105
  const modelMessages = await convertToModelMessages(validatedMessages, {
93
106
  tools: agent.tools,
107
+ convertDataPart,
94
108
  });
95
109
 
96
110
  const result = await agent.stream({
@@ -15,8 +15,9 @@ import type { UIMessageStreamOptions } from '../generate-text/stream-text-result
15
15
  import type { TimeoutConfiguration } from '../prompt/request-options';
16
16
  import { pipeUIMessageStreamToResponse } from '../ui-message-stream';
17
17
  import type { UIMessageStreamResponseInit } from '../ui-message-stream/ui-message-stream-response-init';
18
- import type { InferUITools, UIMessage } from '../ui/ui-messages';
18
+ import type { InferUITools, UIMessage, UIDataTypes } from '../ui/ui-messages';
19
19
  import type { Agent } from './agent';
20
+ import type { convertToModelMessages } from '../ui/convert-to-model-messages';
20
21
  import { createAgentUIStream } from './create-agent-ui-stream';
21
22
 
22
23
  /**
@@ -25,6 +26,7 @@ import { createAgentUIStream } from './create-agent-ui-stream';
25
26
  * @param response - The Node.js ServerResponse object to pipe to.
26
27
  * @param agent - The agent to run.
27
28
  * @param uiMessages - The input UI messages.
29
+ * @param convertDataPart - Optional function to convert custom data parts to text or file model message parts.
28
30
  * @param abortSignal - Abort signal. Optional.
29
31
  * @param timeout - Timeout in milliseconds. Optional.
30
32
  * @param experimental_sandbox - The sandbox environment that is passed through to tool execution. Optional.
@@ -44,6 +46,11 @@ export async function pipeAgentUIStreamToResponse<
44
46
  RUNTIME_CONTEXT extends Context = Context,
45
47
  OUTPUT extends Output = never,
46
48
  MESSAGE_METADATA = unknown,
49
+ UI_MESSAGE extends UIMessage<
50
+ MESSAGE_METADATA,
51
+ UIDataTypes,
52
+ InferUITools<TOOLS>
53
+ > = UIMessage<MESSAGE_METADATA, UIDataTypes, InferUITools<TOOLS>>,
47
54
  >({
48
55
  response,
49
56
  headers,
@@ -56,6 +63,13 @@ export async function pipeAgentUIStreamToResponse<
56
63
  response: ServerResponse;
57
64
  agent: Agent<CALL_OPTIONS, TOOLS, RUNTIME_CONTEXT, OUTPUT>;
58
65
  uiMessages: unknown[];
66
+ /**
67
+ * Converts custom UI data parts to text or file model message parts.
68
+ * Data parts are ignored when omitted or when the callback returns undefined.
69
+ */
70
+ convertDataPart?: NonNullable<
71
+ Parameters<typeof convertToModelMessages<UI_MESSAGE>>[1]
72
+ >['convertDataPart'];
59
73
  abortSignal?: AbortSignal;
60
74
  timeout?: TimeoutConfiguration<TOOLS>;
61
75
  experimental_sandbox?: SandboxSession;
@@ -65,9 +79,7 @@ export async function pipeAgentUIStreamToResponse<
65
79
  /** @deprecated Use `onStepEnd` instead. */
66
80
  onStepFinish?: GenerateTextOnStepFinishCallback<TOOLS>;
67
81
  } & UIMessageStreamResponseInit &
68
- UIMessageStreamOptions<
69
- UIMessage<MESSAGE_METADATA, never, InferUITools<TOOLS>>
70
- >): Promise<void> {
82
+ UIMessageStreamOptions<UI_MESSAGE>): Promise<void> {
71
83
  return pipeUIMessageStreamToResponse({
72
84
  response,
73
85
  headers,
package/src/ui/chat.ts CHANGED
@@ -609,7 +609,7 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
609
609
  });
610
610
 
611
611
  addToolOutput: ChatAddToolOutputFunction<UI_MESSAGE> = async ({
612
- state = 'output-available',
612
+ state,
613
613
  toolCallId,
614
614
  output,
615
615
  errorText,
@@ -621,10 +621,41 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
621
621
 
622
622
  const updatePart = (
623
623
  part: UIMessagePart<UIDataTypes, UITools>,
624
- ): UIMessagePart<UIDataTypes, UITools> =>
625
- isToolUIPart(part) && part.toolCallId === toolCallId
626
- ? ({ ...part, state, output, errorText } as typeof part)
627
- : part;
624
+ ): UIMessagePart<UIDataTypes, UITools> => {
625
+ if (!isToolUIPart(part) || part.toolCallId !== toolCallId) {
626
+ return part;
627
+ }
628
+
629
+ // Output states can only retain approvals that were granted.
630
+ const { approval: existingApproval, ...toolPart } = part;
631
+ const approval =
632
+ existingApproval?.approved === true
633
+ ? {
634
+ approval: {
635
+ ...existingApproval,
636
+ approved: existingApproval.approved,
637
+ },
638
+ }
639
+ : {};
640
+
641
+ return state === 'output-error'
642
+ ? {
643
+ ...toolPart,
644
+ ...approval,
645
+ state,
646
+ input: part.input,
647
+ output: undefined,
648
+ errorText,
649
+ }
650
+ : {
651
+ ...toolPart,
652
+ ...approval,
653
+ state: 'output-available',
654
+ input: part.input,
655
+ output,
656
+ errorText: undefined,
657
+ };
658
+ };
628
659
 
629
660
  // update the message to trigger an immediate UI update
630
661
  this.state.replaceMessage(messages.length - 1, {