ai 5.0.217 → 5.0.219

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,26 @@
1
1
  # ai
2
2
 
3
+ ## 5.0.219
4
+
5
+ ### Patch Changes
6
+
7
+ - 649bd0f: fix(ai): bound media-type sniffing decode for ID3-prefixed input
8
+
9
+ Media-type detection stripped ID3 tags before the ~18-byte prefix cap, decoding the entire base64 attachment (plus a full-size copy) whenever the data began with `ID3`/`SUQz`. This turned the intended O(1) sniff into an O(N) decode of the whole attachment. Detection now decodes at most a bounded prefix and skips the ID3 tag within that bound, keeping cost O(1) in input size on both image and audio paths.
10
+
11
+ - 965545b: Return response piping promises so callers can catch stream read and write errors.
12
+ - Updated dependencies [fb4c0d7]
13
+ - @ai-sdk/gateway@2.0.118
14
+
15
+ ## 5.0.218
16
+
17
+ ### Patch Changes
18
+
19
+ - a322c62: fix: detect MP4 audio from its ftyp box during transcription
20
+ - cf778a9: fix(ai): preserve tool parts when tool call IDs repeat across steps
21
+ - Updated dependencies [b05bffb]
22
+ - @ai-sdk/gateway@2.0.117
23
+
3
24
  ## 5.0.217
4
25
 
5
26
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -2108,7 +2108,7 @@ interface StreamTextResult<TOOLS extends ToolSet, PARTIAL_OUTPUT> {
2108
2108
  /**
2109
2109
  *Writes UI message stream output to a Node.js response-like object.
2110
2110
  */
2111
- pipeUIMessageStreamToResponse<UI_MESSAGE extends UIMessage>(response: ServerResponse, options?: UIMessageStreamResponseInit & UIMessageStreamOptions<UI_MESSAGE>): void;
2111
+ pipeUIMessageStreamToResponse<UI_MESSAGE extends UIMessage>(response: ServerResponse, options?: UIMessageStreamResponseInit & UIMessageStreamOptions<UI_MESSAGE>): Promise<void>;
2112
2112
  /**
2113
2113
  Writes text delta output to a Node.js response-like object.
2114
2114
  It sets a `Content-Type` header to `text/plain; charset=utf-8` and
@@ -2117,7 +2117,7 @@ interface StreamTextResult<TOOLS extends ToolSet, PARTIAL_OUTPUT> {
2117
2117
  @param response A Node.js response-like object (ServerResponse).
2118
2118
  @param init Optional headers, status code, and status text.
2119
2119
  */
2120
- pipeTextStreamToResponse(response: ServerResponse, init?: ResponseInit): void;
2120
+ pipeTextStreamToResponse(response: ServerResponse, init?: ResponseInit): Promise<void>;
2121
2121
  /**
2122
2122
  Converts the result to a streamed response object with a stream data part stream.
2123
2123
 
@@ -3238,7 +3238,7 @@ interface StreamObjectResult<PARTIAL, RESULT, ELEMENT_STREAM> {
3238
3238
  @param response A Node.js response-like object (ServerResponse).
3239
3239
  @param init Optional headers, status code, and status text.
3240
3240
  */
3241
- pipeTextStreamToResponse(response: ServerResponse$1, init?: ResponseInit): void;
3241
+ pipeTextStreamToResponse(response: ServerResponse$1, init?: ResponseInit): Promise<void>;
3242
3242
  /**
3243
3243
  Creates a simple text stream response.
3244
3244
  The response has a `Content-Type` header set to `text/plain; charset=utf-8`.
@@ -3713,7 +3713,7 @@ declare function createTextStreamResponse({ status, statusText, headers, textStr
3713
3713
  declare function pipeTextStreamToResponse({ response, status, statusText, headers, textStream, }: {
3714
3714
  response: ServerResponse;
3715
3715
  textStream: ReadableStream<string>;
3716
- } & ResponseInit): void;
3716
+ } & ResponseInit): Promise<void>;
3717
3717
 
3718
3718
  /**
3719
3719
  The result of a `transcribe` call.
@@ -3893,7 +3893,7 @@ declare class JsonToSseTransformStream extends TransformStream<unknown, string>
3893
3893
  declare function pipeUIMessageStreamToResponse({ response, status, statusText, headers, stream, consumeSseStream, }: {
3894
3894
  response: ServerResponse;
3895
3895
  stream: ReadableStream<UIMessageChunk>;
3896
- } & UIMessageStreamResponseInit): void;
3896
+ } & UIMessageStreamResponseInit): Promise<void>;
3897
3897
 
3898
3898
  /**
3899
3899
  * Transforms a stream of `UIMessageChunk`s into an `AsyncIterableStream` of `UIMessage`s.
package/dist/index.d.ts CHANGED
@@ -2108,7 +2108,7 @@ interface StreamTextResult<TOOLS extends ToolSet, PARTIAL_OUTPUT> {
2108
2108
  /**
2109
2109
  *Writes UI message stream output to a Node.js response-like object.
2110
2110
  */
2111
- pipeUIMessageStreamToResponse<UI_MESSAGE extends UIMessage>(response: ServerResponse, options?: UIMessageStreamResponseInit & UIMessageStreamOptions<UI_MESSAGE>): void;
2111
+ pipeUIMessageStreamToResponse<UI_MESSAGE extends UIMessage>(response: ServerResponse, options?: UIMessageStreamResponseInit & UIMessageStreamOptions<UI_MESSAGE>): Promise<void>;
2112
2112
  /**
2113
2113
  Writes text delta output to a Node.js response-like object.
2114
2114
  It sets a `Content-Type` header to `text/plain; charset=utf-8` and
@@ -2117,7 +2117,7 @@ interface StreamTextResult<TOOLS extends ToolSet, PARTIAL_OUTPUT> {
2117
2117
  @param response A Node.js response-like object (ServerResponse).
2118
2118
  @param init Optional headers, status code, and status text.
2119
2119
  */
2120
- pipeTextStreamToResponse(response: ServerResponse, init?: ResponseInit): void;
2120
+ pipeTextStreamToResponse(response: ServerResponse, init?: ResponseInit): Promise<void>;
2121
2121
  /**
2122
2122
  Converts the result to a streamed response object with a stream data part stream.
2123
2123
 
@@ -3238,7 +3238,7 @@ interface StreamObjectResult<PARTIAL, RESULT, ELEMENT_STREAM> {
3238
3238
  @param response A Node.js response-like object (ServerResponse).
3239
3239
  @param init Optional headers, status code, and status text.
3240
3240
  */
3241
- pipeTextStreamToResponse(response: ServerResponse$1, init?: ResponseInit): void;
3241
+ pipeTextStreamToResponse(response: ServerResponse$1, init?: ResponseInit): Promise<void>;
3242
3242
  /**
3243
3243
  Creates a simple text stream response.
3244
3244
  The response has a `Content-Type` header set to `text/plain; charset=utf-8`.
@@ -3713,7 +3713,7 @@ declare function createTextStreamResponse({ status, statusText, headers, textStr
3713
3713
  declare function pipeTextStreamToResponse({ response, status, statusText, headers, textStream, }: {
3714
3714
  response: ServerResponse;
3715
3715
  textStream: ReadableStream<string>;
3716
- } & ResponseInit): void;
3716
+ } & ResponseInit): Promise<void>;
3717
3717
 
3718
3718
  /**
3719
3719
  The result of a `transcribe` call.
@@ -3893,7 +3893,7 @@ declare class JsonToSseTransformStream extends TransformStream<unknown, string>
3893
3893
  declare function pipeUIMessageStreamToResponse({ response, status, statusText, headers, stream, consumeSseStream, }: {
3894
3894
  response: ServerResponse;
3895
3895
  stream: ReadableStream<UIMessageChunk>;
3896
- } & UIMessageStreamResponseInit): void;
3896
+ } & UIMessageStreamResponseInit): Promise<void>;
3897
3897
 
3898
3898
  /**
3899
3899
  * Transforms a stream of `UIMessageChunk`s into an `AsyncIterableStream` of `UIMessage`s.
package/dist/index.js CHANGED
@@ -738,32 +738,54 @@ var audioMediaTypeSignatures = [
738
738
  },
739
739
  {
740
740
  mediaType: "audio/mp4",
741
- bytesPrefix: [102, 116, 121, 112]
741
+ bytesPrefix: [
742
+ 0,
743
+ 0,
744
+ 0,
745
+ null,
746
+ 102,
747
+ 116,
748
+ 121,
749
+ 112
750
+ // ftyp
751
+ ]
742
752
  },
743
753
  {
744
754
  mediaType: "audio/webm",
745
755
  bytesPrefix: [26, 69, 223, 163]
746
756
  }
747
757
  ];
748
- var stripID3 = (data) => {
749
- const bytes = typeof data === "string" ? (0, import_provider_utils.convertBase64ToUint8Array)(data) : data;
758
+ var DEFAULT_SNIFF_BYTES = 18;
759
+ var MAX_SIGNATURE_BYTES = 12;
760
+ var MAX_ID3_TAG_BYTES = 128 * 1024;
761
+ var ID3_SCAN_BYTES = MAX_ID3_TAG_BYTES + MAX_SIGNATURE_BYTES;
762
+ function decodePrefix(data, maxBytes) {
763
+ if (typeof data !== "string") {
764
+ return data.length > maxBytes ? data.subarray(0, maxBytes) : data;
765
+ }
766
+ const maxChars = Math.ceil(maxBytes / 3) * 4;
767
+ const bytes = (0, import_provider_utils.convertBase64ToUint8Array)(
768
+ data.substring(0, Math.min(data.length, maxChars))
769
+ );
770
+ return bytes.length > maxBytes ? bytes.subarray(0, maxBytes) : bytes;
771
+ }
772
+ function hasID3(bytes) {
773
+ return bytes.length > 10 && bytes[0] === 73 && // 'I'
774
+ bytes[1] === 68 && // 'D'
775
+ bytes[2] === 51;
776
+ }
777
+ var stripID3 = (bytes) => {
750
778
  const id3Size = (bytes[6] & 127) << 21 | (bytes[7] & 127) << 14 | (bytes[8] & 127) << 7 | bytes[9] & 127;
751
- return bytes.slice(id3Size + 10);
779
+ return bytes.subarray(id3Size + 10);
752
780
  };
753
- function stripID3TagsIfPresent(data) {
754
- const hasId3 = typeof data === "string" && data.startsWith("SUQz") || typeof data !== "string" && data.length > 10 && data[0] === 73 && // 'I'
755
- data[1] === 68 && // 'D'
756
- data[2] === 51;
757
- return hasId3 ? stripID3(data) : data;
758
- }
759
781
  function detectMediaType({
760
782
  data,
761
783
  signatures
762
784
  }) {
763
- const processedData = stripID3TagsIfPresent(data);
764
- const bytes = typeof processedData === "string" ? (0, import_provider_utils.convertBase64ToUint8Array)(
765
- processedData.substring(0, Math.min(processedData.length, 24))
766
- ) : processedData;
785
+ let bytes = decodePrefix(data, DEFAULT_SNIFF_BYTES);
786
+ if (hasID3(bytes)) {
787
+ bytes = stripID3(decodePrefix(data, ID3_SCAN_BYTES));
788
+ }
767
789
  for (const signature of signatures) {
768
790
  if (bytes.length >= signature.bytesPrefix.length && signature.bytesPrefix.every(
769
791
  (byte, index) => byte === null || bytes[index] === byte
@@ -778,7 +800,7 @@ function detectMediaType({
778
800
  var import_provider_utils2 = require("@ai-sdk/provider-utils");
779
801
 
780
802
  // src/version.ts
781
- var VERSION = true ? "5.0.217" : "0.0.0-test";
803
+ var VERSION = true ? "5.0.219" : "0.0.0-test";
782
804
 
783
805
  // src/util/download/download.ts
784
806
  var download = async ({
@@ -2932,7 +2954,7 @@ function writeToServerResponse({
2932
2954
  response.end();
2933
2955
  }
2934
2956
  };
2935
- read();
2957
+ return read();
2936
2958
  }
2937
2959
 
2938
2960
  // src/text-stream/pipe-text-stream-to-response.ts
@@ -2943,7 +2965,7 @@ function pipeTextStreamToResponse({
2943
2965
  headers,
2944
2966
  textStream
2945
2967
  }) {
2946
- writeToServerResponse({
2968
+ return writeToServerResponse({
2947
2969
  response,
2948
2970
  status,
2949
2971
  statusText,
@@ -3612,11 +3634,32 @@ function processUIMessageStream({
3612
3634
  async transform(chunk, controller) {
3613
3635
  await runUpdateMessageJob(async ({ state, write }) => {
3614
3636
  var _a16, _b, _c, _d;
3637
+ function getCurrentStepParts() {
3638
+ const parts = state.message.parts;
3639
+ let currentStepStartIndex = parts.length - 1;
3640
+ while (currentStepStartIndex >= 0 && parts[currentStepStartIndex].type !== "step-start") {
3641
+ currentStepStartIndex--;
3642
+ }
3643
+ return parts.slice(currentStepStartIndex + 1);
3644
+ }
3645
+ function getCurrentStepToolInvocations() {
3646
+ return getCurrentStepParts().filter(isToolUIPart);
3647
+ }
3615
3648
  function getToolInvocation(toolCallId) {
3616
- const toolInvocations = state.message.parts.filter(isToolUIPart);
3617
- const toolInvocation = toolInvocations.find(
3649
+ const toolInvocations = getCurrentStepToolInvocations();
3650
+ let toolInvocation = toolInvocations.find(
3618
3651
  (invocation) => invocation.toolCallId === toolCallId
3619
3652
  );
3653
+ if (toolInvocation == null) {
3654
+ const parts = state.message.parts;
3655
+ for (let i = parts.length - 1; i >= 0; i--) {
3656
+ const part = parts[i];
3657
+ if (isToolUIPart(part) && part.toolCallId === toolCallId) {
3658
+ toolInvocation = part;
3659
+ break;
3660
+ }
3661
+ }
3662
+ }
3620
3663
  if (toolInvocation == null) {
3621
3664
  throw new Error(
3622
3665
  "tool-output-error must be preceded by a tool-input-available"
@@ -3625,12 +3668,22 @@ function processUIMessageStream({
3625
3668
  return toolInvocation;
3626
3669
  }
3627
3670
  function getDynamicToolInvocation(toolCallId) {
3628
- const toolInvocations = state.message.parts.filter(
3671
+ const toolInvocations = getCurrentStepParts().filter(
3629
3672
  (part) => part.type === "dynamic-tool"
3630
3673
  );
3631
- const toolInvocation = toolInvocations.find(
3674
+ let toolInvocation = toolInvocations.find(
3632
3675
  (invocation) => invocation.toolCallId === toolCallId
3633
3676
  );
3677
+ if (toolInvocation == null) {
3678
+ const parts = state.message.parts;
3679
+ for (let i = parts.length - 1; i >= 0; i--) {
3680
+ const part = parts[i];
3681
+ if (part.type === "dynamic-tool" && part.toolCallId === toolCallId) {
3682
+ toolInvocation = part;
3683
+ break;
3684
+ }
3685
+ }
3686
+ }
3634
3687
  if (toolInvocation == null) {
3635
3688
  throw new Error(
3636
3689
  "tool-output-error must be preceded by a tool-input-available"
@@ -3638,9 +3691,9 @@ function processUIMessageStream({
3638
3691
  }
3639
3692
  return toolInvocation;
3640
3693
  }
3641
- function updateToolPart(options) {
3694
+ function updateToolPart(options, existingPart) {
3642
3695
  var _a17;
3643
- const part = state.message.parts.find(
3696
+ const part = existingPart != null ? existingPart : getCurrentStepParts().find(
3644
3697
  (part2) => isToolUIPart(part2) && part2.toolCallId === options.toolCallId
3645
3698
  );
3646
3699
  const anyOptions = options;
@@ -3671,9 +3724,9 @@ function processUIMessageStream({
3671
3724
  });
3672
3725
  }
3673
3726
  }
3674
- function updateDynamicToolPart(options) {
3727
+ function updateDynamicToolPart(options, existingPart) {
3675
3728
  var _a17, _b2;
3676
- const part = state.message.parts.find(
3729
+ const part = existingPart != null ? existingPart : getCurrentStepParts().find(
3677
3730
  (part2) => part2.type === "dynamic-tool" && part2.toolCallId === options.toolCallId
3678
3731
  );
3679
3732
  const anyOptions = options;
@@ -3805,7 +3858,7 @@ function processUIMessageStream({
3805
3858
  break;
3806
3859
  }
3807
3860
  case "tool-input-start": {
3808
- const toolInvocations = state.message.parts.filter(isToolUIPart);
3861
+ const toolInvocations = getCurrentStepParts().filter(isToolUIPart);
3809
3862
  state.partialToolCalls[chunk.toolCallId] = {
3810
3863
  text: "",
3811
3864
  toolName: chunk.toolName,
@@ -3915,25 +3968,31 @@ function processUIMessageStream({
3915
3968
  const toolInvocation = getDynamicToolInvocation(
3916
3969
  chunk.toolCallId
3917
3970
  );
3918
- updateDynamicToolPart({
3919
- toolCallId: chunk.toolCallId,
3920
- toolName: toolInvocation.toolName,
3921
- state: "output-available",
3922
- input: toolInvocation.input,
3923
- output: chunk.output,
3924
- preliminary: chunk.preliminary
3925
- });
3971
+ updateDynamicToolPart(
3972
+ {
3973
+ toolCallId: chunk.toolCallId,
3974
+ toolName: toolInvocation.toolName,
3975
+ state: "output-available",
3976
+ input: toolInvocation.input,
3977
+ output: chunk.output,
3978
+ preliminary: chunk.preliminary
3979
+ },
3980
+ toolInvocation
3981
+ );
3926
3982
  } else {
3927
3983
  const toolInvocation = getToolInvocation(chunk.toolCallId);
3928
- updateToolPart({
3929
- toolCallId: chunk.toolCallId,
3930
- toolName: getToolName(toolInvocation),
3931
- state: "output-available",
3932
- input: toolInvocation.input,
3933
- output: chunk.output,
3934
- providerExecuted: chunk.providerExecuted,
3935
- preliminary: chunk.preliminary
3936
- });
3984
+ updateToolPart(
3985
+ {
3986
+ toolCallId: chunk.toolCallId,
3987
+ toolName: getToolName(toolInvocation),
3988
+ state: "output-available",
3989
+ input: toolInvocation.input,
3990
+ output: chunk.output,
3991
+ providerExecuted: chunk.providerExecuted,
3992
+ preliminary: chunk.preliminary
3993
+ },
3994
+ toolInvocation
3995
+ );
3937
3996
  }
3938
3997
  write();
3939
3998
  break;
@@ -3943,25 +4002,31 @@ function processUIMessageStream({
3943
4002
  const toolInvocation = getDynamicToolInvocation(
3944
4003
  chunk.toolCallId
3945
4004
  );
3946
- updateDynamicToolPart({
3947
- toolCallId: chunk.toolCallId,
3948
- toolName: toolInvocation.toolName,
3949
- state: "output-error",
3950
- input: toolInvocation.input,
3951
- errorText: chunk.errorText,
3952
- providerExecuted: chunk.providerExecuted
3953
- });
4005
+ updateDynamicToolPart(
4006
+ {
4007
+ toolCallId: chunk.toolCallId,
4008
+ toolName: toolInvocation.toolName,
4009
+ state: "output-error",
4010
+ input: toolInvocation.input,
4011
+ errorText: chunk.errorText,
4012
+ providerExecuted: chunk.providerExecuted
4013
+ },
4014
+ toolInvocation
4015
+ );
3954
4016
  } else {
3955
4017
  const toolInvocation = getToolInvocation(chunk.toolCallId);
3956
- updateToolPart({
3957
- toolCallId: chunk.toolCallId,
3958
- toolName: getToolName(toolInvocation),
3959
- state: "output-error",
3960
- input: toolInvocation.input,
3961
- rawInput: toolInvocation.rawInput,
3962
- errorText: chunk.errorText,
3963
- providerExecuted: chunk.providerExecuted
3964
- });
4018
+ updateToolPart(
4019
+ {
4020
+ toolCallId: chunk.toolCallId,
4021
+ toolName: getToolName(toolInvocation),
4022
+ state: "output-error",
4023
+ input: toolInvocation.input,
4024
+ rawInput: toolInvocation.rawInput,
4025
+ errorText: chunk.errorText,
4026
+ providerExecuted: chunk.providerExecuted
4027
+ },
4028
+ toolInvocation
4029
+ );
3965
4030
  }
3966
4031
  write();
3967
4032
  break;
@@ -4135,7 +4200,7 @@ function pipeUIMessageStreamToResponse({
4135
4200
  sseStream = stream1;
4136
4201
  consumeSseStream({ stream: stream2 });
4137
4202
  }
4138
- writeToServerResponse({
4203
+ return writeToServerResponse({
4139
4204
  response,
4140
4205
  status,
4141
4206
  statusText,
@@ -5882,7 +5947,7 @@ var DefaultStreamTextResult = class {
5882
5947
  onError,
5883
5948
  ...init
5884
5949
  } = {}) {
5885
- pipeUIMessageStreamToResponse({
5950
+ return pipeUIMessageStreamToResponse({
5886
5951
  response,
5887
5952
  stream: this.toUIMessageStream({
5888
5953
  originalMessages,
@@ -5899,7 +5964,7 @@ var DefaultStreamTextResult = class {
5899
5964
  });
5900
5965
  }
5901
5966
  pipeTextStreamToResponse(response, init) {
5902
- pipeTextStreamToResponse({
5967
+ return pipeTextStreamToResponse({
5903
5968
  response,
5904
5969
  textStream: this.textStream,
5905
5970
  ...init
@@ -8025,7 +8090,7 @@ var DefaultStreamObjectResult = class {
8025
8090
  return createAsyncIterableStream(this.baseStream);
8026
8091
  }
8027
8092
  pipeTextStreamToResponse(response, init) {
8028
- pipeTextStreamToResponse({
8093
+ return pipeTextStreamToResponse({
8029
8094
  response,
8030
8095
  textStream: this.textStream,
8031
8096
  ...init