ai-resilience 0.1.3 → 0.3.0

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
@@ -1,6 +1,6 @@
1
1
  # ai-resilience
2
2
 
3
- `ai-resilience` is an axios-retry++ foundation for modern AI and backend systems. It keeps axios compatibility while adding configurable retry strategies, advanced jitter, retry conditions, hooks, structured logging, and strong TypeScript types.
3
+ `ai-resilience` is an axios-retry++ toolkit for modern AI and backend systems. It keeps axios compatibility while adding configurable retry strategies, semantic recovery, provider fallback, circuit breakers, distributed coordination, streaming recovery, telemetry hooks, and strong TypeScript types.
4
4
 
5
5
  ## Install
6
6
 
@@ -12,7 +12,8 @@ npm install ai-resilience axios axios-retry
12
12
 
13
13
  ```ts
14
14
  import axios from "axios";
15
- import { applyAiResilience, ConsoleRetryLogger } from "ai-resilience";
15
+ import { applyAiResilience, ConsoleRetryLogger, requestWithSemanticRetry } from "ai-resilience";
16
+ import { z } from "zod";
16
17
 
17
18
  const client = axios.create({ baseURL: "https://api.example.com" });
18
19
 
@@ -29,6 +30,13 @@ applyAiResilience(client, {
29
30
  },
30
31
  },
31
32
  });
33
+
34
+ const result = await requestWithSemanticRetry(client, {
35
+ request: { method: "post", url: "/chat/completions", data: { prompt: "Return JSON" } },
36
+ schema: z.object({ answer: z.string() }),
37
+ repairJson: true,
38
+ requireJson: true,
39
+ });
32
40
  ```
33
41
 
34
42
  ## Features
@@ -40,6 +48,14 @@ applyAiResilience(client, {
40
48
  - Async custom retry conditions
41
49
  - EventEmitter-based hooks plus direct hook callbacks
42
50
  - Structured logger interface and console logger
51
+ - Semantic retry for valid HTTP responses with invalid AI payloads
52
+ - JSON validation, Zod schema validation, and JSON repair
53
+ - AI-aware failure detection for empty responses, refusals, truncation, and schema mismatches
54
+ - AI retry policies and semantic lifecycle hooks
55
+ - Provider fallback for OpenAI, Anthropic, Gemini, or custom providers
56
+ - Circuit breaker, provider health tracking, adaptive fallback delay, and provider metrics
57
+ - Redis-compatible retry coordination and distributed rate limiting through lightweight adapters
58
+ - Adaptive routing, streaming recovery, OpenTelemetry-compatible spans, and advanced metrics
43
59
  - TypeScript-first public API
44
60
 
45
61
  ## API
@@ -52,6 +68,134 @@ Installs retry behavior on an existing axios instance and returns `{ axios, hook
52
68
 
53
69
  Creates a new axios instance with retry behavior already applied.
54
70
 
71
+ ### `requestWithSemanticRetry(instance, config)`
72
+
73
+ Runs an axios request and retries when the response is semantically invalid, such as malformed JSON, a schema mismatch, an empty body, a refusal, or a truncated answer.
74
+
75
+ ```ts
76
+ import { requestWithSemanticRetry } from "ai-resilience";
77
+ import { z } from "zod";
78
+
79
+ const data = await requestWithSemanticRetry(client, {
80
+ request: { url: "/generate", method: "post", data: { prompt } },
81
+ schema: z.object({
82
+ title: z.string(),
83
+ tags: z.array(z.string()),
84
+ }),
85
+ repairJson: true,
86
+ requireJson: true,
87
+ hooks: {
88
+ onSemanticRetry: ({ issue, attempt }) => {
89
+ console.log(`semantic retry ${attempt}: ${issue.kind}`);
90
+ },
91
+ },
92
+ });
93
+ ```
94
+
95
+ ### `semanticRetry(operation, policy)`
96
+
97
+ Wraps any async operation that returns either an axios response or raw data and retries until the payload passes semantic validation.
98
+
99
+ ### `parseJsonResponse(data, options)`
100
+
101
+ Parses JSON strings, optionally repairs common model-output issues, and validates against a Zod schema.
102
+
103
+ ### `applySemanticRecovery(instance, policy)`
104
+
105
+ Installs a response interceptor that validates and repairs successful axios responses. Use `requestWithSemanticRetry` when you also want semantic retries.
106
+
107
+ ### `createProviderFallback(providers, options)`
108
+
109
+ Creates a provider fallback engine with provider routing, circuit breakers, health tracking, adaptive delay, fallback hooks, and metrics.
110
+
111
+ ```ts
112
+ import { createProviderFallback } from "ai-resilience";
113
+
114
+ const fallback = createProviderFallback(
115
+ [
116
+ {
117
+ id: "openai-primary",
118
+ type: "openai",
119
+ priority: 1,
120
+ request: (input) => openaiClient.responses.create(input),
121
+ },
122
+ {
123
+ id: "anthropic-backup",
124
+ type: "anthropic",
125
+ priority: 2,
126
+ request: (input) => anthropicClient.messages.create(input),
127
+ },
128
+ ],
129
+ {
130
+ strategy: "priority",
131
+ circuitBreaker: { failureThreshold: 3, cooldownMs: 30_000 },
132
+ hooks: {
133
+ onProviderFallback: ({ fromProviderId, toProviderId }) => {
134
+ console.log(`fallback ${fromProviderId} -> ${toProviderId}`);
135
+ },
136
+ },
137
+ },
138
+ );
139
+
140
+ const response = await fallback.request({ prompt: "Summarize this" });
141
+ const metrics = fallback.snapshot();
142
+ ```
143
+
144
+ ### `RedisRetryCoordinator`
145
+
146
+ Coordinates retries and locks across processes. Pass an `ioredis`-compatible client through the `redis` option, or omit it for local in-memory coordination during tests and development.
147
+
148
+ ```ts
149
+ import { RedisRetryCoordinator } from "ai-resilience";
150
+
151
+ const coordinator = new RedisRetryCoordinator({
152
+ namespace: "my-api",
153
+ redis,
154
+ });
155
+
156
+ await coordinator.incrementRetry("tenant-a:request-123");
157
+ const locked = await coordinator.acquireLock("provider-routing");
158
+ ```
159
+
160
+ ### `DistributedRateLimiter`
161
+
162
+ Provides Redis-compatible fixed-window rate limiting.
163
+
164
+ ```ts
165
+ import { DistributedRateLimiter } from "ai-resilience";
166
+
167
+ const limiter = new DistributedRateLimiter(redis);
168
+ const result = await limiter.consume({
169
+ key: "tenant-a:openai",
170
+ limit: 100,
171
+ windowSeconds: 60,
172
+ });
173
+ ```
174
+
175
+ ### `AdaptiveRouter`
176
+
177
+ Ranks providers using latency, failure, and cost signals.
178
+
179
+ ```ts
180
+ import { AdaptiveRouter } from "ai-resilience";
181
+
182
+ const router = new AdaptiveRouter(providers, {
183
+ latencyWeight: 1,
184
+ failureWeight: 2,
185
+ costWeight: 0.5,
186
+ });
187
+
188
+ const provider = router.select(metricsByProvider);
189
+ ```
190
+
191
+ ### `recoverStream(stream, options)`
192
+
193
+ Collects streaming chunks and calls recovery hooks when chunk gaps exceed a configured threshold.
194
+
195
+ ### `withTelemetry(tracer, name, operation, attributes)`
196
+
197
+ Wraps an async operation with an OpenTelemetry-style tracer adapter. This package does not force `@opentelemetry/api` into runtime dependencies; pass a tracer with `startSpan`.
198
+
55
199
  ### Retry config
56
200
 
57
201
  ```ts
@@ -70,6 +214,26 @@ type AiResilienceRetryConfig = {
70
214
  };
71
215
  ```
72
216
 
217
+ ### Semantic policy
218
+
219
+ ```ts
220
+ type AiRetryPolicy = {
221
+ maxSemanticRetries?: number;
222
+ retryOnFailureKinds?: Array<
223
+ "invalid_json" | "schema_mismatch" | "empty_response" | "refusal" | "truncated"
224
+ >;
225
+ repairJson?: boolean;
226
+ requireJson?: boolean;
227
+ detectRefusals?: boolean;
228
+ detectTruncation?: boolean;
229
+ schema?: z.ZodType;
230
+ validate?: (data, response) => SemanticValidationResult | Promise<SemanticValidationResult>;
231
+ hooks?: SemanticRetryHooks;
232
+ logger?: RetryLogger;
233
+ metadata?: Record<string, unknown>;
234
+ };
235
+ ```
236
+
73
237
  ## Scripts
74
238
 
75
239
  ```sh