ai 7.0.98 → 7.0.100

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,21 @@
1
1
  # ai
2
2
 
3
+ ## 7.0.100
4
+
5
+ ### Patch Changes
6
+
7
+ - 6431635: feat(ai): expose typed AI SDK errors for UI transport and completion failures
8
+ - Updated dependencies [23a0fff]
9
+ - @ai-sdk/gateway@4.0.81
10
+
11
+ ## 7.0.99
12
+
13
+ ### Patch Changes
14
+
15
+ - 615ac89: feat(ai): use InvalidArgumentError for utility input validation
16
+ - Updated dependencies [7f76d83]
17
+ - @ai-sdk/gateway@4.0.80
18
+
3
19
  ## 7.0.98
4
20
 
5
21
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -7052,7 +7052,9 @@ interface EmbedManyResult {
7052
7052
  * @param abortSignal - An optional abort signal that can be used to cancel the call.
7053
7053
  * @param headers - Additional HTTP headers to be sent with the request. Only applicable for HTTP-based providers.
7054
7054
  *
7055
- * @param maxParallelCalls - Maximum number of concurrent requests. Default: Infinity.
7055
+ * @param maxParallelCalls - Maximum number of concurrent requests when a request is split into
7056
+ * multiple model calls. Must be greater than 0 when the model supports parallel calls.
7057
+ * Default: Infinity.
7056
7058
  *
7057
7059
  * @param telemetry - Optional telemetry configuration.
7058
7060
  * @param runtimeContext - User-defined runtime context passed to callbacks and, when explicitly included, telemetry.
@@ -7108,7 +7110,8 @@ declare function embedMany<RUNTIME_CONTEXT extends Context = Context>({ model: m
7108
7110
  */
7109
7111
  providerOptions?: ProviderOptions;
7110
7112
  /**
7111
- * Maximum number of concurrent requests.
7113
+ * Maximum number of concurrent requests when a request is split into multiple model calls.
7114
+ * Must be greater than 0 when the model supports parallel calls.
7112
7115
  *
7113
7116
  * @default Infinity
7114
7117
  */
@@ -7516,9 +7519,11 @@ declare class UnsupportedModelVersionError extends AISDKError {
7516
7519
 
7517
7520
  declare const symbol$5: unique symbol;
7518
7521
  /**
7519
- * Error thrown when a UI message stream contains invalid or out-of-sequence chunks.
7522
+ * Error thrown when a UI message stream reports an error or contains invalid
7523
+ * or out-of-sequence chunks.
7520
7524
  *
7521
7525
  * This typically occurs when:
7526
+ * - An error chunk is received
7522
7527
  * - A delta chunk is received without a corresponding start chunk
7523
7528
  * - An end chunk is received without a corresponding start chunk
7524
7529
  * - A tool invocation is not found for the given toolCallId
@@ -7532,7 +7537,8 @@ declare class UIMessageStreamError extends AISDKError {
7532
7537
  */
7533
7538
  readonly chunkType: string;
7534
7539
  /**
7535
- * The ID associated with the failing chunk (part ID or toolCallId).
7540
+ * The ID associated with the failing chunk (part ID or toolCallId), or an
7541
+ * empty string when the chunk does not have an ID.
7536
7542
  */
7537
7543
  readonly chunkId: string;
7538
7544
  constructor({ chunkType, chunkId, message, }: {
@@ -7887,6 +7893,8 @@ declare function createDownload(options?: {
7887
7893
 
7888
7894
  /**
7889
7895
  * Converts a data URL of type text/* to a text string.
7896
+ *
7897
+ * @throws {InvalidArgumentError} If the data URL is malformed or cannot be decoded.
7890
7898
  */
7891
7899
  declare function getTextFromDataUrl(dataUrl: string): string;
7892
7900
 
package/dist/index.js CHANGED
@@ -1178,7 +1178,7 @@ import {
1178
1178
  } from "@ai-sdk/provider-utils";
1179
1179
 
1180
1180
  // src/version.ts
1181
- var VERSION = true ? "7.0.98" : "0.0.0-test";
1181
+ var VERSION = true ? "7.0.100" : "0.0.0-test";
1182
1182
 
1183
1183
  // src/util/download/download.ts
1184
1184
  var download = async ({
@@ -13639,7 +13639,11 @@ function getEmbeddingModelMaxInputBytesPerCall(model) {
13639
13639
  // src/util/split-array.ts
13640
13640
  function splitArray(array3, chunkSize) {
13641
13641
  if (chunkSize <= 0) {
13642
- throw new Error("chunkSize must be greater than 0");
13642
+ throw new InvalidArgumentError({
13643
+ parameter: "chunkSize",
13644
+ value: chunkSize,
13645
+ message: "chunkSize must be greater than 0"
13646
+ });
13643
13647
  }
13644
13648
  const result = [];
13645
13649
  for (let i = 0; i < array3.length; i += chunkSize) {
@@ -14737,12 +14741,20 @@ function getTextFromDataUrl(dataUrl) {
14737
14741
  const [header, base64Content] = dataUrl.split(",");
14738
14742
  const mediaType = header.split(";")[0].split(":")[1];
14739
14743
  if (mediaType == null || base64Content == null) {
14740
- throw new Error("Invalid data URL format");
14744
+ throw new InvalidArgumentError({
14745
+ parameter: "dataUrl",
14746
+ value: dataUrl,
14747
+ message: "Invalid data URL format"
14748
+ });
14741
14749
  }
14742
14750
  try {
14743
14751
  return atob2(base64Content);
14744
14752
  } catch (e) {
14745
- throw new Error(`Error decoding data URL`);
14753
+ throw new InvalidArgumentError({
14754
+ parameter: "dataUrl",
14755
+ value: dataUrl,
14756
+ message: "Error decoding data URL"
14757
+ });
14746
14758
  }
14747
14759
  }
14748
14760
 
@@ -18962,6 +18974,26 @@ import {
18962
18974
  withUserAgentSuffix as withUserAgentSuffix16,
18963
18975
  getRuntimeEnvironmentUserAgent as getRuntimeEnvironmentUserAgent2
18964
18976
  } from "@ai-sdk/provider-utils";
18977
+ import { EmptyResponseBodyError as EmptyResponseBodyError2 } from "@ai-sdk/provider";
18978
+
18979
+ // src/ui/create-ui-api-call-error.ts
18980
+ import { APICallError as APICallError3 } from "@ai-sdk/provider";
18981
+ async function createUIApiCallError({
18982
+ response,
18983
+ url,
18984
+ fallbackMessage
18985
+ }) {
18986
+ const responseBody = await response.text();
18987
+ return new APICallError3({
18988
+ message: responseBody || fallbackMessage,
18989
+ url,
18990
+ // UI requests can contain prompts, messages, and other sensitive values.
18991
+ // Keep them out of client-facing error objects.
18992
+ requestBodyValues: void 0,
18993
+ statusCode: response.status,
18994
+ responseBody
18995
+ });
18996
+ }
18965
18997
 
18966
18998
  // src/ui/process-text-stream.ts
18967
18999
  async function processTextStream({
@@ -19021,12 +19053,16 @@ async function callCompletionApi({
19021
19053
  throw err;
19022
19054
  });
19023
19055
  if (!response.ok) {
19024
- throw new Error(
19025
- await response.text() || "Failed to fetch the chat response."
19026
- );
19056
+ throw await createUIApiCallError({
19057
+ response,
19058
+ url: api,
19059
+ fallbackMessage: "Failed to fetch the chat response."
19060
+ });
19027
19061
  }
19028
19062
  if (!response.body) {
19029
- throw new Error("The response body is empty.");
19063
+ throw new EmptyResponseBodyError2({
19064
+ message: "The response body is empty."
19065
+ });
19030
19066
  }
19031
19067
  let result = "";
19032
19068
  switch (streamProtocol) {
@@ -19056,7 +19092,11 @@ async function callCompletionApi({
19056
19092
  result += streamPart.delta;
19057
19093
  setCompletion(result);
19058
19094
  } else if (streamPart.type === "error") {
19059
- throw new Error(streamPart.errorText);
19095
+ throw new UIMessageStreamError({
19096
+ chunkType: "error",
19097
+ chunkId: "",
19098
+ message: streamPart.errorText
19099
+ });
19060
19100
  }
19061
19101
  }
19062
19102
  })
@@ -19069,7 +19109,11 @@ async function callCompletionApi({
19069
19109
  }
19070
19110
  default: {
19071
19111
  const exhaustiveCheck = streamProtocol;
19072
- throw new Error(`Unknown stream protocol: ${exhaustiveCheck}`);
19112
+ throw new InvalidArgumentError({
19113
+ parameter: "streamProtocol",
19114
+ value: exhaustiveCheck,
19115
+ message: `Unknown stream protocol: ${exhaustiveCheck}`
19116
+ });
19073
19117
  }
19074
19118
  }
19075
19119
  if (onFinish) {
@@ -19099,12 +19143,16 @@ import {
19099
19143
  } from "@ai-sdk/provider-utils";
19100
19144
 
19101
19145
  // src/ui/convert-file-list-to-file-ui-parts.ts
19146
+ import { UnsupportedFunctionalityError as UnsupportedFunctionalityError6 } from "@ai-sdk/provider";
19102
19147
  async function convertFileListToFileUIParts(files) {
19103
19148
  if (files == null) {
19104
19149
  return [];
19105
19150
  }
19106
19151
  if (!globalThis.FileList || !(files instanceof globalThis.FileList)) {
19107
- throw new Error("FileList is not supported in the current environment");
19152
+ throw new UnsupportedFunctionalityError6({
19153
+ functionality: "FileList",
19154
+ message: "FileList is not supported in the current environment"
19155
+ });
19108
19156
  }
19109
19157
  return Promise.all(
19110
19158
  Array.from(files).map(async (file) => {
@@ -19136,6 +19184,7 @@ import {
19136
19184
  normalizeHeaders,
19137
19185
  resolve as resolve2
19138
19186
  } from "@ai-sdk/provider-utils";
19187
+ import { EmptyResponseBodyError as EmptyResponseBodyError3 } from "@ai-sdk/provider";
19139
19188
  var HttpChatTransport = class {
19140
19189
  constructor({
19141
19190
  api = "/api/chat",
@@ -19200,12 +19249,16 @@ var HttpChatTransport = class {
19200
19249
  signal: abortSignal
19201
19250
  });
19202
19251
  if (!response.ok) {
19203
- throw new Error(
19204
- await response.text() || "Failed to fetch the chat response."
19205
- );
19252
+ throw await createUIApiCallError({
19253
+ response,
19254
+ url: api,
19255
+ fallbackMessage: "Failed to fetch the chat response."
19256
+ });
19206
19257
  }
19207
19258
  if (!response.body) {
19208
- throw new Error("The response body is empty.");
19259
+ throw new EmptyResponseBodyError3({
19260
+ message: "The response body is empty."
19261
+ });
19209
19262
  }
19210
19263
  return this.processResponseStream(response.body);
19211
19264
  }
@@ -19240,12 +19293,16 @@ var HttpChatTransport = class {
19240
19293
  return null;
19241
19294
  }
19242
19295
  if (!response.ok) {
19243
- throw new Error(
19244
- await response.text() || "Failed to fetch the chat response."
19245
- );
19296
+ throw await createUIApiCallError({
19297
+ response,
19298
+ url: api,
19299
+ fallbackMessage: "Failed to fetch the chat response."
19300
+ });
19246
19301
  }
19247
19302
  if (!response.body) {
19248
- throw new Error("The response body is empty.");
19303
+ throw new EmptyResponseBodyError3({
19304
+ message: "The response body is empty."
19305
+ });
19249
19306
  }
19250
19307
  return this.processResponseStream(response.body);
19251
19308
  }
@@ -19335,12 +19392,18 @@ var AbstractChat = class {
19335
19392
  (m) => m.id === message.messageId
19336
19393
  );
19337
19394
  if (messageIndex === -1) {
19338
- throw new Error(`message with id ${message.messageId} not found`);
19395
+ throw new InvalidArgumentError({
19396
+ parameter: "message.messageId",
19397
+ value: message.messageId,
19398
+ message: `message with id ${message.messageId} not found`
19399
+ });
19339
19400
  }
19340
19401
  if (this.state.messages[messageIndex].role !== "user") {
19341
- throw new Error(
19342
- `message with id ${message.messageId} is not a user message`
19343
- );
19402
+ throw new InvalidArgumentError({
19403
+ parameter: "message.messageId",
19404
+ value: message.messageId,
19405
+ message: `message with id ${message.messageId} is not a user message`
19406
+ });
19344
19407
  }
19345
19408
  this.state.messages = this.state.messages.slice(0, messageIndex + 1);
19346
19409
  this.state.replaceMessage(messageIndex, {
@@ -19373,7 +19436,11 @@ var AbstractChat = class {
19373
19436
  } = {}) => {
19374
19437
  const messageIndex = messageId == null ? this.state.messages.length - 1 : this.state.messages.findIndex((message) => message.id === messageId);
19375
19438
  if (messageIndex === -1) {
19376
- throw new Error(`message ${messageId} not found`);
19439
+ throw new InvalidArgumentError({
19440
+ parameter: "messageId",
19441
+ value: messageId,
19442
+ message: `message ${messageId} not found`
19443
+ });
19377
19444
  }
19378
19445
  this.state.messages = this.state.messages.slice(
19379
19446
  0,