ai 6.0.294 → 6.0.296

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.
@@ -164,7 +164,7 @@ function detectMediaType({
164
164
  var import_provider_utils2 = require("@ai-sdk/provider-utils");
165
165
 
166
166
  // src/version.ts
167
- var VERSION = true ? "6.0.294" : "0.0.0-test";
167
+ var VERSION = true ? "6.0.296" : "0.0.0-test";
168
168
 
169
169
  // src/util/download/download.ts
170
170
  var download = async ({
@@ -144,7 +144,7 @@ import {
144
144
  } from "@ai-sdk/provider-utils";
145
145
 
146
146
  // src/version.ts
147
- var VERSION = true ? "6.0.294" : "0.0.0-test";
147
+ var VERSION = true ? "6.0.296" : "0.0.0-test";
148
148
 
149
149
  // src/util/download/download.ts
150
150
  var download = async ({
@@ -142,6 +142,7 @@ Here are the capabilities of popular models:
142
142
  | [OpenAI](/providers/ai-sdk-providers/openai) | `gpt-5-chat-latest` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
143
143
  | [Anthropic](/providers/ai-sdk-providers/anthropic) | `claude-fable-5-1` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
144
144
  | [Anthropic](/providers/ai-sdk-providers/anthropic) | `claude-opus-5-5` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
145
+ | [Anthropic](/providers/ai-sdk-providers/anthropic) | `claude-sonnet-5-5` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
145
146
  | [Anthropic](/providers/ai-sdk-providers/anthropic) | `claude-sonnet-5` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
146
147
  | [Anthropic](/providers/ai-sdk-providers/anthropic) | `claude-fable-5` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
147
148
  | [Anthropic](/providers/ai-sdk-providers/anthropic) | `claude-opus-4-8` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
@@ -54,9 +54,9 @@ export async function* streamAgent(
54
54
  {
55
55
  name: 'uiMessages',
56
56
  type: 'unknown[]',
57
- isRequired: true,
57
+ isRequired: false,
58
58
  description:
59
- 'Array of input UI message objects (e.g., user/assistant/chat history). These will be validated and converted for the agent.',
59
+ 'Array of input UI message objects (e.g., user/assistant/chat history). These will be validated and converted for the agent. When omitted, originalMessages is used as the input.',
60
60
  },
61
61
  {
62
62
  name: 'abortSignal',
@@ -141,7 +141,7 @@ for await (const chunk of stream) {
141
141
 
142
142
  - The agent **must** implement the `.stream({ prompt, ... })` method and define its supported `tools` property.
143
143
  - This utility returns an async iterable for maximal streaming flexibility. For HTTP responses, see [`createAgentUIStreamResponse`](/docs/reference/ai-sdk-core/create-agent-ui-stream-response) (Web) or [`pipeAgentUIStreamToResponse`](/docs/reference/ai-sdk-core/pipe-agent-ui-stream-to-response) (Node.js).
144
- - The `uiMessages` parameter is named `uiMessages`, **not** just `messages`.
144
+ - The `uiMessages` parameter is named `uiMessages`, **not** just `messages`. It can be omitted when `originalMessages` is provided.
145
145
  - You can provide advanced options via `UIMessageStreamOptions` (for example, to include sources or usage).
146
146
  - To cancel the stream, pass an [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) via the `abortSignal` parameter.
147
147
 
@@ -55,9 +55,9 @@ export async function POST(request: Request) {
55
55
  {
56
56
  name: 'uiMessages',
57
57
  type: 'unknown[]',
58
- isRequired: true,
58
+ isRequired: false,
59
59
  description:
60
- 'Array of input UI messages provided to the agent (e.g., user and assistant messages).',
60
+ 'Array of input UI messages provided to the agent (e.g., user and assistant messages). When omitted, originalMessages is used as the input.',
61
61
  },
62
62
  {
63
63
  name: 'abortSignal',
@@ -56,9 +56,9 @@ export async function handler(req, res) {
56
56
  {
57
57
  name: 'uiMessages',
58
58
  type: 'unknown[]',
59
- isRequired: true,
59
+ isRequired: false,
60
60
  description:
61
- 'Array of input UI messages sent to the agent (such as user/assistant message objects).',
61
+ 'Array of input UI messages sent to the agent (such as user/assistant message objects). When omitted, originalMessages is used as the input.',
62
62
  },
63
63
  {
64
64
  name: 'abortSignal',
@@ -141,7 +141,7 @@ app.post('/chat', async (req, res) => {
141
141
  - **Abort Handling:** For best robustness, use an `AbortSignal` (for example, wired to Express/Hono client disconnects) to ensure quick cancellation of agent computation and streaming.
142
142
  - **Node.js Only:** Only works with Node.js [ServerResponse](https://nodejs.org/api/http.html#class-httpserverresponse) objects (e.g., in Express, Hono’s node adapter, etc.), not Edge/serverless/web Response APIs.
143
143
  - **Streaming Support:** Make sure your client (and any proxies) correctly support streaming HTTP responses for full effect.
144
- - **Parameter Names:** The property for input messages is `uiMessages` (not `messages`) for consistency with SDK agent utilities.
144
+ - **Parameter Names:** The property for input messages is `uiMessages` (not `messages`) for consistency with SDK agent utilities. It can be omitted when `originalMessages` is provided.
145
145
 
146
146
  ## See Also
147
147
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "6.0.294",
3
+ "version": "6.0.296",
4
4
  "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.",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@opentelemetry/api": "^1.9.0",
48
- "@ai-sdk/gateway": "3.0.204",
48
+ "@ai-sdk/gateway": "3.0.205",
49
49
  "@ai-sdk/provider": "3.0.18",
50
50
  "@ai-sdk/provider-utils": "4.0.56"
51
51
  },
@@ -16,7 +16,7 @@ import type { ToolLoopAgentOnStepFinishCallback } from './tool-loop-agent-settin
16
16
  * Runs the agent and returns a response object with a UI message stream.
17
17
  *
18
18
  * @param agent - The agent to run.
19
- * @param uiMessages - The input UI messages.
19
+ * @param uiMessages - The input UI messages. Defaults to originalMessages.
20
20
  * @param abortSignal - Abort signal. Optional.
21
21
  * @param timeout - Timeout in milliseconds. Optional.
22
22
  * @param options - The options for the agent. Optional.
@@ -42,7 +42,7 @@ export async function createAgentUIStreamResponse<
42
42
  ...options
43
43
  }: {
44
44
  agent: Agent<CALL_OPTIONS, TOOLS, OUTPUT>;
45
- uiMessages: unknown[];
45
+ uiMessages?: unknown[];
46
46
  abortSignal?: AbortSignal;
47
47
  timeout?: TimeoutConfiguration;
48
48
  options?: CALL_OPTIONS;
@@ -17,7 +17,7 @@ import type { ToolLoopAgentOnStepFinishCallback } from './tool-loop-agent-settin
17
17
  * Runs the agent and stream the output as a UI message stream.
18
18
  *
19
19
  * @param agent - The agent to run.
20
- * @param uiMessages - The input UI messages.
20
+ * @param uiMessages - The input UI messages. Defaults to originalMessages.
21
21
  * @param abortSignal - The abort signal. Optional.
22
22
  * @param timeout - Timeout in milliseconds. Optional.
23
23
  * @param options - The options for the agent.
@@ -42,7 +42,7 @@ export async function createAgentUIStream<
42
42
  ...uiMessageStreamOptions
43
43
  }: {
44
44
  agent: Agent<CALL_OPTIONS, TOOLS, OUTPUT>;
45
- uiMessages: unknown[];
45
+ uiMessages?: unknown[];
46
46
  abortSignal?: AbortSignal;
47
47
  timeout?: TimeoutConfiguration;
48
48
  options?: CALL_OPTIONS;
@@ -58,10 +58,12 @@ export async function createAgentUIStream<
58
58
  InferUIMessageChunk<UIMessage<MESSAGE_METADATA, never, InferUITools<TOOLS>>>
59
59
  >
60
60
  > {
61
+ const inputMessages = uiMessages ?? uiMessageStreamOptions.originalMessages;
62
+
61
63
  const validatedMessages = await validateUIMessagesForAgent<
62
64
  UIMessage<MESSAGE_METADATA, never, InferUITools<TOOLS>>
63
65
  >({
64
- messages: uiMessages,
66
+ messages: inputMessages,
65
67
  tools: agent.tools,
66
68
  });
67
69
 
@@ -18,7 +18,7 @@ import type { ToolLoopAgentOnStepFinishCallback } from './tool-loop-agent-settin
18
18
  *
19
19
  * @param response - The Node.js ServerResponse object to pipe to.
20
20
  * @param agent - The agent to run.
21
- * @param uiMessages - The input UI messages.
21
+ * @param uiMessages - The input UI messages. Defaults to originalMessages.
22
22
  * @param abortSignal - Abort signal. Optional.
23
23
  * @param timeout - Timeout in milliseconds. Optional.
24
24
  * @param options - The options for the agent. Optional.
@@ -44,7 +44,7 @@ export async function pipeAgentUIStreamToResponse<
44
44
  }: {
45
45
  response: ServerResponse;
46
46
  agent: Agent<CALL_OPTIONS, TOOLS, OUTPUT>;
47
- uiMessages: unknown[];
47
+ uiMessages?: unknown[];
48
48
  abortSignal?: AbortSignal;
49
49
  timeout?: TimeoutConfiguration;
50
50
  options?: CALL_OPTIONS;
@@ -148,10 +148,20 @@ export function smoothStream<TOOLS extends ToolSet>({
148
148
  return;
149
149
  }
150
150
 
151
- // Flush buffer when type or id changes
151
+ if (chunk.text.length === 0 && chunk.providerMetadata != null) {
152
+ flushBuffer(controller);
153
+ controller.enqueue(chunk);
154
+ return;
155
+ }
156
+
157
+ // Flush at metadata boundaries because one output part cannot preserve
158
+ // metadata from multiple input deltas.
152
159
  if (
153
- (chunk.type !== type || chunk.id !== id) &&
154
- (buffer.length > 0 || providerMetadata != null)
160
+ buffer.length > 0 &&
161
+ (chunk.type !== type ||
162
+ chunk.id !== id ||
163
+ providerMetadata != null ||
164
+ chunk.providerMetadata != null)
155
165
  ) {
156
166
  flushBuffer(controller);
157
167
  }
@@ -159,20 +169,25 @@ export function smoothStream<TOOLS extends ToolSet>({
159
169
  buffer += chunk.text;
160
170
  id = chunk.id;
161
171
  type = chunk.type;
162
-
163
- // Preserve providerMetadata (e.g., Anthropic thinking signatures)
164
- if (chunk.providerMetadata != null) {
165
- providerMetadata = chunk.providerMetadata;
166
- }
172
+ providerMetadata = chunk.providerMetadata;
167
173
 
168
174
  let match;
169
175
 
170
176
  while ((match = detectChunk(buffer)) != null) {
171
- controller.enqueue({ type, text: match, id });
177
+ controller.enqueue({
178
+ type,
179
+ text: match,
180
+ id,
181
+ ...(providerMetadata != null ? { providerMetadata } : {}),
182
+ });
172
183
  buffer = buffer.slice(match.length);
173
184
 
174
185
  await delay(isDocumentHidden() ? null : delayInMs);
175
186
  }
187
+
188
+ if (buffer.length === 0) {
189
+ providerMetadata = undefined;
190
+ }
176
191
  },
177
192
  });
178
193
  };
package/src/ui/chat.ts CHANGED
@@ -262,6 +262,9 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
262
262
  private pendingApprovalMessageId: string | undefined;
263
263
  private activeResponse: ActiveResponse<UI_MESSAGE> | undefined = undefined;
264
264
  private activeResumeRequest: ActiveResumeRequest | undefined = undefined;
265
+ private resumableStreamState:
266
+ | StreamingUIMessageState<UI_MESSAGE>
267
+ | undefined = undefined;
265
268
  private jobExecutor = new SerialJobExecutor();
266
269
 
267
270
  constructor({
@@ -697,6 +700,10 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
697
700
  trigger: 'submit-message' | 'resume-stream' | 'regenerate-message';
698
701
  messageId?: string;
699
702
  } & ChatRequestOptions) {
703
+ if (trigger !== 'resume-stream') {
704
+ this.resumableStreamState = undefined;
705
+ }
706
+
700
707
  const abortController = new AbortController();
701
708
  const activeResumeRequest =
702
709
  trigger === 'resume-stream' ? { abortController } : undefined;
@@ -734,6 +741,7 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
734
741
  await reconnect?.cancel().catch(() => {});
735
742
  if (isCurrentRequest()) {
736
743
  this.setStatus({ status: 'ready' });
744
+ this.resumableStreamState = undefined;
737
745
  }
738
746
  clearActiveResumeRequest();
739
747
  return;
@@ -741,6 +749,7 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
741
749
 
742
750
  if (reconnect == null) {
743
751
  this.setStatus({ status: 'ready' });
752
+ this.resumableStreamState = undefined;
744
753
  clearActiveResumeRequest();
745
754
  return; // no active stream found, so we do not resume
746
755
  }
@@ -753,6 +762,7 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
753
762
  ) {
754
763
  if (isCurrentRequest()) {
755
764
  this.setStatus({ status: 'ready' });
765
+ this.resumableStreamState = undefined;
756
766
  }
757
767
  clearActiveResumeRequest();
758
768
  return;
@@ -794,13 +804,17 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
794
804
 
795
805
  try {
796
806
  const response = {
797
- state: createStreamingUIMessageState({
798
- lastMessage:
799
- trigger === 'resume-stream' || trigger === 'regenerate-message'
800
- ? undefined
801
- : this.state.snapshot(responseMessage),
802
- messageId: this.generateId(),
803
- }),
807
+ state:
808
+ trigger === 'resume-stream' && this.resumableStreamState != null
809
+ ? this.resumableStreamState
810
+ : createStreamingUIMessageState({
811
+ lastMessage:
812
+ trigger === 'resume-stream' ||
813
+ trigger === 'regenerate-message'
814
+ ? undefined
815
+ : this.state.snapshot(responseMessage),
816
+ messageId: this.generateId(),
817
+ }),
804
818
  abortController,
805
819
  } as ActiveResponse<UI_MESSAGE>;
806
820
 
@@ -890,12 +904,18 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
890
904
  if (isAbort) {
891
905
  if (isCurrentRequest()) {
892
906
  this.setStatus({ status: 'ready' });
907
+ if (this.resumableStreamState === response.state) {
908
+ this.resumableStreamState = undefined;
909
+ }
893
910
  }
894
911
  return null;
895
912
  }
896
913
 
897
914
  if (isCurrentRequest()) {
898
915
  this.setStatus({ status: 'ready' });
916
+ if (this.resumableStreamState === response.state) {
917
+ this.resumableStreamState = undefined;
918
+ }
899
919
  }
900
920
  } catch (err) {
901
921
  // Ignore abort errors as they are expected.
@@ -903,6 +923,9 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
903
923
  isAbort = true;
904
924
  if (isCurrentRequest()) {
905
925
  this.setStatus({ status: 'ready' });
926
+ if (this.resumableStreamState === activeResponse?.state) {
927
+ this.resumableStreamState = undefined;
928
+ }
906
929
  }
907
930
  return null;
908
931
  }
@@ -922,6 +945,12 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
922
945
  isDisconnect = true;
923
946
  }
924
947
 
948
+ if (isDisconnect) {
949
+ this.resumableStreamState = activeResponse?.state;
950
+ } else if (this.resumableStreamState === activeResponse?.state) {
951
+ this.resumableStreamState = undefined;
952
+ }
953
+
925
954
  if (this.onError && err instanceof Error) {
926
955
  this.onError(err);
927
956
  }
@@ -757,7 +757,8 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
757
757
  providerExecuted: chunk.providerExecuted,
758
758
  providerMetadata: chunk.providerMetadata,
759
759
  title: toolInvocation.title,
760
- toolMetadata: toolInvocation.toolMetadata,
760
+ toolMetadata:
761
+ chunk.toolMetadata ?? toolInvocation.toolMetadata,
761
762
  },
762
763
  toolInvocation,
763
764
  );
@@ -773,7 +774,8 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
773
774
  preliminary: chunk.preliminary,
774
775
  providerMetadata: chunk.providerMetadata,
775
776
  title: toolInvocation.title,
776
- toolMetadata: toolInvocation.toolMetadata,
777
+ toolMetadata:
778
+ chunk.toolMetadata ?? toolInvocation.toolMetadata,
777
779
  },
778
780
  toolInvocation as ToolUIPart<InferUIMessageTools<UI_MESSAGE>>,
779
781
  );
@@ -797,7 +799,8 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
797
799
  providerExecuted: chunk.providerExecuted,
798
800
  providerMetadata: chunk.providerMetadata,
799
801
  title: toolInvocation.title,
800
- toolMetadata: toolInvocation.toolMetadata,
802
+ toolMetadata:
803
+ chunk.toolMetadata ?? toolInvocation.toolMetadata,
801
804
  },
802
805
  toolInvocation,
803
806
  );
@@ -813,7 +816,8 @@ export function processUIMessageStream<UI_MESSAGE extends UIMessage>({
813
816
  providerExecuted: chunk.providerExecuted,
814
817
  providerMetadata: chunk.providerMetadata,
815
818
  title: toolInvocation.title,
816
- toolMetadata: toolInvocation.toolMetadata,
819
+ toolMetadata:
820
+ chunk.toolMetadata ?? toolInvocation.toolMetadata,
817
821
  },
818
822
  toolInvocation as ToolUIPart<InferUIMessageTools<UI_MESSAGE>>,
819
823
  );