ai-retry 1.7.0 → 1.7.2

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/README.md CHANGED
@@ -598,13 +598,20 @@ console.log(result.object); // { name: "Alice", age: 30 }
598
598
  > Each entry point also re-exports `createRetryable` already typed for that model family, so you can either import everything from one path:
599
599
  >
600
600
  > ```ts
601
- > import { createRetryable, error, httpStatus } from 'ai-retry/experimental/language-model';
601
+ > import {
602
+ > createRetryable,
603
+ > error,
604
+ > httpStatus,
605
+ > } from 'ai-retry/experimental/language-model';
602
606
  > ```
603
607
  >
604
608
  > or pull retryables from the dedicated `/retryables` subpath:
605
609
  >
606
610
  > ```ts
607
- > import { error, httpStatus } from 'ai-retry/experimental/language-model/retryables';
611
+ > import {
612
+ > error,
613
+ > httpStatus,
614
+ > } from 'ai-retry/experimental/language-model/retryables';
608
615
  > // or
609
616
  > import * as retryables from 'ai-retry/experimental/language-model/retryables';
610
617
  > ```
@@ -647,14 +654,14 @@ Pick the entry point that matches the model you pass to `createRetryable`. Each
647
654
 
648
655
  The primitive builders `error(...)` and `result(...)` take a predicate and turn it into a condition; their namespaces bundle the most common field matchers on top.
649
656
 
650
- | Helper | Matches when | Available in |
651
- | --------------------------------- | ------------------------------------------------------------------------------------- | ------------------------- |
652
- | `error(predicate)` | The current attempt failed and `predicate(err, ctx)` returns true | all three entry points |
653
- | `error.isRetryable(flag)` | `APICallError.isRetryable === flag` (default `true`) | all three entry points |
654
- | `error.statusCode(...patterns)` | Numbers match exactly; regex matches the stringified code (e.g. `/^5\d\d$/` for 5xx) | all three entry points |
655
- | `error.message(...patterns)` | Substring (case-insensitive) or regex match against the error message | all three entry points |
656
- | `result(predicate)` | The current attempt succeeded and `predicate(res, ctx)` returns true | `language-model` only |
657
- | `result.finishReason(...reasons)` | The result's `finishReason.unified` matches one of the given values | `language-model` only |
657
+ | Helper | Matches when | Available in |
658
+ | --------------------------------- | ------------------------------------------------------------------------------------ | ---------------------- |
659
+ | `error(predicate)` | The current attempt failed and `predicate(err, ctx)` returns true | all three entry points |
660
+ | `error.isRetryable(flag)` | `APICallError.isRetryable === flag` (default `true`) | all three entry points |
661
+ | `error.statusCode(...patterns)` | Numbers match exactly; regex matches the stringified code (e.g. `/^5\d\d$/` for 5xx) | all three entry points |
662
+ | `error.message(...patterns)` | Substring (case-insensitive) or regex match against the error message | all three entry points |
663
+ | `result(predicate)` | The current attempt succeeded and `predicate(res, ctx)` returns true | `language-model` only |
664
+ | `result.finishReason(...reasons)` | The result's `finishReason.unified` matches one of the given values | `language-model` only |
658
665
 
659
666
  ```typescript
660
667
  import { APICallError } from 'ai';
@@ -680,22 +687,20 @@ Convenience matchers built on top of the low-level ones for the common cases. Ea
680
687
 
681
688
  What each one matches:
682
689
 
683
- | Helper | Matches when |
684
- | -------------------------- | -------------------------------------------------------------------------------------------------- |
685
- | `httpStatus(...patterns)` | Numbers match the status code; strings match the message (substring); regex matches either |
686
- | `timeout()` | `Error.name === 'TimeoutError'` (`AbortSignal.timeout()` fired) |
687
- | `aborted()` | `Error.name === 'AbortError'` (manual `controller.abort()`) |
688
- | `finishReason(...reasons)` | The result's `finishReason.unified` matches one of the given values |
689
- | `schemaInvalid()` | The result text fails JSON-schema validation against the call's `responseFormat` |
690
- | `noImage()` | The image model threw `NoImageGeneratedError` |
690
+ | Helper | Matches when |
691
+ | -------------------------- | ------------------------------------------------------------------------------------------ |
692
+ | `httpStatus(...patterns)` | Numbers match the status code; strings match the message (substring); regex matches either |
693
+ | `timeout()` | `Error.name === 'TimeoutError'` (`AbortSignal.timeout()` fired) |
694
+ | `aborted()` | `Error.name === 'AbortError'` (manual `controller.abort()`) |
695
+ | `finishReason(...reasons)` | The result's `finishReason.unified` matches one of the given values |
696
+ | `schemaInvalid()` | The result text fails JSON-schema validation against the call's `responseFormat` |
697
+ | `noImage()` | The image model threw `NoImageGeneratedError` |
691
698
 
692
699
  Each high-level helper is a thin wrapper around the low-level ones. For example, `timeout()` is roughly:
693
700
 
694
701
  ```typescript
695
702
  function timeout() {
696
- return error(
697
- (err) => err instanceof Error && err.name === 'TimeoutError',
698
- );
703
+ return error((err) => err instanceof Error && err.name === 'TimeoutError');
699
704
  }
700
705
  ```
701
706
 
@@ -719,10 +724,7 @@ Every condition exposes two terminal actions that turn it into a `Retryable`:
719
724
  Compose conditions with `.and`, `.or`, `.not`:
720
725
 
721
726
  ```typescript
722
- import {
723
- error,
724
- httpStatus,
725
- } from 'ai-retry/experimental/language-model';
727
+ import { error, httpStatus } from 'ai-retry/experimental/language-model';
726
728
 
727
729
  httpStatus(429).or(error.message('overloaded'));
728
730
  httpStatus(503).and(error.message('temporary'));
@@ -733,16 +735,16 @@ error.isRetryable(true).not();
733
735
 
734
736
  Each stable retryable has an equivalent in the new shape (imports from `ai-retry/experimental/language-model` unless noted):
735
737
 
736
- | Built-in | Composable form |
737
- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
738
- | `contentFilterTriggered(m)` | `error(/* check e.data.error.code === 'content_filter' */).or(finishReason('content-filter')).switch({ model: m })` |
739
- | `requestTimeout(m)` | `timeout().switch({ model: m, timeout: 60_000 })` |
740
- | `requestNotRetryable(m)` | `error.isRetryable(false).switch({ model: m })` |
741
- | `schemaMismatch(m)` | `schemaInvalid().switch({ model: m })` |
742
- | `serviceOverloaded(m)` | `httpStatus(529, 'overloaded').switch({ model: m })` |
743
- | `serviceUnavailable(m)` | `error.statusCode(503).switch({ model: m })` |
744
- | `noImageGenerated(m)` | `noImage().switch({ model: m })` (from `image-model`) |
745
- | `retryAfterDelay({ delay, backoffFactor })` | `error.isRetryable(true).retry({ delay, backoffFactor })` |
738
+ | Built-in | Composable form |
739
+ | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
740
+ | `contentFilterTriggered(m)` | `error(/* check e.data.error.code === 'content_filter' */).or(finishReason('content-filter')).switch({ model: m })` |
741
+ | `requestTimeout(m)` | `timeout().switch({ model: m, timeout: 60_000 })` |
742
+ | `requestNotRetryable(m)` | `error.isRetryable(false).switch({ model: m })` |
743
+ | `schemaMismatch(m)` | `schemaInvalid().switch({ model: m })` |
744
+ | `serviceOverloaded(m)` | `httpStatus(529, 'overloaded').switch({ model: m })` |
745
+ | `serviceUnavailable(m)` | `error.statusCode(503).switch({ model: m })` |
746
+ | `noImageGenerated(m)` | `noImage().switch({ model: m })` (from `image-model`) |
747
+ | `retryAfterDelay({ delay, backoffFactor })` | `error.isRetryable(true).retry({ delay, backoffFactor })` |
746
748
 
747
749
  > [!NOTE]
748
750
  > `error.isRetryable(true)` matches whatever the AI SDK's `APICallError` marks retryable. By default that's status codes 408, 409, 429, and any 5xx, plus network errors and provider-specific overrides (e.g. Anthropic flips it on `error.type === 'overloaded_error'`). It picks up more cases than a manual status-code list.
@@ -664,8 +664,9 @@ var RetryableLanguageModel = class extends BaseRetryableModel {
664
664
  callOptions: retryCallOptions
665
665
  };
666
666
  } catch (error) {
667
- const { retryModel, attempt } = await this.handleError(error, attempts, retryCallOptions);
667
+ const { retryModel, attempt, finalError } = await this.handleError(error, attempts, retryCallOptions);
668
668
  attempts.push(attempt);
669
+ if (!retryModel) throw finalError;
669
670
  /**
670
671
  * If the inbound abort signal is already aborted and the chosen
671
672
  * retry does not supply a fresh deadline, the retry would die
@@ -706,7 +707,13 @@ var RetryableLanguageModel = class extends BaseRetryableModel {
706
707
  };
707
708
  }
708
709
  /**
709
- * Handle an error and determine if a retry is needed
710
+ * Handle an error and determine if a retry is needed.
711
+ *
712
+ * Returns a `finalError` (and undefined `retryModel`) when no retry
713
+ * matched, so callers can decide how to surface it: throwing for the
714
+ * generate path, or enqueuing a `{ type: 'error' }` stream part for
715
+ * the stream path. If multiple attempts were made, the original error
716
+ * is wrapped in a `RetryError`.
710
717
  */
711
718
  async handleError(error, attempts, callOptions) {
712
719
  const errorAttempt = {
@@ -715,9 +722,6 @@ var RetryableLanguageModel = class extends BaseRetryableModel {
715
722
  model: this.currentModel,
716
723
  options: callOptions
717
724
  };
718
- /**
719
- * Save the current attempt
720
- */
721
725
  const updatedAttempts = [...attempts, errorAttempt];
722
726
  const context = {
723
727
  current: errorAttempt,
@@ -725,17 +729,10 @@ var RetryableLanguageModel = class extends BaseRetryableModel {
725
729
  };
726
730
  this.options.onError?.(context);
727
731
  const retryModel = await findRetryModel(this.options.retries, context);
728
- /**
729
- * Handler didn't return any models to try next, rethrow the error.
730
- * If we retried the request, wrap the error into a `RetryError` for better visibility.
731
- */
732
- if (!retryModel) {
733
- if (updatedAttempts.length > 1) throw prepareRetryError(error, updatedAttempts);
734
- throw error;
735
- }
736
732
  return {
737
733
  retryModel,
738
- attempt: errorAttempt
734
+ attempt: errorAttempt,
735
+ finalError: retryModel ? void 0 : updatedAttempts.length > 1 ? prepareRetryError(error, updatedAttempts) : error
739
736
  };
740
737
  }
741
738
  async doGenerate(callOptions) {
@@ -916,20 +913,40 @@ var RetryableLanguageModel = class extends BaseRetryableModel {
916
913
  });
917
914
  /**
918
915
  * Check if the error from the stream can be retried.
919
- * Otherwise it will rethrow the error.
920
916
  */
921
- const { retryModel, attempt } = await this.handleError(error, attempts, retryCallOptions);
917
+ const { retryModel, attempt, finalError } = await this.handleError(error, attempts, retryCallOptions);
922
918
  /**
923
919
  * Save the attempt
924
920
  */
925
921
  attempts.push(attempt);
926
922
  /**
923
+ * No retry matched. Surface the error as a stream part so
924
+ * `streamText`'s `onError` fires for the consumer. Throwing
925
+ * here would escape `start()` and become a stream rejection,
926
+ * which silently bypasses `onError`.
927
+ */
928
+ if (!retryModel) {
929
+ controller.enqueue({
930
+ type: "error",
931
+ error: finalError
932
+ });
933
+ controller.close();
934
+ return;
935
+ }
936
+ /**
927
937
  * If the inbound abort signal is already aborted and the chosen
928
938
  * retry does not supply a fresh deadline, the retry would die
929
- * instantly with the same abort. Rethrow rather than fire a
930
- * misleading retry against a dead signal.
939
+ * instantly with the same abort. Surface the error rather than
940
+ * fire a misleading retry against a dead signal.
931
941
  */
932
- if (callOptions.abortSignal?.aborted && retryModel.timeout === void 0) throw error;
942
+ if (callOptions.abortSignal?.aborted && retryModel.timeout === void 0) {
943
+ controller.enqueue({
944
+ type: "error",
945
+ error
946
+ });
947
+ controller.close();
948
+ return;
949
+ }
933
950
  if (retryModel.delay) {
934
951
  /**
935
952
  * Calculate exponential backoff delay based on the number of attempts for this specific model.
@@ -1,4 +1,4 @@
1
- import { t as createRetryable$1 } from "../../create-retryable-model-CgYBIeV6.mjs";
1
+ import { t as createRetryable$1 } from "../../create-retryable-model-HLobeUXU.mjs";
2
2
  import "../../error-_63RHJTp.mjs";
3
3
  import { aborted, error, httpStatus, timeout } from "./retryables/index.mjs";
4
4
 
@@ -1,6 +1,6 @@
1
1
  import { k as RetryContext } from "../../../types-DYMm5YMu.mjs";
2
2
  import { n as Condition, t as StatusPattern } from "../../../error-CPbAtI-h.mjs";
3
- import * as _ai_sdk_provider13 from "@ai-sdk/provider";
3
+ import * as _ai_sdk_provider21 from "@ai-sdk/provider";
4
4
 
5
5
  //#region src/experimental/embedding-model/retryables/index.d.ts
6
6
  /**
@@ -11,10 +11,10 @@ import * as _ai_sdk_provider13 from "@ai-sdk/provider";
11
11
  * from 'ai-retry/experimental/embedding-model/retryables';
12
12
  */
13
13
  declare const error: {
14
- <MODEL extends _ai_sdk_provider13.EmbeddingModelV3 = _ai_sdk_provider13.EmbeddingModelV3, E = unknown>(predicate: (err: E, ctx: RetryContext<MODEL>) => boolean | Promise<boolean>): Condition<MODEL>;
15
- isRetryable<MODEL extends _ai_sdk_provider13.EmbeddingModelV3 = _ai_sdk_provider13.EmbeddingModelV3>(flag?: boolean): Condition<MODEL>;
16
- statusCode<MODEL extends _ai_sdk_provider13.EmbeddingModelV3 = _ai_sdk_provider13.EmbeddingModelV3>(...patterns: Array<number | RegExp>): Condition<MODEL>;
17
- message<MODEL extends _ai_sdk_provider13.EmbeddingModelV3 = _ai_sdk_provider13.EmbeddingModelV3>(...patterns: Array<string | RegExp>): Condition<MODEL>;
18
- }, httpStatus: <MODEL extends _ai_sdk_provider13.EmbeddingModelV3 = _ai_sdk_provider13.EmbeddingModelV3>(...patterns: Array<StatusPattern>) => Condition<MODEL>, timeout: <MODEL extends _ai_sdk_provider13.EmbeddingModelV3 = _ai_sdk_provider13.EmbeddingModelV3>() => Condition<MODEL>, aborted: <MODEL extends _ai_sdk_provider13.EmbeddingModelV3 = _ai_sdk_provider13.EmbeddingModelV3>() => Condition<MODEL>;
14
+ <MODEL extends _ai_sdk_provider21.EmbeddingModelV3 = _ai_sdk_provider21.EmbeddingModelV3, E = unknown>(predicate: (err: E, ctx: RetryContext<MODEL>) => boolean | Promise<boolean>): Condition<MODEL>;
15
+ isRetryable<MODEL extends _ai_sdk_provider21.EmbeddingModelV3 = _ai_sdk_provider21.EmbeddingModelV3>(flag?: boolean): Condition<MODEL>;
16
+ statusCode<MODEL extends _ai_sdk_provider21.EmbeddingModelV3 = _ai_sdk_provider21.EmbeddingModelV3>(...patterns: Array<number | RegExp>): Condition<MODEL>;
17
+ message<MODEL extends _ai_sdk_provider21.EmbeddingModelV3 = _ai_sdk_provider21.EmbeddingModelV3>(...patterns: Array<string | RegExp>): Condition<MODEL>;
18
+ }, httpStatus: <MODEL extends _ai_sdk_provider21.EmbeddingModelV3 = _ai_sdk_provider21.EmbeddingModelV3>(...patterns: Array<StatusPattern>) => Condition<MODEL>, timeout: <MODEL extends _ai_sdk_provider21.EmbeddingModelV3 = _ai_sdk_provider21.EmbeddingModelV3>() => Condition<MODEL>, aborted: <MODEL extends _ai_sdk_provider21.EmbeddingModelV3 = _ai_sdk_provider21.EmbeddingModelV3>() => Condition<MODEL>;
19
19
  //#endregion
20
20
  export { aborted, error, httpStatus, timeout };
@@ -1,6 +1,6 @@
1
1
  import { N as RetryableModelOptions, s as ImageModel } from "../../types-DYMm5YMu.mjs";
2
2
  import "../../error-CPbAtI-h.mjs";
3
- import { a as noImage, i as timeout, n as error, r as httpStatus, t as aborted } from "../../index-Dvxg4bnp.mjs";
3
+ import { a as noImage, i as timeout, n as error, r as httpStatus, t as aborted } from "../../index-TcUPTMfl.mjs";
4
4
 
5
5
  //#region src/experimental/image-model/index.d.ts
6
6
  declare function createRetryable<MODEL extends ImageModel>(options: RetryableModelOptions<MODEL>): ImageModel;
@@ -1,4 +1,4 @@
1
- import { t as createRetryable$1 } from "../../create-retryable-model-CgYBIeV6.mjs";
1
+ import { t as createRetryable$1 } from "../../create-retryable-model-HLobeUXU.mjs";
2
2
  import "../../error-_63RHJTp.mjs";
3
3
  import { a as noImage, i as timeout, n as error, r as httpStatus, t as aborted } from "../../retryables-D0wMy6Qt.mjs";
4
4
 
@@ -1,4 +1,4 @@
1
1
  import "../../../types-DYMm5YMu.mjs";
2
2
  import "../../../error-CPbAtI-h.mjs";
3
- import { a as noImage, i as timeout, n as error, r as httpStatus, t as aborted } from "../../../index-Dvxg4bnp.mjs";
3
+ import { a as noImage, i as timeout, n as error, r as httpStatus, t as aborted } from "../../../index-TcUPTMfl.mjs";
4
4
  export { aborted, error, httpStatus, noImage, timeout };
@@ -1,6 +1,6 @@
1
1
  import { N as RetryableModelOptions, d as LanguageModel, o as GatewayLanguageModelId } from "../../types-DYMm5YMu.mjs";
2
2
  import "../../error-CPbAtI-h.mjs";
3
- import { a as schemaInvalid, i as timeout, n as error, o as finishReason, r as httpStatus, s as result, t as aborted } from "../../index-DOM9pSF9.mjs";
3
+ import { a as result, i as httpStatus, n as error, o as schemaInvalid, r as finishReason, s as timeout, t as aborted } from "../../index-C9DEYXL_.mjs";
4
4
 
5
5
  //#region src/experimental/language-model/index.d.ts
6
6
  declare function createRetryable(options: Omit<RetryableModelOptions<LanguageModel>, 'model'> & {
@@ -1,6 +1,6 @@
1
- import { t as createRetryable$1 } from "../../create-retryable-model-CgYBIeV6.mjs";
1
+ import { t as createRetryable$1 } from "../../create-retryable-model-HLobeUXU.mjs";
2
2
  import "../../error-_63RHJTp.mjs";
3
- import { a as schemaInvalid, i as timeout, n as error, o as finishReason, r as httpStatus, s as result, t as aborted } from "../../retryables-nm5-elvB.mjs";
3
+ import { a as result, i as httpStatus, n as error, o as schemaInvalid, r as finishReason, s as timeout, t as aborted } from "../../retryables-DBiDOfIF.mjs";
4
4
 
5
5
  //#region src/experimental/language-model/index.ts
6
6
  /**
@@ -1,4 +1,4 @@
1
1
  import "../../../types-DYMm5YMu.mjs";
2
2
  import "../../../error-CPbAtI-h.mjs";
3
- import { a as schemaInvalid, i as timeout, n as error, o as finishReason, r as httpStatus, s as result, t as aborted } from "../../../index-DOM9pSF9.mjs";
3
+ import { a as result, i as httpStatus, n as error, o as schemaInvalid, r as finishReason, s as timeout, t as aborted } from "../../../index-C9DEYXL_.mjs";
4
4
  export { aborted, error, finishReason, httpStatus, result, schemaInvalid, timeout };
@@ -1,4 +1,4 @@
1
1
  import "../../../error-_63RHJTp.mjs";
2
- import { a as schemaInvalid, i as timeout, n as error, o as finishReason, r as httpStatus, s as result, t as aborted } from "../../../retryables-nm5-elvB.mjs";
2
+ import { a as result, i as httpStatus, n as error, o as schemaInvalid, r as finishReason, s as timeout, t as aborted } from "../../../retryables-DBiDOfIF.mjs";
3
3
 
4
4
  export { aborted, error, finishReason, httpStatus, result, schemaInvalid, timeout };
@@ -0,0 +1,30 @@
1
+ import { k as RetryContext, m as LanguageModelResult } from "./types-DYMm5YMu.mjs";
2
+ import { n as Condition, t as StatusPattern } from "./error-CPbAtI-h.mjs";
3
+ import * as _ai_sdk_provider0 from "@ai-sdk/provider";
4
+
5
+ //#region src/experimental/internal/result.d.ts
6
+ /**
7
+ * The unified finish reason produced by the AI SDK.
8
+ */
9
+ type FinishReason = LanguageModelResult['finishReason']['unified'];
10
+ //#endregion
11
+ //#region src/experimental/language-model/retryables/index.d.ts
12
+ /**
13
+ * Experimental composable conditions bound to `LanguageModel`. For use
14
+ * with `generateText`, `generateObject`, `streamText`, `streamObject`.
15
+ *
16
+ * import { error, httpStatus, finishReason, ... }
17
+ * from 'ai-retry/experimental/language-model/retryables';
18
+ */
19
+ declare const error: {
20
+ <MODEL extends _ai_sdk_provider0.LanguageModelV3 = _ai_sdk_provider0.LanguageModelV3, E = unknown>(predicate: (err: E, ctx: RetryContext<MODEL>) => boolean | Promise<boolean>): Condition<MODEL>;
21
+ isRetryable<MODEL extends _ai_sdk_provider0.LanguageModelV3 = _ai_sdk_provider0.LanguageModelV3>(flag?: boolean): Condition<MODEL>;
22
+ statusCode<MODEL extends _ai_sdk_provider0.LanguageModelV3 = _ai_sdk_provider0.LanguageModelV3>(...patterns: Array<number | RegExp>): Condition<MODEL>;
23
+ message<MODEL extends _ai_sdk_provider0.LanguageModelV3 = _ai_sdk_provider0.LanguageModelV3>(...patterns: Array<string | RegExp>): Condition<MODEL>;
24
+ }, httpStatus: <MODEL extends _ai_sdk_provider0.LanguageModelV3 = _ai_sdk_provider0.LanguageModelV3>(...patterns: Array<StatusPattern>) => Condition<MODEL>, timeout: <MODEL extends _ai_sdk_provider0.LanguageModelV3 = _ai_sdk_provider0.LanguageModelV3>() => Condition<MODEL>, aborted: <MODEL extends _ai_sdk_provider0.LanguageModelV3 = _ai_sdk_provider0.LanguageModelV3>() => Condition<MODEL>;
25
+ declare const result: {
26
+ <MODEL extends _ai_sdk_provider0.LanguageModelV3 = _ai_sdk_provider0.LanguageModelV3>(predicate: (res: LanguageModelResult, ctx: RetryContext<MODEL>) => boolean | Promise<boolean>): Condition<MODEL>;
27
+ finishReason<MODEL extends _ai_sdk_provider0.LanguageModelV3 = _ai_sdk_provider0.LanguageModelV3>(...reasons: Array<FinishReason>): Condition<MODEL>;
28
+ }, finishReason: <MODEL extends _ai_sdk_provider0.LanguageModelV3 = _ai_sdk_provider0.LanguageModelV3>(...reasons: Array<FinishReason>) => Condition<MODEL>, schemaInvalid: <MODEL extends _ai_sdk_provider0.LanguageModelV3 = _ai_sdk_provider0.LanguageModelV3>() => Condition<MODEL>;
29
+ //#endregion
30
+ export { result as a, httpStatus as i, error as n, schemaInvalid as o, finishReason as r, timeout as s, aborted as t };
@@ -0,0 +1,30 @@
1
+ import { k as RetryContext, s as ImageModel } from "./types-DYMm5YMu.mjs";
2
+ import { n as Condition, t as StatusPattern } from "./error-CPbAtI-h.mjs";
3
+ import * as _ai_sdk_provider35 from "@ai-sdk/provider";
4
+
5
+ //#region src/experimental/internal/no-image.d.ts
6
+ /**
7
+ * Match when image generation produced no images
8
+ * (`NoImageGeneratedError`).
9
+ *
10
+ * @example
11
+ * noImage().switch({ model: fallback })
12
+ */
13
+ declare function noImage<MODEL extends ImageModel = ImageModel>(): Condition<MODEL>;
14
+ //#endregion
15
+ //#region src/experimental/image-model/retryables/index.d.ts
16
+ /**
17
+ * Experimental composable conditions bound to `ImageModel`. For use with
18
+ * `generateImage`.
19
+ *
20
+ * import { error, noImage, ... }
21
+ * from 'ai-retry/experimental/image-model/retryables';
22
+ */
23
+ declare const error: {
24
+ <MODEL extends _ai_sdk_provider35.ImageModelV3 = _ai_sdk_provider35.ImageModelV3, E = unknown>(predicate: (err: E, ctx: RetryContext<MODEL>) => boolean | Promise<boolean>): Condition<MODEL>;
25
+ isRetryable<MODEL extends _ai_sdk_provider35.ImageModelV3 = _ai_sdk_provider35.ImageModelV3>(flag?: boolean): Condition<MODEL>;
26
+ statusCode<MODEL extends _ai_sdk_provider35.ImageModelV3 = _ai_sdk_provider35.ImageModelV3>(...patterns: Array<number | RegExp>): Condition<MODEL>;
27
+ message<MODEL extends _ai_sdk_provider35.ImageModelV3 = _ai_sdk_provider35.ImageModelV3>(...patterns: Array<string | RegExp>): Condition<MODEL>;
28
+ }, httpStatus: <MODEL extends _ai_sdk_provider35.ImageModelV3 = _ai_sdk_provider35.ImageModelV3>(...patterns: Array<StatusPattern>) => Condition<MODEL>, timeout: <MODEL extends _ai_sdk_provider35.ImageModelV3 = _ai_sdk_provider35.ImageModelV3>() => Condition<MODEL>, aborted: <MODEL extends _ai_sdk_provider35.ImageModelV3 = _ai_sdk_provider35.ImageModelV3>() => Condition<MODEL>;
29
+ //#endregion
30
+ export { noImage as a, timeout as i, error as n, httpStatus as r, aborted as t };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as getModelKey, t as createRetryable } from "./create-retryable-model-CgYBIeV6.mjs";
1
+ import { n as getModelKey, t as createRetryable } from "./create-retryable-model-HLobeUXU.mjs";
2
2
  import { n as isErrorAttempt, s as isResultAttempt } from "./guards-D8UJtxDK.mjs";
3
3
 
4
4
  export { createRetryable, getModelKey, isErrorAttempt, isResultAttempt };
@@ -0,0 +1,87 @@
1
+ import { s as isResultAttempt } from "./guards-D8UJtxDK.mjs";
2
+ import { n as Condition, t as createErrorAPI } from "./error-_63RHJTp.mjs";
3
+ import { safeParseJSON } from "@ai-sdk/provider-utils";
4
+ import { fromJSONSchema } from "zod";
5
+
6
+ //#region src/experimental/internal/result.ts
7
+ /**
8
+ * Build the result-side condition helpers (`result`, `finishReason`,
9
+ * `schemaInvalid`) bound to a specific language-model family. Consumed
10
+ * by `language-model/retryables/index.ts` so the entry point exposes
11
+ * helpers whose `MODEL` generic is constrained to the right family.
12
+ *
13
+ * Result-based conditions are language-model only — embedding and image
14
+ * results have a different shape and are not supported.
15
+ */
16
+ function createResultAPI() {
17
+ /**
18
+ * Build a condition from a predicate over the current generate result.
19
+ * The predicate runs only when the current attempt succeeded; error
20
+ * attempts return false.
21
+ *
22
+ * @example
23
+ * result<MODEL>((res) => res.finishReason.unified === 'length')
24
+ */
25
+ function result(predicate) {
26
+ return new Condition(async (ctx) => {
27
+ if (!isResultAttempt(ctx.current)) return false;
28
+ return predicate(ctx.current.result, ctx);
29
+ });
30
+ }
31
+ /**
32
+ * Match the result's finish reason against one of the given values.
33
+ *
34
+ * @example
35
+ * result.finishReason('content-filter')
36
+ * result.finishReason('content-filter', 'length')
37
+ */
38
+ result.finishReason = function finishReason(...reasons) {
39
+ return result((res) => reasons.includes(res.finishReason.unified));
40
+ };
41
+ /**
42
+ * Match the result's finish reason against one of the given values.
43
+ * Thin wrapper around `result.finishReason(...)`.
44
+ *
45
+ * @example
46
+ * finishReason('content-filter')
47
+ * finishReason('content-filter', 'length')
48
+ */
49
+ function finishReason(...reasons) {
50
+ return result.finishReason(...reasons);
51
+ }
52
+ /**
53
+ * Match when the result text fails JSON schema validation. The schema
54
+ * is read from the call's `responseFormat`, which `Output.object()`
55
+ * sets automatically. No-op when no schema is configured.
56
+ *
57
+ * @example
58
+ * schemaInvalid().switch({ model: fallback })
59
+ */
60
+ function schemaInvalid() {
61
+ return result(async (res, ctx) => {
62
+ if (!isResultAttempt(ctx.current)) return false;
63
+ const callOptions = ctx.current.options;
64
+ const text = res.content.filter((part) => part.type === "text").map((part) => part.text).join("");
65
+ if (!text) return false;
66
+ const responseFormat = callOptions.responseFormat;
67
+ if (responseFormat?.type !== "json" || !responseFormat.schema) return false;
68
+ return !(await safeParseJSON({
69
+ text,
70
+ schema: fromJSONSchema(responseFormat.schema)
71
+ })).success;
72
+ });
73
+ }
74
+ return {
75
+ result,
76
+ finishReason,
77
+ schemaInvalid
78
+ };
79
+ }
80
+
81
+ //#endregion
82
+ //#region src/experimental/language-model/retryables/index.ts
83
+ const { error, httpStatus, timeout, aborted } = createErrorAPI();
84
+ const { result, finishReason, schemaInvalid } = createResultAPI();
85
+
86
+ //#endregion
87
+ export { result as a, httpStatus as i, error as n, schemaInvalid as o, finishReason as r, timeout as s, aborted as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-retry",
3
- "version": "1.7.0",
3
+ "version": "1.7.2",
4
4
  "description": "Retry and fallback mechanisms for AI SDK",
5
5
  "keywords": [
6
6
  "ai",
@@ -1,60 +0,0 @@
1
- import { k as RetryContext, m as LanguageModelResult, x as ResolvableLanguageModel } from "./types-DYMm5YMu.mjs";
2
- import { n as Condition, t as StatusPattern } from "./error-CPbAtI-h.mjs";
3
- import * as _ai_sdk_provider27 from "@ai-sdk/provider";
4
-
5
- //#region src/experimental/internal/result.d.ts
6
- /**
7
- * Build a condition from a predicate over the current generate result.
8
- * Available for language models only. The predicate runs only when the
9
- * current attempt succeeded; error attempts return false.
10
- *
11
- * @example
12
- * result<MODEL>((res) => res.finishReason.unified === 'length')
13
- */
14
- declare function result<MODEL extends ResolvableLanguageModel = ResolvableLanguageModel>(predicate: (res: LanguageModelResult, ctx: RetryContext<MODEL>) => boolean | Promise<boolean>): Condition<MODEL>;
15
- declare namespace result {
16
- var finishReason: <MODEL extends ResolvableLanguageModel = ResolvableLanguageModel>(...reasons: Array<FinishReason>) => Condition<MODEL>;
17
- }
18
- /**
19
- * The unified finish reason produced by the AI SDK.
20
- */
21
- type FinishReason = LanguageModelResult['finishReason']['unified'];
22
- //#endregion
23
- //#region src/experimental/internal/finish-reason.d.ts
24
- /**
25
- * Match the result's finish reason against one of the given values.
26
- * Thin wrapper around `result.finishReason(...)`.
27
- *
28
- * @example
29
- * finishReason('content-filter')
30
- * finishReason('content-filter', 'length')
31
- */
32
- declare function finishReason<MODEL extends ResolvableLanguageModel = ResolvableLanguageModel>(...reasons: Array<FinishReason>): Condition<MODEL>;
33
- //#endregion
34
- //#region src/experimental/internal/schema-invalid.d.ts
35
- /**
36
- * Match when the result text fails JSON schema validation. The schema is
37
- * read from the call's `responseFormat`, which `Output.object()` sets
38
- * automatically. No-op when no schema is configured.
39
- *
40
- * @example
41
- * schemaInvalid().switch({ model: fallback })
42
- */
43
- declare function schemaInvalid<MODEL extends ResolvableLanguageModel = ResolvableLanguageModel>(): Condition<MODEL>;
44
- //#endregion
45
- //#region src/experimental/language-model/retryables/index.d.ts
46
- /**
47
- * Experimental composable conditions bound to `LanguageModel`. For use
48
- * with `generateText`, `generateObject`, `streamText`, `streamObject`.
49
- *
50
- * import { error, httpStatus, finishReason, ... }
51
- * from 'ai-retry/experimental/language-model/retryables';
52
- */
53
- declare const error: {
54
- <MODEL extends _ai_sdk_provider27.LanguageModelV3 = _ai_sdk_provider27.LanguageModelV3, E = unknown>(predicate: (err: E, ctx: RetryContext<MODEL>) => boolean | Promise<boolean>): Condition<MODEL>;
55
- isRetryable<MODEL extends _ai_sdk_provider27.LanguageModelV3 = _ai_sdk_provider27.LanguageModelV3>(flag?: boolean): Condition<MODEL>;
56
- statusCode<MODEL extends _ai_sdk_provider27.LanguageModelV3 = _ai_sdk_provider27.LanguageModelV3>(...patterns: Array<number | RegExp>): Condition<MODEL>;
57
- message<MODEL extends _ai_sdk_provider27.LanguageModelV3 = _ai_sdk_provider27.LanguageModelV3>(...patterns: Array<string | RegExp>): Condition<MODEL>;
58
- }, httpStatus: <MODEL extends _ai_sdk_provider27.LanguageModelV3 = _ai_sdk_provider27.LanguageModelV3>(...patterns: Array<StatusPattern>) => Condition<MODEL>, timeout: <MODEL extends _ai_sdk_provider27.LanguageModelV3 = _ai_sdk_provider27.LanguageModelV3>() => Condition<MODEL>, aborted: <MODEL extends _ai_sdk_provider27.LanguageModelV3 = _ai_sdk_provider27.LanguageModelV3>() => Condition<MODEL>;
59
- //#endregion
60
- export { schemaInvalid as a, timeout as i, error as n, finishReason as o, httpStatus as r, result as s, aborted as t };
@@ -1,30 +0,0 @@
1
- import { k as RetryContext, s as ImageModel } from "./types-DYMm5YMu.mjs";
2
- import { n as Condition, t as StatusPattern } from "./error-CPbAtI-h.mjs";
3
- import * as _ai_sdk_provider0 from "@ai-sdk/provider";
4
-
5
- //#region src/experimental/internal/no-image.d.ts
6
- /**
7
- * Match when image generation produced no images
8
- * (`NoImageGeneratedError`).
9
- *
10
- * @example
11
- * noImage().switch({ model: fallback })
12
- */
13
- declare function noImage<MODEL extends ImageModel = ImageModel>(): Condition<MODEL>;
14
- //#endregion
15
- //#region src/experimental/image-model/retryables/index.d.ts
16
- /**
17
- * Experimental composable conditions bound to `ImageModel`. For use with
18
- * `generateImage`.
19
- *
20
- * import { error, noImage, ... }
21
- * from 'ai-retry/experimental/image-model/retryables';
22
- */
23
- declare const error: {
24
- <MODEL extends _ai_sdk_provider0.ImageModelV3 = _ai_sdk_provider0.ImageModelV3, E = unknown>(predicate: (err: E, ctx: RetryContext<MODEL>) => boolean | Promise<boolean>): Condition<MODEL>;
25
- isRetryable<MODEL extends _ai_sdk_provider0.ImageModelV3 = _ai_sdk_provider0.ImageModelV3>(flag?: boolean): Condition<MODEL>;
26
- statusCode<MODEL extends _ai_sdk_provider0.ImageModelV3 = _ai_sdk_provider0.ImageModelV3>(...patterns: Array<number | RegExp>): Condition<MODEL>;
27
- message<MODEL extends _ai_sdk_provider0.ImageModelV3 = _ai_sdk_provider0.ImageModelV3>(...patterns: Array<string | RegExp>): Condition<MODEL>;
28
- }, httpStatus: <MODEL extends _ai_sdk_provider0.ImageModelV3 = _ai_sdk_provider0.ImageModelV3>(...patterns: Array<StatusPattern>) => Condition<MODEL>, timeout: <MODEL extends _ai_sdk_provider0.ImageModelV3 = _ai_sdk_provider0.ImageModelV3>() => Condition<MODEL>, aborted: <MODEL extends _ai_sdk_provider0.ImageModelV3 = _ai_sdk_provider0.ImageModelV3>() => Condition<MODEL>;
29
- //#endregion
30
- export { noImage as a, timeout as i, error as n, httpStatus as r, aborted as t };
@@ -1,76 +0,0 @@
1
- import { s as isResultAttempt } from "./guards-D8UJtxDK.mjs";
2
- import { n as Condition, t as createErrorAPI } from "./error-_63RHJTp.mjs";
3
- import { safeParseJSON } from "@ai-sdk/provider-utils";
4
- import { fromJSONSchema } from "zod";
5
-
6
- //#region src/experimental/internal/result.ts
7
- /**
8
- * Build a condition from a predicate over the current generate result.
9
- * Available for language models only. The predicate runs only when the
10
- * current attempt succeeded; error attempts return false.
11
- *
12
- * @example
13
- * result<MODEL>((res) => res.finishReason.unified === 'length')
14
- */
15
- function result(predicate) {
16
- return new Condition(async (ctx) => {
17
- if (!isResultAttempt(ctx.current)) return false;
18
- return predicate(ctx.current.result, ctx);
19
- });
20
- }
21
- /**
22
- * Match the result's finish reason against one of the given values.
23
- *
24
- * @example
25
- * result.finishReason('content-filter')
26
- * result.finishReason('content-filter', 'length')
27
- */
28
- result.finishReason = function finishReason(...reasons) {
29
- return result((res) => reasons.includes(res.finishReason.unified));
30
- };
31
-
32
- //#endregion
33
- //#region src/experimental/internal/finish-reason.ts
34
- /**
35
- * Match the result's finish reason against one of the given values.
36
- * Thin wrapper around `result.finishReason(...)`.
37
- *
38
- * @example
39
- * finishReason('content-filter')
40
- * finishReason('content-filter', 'length')
41
- */
42
- function finishReason(...reasons) {
43
- return result.finishReason(...reasons);
44
- }
45
-
46
- //#endregion
47
- //#region src/experimental/internal/schema-invalid.ts
48
- /**
49
- * Match when the result text fails JSON schema validation. The schema is
50
- * read from the call's `responseFormat`, which `Output.object()` sets
51
- * automatically. No-op when no schema is configured.
52
- *
53
- * @example
54
- * schemaInvalid().switch({ model: fallback })
55
- */
56
- function schemaInvalid() {
57
- return result(async (res, ctx) => {
58
- if (!isResultAttempt(ctx.current)) return false;
59
- const callOptions = ctx.current.options;
60
- const text = res.content.filter((part) => part.type === "text").map((part) => part.text).join("");
61
- if (!text) return false;
62
- const responseFormat = callOptions.responseFormat;
63
- if (responseFormat?.type !== "json" || !responseFormat.schema) return false;
64
- return !(await safeParseJSON({
65
- text,
66
- schema: fromJSONSchema(responseFormat.schema)
67
- })).success;
68
- });
69
- }
70
-
71
- //#endregion
72
- //#region src/experimental/language-model/retryables/index.ts
73
- const { error, httpStatus, timeout, aborted } = createErrorAPI();
74
-
75
- //#endregion
76
- export { schemaInvalid as a, timeout as i, error as n, finishReason as o, httpStatus as r, result as s, aborted as t };