@ai-sdk/provider-utils 4.0.49 → 4.0.50

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,11 @@
1
1
  # @ai-sdk/provider-utils
2
2
 
3
+ ## 4.0.50
4
+
5
+ ### Patch Changes
6
+
7
+ - cc23556: Mark transient network errors that occur while reading successful response bodies as retryable.
8
+
3
9
  ## 4.0.49
4
10
 
5
11
  ### Patch Changes
package/dist/index.js CHANGED
@@ -796,24 +796,31 @@ function isAbortError(error) {
796
796
 
797
797
  // src/handle-fetch-error.ts
798
798
  var FETCH_FAILED_ERROR_MESSAGES = ["fetch failed", "failed to fetch"];
799
- var BUN_ERROR_CODES = [
799
+ var RETRYABLE_NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
800
800
  "ConnectionRefused",
801
801
  "ConnectionClosed",
802
802
  "FailedToOpenSocket",
803
803
  "ECONNRESET",
804
804
  "ECONNREFUSED",
805
805
  "ETIMEDOUT",
806
- "EPIPE"
807
- ];
808
- function isBunNetworkError(error) {
809
- if (!(error instanceof Error)) {
810
- return false;
811
- }
812
- const code = error.code;
813
- if (typeof code === "string" && BUN_ERROR_CODES.includes(code)) {
814
- return true;
815
- }
816
- return false;
806
+ "EPIPE",
807
+ "UND_ERR_SOCKET",
808
+ "UND_ERR_HEADERS_TIMEOUT",
809
+ "UND_ERR_BODY_TIMEOUT",
810
+ "UND_ERR_CONNECT_TIMEOUT"
811
+ ]);
812
+ function findNetworkError(error) {
813
+ const visited = /* @__PURE__ */ new Set();
814
+ let current = error;
815
+ while (current instanceof Error && !visited.has(current)) {
816
+ visited.add(current);
817
+ const errorWithCode = current;
818
+ if (typeof errorWithCode.code === "string" && RETRYABLE_NETWORK_ERROR_CODES.has(errorWithCode.code)) {
819
+ return errorWithCode;
820
+ }
821
+ current = current.cause;
822
+ }
823
+ return void 0;
817
824
  }
818
825
  function handleFetchError({
819
826
  error,
@@ -836,9 +843,23 @@ function handleFetchError({
836
843
  });
837
844
  }
838
845
  }
839
- if (isBunNetworkError(error)) {
846
+ const networkError = findNetworkError(error);
847
+ if (networkError != null) {
848
+ if (import_provider3.APICallError.isInstance(error)) {
849
+ return new import_provider3.APICallError({
850
+ message: error.message,
851
+ cause: error.cause,
852
+ url: error.url,
853
+ requestBodyValues: error.requestBodyValues,
854
+ statusCode: error.statusCode,
855
+ responseHeaders: error.responseHeaders,
856
+ responseBody: error.responseBody,
857
+ data: error.data,
858
+ isRetryable: true
859
+ });
860
+ }
840
861
  return new import_provider3.APICallError({
841
- message: `Cannot connect to API: ${error.message}`,
862
+ message: `Cannot connect to API: ${error instanceof Error ? error.message : networkError.message}`,
842
863
  cause: error,
843
864
  url,
844
865
  requestBodyValues,
@@ -901,7 +922,7 @@ function withUserAgentSuffix(headers, ...userAgentSuffixParts) {
901
922
  }
902
923
 
903
924
  // src/version.ts
904
- var VERSION = true ? "4.0.49" : "0.0.0-test";
925
+ var VERSION = true ? "4.0.50" : "0.0.0-test";
905
926
 
906
927
  // src/get-from-api.ts
907
928
  var getOriginalFetch = () => globalThis.fetch;
@@ -2936,6 +2957,62 @@ async function retryWithExponentialBackoffInternal(f, {
2936
2957
  // src/response-handler.ts
2937
2958
  var import_provider12 = require("@ai-sdk/provider");
2938
2959
  var textDecoder = new TextDecoder();
2960
+ function wrapResponseBodyStream({
2961
+ stream,
2962
+ url,
2963
+ requestBodyValues,
2964
+ statusCode,
2965
+ responseHeaders
2966
+ }) {
2967
+ const reader = stream.getReader();
2968
+ let readerReleased = false;
2969
+ const releaseReader = () => {
2970
+ if (!readerReleased) {
2971
+ reader.releaseLock();
2972
+ readerReleased = true;
2973
+ }
2974
+ };
2975
+ return new ReadableStream({
2976
+ async pull(controller) {
2977
+ try {
2978
+ const { done, value } = await reader.read();
2979
+ if (done) {
2980
+ releaseReader();
2981
+ controller.close();
2982
+ } else {
2983
+ controller.enqueue(value);
2984
+ }
2985
+ } catch (error) {
2986
+ releaseReader();
2987
+ if (isAbortError(error)) {
2988
+ controller.error(error);
2989
+ return;
2990
+ }
2991
+ controller.error(
2992
+ handleFetchError({
2993
+ error: new import_provider12.APICallError({
2994
+ message: "Failed to process successful response",
2995
+ cause: error,
2996
+ statusCode,
2997
+ url,
2998
+ responseHeaders,
2999
+ requestBodyValues
3000
+ }),
3001
+ url,
3002
+ requestBodyValues
3003
+ })
3004
+ );
3005
+ }
3006
+ },
3007
+ async cancel(reason) {
3008
+ try {
3009
+ await reader.cancel(reason);
3010
+ } finally {
3011
+ releaseReader();
3012
+ }
3013
+ }
3014
+ });
3015
+ }
2939
3016
  async function readResponseBodyAsText({
2940
3017
  response,
2941
3018
  url
@@ -3001,7 +3078,7 @@ var createJsonErrorResponseHandler = ({
3001
3078
  };
3002
3079
  }
3003
3080
  };
3004
- var createEventSourceResponseHandler = (chunkSchema) => async ({ response }) => {
3081
+ var createEventSourceResponseHandler = (chunkSchema) => async ({ response, url, requestBodyValues }) => {
3005
3082
  const responseHeaders = extractResponseHeaders(response);
3006
3083
  if (response.body == null) {
3007
3084
  throw new import_provider12.EmptyResponseBodyError({});
@@ -3009,7 +3086,13 @@ var createEventSourceResponseHandler = (chunkSchema) => async ({ response }) =>
3009
3086
  return {
3010
3087
  responseHeaders,
3011
3088
  value: parseJsonEventStream({
3012
- stream: response.body,
3089
+ stream: wrapResponseBodyStream({
3090
+ stream: response.body,
3091
+ url,
3092
+ requestBodyValues,
3093
+ statusCode: response.status,
3094
+ responseHeaders
3095
+ }),
3013
3096
  schema: chunkSchema
3014
3097
  })
3015
3098
  };