llm-retry-kit 0.2.1 → 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 +180 -5
- package/dist/circuit-breaker.d.ts +17 -0
- package/dist/circuit-breaker.d.ts.map +1 -0
- package/dist/circuit-breaker.js +63 -0
- package/dist/circuit-breaker.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/retry.d.ts +4 -0
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +212 -16
- package/dist/retry.js.map +1 -1
- package/dist/stream.d.ts +3 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +388 -0
- package/dist/stream.js.map +1 -0
- package/dist/types.d.ts +87 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
|
|
10
10
|
Small resilience layer for production LLM calls. `llm-retry-kit` gives you
|
|
11
11
|
provider-aware retries, fallback chains, jittered exponential backoff,
|
|
12
|
-
`Retry-After` handling,
|
|
13
|
-
observability hooks without
|
|
12
|
+
`Retry-After` handling, streaming retries, circuit breakers, hedged requests,
|
|
13
|
+
budget tracking, cancellation, timeouts, and observability hooks without
|
|
14
|
+
runtime dependencies.
|
|
14
15
|
|
|
15
16
|
```bash
|
|
16
17
|
npm install llm-retry-kit
|
|
@@ -42,6 +43,12 @@ and `llm-retry-kit` manages the reliability policy around it.
|
|
|
42
43
|
`shouldFallback`.
|
|
43
44
|
- Track token usage and estimated cost.
|
|
44
45
|
- Use custom input/output token pricing through `costCalculator`.
|
|
46
|
+
- Wrap streaming responses with retry-before-first-chunk safety.
|
|
47
|
+
- Track partial stream token usage from provider events.
|
|
48
|
+
- Skip unhealthy providers with `CircuitBreaker`.
|
|
49
|
+
- Set timeout budgets per provider/model.
|
|
50
|
+
- Start hedged requests to reduce tail latency.
|
|
51
|
+
- Pass request `meta` and `payload` through every context for logging.
|
|
45
52
|
- Abort long calls and retry sleeps with `AbortSignal` or `timeoutMs`.
|
|
46
53
|
- Observe attempts, retries, success, failure, and budget events.
|
|
47
54
|
- Strict TypeScript types.
|
|
@@ -169,6 +176,136 @@ console.log({
|
|
|
169
176
|
})
|
|
170
177
|
```
|
|
171
178
|
|
|
179
|
+
## Streaming
|
|
180
|
+
|
|
181
|
+
OpenAI and Anthropic both expose streaming APIs, but their event formats and
|
|
182
|
+
resume behavior are provider-specific. `llm-retry-kit` therefore keeps the
|
|
183
|
+
stream wrapper provider-agnostic and conservative:
|
|
184
|
+
|
|
185
|
+
- By default, it retries only if the stream fails before the first chunk.
|
|
186
|
+
- After a chunk has been yielded, retrying could duplicate output, so it stops
|
|
187
|
+
unless you explicitly set `retryMode: 'always'`.
|
|
188
|
+
- Token usage can be tracked from stream events with `getChunkUsage`.
|
|
189
|
+
- Use `chunkUsageMode: 'cumulative'` for providers that send cumulative usage
|
|
190
|
+
snapshots during a stream.
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
import { llmRetryStream } from 'llm-retry-kit'
|
|
194
|
+
|
|
195
|
+
const result = llmRetryStream({
|
|
196
|
+
stream: async ({ signal }) => {
|
|
197
|
+
const stream = await openai.responses.create({
|
|
198
|
+
model: 'gpt-4o-mini',
|
|
199
|
+
input: 'Write a short incident summary.',
|
|
200
|
+
stream: true,
|
|
201
|
+
}, { signal })
|
|
202
|
+
|
|
203
|
+
return stream
|
|
204
|
+
},
|
|
205
|
+
retryMode: 'before-first-chunk',
|
|
206
|
+
getChunkUsage: (event) => {
|
|
207
|
+
if (!('usage' in event) || !event.usage) return undefined
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
promptTokens: event.usage.input_tokens ?? 0,
|
|
211
|
+
completionTokens: event.usage.output_tokens ?? 0,
|
|
212
|
+
totalTokens: event.usage.total_tokens ?? 0,
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
chunkUsageMode: 'cumulative',
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
for await (const event of result.stream) {
|
|
219
|
+
// Send provider events to your UI, parser, or SSE response.
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
console.log(result.getStats())
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Advanced Production Controls
|
|
226
|
+
|
|
227
|
+
### Circuit Breaker
|
|
228
|
+
|
|
229
|
+
Keep one `CircuitBreaker` instance per provider/model at application scope. If
|
|
230
|
+
the failure threshold is reached inside the time window, later calls skip that
|
|
231
|
+
provider until the cooldown expires.
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
import { CircuitBreaker, llmRetry } from 'llm-retry-kit'
|
|
235
|
+
|
|
236
|
+
const openaiBreaker = new CircuitBreaker({
|
|
237
|
+
failureThreshold: 5,
|
|
238
|
+
windowMs: 60_000,
|
|
239
|
+
cooldownMs: 120_000,
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
await llmRetry({
|
|
243
|
+
providers: [
|
|
244
|
+
{
|
|
245
|
+
name: 'openai:gpt-4o-mini',
|
|
246
|
+
fn: callOpenAI,
|
|
247
|
+
circuitBreaker: openaiBreaker,
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
name: 'anthropic:claude-sonnet',
|
|
251
|
+
fn: callAnthropic,
|
|
252
|
+
},
|
|
253
|
+
],
|
|
254
|
+
})
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Per-Provider Timeout
|
|
258
|
+
|
|
259
|
+
Use global `timeoutMs` for the whole workflow and provider `timeoutMs` for a
|
|
260
|
+
single attempt.
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
await llmRetry({
|
|
264
|
+
providers: [
|
|
265
|
+
{ name: 'openai:fast', fn: callOpenAI, timeoutMs: 3_000, maxRetries: 1 },
|
|
266
|
+
{ name: 'anthropic:steady', fn: callAnthropic, timeoutMs: 10_000 },
|
|
267
|
+
],
|
|
268
|
+
timeoutMs: 30_000,
|
|
269
|
+
})
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Hedged Requests
|
|
273
|
+
|
|
274
|
+
Hedging starts the next provider in parallel if the current provider has not
|
|
275
|
+
answered after `hedgeDelayMs`. The first successful response wins and the
|
|
276
|
+
slower request is aborted through the context signal.
|
|
277
|
+
|
|
278
|
+
```ts
|
|
279
|
+
await llmRetry({
|
|
280
|
+
providers: [
|
|
281
|
+
{ name: 'primary', fn: callPrimary },
|
|
282
|
+
{ name: 'hedge', fn: callBackup },
|
|
283
|
+
],
|
|
284
|
+
hedgeDelayMs: 750,
|
|
285
|
+
})
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Hedging is best for latency-sensitive read paths. It can increase provider
|
|
289
|
+
traffic, so pair it with budget tracking and conservative delay values.
|
|
290
|
+
|
|
291
|
+
### Metadata And Payload Tracking
|
|
292
|
+
|
|
293
|
+
Attach request metadata once and it flows into provider calls and hooks.
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
await llmRetry({
|
|
297
|
+
fn: callModel,
|
|
298
|
+
meta: { requestId: 'req_123', tenant: 'acme' },
|
|
299
|
+
payload: { prompt: 'Classify this ticket', userId: 'user_42' },
|
|
300
|
+
onAttempt: (context) => {
|
|
301
|
+
console.log(context.meta, context.payload)
|
|
302
|
+
},
|
|
303
|
+
onFailure: (error, context) => {
|
|
304
|
+
console.error(context.meta, error)
|
|
305
|
+
},
|
|
306
|
+
})
|
|
307
|
+
```
|
|
308
|
+
|
|
172
309
|
## Simple Fallback API
|
|
173
310
|
|
|
174
311
|
For smaller apps, `fn` plus `fallback` is still supported.
|
|
@@ -298,8 +435,8 @@ await llmRetry({
|
|
|
298
435
|
onSuccess: (context) => {
|
|
299
436
|
console.log(`Cost so far: $${context.totalCostUSD}`)
|
|
300
437
|
},
|
|
301
|
-
onFailure: (error) => {
|
|
302
|
-
console.error(error)
|
|
438
|
+
onFailure: (error, context) => {
|
|
439
|
+
console.error(context.meta, error)
|
|
303
440
|
},
|
|
304
441
|
})
|
|
305
442
|
```
|
|
@@ -320,13 +457,16 @@ await llmRetry({
|
|
|
320
457
|
| `initialDelayMs` | `number` | `1000` | Initial retry delay. |
|
|
321
458
|
| `maxDelayMs` | `number` | `30000` | Maximum retry delay. |
|
|
322
459
|
| `timeoutMs` | `number` | optional | Abort wrapper after this time. |
|
|
460
|
+
| `hedgeDelayMs` | `number` | optional | Start the next provider after this delay if the current provider is still pending. |
|
|
323
461
|
| `signal` | `AbortSignal` | optional | External cancellation signal. |
|
|
462
|
+
| `meta` | `unknown` | optional | User metadata copied into attempt/failure contexts. |
|
|
463
|
+
| `payload` | `unknown` | optional | Request payload copied into attempt/failure contexts. |
|
|
324
464
|
| `shouldRetry` | `(error, context) => boolean \| Promise<boolean>` | optional | Override retry decisions. |
|
|
325
465
|
| `shouldFallback` | `(error, context) => boolean \| Promise<boolean>` | optional | Override provider fallback decisions. |
|
|
326
466
|
| `onAttempt` | `(context) => void` | optional | Called before each attempt. |
|
|
327
467
|
| `onRetry` | `(attempt, error, delayMs, context) => void` | optional | Called before retry wait. |
|
|
328
468
|
| `onSuccess` | `(context) => void` | optional | Called after a successful response. |
|
|
329
|
-
| `onFailure` | `(error) => void` | optional | Called before final failure is thrown. |
|
|
469
|
+
| `onFailure` | `(error, context) => void` | optional | Called before final failure is thrown. |
|
|
330
470
|
| `onBudgetExceeded` | `(spentUSD, limitUSD) => void` | optional | Called when budget is exhausted. |
|
|
331
471
|
|
|
332
472
|
### `RetryProvider<T>`
|
|
@@ -336,11 +476,45 @@ await llmRetry({
|
|
|
336
476
|
name: string
|
|
337
477
|
fn: (context: RetryAttemptContext) => Promise<LLMResponse<T>>
|
|
338
478
|
maxRetries?: number
|
|
479
|
+
timeoutMs?: number
|
|
480
|
+
hedgeDelayMs?: number
|
|
481
|
+
circuitBreaker?: CircuitBreaker | CircuitBreakerOptions
|
|
339
482
|
costPer1kTokens?: number
|
|
340
483
|
costCalculator?: (usage, context) => number
|
|
341
484
|
}
|
|
342
485
|
```
|
|
343
486
|
|
|
487
|
+
### `llmRetryStream(options)`
|
|
488
|
+
|
|
489
|
+
Returns `{ stream, getStats }`. The request begins when the returned async
|
|
490
|
+
iterable is consumed.
|
|
491
|
+
|
|
492
|
+
| Option | Type | Default | Description |
|
|
493
|
+
| --- | --- | --- | --- |
|
|
494
|
+
| `stream` | `(context) => AsyncIterable<TChunk> \| Promise<AsyncIterable<TChunk>>` | optional | Primary stream call for the simple API. |
|
|
495
|
+
| `fallbackStream` | `(context) => AsyncIterable<TChunk> \| Promise<AsyncIterable<TChunk>>` | optional | Backup stream call. |
|
|
496
|
+
| `providers` | `StreamRetryProvider<TChunk>[]` | optional | Explicit stream provider chain. |
|
|
497
|
+
| `retryMode` | `'before-first-chunk' \| 'always' \| 'never'` | `'before-first-chunk'` | Controls whether interrupted streams are retried. |
|
|
498
|
+
| `getChunkUsage` | `(chunk, context) => TokenUsage \| undefined` | optional | Extract token usage from stream chunks/events. |
|
|
499
|
+
| `chunkUsageMode` | `'delta' \| 'cumulative'` | `'delta'` | Interpret chunk usage as incremental or cumulative. |
|
|
500
|
+
| `maxRetries` | `number` | `3` | Retries after the first attempt. |
|
|
501
|
+
| `timeoutMs` | `number` | optional | Abort the whole stream workflow after this time. |
|
|
502
|
+
| `meta` | `unknown` | optional | User metadata copied into contexts. |
|
|
503
|
+
| `payload` | `unknown` | optional | Request payload copied into contexts. |
|
|
504
|
+
|
|
505
|
+
### `CircuitBreaker`
|
|
506
|
+
|
|
507
|
+
```ts
|
|
508
|
+
new CircuitBreaker({
|
|
509
|
+
failureThreshold: 5,
|
|
510
|
+
windowMs: 60_000,
|
|
511
|
+
cooldownMs: 120_000,
|
|
512
|
+
})
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
`snapshot()` returns `{ state, failures, openedAt }`, where state is
|
|
516
|
+
`'closed'`, `'open'`, or `'half_open'`.
|
|
517
|
+
|
|
344
518
|
### `RetryResult<T>`
|
|
345
519
|
|
|
346
520
|
```ts
|
|
@@ -377,6 +551,7 @@ await llmRetry({
|
|
|
377
551
|
| `initialDelayMs` | `1000` |
|
|
378
552
|
| `maxDelayMs` | `30000` |
|
|
379
553
|
| `costPer1kTokens` | `0.002` |
|
|
554
|
+
| stream retry mode | `before-first-chunk` |
|
|
380
555
|
| fallback on client errors | `false` |
|
|
381
556
|
| fallback on transient errors | `true` |
|
|
382
557
|
| runtime dependencies | none |
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CircuitBreakerOptions, CircuitBreakerSnapshot } from './types.js';
|
|
2
|
+
export declare class CircuitBreaker {
|
|
3
|
+
private readonly options;
|
|
4
|
+
private failureTimestamps;
|
|
5
|
+
private state;
|
|
6
|
+
private openedAt;
|
|
7
|
+
constructor(options: CircuitBreakerOptions);
|
|
8
|
+
canRequest(): boolean;
|
|
9
|
+
recordSuccess(): void;
|
|
10
|
+
recordFailure(): void;
|
|
11
|
+
snapshot(): CircuitBreakerSnapshot;
|
|
12
|
+
}
|
|
13
|
+
export declare class CircuitBreakerOpenError extends Error {
|
|
14
|
+
readonly provider: string;
|
|
15
|
+
constructor(provider: string);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=circuit-breaker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuit-breaker.d.ts","sourceRoot":"","sources":["../src/circuit-breaker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,sBAAsB,EAEvB,MAAM,YAAY,CAAA;AAEnB,qBAAa,cAAc;IAKb,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJpC,OAAO,CAAC,iBAAiB,CAAe;IACxC,OAAO,CAAC,KAAK,CAAgC;IAC7C,OAAO,CAAC,QAAQ,CAAsB;gBAET,OAAO,EAAE,qBAAqB;IAI3D,UAAU,IAAI,OAAO;IAcrB,aAAa,IAAI,IAAI;IAMrB,aAAa,IAAI,IAAI;IAiBrB,QAAQ,IAAI,sBAAsB;CAOnC;AAED,qBAAa,uBAAwB,SAAQ,KAAK;aACpB,QAAQ,EAAE,MAAM;gBAAhB,QAAQ,EAAE,MAAM;CAI7C"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export class CircuitBreaker {
|
|
2
|
+
options;
|
|
3
|
+
failureTimestamps = [];
|
|
4
|
+
state = 'closed';
|
|
5
|
+
openedAt = null;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.options = options;
|
|
8
|
+
validateCircuitBreakerOptions(options);
|
|
9
|
+
}
|
|
10
|
+
canRequest() {
|
|
11
|
+
if (this.state !== 'open') {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
const openedAt = this.openedAt ?? 0;
|
|
15
|
+
if (Date.now() - openedAt >= this.options.cooldownMs) {
|
|
16
|
+
this.state = 'half_open';
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
recordSuccess() {
|
|
22
|
+
this.failureTimestamps = [];
|
|
23
|
+
this.state = 'closed';
|
|
24
|
+
this.openedAt = null;
|
|
25
|
+
}
|
|
26
|
+
recordFailure() {
|
|
27
|
+
const now = Date.now();
|
|
28
|
+
const windowStart = now - this.options.windowMs;
|
|
29
|
+
this.failureTimestamps = [...this.failureTimestamps, now].filter((timestamp) => timestamp >= windowStart);
|
|
30
|
+
if (this.state === 'half_open' ||
|
|
31
|
+
this.failureTimestamps.length >= this.options.failureThreshold) {
|
|
32
|
+
this.state = 'open';
|
|
33
|
+
this.openedAt = now;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
snapshot() {
|
|
37
|
+
return {
|
|
38
|
+
state: this.state,
|
|
39
|
+
failures: this.failureTimestamps.length,
|
|
40
|
+
openedAt: this.openedAt,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export class CircuitBreakerOpenError extends Error {
|
|
45
|
+
provider;
|
|
46
|
+
constructor(provider) {
|
|
47
|
+
super(`Circuit breaker is open for provider "${provider}"`);
|
|
48
|
+
this.provider = provider;
|
|
49
|
+
this.name = 'CircuitBreakerOpenError';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function validateCircuitBreakerOptions(options) {
|
|
53
|
+
if (!Number.isInteger(options.failureThreshold) || options.failureThreshold <= 0) {
|
|
54
|
+
throw new Error('failureThreshold must be a positive integer');
|
|
55
|
+
}
|
|
56
|
+
if (options.windowMs < 0) {
|
|
57
|
+
throw new Error('windowMs must be greater than or equal to 0');
|
|
58
|
+
}
|
|
59
|
+
if (options.cooldownMs < 0) {
|
|
60
|
+
throw new Error('cooldownMs must be greater than or equal to 0');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=circuit-breaker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuit-breaker.js","sourceRoot":"","sources":["../src/circuit-breaker.ts"],"names":[],"mappings":"AAMA,MAAM,OAAO,cAAc;IAKI;IAJrB,iBAAiB,GAAa,EAAE,CAAA;IAChC,KAAK,GAAwB,QAAQ,CAAA;IACrC,QAAQ,GAAkB,IAAI,CAAA;IAEtC,YAA6B,OAA8B;QAA9B,YAAO,GAAP,OAAO,CAAuB;QACzD,6BAA6B,CAAC,OAAO,CAAC,CAAA;IACxC,CAAC;IAED,UAAU;QACR,IAAI,IAAI,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAA;QACb,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAA;QACnC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;YACrD,IAAI,CAAC,KAAK,GAAG,WAAW,CAAA;YACxB,OAAO,IAAI,CAAA;QACb,CAAC;QAED,OAAO,KAAK,CAAA;IACd,CAAC;IAED,aAAa;QACX,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAA;QAC3B,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAA;QACrB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;IACtB,CAAC;IAED,aAAa;QACX,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACtB,MAAM,WAAW,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAA;QAE/C,IAAI,CAAC,iBAAiB,GAAG,CAAC,GAAG,IAAI,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC,MAAM,CAC9D,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,IAAI,WAAW,CACxC,CAAA;QAED,IACE,IAAI,CAAC,KAAK,KAAK,WAAW;YAC1B,IAAI,CAAC,iBAAiB,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAC9D,CAAC;YACD,IAAI,CAAC,KAAK,GAAG,MAAM,CAAA;YACnB,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAA;QACrB,CAAC;IACH,CAAC;IAED,QAAQ;QACN,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,IAAI,CAAC,iBAAiB,CAAC,MAAM;YACvC,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAA;IACH,CAAC;CACF;AAED,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IACpB;IAA5B,YAA4B,QAAgB;QAC1C,KAAK,CAAC,yCAAyC,QAAQ,GAAG,CAAC,CAAA;QADjC,aAAQ,GAAR,QAAQ,CAAQ;QAE1C,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAA;IACvC,CAAC;CACF;AAED,SAAS,6BAA6B,CAAC,OAA8B;IACnE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,OAAO,CAAC,gBAAgB,IAAI,CAAC,EAAE,CAAC;QACjF,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;IAChE,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;IAChE,CAAC;IAED,IAAI,OAAO,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { CircuitBreaker, CircuitBreakerOpenError } from './circuit-breaker.js';
|
|
2
|
+
export { BudgetExceededError, llmRetry, LLMRetryError, ProviderTimeoutError } from './retry.js';
|
|
3
|
+
export { llmRetryStream } from './stream.js';
|
|
2
4
|
export { BudgetTracker } from './budget.js';
|
|
3
5
|
export { calculateBackoff, extractRetryAfter, isRetryableError } from './backoff.js';
|
|
4
|
-
export type { CostCalculator, FallbackDecisionContext, LLMCall, LLMResponse, RetryAttemptContext, RetryDecisionContext, RetryOptions, RetryProvider, RetryResult, RetrySuccessContext, RetryableError, ShouldFallback, ShouldRetry, TokenUsage, } from './types.js';
|
|
6
|
+
export type { CircuitBreakerLike, CircuitBreakerOptions, CircuitBreakerSnapshot, CircuitBreakerState, CostCalculator, FallbackDecisionContext, LLMCall, LLMResponse, RetryAttemptContext, RetryDecisionContext, RetryFailureContext, RetryOptions, RetryProvider, RetryResult, RetrySuccessContext, RetryableError, ShouldFallback, ShouldRetry, StreamLLMCall, StreamRetryMode, StreamRetryOptions, StreamRetryProvider, StreamRetryResult, StreamRetryStats, StreamUsageExtractor, StreamUsageMode, TokenUsage, } from './types.js';
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAC9E,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAC/F,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AACpF,YAAY,EACV,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,cAAc,EACd,uBAAuB,EACvB,OAAO,EACP,WAAW,EACX,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,WAAW,EACX,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,UAAU,GACX,MAAM,YAAY,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { CircuitBreaker, CircuitBreakerOpenError } from './circuit-breaker.js';
|
|
2
|
+
export { BudgetExceededError, llmRetry, LLMRetryError, ProviderTimeoutError } from './retry.js';
|
|
3
|
+
export { llmRetryStream } from './stream.js';
|
|
2
4
|
export { BudgetTracker } from './budget.js';
|
|
3
5
|
export { calculateBackoff, extractRetryAfter, isRetryableError } from './backoff.js';
|
|
4
6
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAC9E,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAC/F,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA"}
|
package/dist/retry.d.ts
CHANGED
|
@@ -15,4 +15,8 @@ export declare class BudgetExceededError extends Error {
|
|
|
15
15
|
readonly limitUSD: number | null;
|
|
16
16
|
constructor(spentUSD: number, limitUSD: number | null);
|
|
17
17
|
}
|
|
18
|
+
export declare class ProviderTimeoutError extends Error {
|
|
19
|
+
readonly timeoutMs: number;
|
|
20
|
+
constructor(timeoutMs: number);
|
|
21
|
+
}
|
|
18
22
|
//# sourceMappingURL=retry.d.ts.map
|
package/dist/retry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAOV,YAAY,EAEZ,WAAW,EAGZ,MAAM,YAAY,CAAA;AAMnB,wBAAsB,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CA+NnF;AAmZD,qBAAa,aAAc,SAAQ,KAAK;aAGpB,YAAY,EAAE,KAAK,GAAG,IAAI;aAC1B,aAAa,EAAE,KAAK,GAAG,IAAI;aAC3B,YAAY,EAAE,MAAM;aACpB,WAAW,EAAE,MAAM;aACnB,QAAQ;aACR,SAAS,EAAE,MAAM,EAAE;aACnB,MAAM,EAAE,SAAS,GAAG,iBAAiB,GAAG,SAAS;gBAPjE,OAAO,EAAE,MAAM,EACC,YAAY,EAAE,KAAK,GAAG,IAAI,EAC1B,aAAa,EAAE,KAAK,GAAG,IAAI,EAC3B,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,QAAQ,SAAI,EACZ,SAAS,GAAE,MAAM,EAAO,EACxB,MAAM,GAAE,SAAS,GAAG,iBAAiB,GAAG,SAAqB;CAKhF;AAED,qBAAa,mBAAoB,SAAQ,KAAK;aAE1B,QAAQ,EAAE,MAAM;aAChB,QAAQ,EAAE,MAAM,GAAG,IAAI;gBADvB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GAAG,IAAI;CAM1C;AAED,qBAAa,oBAAqB,SAAQ,KAAK;aACjB,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM;CAI9C"}
|