ai 5.0.268 → 5.0.270

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # ai
2
2
 
3
+ ## 5.0.270
4
+
5
+ ### Patch Changes
6
+
7
+ - 1849a5f: fix(ai): preserve hydrated partial static tool input across stream resumptions
8
+ - 5381c08: fix(ai): keep idle UI message streams open with optional SSE heartbeats
9
+ - 06e8d1c: 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.
10
+ - 58d303f: 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.
11
+ - 430ae0a: 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.
12
+ - Updated dependencies [07e394b]
13
+ - Updated dependencies [b6cf409]
14
+ - @ai-sdk/gateway@2.0.161
15
+
16
+ ## 5.0.269
17
+
18
+ ### Patch Changes
19
+
20
+ - 11f5cda: Preserve provider metadata on corresponding `smoothStream` chunks without carrying it into subsequent metadata-free deltas.
21
+
3
22
  ## 5.0.268
4
23
 
5
24
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -1632,6 +1632,13 @@ type UIToolInvocation<TOOL extends UITool | Tool> = {
1632
1632
  state: 'input-streaming';
1633
1633
  input: DeepPartial<asUITool<TOOL>['input']> | undefined;
1634
1634
  providerExecuted?: boolean;
1635
+ /**
1636
+ * The raw tool input text received so far.
1637
+ *
1638
+ * This is used to continue input streaming when a message is persisted
1639
+ * and later resumed.
1640
+ */
1641
+ rawInput?: string;
1635
1642
  output?: never;
1636
1643
  errorText?: never;
1637
1644
  } | {
@@ -1681,6 +1688,13 @@ type DynamicToolUIPart = {
1681
1688
  } & ({
1682
1689
  state: 'input-streaming';
1683
1690
  input: unknown | undefined;
1691
+ /**
1692
+ * The raw tool input text received so far.
1693
+ *
1694
+ * This is used to continue input streaming when a message is persisted
1695
+ * and later resumed.
1696
+ */
1697
+ rawInput?: string;
1684
1698
  output?: never;
1685
1699
  errorText?: never;
1686
1700
  } | {
@@ -1896,6 +1910,12 @@ type UIMessageStreamOnFinishCallback<UI_MESSAGE extends UIMessage> = (event: {
1896
1910
  }) => PromiseLike<void> | void;
1897
1911
 
1898
1912
  type UIMessageStreamResponseInit = ResponseInit & {
1913
+ /**
1914
+ * Optional interval in milliseconds for sending SSE keep-alive comments.
1915
+ * When set, an opening comment is sent immediately and additional comments
1916
+ * are sent after the stream has been idle for the configured interval.
1917
+ */
1918
+ keepAliveMs?: number;
1899
1919
  consumeSseStream?: (options: {
1900
1920
  stream: ReadableStream<string>;
1901
1921
  }) => PromiseLike<void> | void;
@@ -3926,7 +3946,7 @@ originalMessages, onFinish, generateId, }: {
3926
3946
  generateId?: IdGenerator;
3927
3947
  }): ReadableStream<InferUIMessageChunk<UI_MESSAGE>>;
3928
3948
 
3929
- declare function createUIMessageStreamResponse({ status, statusText, headers, stream, consumeSseStream, }: UIMessageStreamResponseInit & {
3949
+ declare function createUIMessageStreamResponse({ status, statusText, headers, stream, keepAliveMs, consumeSseStream, }: UIMessageStreamResponseInit & {
3930
3950
  stream: ReadableStream<UIMessageChunk>;
3931
3951
  }): Response;
3932
3952
 
@@ -3934,7 +3954,7 @@ declare class JsonToSseTransformStream extends TransformStream<unknown, string>
3934
3954
  constructor();
3935
3955
  }
3936
3956
 
3937
- declare function pipeUIMessageStreamToResponse({ response, status, statusText, headers, stream, consumeSseStream, }: {
3957
+ declare function pipeUIMessageStreamToResponse({ response, status, statusText, headers, stream, keepAliveMs, consumeSseStream, }: {
3938
3958
  response: ServerResponse;
3939
3959
  stream: ReadableStream<UIMessageChunk>;
3940
3960
  } & UIMessageStreamResponseInit): Promise<void>;
@@ -4392,9 +4412,11 @@ declare class DefaultChatTransport<UI_MESSAGE extends UIMessage> extends HttpCha
4392
4412
  }
4393
4413
 
4394
4414
  /**
4395
- Check if the message is an assistant message with completed tool calls.
4396
- The last step of the message must have at least one tool invocation and
4397
- all tool invocations must have a result.
4415
+ * Check if the last message is an assistant message with completed tool calls.
4416
+ * The last step of the message must have at least one tool invocation and
4417
+ * all tool invocations must have a result. Completed model text may follow
4418
+ * the tool invocation because client-side tool results update parts in place,
4419
+ * but trailing text without a completed stream state prevents resubmission.
4398
4420
  */
4399
4421
  declare function lastAssistantMessageIsCompleteWithToolCalls({ messages, }: {
4400
4422
  messages: UIMessage[];
package/dist/index.d.ts CHANGED
@@ -1632,6 +1632,13 @@ type UIToolInvocation<TOOL extends UITool | Tool> = {
1632
1632
  state: 'input-streaming';
1633
1633
  input: DeepPartial<asUITool<TOOL>['input']> | undefined;
1634
1634
  providerExecuted?: boolean;
1635
+ /**
1636
+ * The raw tool input text received so far.
1637
+ *
1638
+ * This is used to continue input streaming when a message is persisted
1639
+ * and later resumed.
1640
+ */
1641
+ rawInput?: string;
1635
1642
  output?: never;
1636
1643
  errorText?: never;
1637
1644
  } | {
@@ -1681,6 +1688,13 @@ type DynamicToolUIPart = {
1681
1688
  } & ({
1682
1689
  state: 'input-streaming';
1683
1690
  input: unknown | undefined;
1691
+ /**
1692
+ * The raw tool input text received so far.
1693
+ *
1694
+ * This is used to continue input streaming when a message is persisted
1695
+ * and later resumed.
1696
+ */
1697
+ rawInput?: string;
1684
1698
  output?: never;
1685
1699
  errorText?: never;
1686
1700
  } | {
@@ -1896,6 +1910,12 @@ type UIMessageStreamOnFinishCallback<UI_MESSAGE extends UIMessage> = (event: {
1896
1910
  }) => PromiseLike<void> | void;
1897
1911
 
1898
1912
  type UIMessageStreamResponseInit = ResponseInit & {
1913
+ /**
1914
+ * Optional interval in milliseconds for sending SSE keep-alive comments.
1915
+ * When set, an opening comment is sent immediately and additional comments
1916
+ * are sent after the stream has been idle for the configured interval.
1917
+ */
1918
+ keepAliveMs?: number;
1899
1919
  consumeSseStream?: (options: {
1900
1920
  stream: ReadableStream<string>;
1901
1921
  }) => PromiseLike<void> | void;
@@ -3926,7 +3946,7 @@ originalMessages, onFinish, generateId, }: {
3926
3946
  generateId?: IdGenerator;
3927
3947
  }): ReadableStream<InferUIMessageChunk<UI_MESSAGE>>;
3928
3948
 
3929
- declare function createUIMessageStreamResponse({ status, statusText, headers, stream, consumeSseStream, }: UIMessageStreamResponseInit & {
3949
+ declare function createUIMessageStreamResponse({ status, statusText, headers, stream, keepAliveMs, consumeSseStream, }: UIMessageStreamResponseInit & {
3930
3950
  stream: ReadableStream<UIMessageChunk>;
3931
3951
  }): Response;
3932
3952
 
@@ -3934,7 +3954,7 @@ declare class JsonToSseTransformStream extends TransformStream<unknown, string>
3934
3954
  constructor();
3935
3955
  }
3936
3956
 
3937
- declare function pipeUIMessageStreamToResponse({ response, status, statusText, headers, stream, consumeSseStream, }: {
3957
+ declare function pipeUIMessageStreamToResponse({ response, status, statusText, headers, stream, keepAliveMs, consumeSseStream, }: {
3938
3958
  response: ServerResponse;
3939
3959
  stream: ReadableStream<UIMessageChunk>;
3940
3960
  } & UIMessageStreamResponseInit): Promise<void>;
@@ -4392,9 +4412,11 @@ declare class DefaultChatTransport<UI_MESSAGE extends UIMessage> extends HttpCha
4392
4412
  }
4393
4413
 
4394
4414
  /**
4395
- Check if the message is an assistant message with completed tool calls.
4396
- The last step of the message must have at least one tool invocation and
4397
- all tool invocations must have a result.
4415
+ * Check if the last message is an assistant message with completed tool calls.
4416
+ * The last step of the message must have at least one tool invocation and
4417
+ * all tool invocations must have a result. Completed model text may follow
4418
+ * the tool invocation because client-side tool results update parts in place,
4419
+ * but trailing text without a completed stream state prevents resubmission.
4398
4420
  */
4399
4421
  declare function lastAssistantMessageIsCompleteWithToolCalls({ messages, }: {
4400
4422
  messages: UIMessage[];
package/dist/index.js CHANGED
@@ -816,7 +816,7 @@ function detectMediaType({
816
816
  var import_provider_utils2 = require("@ai-sdk/provider-utils");
817
817
 
818
818
  // src/version.ts
819
- var VERSION = true ? "5.0.268" : "0.0.0-test";
819
+ var VERSION = true ? "5.0.270" : "0.0.0-test";
820
820
 
821
821
  // src/util/download/download.ts
822
822
  var download = async ({
@@ -3070,6 +3070,75 @@ function pipeTextStreamToResponse({
3070
3070
  });
3071
3071
  }
3072
3072
 
3073
+ // src/ui-message-stream/create-sse-stream-with-keep-alive.ts
3074
+ var STREAM_OPEN_COMMENT = ": stream-open\n\n";
3075
+ var KEEP_ALIVE_COMMENT = ": keep-alive\n\n";
3076
+ function createSseStreamWithKeepAlive({
3077
+ stream,
3078
+ keepAliveMs
3079
+ }) {
3080
+ if (keepAliveMs == null) {
3081
+ return stream;
3082
+ }
3083
+ if (!Number.isFinite(keepAliveMs) || keepAliveMs <= 0 || keepAliveMs > 2147483647) {
3084
+ throw new Error(
3085
+ "keepAliveMs must be a positive finite timer duration no greater than 2147483647"
3086
+ );
3087
+ }
3088
+ const reader = stream.getReader();
3089
+ let keepAliveTimeout;
3090
+ let isCancelled = false;
3091
+ const clearKeepAliveTimeout = () => {
3092
+ clearTimeout(keepAliveTimeout);
3093
+ keepAliveTimeout = void 0;
3094
+ };
3095
+ const scheduleKeepAlive = (controller) => {
3096
+ clearKeepAliveTimeout();
3097
+ keepAliveTimeout = setTimeout(() => {
3098
+ if (isCancelled) {
3099
+ return;
3100
+ }
3101
+ if (controller.desiredSize != null && controller.desiredSize > 0) {
3102
+ controller.enqueue(KEEP_ALIVE_COMMENT);
3103
+ }
3104
+ scheduleKeepAlive(controller);
3105
+ }, keepAliveMs);
3106
+ };
3107
+ return new ReadableStream({
3108
+ start(controller) {
3109
+ controller.enqueue(STREAM_OPEN_COMMENT);
3110
+ scheduleKeepAlive(controller);
3111
+ },
3112
+ pull(controller) {
3113
+ return reader.read().then(
3114
+ (result) => {
3115
+ clearKeepAliveTimeout();
3116
+ if (isCancelled) {
3117
+ return;
3118
+ }
3119
+ if (result.done) {
3120
+ controller.close();
3121
+ } else {
3122
+ controller.enqueue(result.value);
3123
+ scheduleKeepAlive(controller);
3124
+ }
3125
+ },
3126
+ (error) => {
3127
+ clearKeepAliveTimeout();
3128
+ if (!isCancelled) {
3129
+ throw error;
3130
+ }
3131
+ }
3132
+ );
3133
+ },
3134
+ async cancel(reason) {
3135
+ isCancelled = true;
3136
+ clearKeepAliveTimeout();
3137
+ await reader.cancel(reason);
3138
+ }
3139
+ });
3140
+ }
3141
+
3073
3142
  // src/ui-message-stream/json-to-sse-transform-stream.ts
3074
3143
  var JsonToSseTransformStream = class extends TransformStream {
3075
3144
  constructor() {
@@ -3102,9 +3171,13 @@ function createUIMessageStreamResponse({
3102
3171
  statusText,
3103
3172
  headers,
3104
3173
  stream,
3174
+ keepAliveMs,
3105
3175
  consumeSseStream
3106
3176
  }) {
3107
- let sseStream = stream.pipeThrough(new JsonToSseTransformStream());
3177
+ let sseStream = createSseStreamWithKeepAlive({
3178
+ stream: stream.pipeThrough(new JsonToSseTransformStream()),
3179
+ keepAliveMs
3180
+ });
3108
3181
  if (consumeSseStream) {
3109
3182
  const [stream1, stream2] = sseStream.tee();
3110
3183
  sseStream = stream1;
@@ -3700,16 +3773,41 @@ function createStreamingUIMessageState({
3700
3773
  lastMessage,
3701
3774
  messageId
3702
3775
  }) {
3776
+ var _a16;
3777
+ const message = (lastMessage == null ? void 0 : lastMessage.role) === "assistant" ? lastMessage : {
3778
+ id: messageId,
3779
+ metadata: void 0,
3780
+ role: "assistant",
3781
+ parts: []
3782
+ };
3783
+ const partialToolCalls = createIdMap();
3784
+ const lastStepStartIndex = message.parts.findLastIndex(
3785
+ (part) => part.type === "step-start"
3786
+ );
3787
+ let staticToolIndex = 0;
3788
+ for (const part of message.parts.slice(lastStepStartIndex + 1)) {
3789
+ if (!isToolOrDynamicToolUIPart(part)) {
3790
+ continue;
3791
+ }
3792
+ const index = staticToolIndex;
3793
+ if (isToolUIPart(part)) {
3794
+ staticToolIndex++;
3795
+ }
3796
+ if (part.state !== "input-streaming") {
3797
+ continue;
3798
+ }
3799
+ partialToolCalls[part.toolCallId] = {
3800
+ text: (_a16 = part.rawInput) != null ? _a16 : "",
3801
+ index,
3802
+ toolName: isDynamicToolUIPart(part) ? part.toolName : getToolName(part),
3803
+ dynamic: isDynamicToolUIPart(part)
3804
+ };
3805
+ }
3703
3806
  return {
3704
- message: (lastMessage == null ? void 0 : lastMessage.role) === "assistant" ? lastMessage : {
3705
- id: messageId,
3706
- metadata: void 0,
3707
- role: "assistant",
3708
- parts: []
3709
- },
3807
+ message,
3710
3808
  activeTextParts: createIdMap(),
3711
3809
  activeReasoningParts: createIdMap(),
3712
- partialToolCalls: createIdMap()
3810
+ partialToolCalls
3713
3811
  };
3714
3812
  }
3715
3813
  function processUIMessageStream({
@@ -3817,7 +3915,7 @@ function processUIMessageStream({
3817
3915
  }
3818
3916
  }
3819
3917
  function updateDynamicToolPart(options, existingPart) {
3820
- var _a17, _b2;
3918
+ var _a17;
3821
3919
  const part = existingPart != null ? existingPart : getCurrentStepParts().find(
3822
3920
  (part2) => part2.type === "dynamic-tool" && part2.toolCallId === options.toolCallId
3823
3921
  );
@@ -3829,9 +3927,9 @@ function processUIMessageStream({
3829
3927
  anyPart.input = anyOptions.input;
3830
3928
  anyPart.output = anyOptions.output;
3831
3929
  anyPart.errorText = anyOptions.errorText;
3832
- anyPart.rawInput = (_a17 = anyOptions.rawInput) != null ? _a17 : anyPart.rawInput;
3930
+ anyPart.rawInput = anyOptions.rawInput;
3833
3931
  anyPart.preliminary = anyOptions.preliminary;
3834
- anyPart.providerExecuted = (_b2 = anyOptions.providerExecuted) != null ? _b2 : part.providerExecuted;
3932
+ anyPart.providerExecuted = (_a17 = anyOptions.providerExecuted) != null ? _a17 : part.providerExecuted;
3835
3933
  if (anyOptions.providerMetadata != null && part.state === "input-available") {
3836
3934
  part.callProviderMetadata = anyOptions.providerMetadata;
3837
3935
  }
@@ -3989,14 +4087,16 @@ function processUIMessageStream({
3989
4087
  toolCallId: chunk.toolCallId,
3990
4088
  toolName: partialToolCall.toolName,
3991
4089
  state: "input-streaming",
3992
- input: partialArgs
4090
+ input: partialArgs,
4091
+ rawInput: partialToolCall.text
3993
4092
  });
3994
4093
  } else {
3995
4094
  updateToolPart({
3996
4095
  toolCallId: chunk.toolCallId,
3997
4096
  toolName: partialToolCall.toolName,
3998
4097
  state: "input-streaming",
3999
- input: partialArgs
4098
+ input: partialArgs,
4099
+ rawInput: partialToolCall.text
4000
4100
  });
4001
4101
  }
4002
4102
  write();
@@ -4310,9 +4410,13 @@ function pipeUIMessageStreamToResponse({
4310
4410
  statusText,
4311
4411
  headers,
4312
4412
  stream,
4413
+ keepAliveMs,
4313
4414
  consumeSseStream
4314
4415
  }) {
4315
- let sseStream = stream.pipeThrough(new JsonToSseTransformStream());
4416
+ let sseStream = createSseStreamWithKeepAlive({
4417
+ stream: stream.pipeThrough(new JsonToSseTransformStream()),
4418
+ keepAliveMs
4419
+ });
4316
4420
  if (consumeSseStream) {
4317
4421
  const [stream1, stream2] = sseStream.tee();
4318
4422
  sseStream = stream1;
@@ -6636,6 +6740,21 @@ var DefaultEmbedResult = class {
6636
6740
  }
6637
6741
  };
6638
6742
 
6743
+ // src/util/get-own.ts
6744
+ function getOwn(obj, key) {
6745
+ return obj != null && Object.hasOwn(obj, key) ? obj[key] : void 0;
6746
+ }
6747
+
6748
+ // src/util/set-own.ts
6749
+ function setOwn(object2, key, value) {
6750
+ Object.defineProperty(object2, key, {
6751
+ value,
6752
+ enumerable: true,
6753
+ configurable: true,
6754
+ writable: true
6755
+ });
6756
+ }
6757
+
6639
6758
  // src/embed/embed-many.ts
6640
6759
  var import_provider_utils18 = require("@ai-sdk/provider-utils");
6641
6760
 
@@ -6861,10 +6980,10 @@ async function embedMany({
6861
6980
  for (const [providerName, metadata] of Object.entries(
6862
6981
  result.providerMetadata
6863
6982
  )) {
6864
- providerMetadata[providerName] = {
6865
- ...providerMetadata[providerName],
6983
+ setOwn(providerMetadata, providerName, {
6984
+ ...getOwn(providerMetadata, providerName),
6866
6985
  ...metadata
6867
- };
6986
+ });
6868
6987
  }
6869
6988
  }
6870
6989
  }
@@ -7042,10 +7161,13 @@ async function generateImage({
7042
7161
  delete providerMetadata[providerName].images;
7043
7162
  }
7044
7163
  } else {
7045
- (_b = providerMetadata[providerName]) != null ? _b : providerMetadata[providerName] = { images: [] };
7046
- providerMetadata[providerName].images.push(
7164
+ const currentEntry = (_b = getOwn(providerMetadata, providerName)) != null ? _b : {
7165
+ images: []
7166
+ };
7167
+ currentEntry.images.push(
7047
7168
  ...result.providerMetadata[providerName].images
7048
7169
  );
7170
+ setOwn(providerMetadata, providerName, currentEntry);
7049
7171
  }
7050
7172
  }
7051
7173
  }
@@ -8810,28 +8932,51 @@ function smoothStream({
8810
8932
  return () => {
8811
8933
  let buffer = "";
8812
8934
  let id = "";
8935
+ let providerMetadata;
8936
+ function flushBuffer(controller) {
8937
+ if (buffer.length > 0 || providerMetadata != null) {
8938
+ controller.enqueue({
8939
+ type: "text-delta",
8940
+ text: buffer,
8941
+ id,
8942
+ ...providerMetadata != null ? { providerMetadata } : {}
8943
+ });
8944
+ buffer = "";
8945
+ providerMetadata = void 0;
8946
+ }
8947
+ }
8813
8948
  return new TransformStream({
8814
8949
  async transform(chunk, controller) {
8815
8950
  if (chunk.type !== "text-delta") {
8816
- if (buffer.length > 0) {
8817
- controller.enqueue({ type: "text-delta", text: buffer, id });
8818
- buffer = "";
8819
- }
8951
+ flushBuffer(controller);
8952
+ controller.enqueue(chunk);
8953
+ return;
8954
+ }
8955
+ if (chunk.text.length === 0 && chunk.providerMetadata != null) {
8956
+ flushBuffer(controller);
8820
8957
  controller.enqueue(chunk);
8821
8958
  return;
8822
8959
  }
8823
- if (chunk.id !== id && buffer.length > 0) {
8824
- controller.enqueue({ type: "text-delta", text: buffer, id });
8825
- buffer = "";
8960
+ if (buffer.length > 0 && (chunk.id !== id || providerMetadata != null || chunk.providerMetadata != null)) {
8961
+ flushBuffer(controller);
8826
8962
  }
8827
8963
  buffer += chunk.text;
8828
8964
  id = chunk.id;
8965
+ providerMetadata = chunk.providerMetadata;
8829
8966
  let match;
8830
8967
  while ((match = detectChunk(buffer)) != null) {
8831
- controller.enqueue({ type: "text-delta", text: match, id });
8968
+ controller.enqueue({
8969
+ type: "text-delta",
8970
+ text: match,
8971
+ id,
8972
+ ...providerMetadata != null ? { providerMetadata } : {}
8973
+ });
8832
8974
  buffer = buffer.slice(match.length);
8833
8975
  await delay2(isDocumentHidden() ? null : delayInMs);
8834
8976
  }
8977
+ if (buffer.length === 0) {
8978
+ providerMetadata = void 0;
8979
+ }
8835
8980
  }
8836
8981
  });
8837
8982
  };
@@ -9275,7 +9420,7 @@ var DefaultProviderRegistry = class {
9275
9420
  separator,
9276
9421
  languageModelMiddleware
9277
9422
  }) {
9278
- this.providers = {};
9423
+ this.providers = /* @__PURE__ */ Object.create(null);
9279
9424
  this.separator = separator;
9280
9425
  this.languageModelMiddleware = languageModelMiddleware;
9281
9426
  }
@@ -9630,6 +9775,10 @@ var import_provider_utils31 = require("@ai-sdk/provider-utils");
9630
9775
 
9631
9776
  // src/ui/http-chat-transport.ts
9632
9777
  var import_provider_utils30 = require("@ai-sdk/provider-utils");
9778
+ function appendPathToUrl(url, path) {
9779
+ const queryOrFragmentStart = url.search(/[?#]/);
9780
+ return queryOrFragmentStart === -1 ? `${url}${path}` : `${url.slice(0, queryOrFragmentStart)}${path}${url.slice(queryOrFragmentStart)}`;
9781
+ }
9633
9782
  var HttpChatTransport = class {
9634
9783
  constructor({
9635
9784
  api = "/api/chat",
@@ -9704,7 +9853,7 @@ var HttpChatTransport = class {
9704
9853
  return this.processResponseStream(response.body);
9705
9854
  }
9706
9855
  async reconnectToStream(options) {
9707
- var _a16, _b, _c, _d, _e;
9856
+ var _a16, _b, _c, _d;
9708
9857
  const resolvedBody = await (0, import_provider_utils30.resolve)(this.body);
9709
9858
  const resolvedHeaders = await (0, import_provider_utils30.resolve)(this.headers);
9710
9859
  const resolvedCredentials = await (0, import_provider_utils30.resolve)(this.credentials);
@@ -9720,10 +9869,23 @@ var HttpChatTransport = class {
9720
9869
  credentials: resolvedCredentials,
9721
9870
  requestMetadata: options.metadata
9722
9871
  }));
9723
- const api = (_b = preparedRequest == null ? void 0 : preparedRequest.api) != null ? _b : `${this.api}/${options.chatId}/stream`;
9872
+ let api = preparedRequest == null ? void 0 : preparedRequest.api;
9873
+ if (api == null) {
9874
+ if (options.chatId === "." || options.chatId === "..") {
9875
+ throw new InvalidArgumentError({
9876
+ parameter: "chatId",
9877
+ value: options.chatId,
9878
+ message: 'Chat IDs must not be "." or ".." when using the default reconnect URL.'
9879
+ });
9880
+ }
9881
+ api = appendPathToUrl(
9882
+ this.api,
9883
+ `/${encodeURIComponent(options.chatId)}/stream`
9884
+ );
9885
+ }
9724
9886
  const headers = (preparedRequest == null ? void 0 : preparedRequest.headers) !== void 0 ? (0, import_provider_utils30.normalizeHeaders)(preparedRequest.headers) : baseHeaders;
9725
- const credentials = (_c = preparedRequest == null ? void 0 : preparedRequest.credentials) != null ? _c : resolvedCredentials;
9726
- const fetch2 = (_d = this.fetch) != null ? _d : globalThis.fetch;
9887
+ const credentials = (_b = preparedRequest == null ? void 0 : preparedRequest.credentials) != null ? _b : resolvedCredentials;
9888
+ const fetch2 = (_c = this.fetch) != null ? _c : globalThis.fetch;
9727
9889
  const response = await fetch2(api, {
9728
9890
  method: "GET",
9729
9891
  headers,
@@ -9735,7 +9897,7 @@ var HttpChatTransport = class {
9735
9897
  }
9736
9898
  if (!response.ok) {
9737
9899
  throw new Error(
9738
- (_e = await response.text()) != null ? _e : "Failed to fetch the chat response."
9900
+ (_d = await response.text()) != null ? _d : "Failed to fetch the chat response."
9739
9901
  );
9740
9902
  }
9741
9903
  if (!response.body) {
@@ -9997,6 +10159,9 @@ var AbstractChat = class {
9997
10159
  };
9998
10160
  this.setStatus({ status: "submitted", error: void 0 });
9999
10161
  const lastMessage = this.lastMessage;
10162
+ const resumableResponseMessage = trigger === "resume-stream" && (lastMessage == null ? void 0 : lastMessage.role) === "assistant" && lastMessage.parts.some(
10163
+ (part) => isToolOrDynamicToolUIPart(part) && part.state === "input-streaming"
10164
+ ) ? this.state.snapshot(lastMessage) : void 0;
10000
10165
  let isAbort = false;
10001
10166
  let isDisconnect = false;
10002
10167
  let isError = false;
@@ -10004,7 +10169,7 @@ var AbstractChat = class {
10004
10169
  try {
10005
10170
  const response = {
10006
10171
  state: trigger === "resume-stream" && this.resumableStreamState != null ? this.resumableStreamState : createStreamingUIMessageState({
10007
- lastMessage: trigger === "resume-stream" ? void 0 : this.state.snapshot(lastMessage),
10172
+ lastMessage: trigger === "resume-stream" ? resumableResponseMessage : this.state.snapshot(lastMessage),
10008
10173
  messageId: this.generateId()
10009
10174
  }),
10010
10175
  abortController
@@ -10185,8 +10350,13 @@ function lastAssistantMessageIsCompleteWithToolCalls({
10185
10350
  const lastStepStartIndex = message.parts.reduce((lastIndex, part, index) => {
10186
10351
  return part.type === "step-start" ? index : lastIndex;
10187
10352
  }, -1);
10188
- const lastStepToolInvocations = message.parts.slice(lastStepStartIndex + 1).filter(isToolOrDynamicToolUIPart).filter((part) => !part.providerExecuted);
10189
- return lastStepToolInvocations.length > 0 && lastStepToolInvocations.every(
10353
+ const lastStepParts = message.parts.slice(lastStepStartIndex + 1);
10354
+ const lastStepToolInvocations = lastStepParts.filter(isToolOrDynamicToolUIPart).filter((part) => !part.providerExecuted);
10355
+ const lastToolInvocationIndex = lastStepParts.reduce(
10356
+ (lastIndex, part, index) => isToolOrDynamicToolUIPart(part) && !part.providerExecuted ? index : lastIndex,
10357
+ -1
10358
+ );
10359
+ return lastStepToolInvocations.length > 0 && !lastStepParts.slice(lastToolInvocationIndex + 1).some((part) => part.type === "text" && part.state !== "done") && lastStepToolInvocations.every(
10190
10360
  (part) => part.state === "output-available" || part.state === "output-error"
10191
10361
  );
10192
10362
  }
@@ -10315,6 +10485,7 @@ var uiMessagesSchema = (0, import_provider_utils33.lazyValidator)(
10315
10485
  toolCallId: import_v48.z.string(),
10316
10486
  state: import_v48.z.literal("input-streaming"),
10317
10487
  input: import_v48.z.unknown().optional(),
10488
+ rawInput: import_v48.z.string().optional(),
10318
10489
  providerExecuted: import_v48.z.boolean().optional(),
10319
10490
  output: import_v48.z.never().optional(),
10320
10491
  errorText: import_v48.z.never().optional()
@@ -10360,6 +10531,7 @@ var uiMessagesSchema = (0, import_provider_utils33.lazyValidator)(
10360
10531
  state: import_v48.z.literal("input-streaming"),
10361
10532
  providerExecuted: import_v48.z.boolean().optional(),
10362
10533
  input: import_v48.z.unknown().optional(),
10534
+ rawInput: import_v48.z.string().optional(),
10363
10535
  output: import_v48.z.never().optional(),
10364
10536
  errorText: import_v48.z.never().optional(),
10365
10537
  approval: import_v48.z.never().optional()