ai 7.0.119 → 7.0.122

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 (44) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/index.d.ts +30 -3
  3. package/dist/index.js +132 -36
  4. package/dist/index.js.map +1 -1
  5. package/dist/internal/index.js +1 -1
  6. package/docs/02-foundations/02-providers-and-models.mdx +1 -0
  7. package/docs/02-getting-started/00-choosing-a-provider.mdx +4 -4
  8. package/docs/02-getting-started/02-nextjs-app-router.mdx +2 -2
  9. package/docs/02-getting-started/03-nextjs-pages-router.mdx +2 -2
  10. package/docs/02-getting-started/04-svelte.mdx +6 -6
  11. package/docs/02-getting-started/05-nuxt.mdx +6 -6
  12. package/docs/02-getting-started/06-nodejs.mdx +2 -2
  13. package/docs/02-getting-started/07-expo.mdx +2 -2
  14. package/docs/02-getting-started/08-tanstack-start.mdx +2 -2
  15. package/docs/03-agents/06-policy-tool-approvals.mdx +2 -2
  16. package/docs/03-agents/07-workflow-agent.mdx +10 -10
  17. package/docs/03-ai-sdk-core/20-prompt-engineering.mdx +1 -1
  18. package/docs/03-ai-sdk-core/26-reasoning.mdx +1 -1
  19. package/docs/03-ai-sdk-core/45-provider-management.mdx +4 -4
  20. package/docs/04-ai-sdk-ui/02-chatbot.mdx +10 -1
  21. package/docs/04-ai-sdk-ui/03-chatbot-message-persistence.mdx +8 -0
  22. package/docs/04-ai-sdk-ui/03-chatbot-resume-streams.mdx +10 -3
  23. package/docs/04-ai-sdk-ui/03-chatbot-tool-usage.mdx +10 -1
  24. package/docs/05-ai-sdk-rsc/04-multistep-interfaces.mdx +1 -1
  25. package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +1 -1
  26. package/docs/07-reference/04-ai-sdk-workflow/01-workflow-agent.mdx +8 -8
  27. package/docs/08-migration-guides/29-migration-guide-4-0.mdx +5 -5
  28. package/docs/08-migration-guides/37-migration-guide-3-3.mdx +1 -1
  29. package/package.json +11 -11
  30. package/src/embed/embed-many.ts +5 -3
  31. package/src/generate-image/generate-image.ts +8 -3
  32. package/src/generate-text/smooth-stream.ts +24 -9
  33. package/src/generate-text/stream-text-result.ts +5 -0
  34. package/src/generate-video/generate-video.ts +6 -4
  35. package/src/registry/provider-registry.ts +1 -1
  36. package/src/ui/chat.ts +45 -7
  37. package/src/ui/http-chat-transport.ts +19 -3
  38. package/src/ui/last-assistant-message-is-complete-with-tool-calls.ts +15 -3
  39. package/src/ui/process-ui-message-stream.ts +59 -18
  40. package/src/ui/ui-messages.ts +14 -0
  41. package/src/ui/validate-ui-messages.ts +2 -0
  42. package/src/ui-message-stream/to-ui-message-chunk.ts +9 -1
  43. package/src/ui-message-stream/to-ui-message-stream.ts +1 -1
  44. package/src/util/set-own.ts +16 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # ai
2
2
 
3
+ ## 7.0.122
4
+
5
+ ### Patch Changes
6
+
7
+ - f3575f8: Clarify that provider-executed tool execution errors bypass the UI stream's `onError` callback to preserve provider error data and harness runtime messages. Stream errors and invalid tool calls still use the callback. Runtime behavior is unchanged.
8
+ - 27ab8d4: Encode chat IDs in default stream reconnection URLs so slashes, query delimiters, and fragments stay within the ID. Reject standalone `.` and `..` IDs before fetching. Custom URLs returned by `prepareReconnectToStreamRequest` remain unchanged.
9
+ - Updated dependencies [870f509]
10
+ - Updated dependencies [a75f1fd]
11
+ - @ai-sdk/gateway@4.0.100
12
+
13
+ ## 7.0.121
14
+
15
+ ### Patch Changes
16
+
17
+ - c5e90bb: fix(ai): preserve hydrated partial static tool input across stream resumptions
18
+ - 868c475: Preserve prototype-named tools, providers, and provider metadata as own properties without changing lookup object prototypes. Prevent inherited names from resolving as registered providers or causing image metadata aggregation to fail.
19
+ - 119536f: Preserve provider metadata on corresponding `smoothStream` chunks without carrying it into subsequent metadata-free deltas.
20
+ - 9941f32: Prevent automatic chat resumption when completed tool output is followed by terminal text without a completed stream state, while preserving resumption after completed model text.
21
+ - Updated dependencies [dbddb5b]
22
+ - Updated dependencies [c2511c1]
23
+ - @ai-sdk/gateway@4.0.99
24
+ - @ai-sdk/provider-utils@5.0.51
25
+
26
+ ## 7.0.120
27
+
28
+ ### Patch Changes
29
+
30
+ - b032d70: fix(ai): preserve tool metadata from tool output chunks
31
+ - e21b98b: fix(ai): continue active UI message parts when resuming after a disconnect
32
+ - Updated dependencies [e361d39]
33
+ - @ai-sdk/gateway@4.0.98
34
+
3
35
  ## 7.0.119
4
36
 
5
37
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -2161,6 +2161,13 @@ type UIToolInvocation<TOOL extends UITool | Tool> = {
2161
2161
  } & ({
2162
2162
  state: 'input-streaming';
2163
2163
  input?: DeepPartial<asUITool<TOOL>['input']> | undefined;
2164
+ /**
2165
+ * The raw tool input text received so far.
2166
+ *
2167
+ * This is used to continue input streaming when a message is persisted
2168
+ * and later resumed.
2169
+ */
2170
+ rawInput?: string;
2164
2171
  output?: never;
2165
2172
  errorText?: never;
2166
2173
  callProviderMetadata?: ProviderMetadata;
@@ -2285,6 +2292,13 @@ type DynamicToolUIPart = {
2285
2292
  } & ({
2286
2293
  state: 'input-streaming';
2287
2294
  input?: unknown;
2295
+ /**
2296
+ * The raw tool input text received so far.
2297
+ *
2298
+ * This is used to continue input streaming when a message is persisted
2299
+ * and later resumed.
2300
+ */
2301
+ rawInput?: string;
2288
2302
  output?: never;
2289
2303
  errorText?: never;
2290
2304
  callProviderMetadata?: ProviderMetadata;
@@ -2778,6 +2792,11 @@ type UIMessageStreamOptions<UI_MESSAGE extends UIMessage> = {
2778
2792
  /**
2779
2793
  * Process an error, e.g. to log it. Default to `() => 'An error occurred.'`.
2780
2794
  *
2795
+ * Tool execution errors marked `providerExecuted: true` bypass this callback.
2796
+ * Their strings pass through unchanged; other values are JSON-stringified to
2797
+ * preserve provider error data for model-message round trips and harness
2798
+ * runtime error messages. Stream errors and invalid tool calls still use it.
2799
+ *
2781
2800
  * @returns error message to include in the data stream.
2782
2801
  */
2783
2802
  onError?: (error: unknown) => string;
@@ -5816,6 +5835,7 @@ declare abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
5816
5835
  private pendingApprovalMessageId;
5817
5836
  private activeResponse;
5818
5837
  private activeResumeRequest;
5838
+ private resumableStreamState;
5819
5839
  private jobExecutor;
5820
5840
  constructor({ generateId, id, transport, messageMetadataSchema, dataPartSchemas, state, onError, onToolCall, onFinish, onData, sendAutomaticallyWhen, }: Omit<ChatInit<UI_MESSAGE>, 'messages'> & {
5821
5841
  state: ChatState<UI_MESSAGE>;
@@ -6073,7 +6093,9 @@ declare function lastAssistantMessageIsCompleteWithApprovalResponses({ messages,
6073
6093
  /**
6074
6094
  * Check if the last message is an assistant message with completed tool calls.
6075
6095
  * The last step of the message must have at least one tool invocation and
6076
- * all tool invocations must have a result.
6096
+ * all tool invocations must have a result. Completed model text may follow
6097
+ * the tool invocation because client-side tool results update parts in place,
6098
+ * but trailing text without a completed stream state prevents resubmission.
6077
6099
  */
6078
6100
  declare function lastAssistantMessageIsCompleteWithToolCalls({ messages, }: {
6079
6101
  messages: UIMessage[];
@@ -6332,6 +6354,11 @@ type ToUIMessageChunkOptions<TOOLS extends ToolSet = ToolSet, UI_MESSAGE extends
6332
6354
  sendSources?: boolean;
6333
6355
  sendStart?: boolean;
6334
6356
  sendFinish?: boolean;
6357
+ /**
6358
+ * Formats stream errors, invalid tool calls, and application-executed tool
6359
+ * errors. Provider-executed tool execution errors bypass this callback so
6360
+ * their original error data survives model-message round trips.
6361
+ */
6335
6362
  onError?: (error: unknown) => string;
6336
6363
  messageMetadata?: InferUIMessageMetadata<UI_MESSAGE>;
6337
6364
  responseMessageId?: string;
@@ -6342,7 +6369,7 @@ type ToUIMessageChunkOptions<TOOLS extends ToolSet = ToolSet, UI_MESSAGE extends
6342
6369
  *
6343
6370
  * Returns `undefined` for stream parts that do not produce UI message chunks.
6344
6371
  */
6345
- declare function toUIMessageChunk<TOOLS extends ToolSet = ToolSet, UI_MESSAGE extends UIMessage = UIMessage>(part: TextStreamPart<TOOLS>, { tools, sendReasoning, sendSources, sendStart, sendFinish, onError, // prevent leaking server error details to the client by default
6372
+ declare function toUIMessageChunk<TOOLS extends ToolSet = ToolSet, UI_MESSAGE extends UIMessage = UIMessage>(part: TextStreamPart<TOOLS>, { tools, sendReasoning, sendSources, sendStart, sendFinish, onError, // masks errors except provider-executed tool execution errors
6346
6373
  messageMetadata, responseMessageId, }?: ToUIMessageChunkOptions<TOOLS, UI_MESSAGE>): InferUIMessageChunk<UI_MESSAGE> | undefined;
6347
6374
 
6348
6375
  /**
@@ -6351,7 +6378,7 @@ messageMetadata, responseMessageId, }?: ToUIMessageChunkOptions<TOOLS, UI_MESSAG
6351
6378
  * UI message streaming, including response message ID injection and
6352
6379
  * `onEnd` handling.
6353
6380
  */
6354
- declare function toUIMessageStream<TOOLS extends ToolSet = ToolSet, UI_MESSAGE extends UIMessage = UIMessage>({ stream, tools, sendReasoning, sendSources, sendStart, sendFinish, onError, // prevent leaking server error details to the client by default
6381
+ declare function toUIMessageStream<TOOLS extends ToolSet = ToolSet, UI_MESSAGE extends UIMessage = UIMessage>({ stream, tools, sendReasoning, sendSources, sendStart, sendFinish, onError, // masks errors except provider-executed tool execution errors
6355
6382
  messageMetadata, originalMessages, generateMessageId, onEnd, onFinish, }: {
6356
6383
  stream: ReadableStream<TextStreamPart<TOOLS>>;
6357
6384
  tools?: TOOLS;
package/dist/index.js CHANGED
@@ -1328,7 +1328,7 @@ import {
1328
1328
  } from "@ai-sdk/provider-utils";
1329
1329
 
1330
1330
  // src/version.ts
1331
- var VERSION = true ? "7.0.119" : "0.0.0-test";
1331
+ var VERSION = true ? "7.0.122" : "0.0.0-test";
1332
1332
 
1333
1333
  // src/util/download/download.ts
1334
1334
  var download = async ({
@@ -7476,16 +7476,42 @@ function createStreamingUIMessageState({
7476
7476
  lastMessage,
7477
7477
  messageId
7478
7478
  }) {
7479
+ const message = lastMessage?.role === "assistant" ? lastMessage : {
7480
+ id: messageId,
7481
+ metadata: void 0,
7482
+ role: "assistant",
7483
+ parts: []
7484
+ };
7485
+ const partialToolCalls = createIdMap();
7486
+ const lastStepStartIndex = message.parts.findLastIndex(
7487
+ (part) => part.type === "step-start"
7488
+ );
7489
+ let staticToolIndex = 0;
7490
+ for (const part of message.parts.slice(lastStepStartIndex + 1)) {
7491
+ if (!isToolUIPart(part)) {
7492
+ continue;
7493
+ }
7494
+ const index = staticToolIndex;
7495
+ if (isStaticToolUIPart(part)) {
7496
+ staticToolIndex++;
7497
+ }
7498
+ if (part.state !== "input-streaming") {
7499
+ continue;
7500
+ }
7501
+ partialToolCalls[part.toolCallId] = {
7502
+ text: part.rawInput ?? "",
7503
+ index,
7504
+ toolName: part.type === "dynamic-tool" ? part.toolName : getStaticToolName(part),
7505
+ dynamic: part.type === "dynamic-tool",
7506
+ title: part.title,
7507
+ toolMetadata: part.toolMetadata
7508
+ };
7509
+ }
7479
7510
  return {
7480
- message: lastMessage?.role === "assistant" ? lastMessage : {
7481
- id: messageId,
7482
- metadata: void 0,
7483
- role: "assistant",
7484
- parts: []
7485
- },
7511
+ message,
7486
7512
  activeTextParts: createIdMap(),
7487
7513
  activeReasoningParts: createIdMap(),
7488
- partialToolCalls: createIdMap()
7514
+ partialToolCalls
7489
7515
  };
7490
7516
  }
7491
7517
  function processUIMessageStream({
@@ -7609,7 +7635,7 @@ function processUIMessageStream({
7609
7635
  anyPart.input = anyOptions.input;
7610
7636
  anyPart.output = anyOptions.output;
7611
7637
  anyPart.errorText = anyOptions.errorText;
7612
- anyPart.rawInput = anyOptions.rawInput ?? anyPart.rawInput;
7638
+ anyPart.rawInput = anyOptions.rawInput;
7613
7639
  anyPart.preliminary = anyOptions.preliminary;
7614
7640
  if (options.title !== void 0) {
7615
7641
  anyPart.title = options.title;
@@ -7844,6 +7870,7 @@ function processUIMessageStream({
7844
7870
  toolName: partialToolCall.toolName,
7845
7871
  state: "input-streaming",
7846
7872
  input: partialArgs,
7873
+ rawInput: partialToolCall.text,
7847
7874
  title: partialToolCall.title,
7848
7875
  toolMetadata: partialToolCall.toolMetadata
7849
7876
  });
@@ -7853,6 +7880,7 @@ function processUIMessageStream({
7853
7880
  toolName: partialToolCall.toolName,
7854
7881
  state: "input-streaming",
7855
7882
  input: partialArgs,
7883
+ rawInput: partialToolCall.text,
7856
7884
  title: partialToolCall.title,
7857
7885
  toolMetadata: partialToolCall.toolMetadata
7858
7886
  });
@@ -7979,7 +8007,7 @@ function processUIMessageStream({
7979
8007
  providerExecuted: chunk.providerExecuted,
7980
8008
  providerMetadata: chunk.providerMetadata,
7981
8009
  title: toolInvocation.title,
7982
- toolMetadata: toolInvocation.toolMetadata
8010
+ toolMetadata: chunk.toolMetadata ?? toolInvocation.toolMetadata
7983
8011
  },
7984
8012
  toolInvocation
7985
8013
  );
@@ -7995,7 +8023,7 @@ function processUIMessageStream({
7995
8023
  preliminary: chunk.preliminary,
7996
8024
  providerMetadata: chunk.providerMetadata,
7997
8025
  title: toolInvocation.title,
7998
- toolMetadata: toolInvocation.toolMetadata
8026
+ toolMetadata: chunk.toolMetadata ?? toolInvocation.toolMetadata
7999
8027
  },
8000
8028
  toolInvocation
8001
8029
  );
@@ -8016,7 +8044,7 @@ function processUIMessageStream({
8016
8044
  providerExecuted: chunk.providerExecuted,
8017
8045
  providerMetadata: chunk.providerMetadata,
8018
8046
  title: toolInvocation.title,
8019
- toolMetadata: toolInvocation.toolMetadata
8047
+ toolMetadata: chunk.toolMetadata ?? toolInvocation.toolMetadata
8020
8048
  },
8021
8049
  toolInvocation
8022
8050
  );
@@ -8032,7 +8060,7 @@ function processUIMessageStream({
8032
8060
  providerExecuted: chunk.providerExecuted,
8033
8061
  providerMetadata: chunk.providerMetadata,
8034
8062
  title: toolInvocation.title,
8035
- toolMetadata: toolInvocation.toolMetadata
8063
+ toolMetadata: chunk.toolMetadata ?? toolInvocation.toolMetadata
8036
8064
  },
8037
8065
  toolInvocation
8038
8066
  );
@@ -8275,7 +8303,7 @@ function toUIMessageChunk(part, {
8275
8303
  sendStart = true,
8276
8304
  sendFinish = true,
8277
8305
  onError = () => "An error occurred.",
8278
- // prevent leaking server error details to the client by default
8306
+ // masks errors except provider-executed tool execution errors
8279
8307
  messageMetadata,
8280
8308
  responseMessageId
8281
8309
  } = {}) {
@@ -8533,7 +8561,7 @@ function toUIMessageStream({
8533
8561
  sendStart = true,
8534
8562
  sendFinish = true,
8535
8563
  onError = () => "An error occurred.",
8536
- // prevent leaking server error details to the client by default
8564
+ // masks errors except provider-executed tool execution errors
8537
8565
  messageMetadata,
8538
8566
  originalMessages,
8539
8567
  generateMessageId,
@@ -12632,6 +12660,7 @@ var uiMessagesSchema = lazySchema2(() => {
12632
12660
  toolMetadata: toolMetadataSchema2.optional(),
12633
12661
  state: z.literal("input-streaming"),
12634
12662
  input: z.unknown().optional(),
12663
+ rawInput: z.string().optional(),
12635
12664
  providerExecuted: z.boolean().optional(),
12636
12665
  callProviderMetadata: providerMetadataSchema.optional(),
12637
12666
  output: z.never().optional(),
@@ -12735,6 +12764,7 @@ var uiMessagesSchema = lazySchema2(() => {
12735
12764
  providerExecuted: z.boolean().optional(),
12736
12765
  callProviderMetadata: providerMetadataSchema.optional(),
12737
12766
  input: z.unknown().optional(),
12767
+ rawInput: z.string().optional(),
12738
12768
  output: z.never().optional(),
12739
12769
  errorText: z.never().optional(),
12740
12770
  approval: z.never().optional()
@@ -13130,6 +13160,16 @@ import {
13130
13160
  withUserAgentSuffix as withUserAgentSuffix4
13131
13161
  } from "@ai-sdk/provider-utils";
13132
13162
 
13163
+ // src/util/set-own.ts
13164
+ function setOwn(object3, key, value) {
13165
+ Object.defineProperty(object3, key, {
13166
+ value,
13167
+ enumerable: true,
13168
+ configurable: true,
13169
+ writable: true
13170
+ });
13171
+ }
13172
+
13133
13173
  // src/prompt/data-content.ts
13134
13174
  import {
13135
13175
  convertBase64ToUint8Array as convertBase64ToUint8Array3,
@@ -13316,8 +13356,11 @@ async function generateImage({
13316
13356
  delete providerMetadata[providerName].images;
13317
13357
  }
13318
13358
  } else {
13319
- providerMetadata[providerName] ??= { images: [] };
13320
- providerMetadata[providerName].images.push(...metadata.images);
13359
+ const currentEntry = getOwn(providerMetadata, providerName) ?? {
13360
+ images: []
13361
+ };
13362
+ currentEntry.images.push(...metadata.images);
13363
+ setOwn(providerMetadata, providerName, currentEntry);
13321
13364
  }
13322
13365
  }
13323
13366
  }
@@ -13357,7 +13400,7 @@ function getImageProviderMetadata(providerMetadata, imageIndex) {
13357
13400
  for (const [providerName, metadata] of Object.entries(providerMetadata)) {
13358
13401
  const value = metadata.images?.[imageIndex];
13359
13402
  if (isJSONObject(value) && !Array.isArray(value)) {
13360
- (imageMetadata ??= {})[providerName] = value;
13403
+ setOwn(imageMetadata ??= {}, providerName, value);
13361
13404
  }
13362
13405
  }
13363
13406
  return imageMetadata;
@@ -14386,10 +14429,10 @@ async function embedMany({
14386
14429
  for (const [providerName, metadata] of Object.entries(
14387
14430
  result.providerMetadata
14388
14431
  )) {
14389
- providerMetadata[providerName] = {
14390
- ...providerMetadata[providerName],
14432
+ setOwn(providerMetadata, providerName, {
14433
+ ...getOwn(providerMetadata, providerName),
14391
14434
  ...metadata
14392
- };
14435
+ });
14393
14436
  }
14394
14437
  }
14395
14438
  }
@@ -16615,21 +16658,32 @@ function smoothStream({
16615
16658
  controller.enqueue(chunk);
16616
16659
  return;
16617
16660
  }
16618
- if ((chunk.type !== type || chunk.id !== id) && (buffer.length > 0 || providerMetadata != null)) {
16661
+ if (chunk.text.length === 0 && chunk.providerMetadata != null) {
16662
+ flushBuffer(controller);
16663
+ controller.enqueue(chunk);
16664
+ return;
16665
+ }
16666
+ if (buffer.length > 0 && (chunk.type !== type || chunk.id !== id || providerMetadata != null || chunk.providerMetadata != null)) {
16619
16667
  flushBuffer(controller);
16620
16668
  }
16621
16669
  buffer += chunk.text;
16622
16670
  id = chunk.id;
16623
16671
  type = chunk.type;
16624
- if (chunk.providerMetadata != null) {
16625
- providerMetadata = chunk.providerMetadata;
16626
- }
16672
+ providerMetadata = chunk.providerMetadata;
16627
16673
  let match;
16628
16674
  while ((match = detectChunk(buffer)) != null) {
16629
- controller.enqueue({ type, text: match, id });
16675
+ controller.enqueue({
16676
+ type,
16677
+ text: match,
16678
+ id,
16679
+ ...providerMetadata != null ? { providerMetadata } : {}
16680
+ });
16630
16681
  buffer = buffer.slice(match.length);
16631
16682
  await delay(isDocumentHidden() ? null : delayInMs);
16632
16683
  }
16684
+ if (buffer.length === 0) {
16685
+ providerMetadata = void 0;
16686
+ }
16633
16687
  }
16634
16688
  });
16635
16689
  };
@@ -17028,12 +17082,12 @@ async function waitForWebhook({
17028
17082
  }
17029
17083
  function mergeProviderMetadata(target, source) {
17030
17084
  for (const [providerName, metadataValue] of Object.entries(source)) {
17031
- const existingMetadata = target[providerName];
17085
+ const existingMetadata = getOwn(target, providerName);
17032
17086
  if (existingMetadata != null && typeof existingMetadata === "object" && metadataValue != null && typeof metadataValue === "object") {
17033
- target[providerName] = {
17087
+ setOwn(target, providerName, {
17034
17088
  ...existingMetadata,
17035
17089
  ...metadataValue
17036
- };
17090
+ });
17037
17091
  if ("videos" in existingMetadata && Array.isArray(existingMetadata.videos) && "videos" in metadataValue && Array.isArray(metadataValue.videos)) {
17038
17092
  target[providerName].videos = [
17039
17093
  ...existingMetadata.videos,
@@ -17041,7 +17095,7 @@ function mergeProviderMetadata(target, source) {
17041
17095
  ];
17042
17096
  }
17043
17097
  } else {
17044
- target[providerName] = metadataValue;
17098
+ setOwn(target, providerName, metadataValue);
17045
17099
  }
17046
17100
  }
17047
17101
  }
@@ -20710,7 +20764,7 @@ var DefaultProviderRegistry = class {
20710
20764
  languageModelMiddleware,
20711
20765
  imageModelMiddleware
20712
20766
  }) {
20713
- this.providers = {};
20767
+ this.providers = /* @__PURE__ */ Object.create(null);
20714
20768
  this.separator = separator;
20715
20769
  this.languageModelMiddleware = languageModelMiddleware;
20716
20770
  this.imageModelMiddleware = imageModelMiddleware;
@@ -21938,7 +21992,20 @@ var HttpChatTransport = class {
21938
21992
  credentials: resolvedCredentials,
21939
21993
  requestMetadata: options.metadata
21940
21994
  });
21941
- const api = preparedRequest?.api ?? appendPathToUrl(this.api, `/${options.chatId}/stream`);
21995
+ let api = preparedRequest?.api;
21996
+ if (api == null) {
21997
+ if (options.chatId === "." || options.chatId === "..") {
21998
+ throw new InvalidArgumentError({
21999
+ parameter: "chatId",
22000
+ value: options.chatId,
22001
+ message: 'Chat IDs must not be "." or ".." when using the default reconnect URL.'
22002
+ });
22003
+ }
22004
+ api = appendPathToUrl(
22005
+ this.api,
22006
+ `/${encodeURIComponent(options.chatId)}/stream`
22007
+ );
22008
+ }
21942
22009
  const headers = preparedRequest?.headers !== void 0 ? normalizeHeaders(preparedRequest.headers) : baseHeaders;
21943
22010
  const credentials = preparedRequest?.credentials ?? resolvedCredentials;
21944
22011
  const fetch2 = this.fetch ?? globalThis.fetch;
@@ -22007,6 +22074,7 @@ var AbstractChat = class {
22007
22074
  this.pendingMessagePreparations = /* @__PURE__ */ new Set();
22008
22075
  this.activeResponse = void 0;
22009
22076
  this.activeResumeRequest = void 0;
22077
+ this.resumableStreamState = void 0;
22010
22078
  this.jobExecutor = new SerialJobExecutor();
22011
22079
  /**
22012
22080
  * Appends or replaces a user message to the chat list. This triggers the API call to fetch
@@ -22301,6 +22369,9 @@ var AbstractChat = class {
22301
22369
  body,
22302
22370
  messageId
22303
22371
  }) {
22372
+ if (trigger !== "resume-stream") {
22373
+ this.resumableStreamState = void 0;
22374
+ }
22304
22375
  const abortController = new AbortController();
22305
22376
  const activeResumeRequest = trigger === "resume-stream" ? { abortController } : void 0;
22306
22377
  if (activeResumeRequest) {
@@ -22328,12 +22399,14 @@ var AbstractChat = class {
22328
22399
  });
22329
22400
  if (isCurrentRequest()) {
22330
22401
  this.setStatus({ status: "ready" });
22402
+ this.resumableStreamState = void 0;
22331
22403
  }
22332
22404
  clearActiveResumeRequest();
22333
22405
  return;
22334
22406
  }
22335
22407
  if (reconnect == null) {
22336
22408
  this.setStatus({ status: "ready" });
22409
+ this.resumableStreamState = void 0;
22337
22410
  clearActiveResumeRequest();
22338
22411
  return;
22339
22412
  }
@@ -22342,6 +22415,7 @@ var AbstractChat = class {
22342
22415
  if (abortController.signal.aborted || err.name === "AbortError") {
22343
22416
  if (isCurrentRequest()) {
22344
22417
  this.setStatus({ status: "ready" });
22418
+ this.resumableStreamState = void 0;
22345
22419
  }
22346
22420
  clearActiveResumeRequest();
22347
22421
  return;
@@ -22361,6 +22435,9 @@ var AbstractChat = class {
22361
22435
  const lastMessage = this.lastMessage;
22362
22436
  const responseMessageIndex = trigger === "submit-message" && messageId != null ? this.state.messages.findIndex((message) => message.id === messageId) : this.state.messages.length - 1;
22363
22437
  const responseMessage = responseMessageIndex === -1 ? lastMessage : this.state.messages[responseMessageIndex];
22438
+ const resumableResponseMessage = trigger === "resume-stream" && responseMessage?.role === "assistant" && responseMessage.parts.some(
22439
+ (part) => isToolUIPart(part) && part.state === "input-streaming"
22440
+ ) ? this.state.snapshot(responseMessage) : void 0;
22364
22441
  const usesEarlierAssistantMessage = responseMessageIndex !== -1 && responseMessageIndex < this.state.messages.length - 1 && responseMessage?.role === "assistant";
22365
22442
  let isAbort = false;
22366
22443
  let isDisconnect = false;
@@ -22368,8 +22445,8 @@ var AbstractChat = class {
22368
22445
  let activeResponse;
22369
22446
  try {
22370
22447
  const response = {
22371
- state: createStreamingUIMessageState({
22372
- lastMessage: trigger === "resume-stream" || trigger === "regenerate-message" ? void 0 : this.state.snapshot(responseMessage),
22448
+ state: trigger === "resume-stream" && this.resumableStreamState != null ? this.resumableStreamState : createStreamingUIMessageState({
22449
+ lastMessage: trigger === "resume-stream" ? resumableResponseMessage : trigger === "regenerate-message" ? void 0 : this.state.snapshot(responseMessage),
22373
22450
  messageId: this.generateId()
22374
22451
  }),
22375
22452
  abortController
@@ -22446,17 +22523,26 @@ var AbstractChat = class {
22446
22523
  if (isAbort) {
22447
22524
  if (isCurrentRequest()) {
22448
22525
  this.setStatus({ status: "ready" });
22526
+ if (this.resumableStreamState === response.state) {
22527
+ this.resumableStreamState = void 0;
22528
+ }
22449
22529
  }
22450
22530
  return null;
22451
22531
  }
22452
22532
  if (isCurrentRequest()) {
22453
22533
  this.setStatus({ status: "ready" });
22534
+ if (this.resumableStreamState === response.state) {
22535
+ this.resumableStreamState = void 0;
22536
+ }
22454
22537
  }
22455
22538
  } catch (err) {
22456
22539
  if (isAbort || err.name === "AbortError") {
22457
22540
  isAbort = true;
22458
22541
  if (isCurrentRequest()) {
22459
22542
  this.setStatus({ status: "ready" });
22543
+ if (this.resumableStreamState === activeResponse?.state) {
22544
+ this.resumableStreamState = void 0;
22545
+ }
22460
22546
  }
22461
22547
  return null;
22462
22548
  }
@@ -22467,6 +22553,11 @@ var AbstractChat = class {
22467
22553
  if (err instanceof TypeError && (err.message.toLowerCase().includes("fetch") || err.message.toLowerCase().includes("network"))) {
22468
22554
  isDisconnect = true;
22469
22555
  }
22556
+ if (isDisconnect) {
22557
+ this.resumableStreamState = activeResponse?.state;
22558
+ } else if (this.resumableStreamState === activeResponse?.state) {
22559
+ this.resumableStreamState = void 0;
22560
+ }
22470
22561
  if (this.onError && err instanceof Error) {
22471
22562
  this.onError(err);
22472
22563
  }
@@ -22587,8 +22678,13 @@ function lastAssistantMessageIsCompleteWithToolCalls({
22587
22678
  const lastStepStartIndex = message.parts.reduce((lastIndex, part, index) => {
22588
22679
  return part.type === "step-start" ? index : lastIndex;
22589
22680
  }, -1);
22590
- const lastStepToolInvocations = message.parts.slice(lastStepStartIndex + 1).filter(isToolUIPart).filter((part) => !part.providerExecuted);
22591
- return lastStepToolInvocations.length > 0 && lastStepToolInvocations.every(
22681
+ const lastStepParts = message.parts.slice(lastStepStartIndex + 1);
22682
+ const lastStepToolInvocations = lastStepParts.filter(isToolUIPart).filter((part) => !part.providerExecuted);
22683
+ const lastToolInvocationIndex = lastStepParts.reduce(
22684
+ (lastIndex, part, index) => isToolUIPart(part) && !part.providerExecuted ? index : lastIndex,
22685
+ -1
22686
+ );
22687
+ return lastStepToolInvocations.length > 0 && !lastStepParts.slice(lastToolInvocationIndex + 1).some((part) => part.type === "text" && part.state !== "done") && lastStepToolInvocations.every(
22592
22688
  (part) => part.state === "output-available" && part.preliminary !== true || part.state === "output-error"
22593
22689
  );
22594
22690
  }