llm-retry-kit 0.2.1 → 0.4.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
@@ -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, budget tracking, cancellation, timeouts, and
13
- observability hooks without runtime dependencies.
12
+ `Retry-After` handling, streaming retries, circuit breakers, adaptive hedged
13
+ requests, rolling budget windows, cancellation, timeouts, and observability
14
+ hooks without runtime dependencies.
14
15
 
15
16
  ```bash
16
17
  npm install llm-retry-kit
@@ -42,6 +43,15 @@ 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
+ - Adapt hedge delays from recent provider latency with `AdaptiveHedgeDelay`.
52
+ - Enforce rolling cost windows with `GlobalBudgetTracker`.
53
+ - Await async stream chunk hooks while protecting the stream from hook errors.
54
+ - Pass request `meta` and `payload` through every context for logging.
45
55
  - Abort long calls and retry sleeps with `AbortSignal` or `timeoutMs`.
46
56
  - Observe attempts, retries, success, failure, and budget events.
47
57
  - Strict TypeScript types.
@@ -169,6 +179,193 @@ console.log({
169
179
  })
170
180
  ```
171
181
 
182
+ ## Streaming
183
+
184
+ OpenAI and Anthropic both expose streaming APIs, but their event formats and
185
+ resume behavior are provider-specific. `llm-retry-kit` therefore keeps the
186
+ stream wrapper provider-agnostic and conservative:
187
+
188
+ - By default, it retries only if the stream fails before the first chunk.
189
+ - After a chunk has been yielded, retrying could duplicate output, so it stops
190
+ unless you explicitly set `retryMode: 'always'`.
191
+ - Token usage can be tracked from stream events with `getChunkUsage`.
192
+ - Use `chunkUsageMode: 'cumulative'` for providers that send cumulative usage
193
+ snapshots during a stream.
194
+
195
+ ```ts
196
+ import { llmRetryStream } from 'llm-retry-kit'
197
+
198
+ const result = llmRetryStream({
199
+ stream: async ({ signal }) => {
200
+ const stream = await openai.responses.create({
201
+ model: 'gpt-4o-mini',
202
+ input: 'Write a short incident summary.',
203
+ stream: true,
204
+ }, { signal })
205
+
206
+ return stream
207
+ },
208
+ retryMode: 'before-first-chunk',
209
+ getChunkUsage: (event) => {
210
+ if (!('usage' in event) || !event.usage) return undefined
211
+
212
+ return {
213
+ promptTokens: event.usage.input_tokens ?? 0,
214
+ completionTokens: event.usage.output_tokens ?? 0,
215
+ totalTokens: event.usage.total_tokens ?? 0,
216
+ }
217
+ },
218
+ chunkUsageMode: 'cumulative',
219
+ })
220
+
221
+ for await (const event of result.stream) {
222
+ // Send provider events to your UI, parser, or SSE response.
223
+ }
224
+
225
+ console.log(result.getStats())
226
+ ```
227
+
228
+ ## Advanced Production Controls
229
+
230
+ ### Circuit Breaker
231
+
232
+ Keep one `CircuitBreaker` instance per provider/model at application scope. Do
233
+ not create the breaker inline inside a request handler; its state must survive
234
+ between calls. If the failure threshold is reached inside the time window,
235
+ later calls skip that provider until the cooldown expires.
236
+
237
+ ```ts
238
+ import { CircuitBreaker, llmRetry } from 'llm-retry-kit'
239
+
240
+ const openaiBreaker = new CircuitBreaker({
241
+ failureThreshold: 5,
242
+ windowMs: 60_000,
243
+ cooldownMs: 120_000,
244
+ })
245
+
246
+ await llmRetry({
247
+ providers: [
248
+ {
249
+ name: 'openai:gpt-4o-mini',
250
+ fn: callOpenAI,
251
+ circuitBreaker: openaiBreaker,
252
+ },
253
+ {
254
+ name: 'anthropic:claude-sonnet',
255
+ fn: callAnthropic,
256
+ },
257
+ ],
258
+ })
259
+ ```
260
+
261
+ ### Per-Provider Timeout
262
+
263
+ Use global `timeoutMs` for the whole workflow and provider `timeoutMs` for a
264
+ single attempt.
265
+
266
+ ```ts
267
+ await llmRetry({
268
+ providers: [
269
+ { name: 'openai:fast', fn: callOpenAI, timeoutMs: 3_000, maxRetries: 1 },
270
+ { name: 'anthropic:steady', fn: callAnthropic, timeoutMs: 10_000 },
271
+ ],
272
+ timeoutMs: 30_000,
273
+ })
274
+ ```
275
+
276
+ ### Hedged Requests
277
+
278
+ Hedging starts the next provider in parallel if the current provider has not
279
+ answered after `hedgeDelayMs`. The first successful response wins and the
280
+ slower request is aborted through the context signal.
281
+
282
+ ```ts
283
+ await llmRetry({
284
+ providers: [
285
+ { name: 'primary', fn: callPrimary },
286
+ { name: 'hedge', fn: callBackup },
287
+ ],
288
+ hedgeDelayMs: 750,
289
+ })
290
+ ```
291
+
292
+ Hedging is best for latency-sensitive read paths. It can increase provider
293
+ traffic, so pair it with budget tracking and conservative delay values.
294
+
295
+ ### Adaptive Hedging
296
+
297
+ Use `AdaptiveHedgeDelay` when fixed hedge delays are too brittle. It records
298
+ recent latency samples per provider and uses the configured percentile as the
299
+ next hedge delay. Keep the instance at application scope so the latency history
300
+ survives between requests.
301
+
302
+ ```ts
303
+ import { AdaptiveHedgeDelay, llmRetry } from 'llm-retry-kit'
304
+
305
+ const adaptiveHedge = new AdaptiveHedgeDelay({
306
+ sampleSize: 100,
307
+ percentile: 0.95,
308
+ minSamples: 10,
309
+ minDelayMs: 250,
310
+ maxDelayMs: 5_000,
311
+ })
312
+
313
+ await llmRetry({
314
+ providers: [
315
+ { name: 'openai:gpt-4o-mini', fn: callOpenAI },
316
+ { name: 'anthropic:claude-sonnet', fn: callAnthropic },
317
+ ],
318
+ hedgeDelayStrategy: adaptiveHedge,
319
+ })
320
+ ```
321
+
322
+ If there are not enough samples yet, no hedge is fired unless you set
323
+ `defaultDelayMs`.
324
+
325
+ ### Rolling Global Budget
326
+
327
+ `maxCostUSD` limits a single retry workflow. `GlobalBudgetTracker` limits the
328
+ total spend across many calls inside a rolling time window. Keep one instance at
329
+ application scope.
330
+
331
+ ```ts
332
+ import { GlobalBudgetTracker, llmRetry } from 'llm-retry-kit'
333
+
334
+ const globalBudget = new GlobalBudgetTracker({
335
+ maxCostUSD: 5,
336
+ windowMs: 60_000,
337
+ })
338
+
339
+ await llmRetry({
340
+ fn: callModel,
341
+ globalBudget,
342
+ costCalculator: calculateRealProviderCost,
343
+ })
344
+ ```
345
+
346
+ When the rolling window is exhausted, new attempts fail before the provider is
347
+ called. In-flight non-streaming calls can still finish because final usage is
348
+ known only after the provider returns. Streaming calls are checked as chunk
349
+ usage is reported.
350
+
351
+ ### Metadata And Payload Tracking
352
+
353
+ Attach request metadata once and it flows into provider calls and hooks.
354
+
355
+ ```ts
356
+ await llmRetry({
357
+ fn: callModel,
358
+ meta: { requestId: 'req_123', tenant: 'acme' },
359
+ payload: { prompt: 'Classify this ticket', userId: 'user_42' },
360
+ onAttempt: (context) => {
361
+ console.log(context.meta, context.payload)
362
+ },
363
+ onFailure: (error, context) => {
364
+ console.error(context.meta, error)
365
+ },
366
+ })
367
+ ```
368
+
172
369
  ## Simple Fallback API
173
370
 
174
371
  For smaller apps, `fn` plus `fallback` is still supported.
@@ -298,8 +495,8 @@ await llmRetry({
298
495
  onSuccess: (context) => {
299
496
  console.log(`Cost so far: $${context.totalCostUSD}`)
300
497
  },
301
- onFailure: (error) => {
302
- console.error(error)
498
+ onFailure: (error, context) => {
499
+ console.error(context.meta, error)
303
500
  },
304
501
  })
305
502
  ```
@@ -315,18 +512,23 @@ await llmRetry({
315
512
  | `providers` | `RetryProvider<T>[]` | optional | Explicit provider/model chain. |
316
513
  | `maxRetries` | `number` | `3` | Retries after the first attempt. |
317
514
  | `maxCostUSD` | `number` | optional | Maximum tracked cost before later attempts stop. |
515
+ | `globalBudget` | `GlobalBudgetTracker` | optional | Shared rolling cost budget across calls. |
318
516
  | `costPer1kTokens` | `number` | `0.002` | Simple cost estimate. |
319
517
  | `costCalculator` | `(usage, context) => number` | optional | Custom cost calculation. |
320
518
  | `initialDelayMs` | `number` | `1000` | Initial retry delay. |
321
519
  | `maxDelayMs` | `number` | `30000` | Maximum retry delay. |
322
520
  | `timeoutMs` | `number` | optional | Abort wrapper after this time. |
521
+ | `hedgeDelayMs` | `number` | optional | Start the next provider after this delay if the current provider is still pending. |
522
+ | `hedgeDelayStrategy` | `AdaptiveHedgeDelay` | optional | Compute hedge delay from recent provider latency. |
323
523
  | `signal` | `AbortSignal` | optional | External cancellation signal. |
524
+ | `meta` | `unknown` | optional | User metadata copied into attempt/failure contexts. |
525
+ | `payload` | `unknown` | optional | Request payload copied into attempt/failure contexts. |
324
526
  | `shouldRetry` | `(error, context) => boolean \| Promise<boolean>` | optional | Override retry decisions. |
325
527
  | `shouldFallback` | `(error, context) => boolean \| Promise<boolean>` | optional | Override provider fallback decisions. |
326
528
  | `onAttempt` | `(context) => void` | optional | Called before each attempt. |
327
529
  | `onRetry` | `(attempt, error, delayMs, context) => void` | optional | Called before retry wait. |
328
530
  | `onSuccess` | `(context) => void` | optional | Called after a successful response. |
329
- | `onFailure` | `(error) => void` | optional | Called before final failure is thrown. |
531
+ | `onFailure` | `(error, context) => void` | optional | Called before final failure is thrown. |
330
532
  | `onBudgetExceeded` | `(spentUSD, limitUSD) => void` | optional | Called when budget is exhausted. |
331
533
 
332
534
  ### `RetryProvider<T>`
@@ -336,11 +538,76 @@ await llmRetry({
336
538
  name: string
337
539
  fn: (context: RetryAttemptContext) => Promise<LLMResponse<T>>
338
540
  maxRetries?: number
541
+ timeoutMs?: number
542
+ hedgeDelayMs?: number
543
+ hedgeDelayStrategy?: AdaptiveHedgeDelay
544
+ circuitBreaker?: CircuitBreaker
339
545
  costPer1kTokens?: number
340
546
  costCalculator?: (usage, context) => number
341
547
  }
342
548
  ```
343
549
 
550
+ ### `llmRetryStream(options)`
551
+
552
+ Returns `{ stream, getStats }`. The request begins when the returned async
553
+ iterable is consumed.
554
+
555
+ | Option | Type | Default | Description |
556
+ | --- | --- | --- | --- |
557
+ | `stream` | `(context) => AsyncIterable<TChunk> \| Promise<AsyncIterable<TChunk>>` | optional | Primary stream call for the simple API. |
558
+ | `fallbackStream` | `(context) => AsyncIterable<TChunk> \| Promise<AsyncIterable<TChunk>>` | optional | Backup stream call. |
559
+ | `providers` | `StreamRetryProvider<TChunk>[]` | optional | Explicit stream provider chain. |
560
+ | `retryMode` | `'before-first-chunk' \| 'always' \| 'never'` | `'before-first-chunk'` | Controls whether interrupted streams are retried. |
561
+ | `getChunkUsage` | `(chunk, context) => TokenUsage \| undefined` | optional | Extract token usage from stream chunks/events. |
562
+ | `chunkUsageMode` | `'delta' \| 'cumulative'` | `'delta'` | Interpret chunk usage as incremental or cumulative. |
563
+ | `maxRetries` | `number` | `3` | Retries after the first attempt. |
564
+ | `timeoutMs` | `number` | optional | Abort the whole stream workflow after this time. |
565
+ | `globalBudget` | `GlobalBudgetTracker` | optional | Shared rolling cost budget across calls. |
566
+ | `meta` | `unknown` | optional | User metadata copied into contexts. |
567
+ | `payload` | `unknown` | optional | Request payload copied into contexts. |
568
+ | `onChunk` | `(chunk, context) => void \| Promise<void>` | optional | Called for each chunk before it is yielded. |
569
+ | `onChunkError` | `(error, chunk, context) => void \| Promise<void>` | optional | Called when `onChunk` fails. |
570
+ | `onChunkErrorMode` | `'ignore' \| 'throw'` | `'ignore'` | Decide whether `onChunk` failures should break the stream. |
571
+
572
+ ### `CircuitBreaker`
573
+
574
+ ```ts
575
+ new CircuitBreaker({
576
+ failureThreshold: 5,
577
+ windowMs: 60_000,
578
+ cooldownMs: 120_000,
579
+ })
580
+ ```
581
+
582
+ `snapshot()` returns `{ state, failures, openedAt }`, where state is
583
+ `'closed'`, `'open'`, or `'half_open'`.
584
+
585
+ ### `AdaptiveHedgeDelay`
586
+
587
+ ```ts
588
+ new AdaptiveHedgeDelay({
589
+ sampleSize: 100,
590
+ percentile: 0.95,
591
+ minSamples: 5,
592
+ minDelayMs: 250,
593
+ maxDelayMs: 5_000,
594
+ defaultDelayMs: 750,
595
+ })
596
+ ```
597
+
598
+ `snapshot()` returns the current sample count and computed delay per provider.
599
+
600
+ ### `GlobalBudgetTracker`
601
+
602
+ ```ts
603
+ new GlobalBudgetTracker({
604
+ maxCostUSD: 5,
605
+ windowMs: 60_000,
606
+ })
607
+ ```
608
+
609
+ `snapshot()` returns `{ spentUSD, limitUSD, windowMs, resetAt, entries }`.
610
+
344
611
  ### `RetryResult<T>`
345
612
 
346
613
  ```ts
@@ -377,6 +644,8 @@ await llmRetry({
377
644
  | `initialDelayMs` | `1000` |
378
645
  | `maxDelayMs` | `30000` |
379
646
  | `costPer1kTokens` | `0.002` |
647
+ | stream retry mode | `before-first-chunk` |
648
+ | stream chunk hook error mode | `ignore` |
380
649
  | fallback on client errors | `false` |
381
650
  | fallback on transient errors | `true` |
382
651
  | 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"}
@@ -0,0 +1,13 @@
1
+ import type { GlobalBudgetOptions, GlobalBudgetSnapshot } from './types.js';
2
+ export declare class GlobalBudgetTracker {
3
+ private readonly options;
4
+ private entries;
5
+ constructor(options: GlobalBudgetOptions);
6
+ add(costUSD: number): void;
7
+ isExceeded(): boolean;
8
+ get spent(): number;
9
+ get limit(): number;
10
+ snapshot(): GlobalBudgetSnapshot;
11
+ private prune;
12
+ }
13
+ //# sourceMappingURL=global-budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"global-budget.d.ts","sourceRoot":"","sources":["../src/global-budget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAO3E,qBAAa,mBAAmB;IAGlB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,OAAO,CAAoB;gBAEN,OAAO,EAAE,mBAAmB;IAIzD,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAc1B,UAAU,IAAI,OAAO;IAKrB,IAAI,KAAK,IAAI,MAAM,CAGlB;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,QAAQ,IAAI,oBAAoB;IAchC,OAAO,CAAC,KAAK;CAId"}
@@ -0,0 +1,54 @@
1
+ export class GlobalBudgetTracker {
2
+ options;
3
+ entries = [];
4
+ constructor(options) {
5
+ this.options = options;
6
+ validateGlobalBudgetOptions(options);
7
+ }
8
+ add(costUSD) {
9
+ if (!Number.isFinite(costUSD) || costUSD < 0) {
10
+ throw new Error('costUSD must be greater than or equal to 0');
11
+ }
12
+ this.prune();
13
+ if (costUSD === 0) {
14
+ return;
15
+ }
16
+ this.entries.push({ timestamp: Date.now(), costUSD });
17
+ }
18
+ isExceeded() {
19
+ this.prune();
20
+ return this.spent >= this.options.maxCostUSD;
21
+ }
22
+ get spent() {
23
+ this.prune();
24
+ return this.entries.reduce((total, entry) => total + entry.costUSD, 0);
25
+ }
26
+ get limit() {
27
+ return this.options.maxCostUSD;
28
+ }
29
+ snapshot() {
30
+ this.prune();
31
+ return {
32
+ spentUSD: this.spent,
33
+ limitUSD: this.options.maxCostUSD,
34
+ windowMs: this.options.windowMs,
35
+ resetAt: this.entries[0]
36
+ ? this.entries[0].timestamp + this.options.windowMs
37
+ : null,
38
+ entries: this.entries.length,
39
+ };
40
+ }
41
+ prune() {
42
+ const windowStart = Date.now() - this.options.windowMs;
43
+ this.entries = this.entries.filter((entry) => entry.timestamp > windowStart);
44
+ }
45
+ }
46
+ function validateGlobalBudgetOptions(options) {
47
+ if (options.maxCostUSD < 0) {
48
+ throw new Error('maxCostUSD must be greater than or equal to 0');
49
+ }
50
+ if (!Number.isFinite(options.windowMs) || options.windowMs <= 0) {
51
+ throw new Error('windowMs must be greater than 0');
52
+ }
53
+ }
54
+ //# sourceMappingURL=global-budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"global-budget.js","sourceRoot":"","sources":["../src/global-budget.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,mBAAmB;IAGD;IAFrB,OAAO,GAAkB,EAAE,CAAA;IAEnC,YAA6B,OAA4B;QAA5B,YAAO,GAAP,OAAO,CAAqB;QACvD,2BAA2B,CAAC,OAAO,CAAC,CAAA;IACtC,CAAC;IAED,GAAG,CAAC,OAAe;QACjB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;QAC/D,CAAC;QAED,IAAI,CAAC,KAAK,EAAE,CAAA;QAEZ,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;YAClB,OAAM;QACR,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;IACvD,CAAC;IAED,UAAU;QACR,IAAI,CAAC,KAAK,EAAE,CAAA;QACZ,OAAO,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,CAAA;IAC9C,CAAC;IAED,IAAI,KAAK;QACP,IAAI,CAAC,KAAK,EAAE,CAAA;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;IACxE,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAA;IAChC,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,KAAK,EAAE,CAAA;QAEZ,OAAO;YACL,QAAQ,EAAE,IAAI,CAAC,KAAK;YACpB,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU;YACjC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ;YAC/B,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;gBACtB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ;gBACnD,CAAC,CAAC,IAAI;YACR,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;SAC7B,CAAA;IACH,CAAC;IAEO,KAAK;QACX,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAA;QACtD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,WAAW,CAAC,CAAA;IAC9E,CAAC;CACF;AAED,SAAS,2BAA2B,CAAC,OAA4B;IAC/D,IAAI,OAAO,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACpD,CAAC;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { AdaptiveHedgeDelayOptions, AdaptiveHedgeDelaySnapshot, HedgeDelayRecord, RetryAttemptContext } from './types.js';
2
+ export declare class AdaptiveHedgeDelay {
3
+ private readonly samplesByProvider;
4
+ private readonly sampleSize;
5
+ private readonly percentile;
6
+ private readonly minSamples;
7
+ private readonly minDelayMs;
8
+ private readonly maxDelayMs;
9
+ private readonly defaultDelayMs;
10
+ private readonly recordFailures;
11
+ constructor(options?: AdaptiveHedgeDelayOptions);
12
+ getDelayMs(context: RetryAttemptContext): number | null;
13
+ recordLatency(record: HedgeDelayRecord): void;
14
+ snapshot(): AdaptiveHedgeDelaySnapshot;
15
+ private clamp;
16
+ }
17
+ //# sourceMappingURL=hedging.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hedging.d.ts","sourceRoot":"","sources":["../src/hedging.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,0BAA0B,EAC1B,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,YAAY,CAAA;AAEnB,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA8B;IAChE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;IAC1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;IAC1C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAe;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAE5B,OAAO,GAAE,yBAA8B;IAmBnD,UAAU,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,GAAG,IAAI;IASvD,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAmB7C,QAAQ,IAAI,0BAA0B;IAmBtC,OAAO,CAAC,KAAK;CAad"}
@@ -0,0 +1,105 @@
1
+ export class AdaptiveHedgeDelay {
2
+ samplesByProvider = new Map();
3
+ sampleSize;
4
+ percentile;
5
+ minSamples;
6
+ minDelayMs;
7
+ maxDelayMs;
8
+ defaultDelayMs;
9
+ recordFailures;
10
+ constructor(options = {}) {
11
+ this.sampleSize = options.sampleSize ?? 100;
12
+ this.percentile = options.percentile ?? 0.95;
13
+ this.minSamples = options.minSamples ?? 5;
14
+ this.minDelayMs = options.minDelayMs ?? null;
15
+ this.maxDelayMs = options.maxDelayMs ?? null;
16
+ this.defaultDelayMs = options.defaultDelayMs ?? null;
17
+ this.recordFailures = options.recordFailures ?? false;
18
+ validateAdaptiveHedgeDelay({
19
+ sampleSize: this.sampleSize,
20
+ percentile: this.percentile,
21
+ minSamples: this.minSamples,
22
+ minDelayMs: this.minDelayMs,
23
+ maxDelayMs: this.maxDelayMs,
24
+ defaultDelayMs: this.defaultDelayMs,
25
+ });
26
+ }
27
+ getDelayMs(context) {
28
+ const samples = this.samplesByProvider.get(context.provider) ?? [];
29
+ if (samples.length < this.minSamples) {
30
+ return this.defaultDelayMs;
31
+ }
32
+ return this.clamp(percentile(samples, this.percentile));
33
+ }
34
+ recordLatency(record) {
35
+ if (!Number.isFinite(record.latencyMs) || record.latencyMs < 0) {
36
+ return;
37
+ }
38
+ if (record.outcome === 'failure' && !this.recordFailures) {
39
+ return;
40
+ }
41
+ const samples = this.samplesByProvider.get(record.provider) ?? [];
42
+ samples.push(record.latencyMs);
43
+ if (samples.length > this.sampleSize) {
44
+ samples.splice(0, samples.length - this.sampleSize);
45
+ }
46
+ this.samplesByProvider.set(record.provider, samples);
47
+ }
48
+ snapshot() {
49
+ const providers = {};
50
+ for (const [provider, samples] of this.samplesByProvider) {
51
+ providers[provider] = {
52
+ samples: samples.length,
53
+ delayMs: samples.length < this.minSamples
54
+ ? this.defaultDelayMs
55
+ : this.clamp(percentile(samples, this.percentile)),
56
+ };
57
+ }
58
+ return {
59
+ sampleSize: this.sampleSize,
60
+ percentile: this.percentile,
61
+ providers,
62
+ };
63
+ }
64
+ clamp(delayMs) {
65
+ let clamped = delayMs;
66
+ if (this.minDelayMs !== null) {
67
+ clamped = Math.max(clamped, this.minDelayMs);
68
+ }
69
+ if (this.maxDelayMs !== null) {
70
+ clamped = Math.min(clamped, this.maxDelayMs);
71
+ }
72
+ return clamped;
73
+ }
74
+ }
75
+ function percentile(samples, value) {
76
+ const sorted = [...samples].sort((a, b) => a - b);
77
+ const index = Math.ceil(value * sorted.length) - 1;
78
+ return sorted[Math.min(Math.max(index, 0), sorted.length - 1)] ?? 0;
79
+ }
80
+ function validateAdaptiveHedgeDelay(options) {
81
+ if (!Number.isInteger(options.sampleSize) || options.sampleSize <= 0) {
82
+ throw new Error('sampleSize must be a positive integer');
83
+ }
84
+ if (options.percentile <= 0 || options.percentile > 1) {
85
+ throw new Error('percentile must be greater than 0 and less than or equal to 1');
86
+ }
87
+ if (!Number.isInteger(options.minSamples) || options.minSamples < 0) {
88
+ throw new Error('minSamples must be a non-negative integer');
89
+ }
90
+ for (const [name, value] of [
91
+ ['minDelayMs', options.minDelayMs],
92
+ ['maxDelayMs', options.maxDelayMs],
93
+ ['defaultDelayMs', options.defaultDelayMs],
94
+ ]) {
95
+ if (value !== null && value < 0) {
96
+ throw new Error(`${name} must be greater than or equal to 0`);
97
+ }
98
+ }
99
+ if (options.minDelayMs !== null &&
100
+ options.maxDelayMs !== null &&
101
+ options.maxDelayMs < options.minDelayMs) {
102
+ throw new Error('maxDelayMs must be greater than or equal to minDelayMs');
103
+ }
104
+ }
105
+ //# sourceMappingURL=hedging.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hedging.js","sourceRoot":"","sources":["../src/hedging.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,9 @@
1
- export { BudgetExceededError, llmRetry, LLMRetryError } from './retry.js';
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';
5
+ export { GlobalBudgetTracker } from './global-budget.js';
6
+ export { AdaptiveHedgeDelay } from './hedging.js';
3
7
  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';
8
+ export type { AdaptiveHedgeDelayOptions, AdaptiveHedgeDelaySnapshot, CircuitBreakerLike, CircuitBreakerOptions, CircuitBreakerSnapshot, CircuitBreakerState, CostCalculator, FallbackDecisionContext, GlobalBudgetLike, GlobalBudgetOptions, GlobalBudgetSnapshot, HedgeDelayRecord, HedgeDelayStrategy, 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
9
  //# sourceMappingURL=index.d.ts.map
@@ -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;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AACpF,YAAY,EACV,cAAc,EACd,uBAAuB,EACvB,OAAO,EACP,WAAW,EACX,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,WAAW,EACX,UAAU,GACX,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,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AACpF,YAAY,EACV,yBAAyB,EACzB,0BAA0B,EAC1B,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,cAAc,EACd,uBAAuB,EACvB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,EAClB,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"}