floe-guard 0.8.0 → 0.9.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 +34 -0
- package/dist/index.cjs +271 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +120 -9
- package/dist/index.d.ts +120 -9
- package/dist/index.js +270 -32
- package/dist/index.js.map +1 -1
- package/package.json +6 -1
package/dist/index.d.cts
CHANGED
|
@@ -64,6 +64,23 @@ declare namespace pricing {
|
|
|
64
64
|
* same epsilon handling, same fail-closed default.
|
|
65
65
|
*/
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* A two-dimensional in-flight hold (USD + tokens) returned by
|
|
69
|
+
* {@link BudgetGuard.reserve} when a token ceiling or an active
|
|
70
|
+
* {@link BudgetGuard.step} is involved. A dumb value handle — pass it straight
|
|
71
|
+
* back to {@link BudgetGuard.settle} / {@link BudgetGuard.release}. When neither
|
|
72
|
+
* tokens nor a step are involved, `reserve` returns a plain `number` instead
|
|
73
|
+
* (byte-for-byte the old behaviour), so {@link ReservationHandle} is the union.
|
|
74
|
+
*/
|
|
75
|
+
interface BudgetReservation {
|
|
76
|
+
readonly usd: number;
|
|
77
|
+
readonly tokens: number;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* A plain `number` when USD-only (backward compatible); a
|
|
81
|
+
* {@link BudgetReservation} when a token ceiling or an active step is in play.
|
|
82
|
+
*/
|
|
83
|
+
type ReservationHandle = number | BudgetReservation;
|
|
67
84
|
/**
|
|
68
85
|
* One priced spend event in the guard's per-call ledger.
|
|
69
86
|
*
|
|
@@ -103,7 +120,9 @@ interface BudgetGuardOptions {
|
|
|
103
120
|
/**
|
|
104
121
|
* Optional callback invoked with `(spentUsd, limitUsd)` right before
|
|
105
122
|
* {@link BudgetExceeded} is thrown. Defaults to printing the
|
|
106
|
-
* `BUDGET EXCEEDED — call blocked` banner to stderr.
|
|
123
|
+
* `BUDGET EXCEEDED — call blocked` banner to stderr. Fires on **USD** ceiling
|
|
124
|
+
* crossings only; a token-ceiling block ({@link TokenBudgetExceeded}, aggregate
|
|
125
|
+
* or step) is thrown without invoking it, since the callback is dollar-shaped.
|
|
107
126
|
*/
|
|
108
127
|
onBlock?: (spentUsd: number, limitUsd: number) => void;
|
|
109
128
|
/**
|
|
@@ -118,6 +137,11 @@ interface BudgetGuardOptions {
|
|
|
118
137
|
* unaffected. Default: keep every event.
|
|
119
138
|
*/
|
|
120
139
|
maxLogEvents?: number;
|
|
140
|
+
/**
|
|
141
|
+
* Aggregate token ceiling. `null`/undefined disables the token dimension
|
|
142
|
+
* entirely (a pure USD guard, unchanged). `0` blocks the first token.
|
|
143
|
+
*/
|
|
144
|
+
tokenLimit?: number;
|
|
121
145
|
}
|
|
122
146
|
/**
|
|
123
147
|
* A context-aware spend signal for the single local budget.
|
|
@@ -158,6 +182,19 @@ interface BudgetAdvisory {
|
|
|
158
182
|
* expectedCost; `advisory()` always sets it.
|
|
159
183
|
*/
|
|
160
184
|
estCallsRemaining?: number | null;
|
|
185
|
+
/**
|
|
186
|
+
* Aggregate token utilization in basis points (0..10000), mirroring usedBps
|
|
187
|
+
* for the token ceiling. null when no `tokenLimit` is set (nothing to signal).
|
|
188
|
+
*/
|
|
189
|
+
tokenUsedBps?: number | null;
|
|
190
|
+
/** Tokens left before the aggregate token ceiling. null when no `tokenLimit`. */
|
|
191
|
+
remainingTokens?: number | null;
|
|
192
|
+
/**
|
|
193
|
+
* Per-step headroom for the innermost active step — present (non-null) ONLY
|
|
194
|
+
* while a step() is active AND that dimension is capped. null otherwise.
|
|
195
|
+
*/
|
|
196
|
+
stepRemainingUsd?: number | null;
|
|
197
|
+
stepRemainingTokens?: number | null;
|
|
161
198
|
}
|
|
162
199
|
declare class BudgetGuard {
|
|
163
200
|
readonly limitUsd: number;
|
|
@@ -165,6 +202,14 @@ declare class BudgetGuard {
|
|
|
165
202
|
priceOverrides?: Record<string, ManualPrice>;
|
|
166
203
|
failClosed: boolean;
|
|
167
204
|
nearLimitBps: number;
|
|
205
|
+
/** Aggregate token ceiling, or null when the token dimension is disabled. */
|
|
206
|
+
readonly tokenLimit: number | null;
|
|
207
|
+
/** Aggregate tokens accrued (prompt + completion + cache buckets). */
|
|
208
|
+
spentTokens: number;
|
|
209
|
+
/** Tokens held in-flight — the token twin of `reserved`. */
|
|
210
|
+
private reservedTokens;
|
|
211
|
+
/** Step stack: innermost step is last. Empty when no step() is active. */
|
|
212
|
+
private readonly steps;
|
|
168
213
|
private readonly onBlock;
|
|
169
214
|
/**
|
|
170
215
|
* Costs of the most recent priced LLM call and tool call, tracked
|
|
@@ -203,7 +248,9 @@ declare class BudgetGuard {
|
|
|
203
248
|
* Note: `check` is a non-binding peek. For parallel calls, use `reserve()` /
|
|
204
249
|
* `settle()`, which hold the estimate across the await.
|
|
205
250
|
*/
|
|
206
|
-
check(estimatedNextCost?: number
|
|
251
|
+
check(estimatedNextCost?: number, options?: {
|
|
252
|
+
estimatedTokens?: number;
|
|
253
|
+
}): void;
|
|
207
254
|
/**
|
|
208
255
|
* Atomically check the ceiling AND hold the estimated cost in flight.
|
|
209
256
|
*
|
|
@@ -215,7 +262,9 @@ declare class BudgetGuard {
|
|
|
215
262
|
* `estimatedCost` defaults to the costlier of the last LLM call and the last
|
|
216
263
|
* tool call.
|
|
217
264
|
*/
|
|
218
|
-
reserve(estimatedCost?: number
|
|
265
|
+
reserve(estimatedCost?: number, options?: {
|
|
266
|
+
estimatedTokens?: number;
|
|
267
|
+
}): ReservationHandle;
|
|
219
268
|
/**
|
|
220
269
|
* Release a reservation and record the actual cost. `record` is `settle` with
|
|
221
270
|
* no reservation. Returns the USD cost of this call; unpriceable-model handling
|
|
@@ -226,7 +275,7 @@ declare class BudgetGuard {
|
|
|
226
275
|
* in lockstep with `spentUsd`.
|
|
227
276
|
*/
|
|
228
277
|
settle(model: string, promptTokens: number, completionTokens: number, options?: {
|
|
229
|
-
reserved?:
|
|
278
|
+
reserved?: ReservationHandle;
|
|
230
279
|
price?: ManualPrice;
|
|
231
280
|
label?: string;
|
|
232
281
|
}): number;
|
|
@@ -258,7 +307,7 @@ declare class BudgetGuard {
|
|
|
258
307
|
* worth falling back to. Pass the returned handle to
|
|
259
308
|
* {@link BudgetGuard.settleTool}, or {@link BudgetGuard.release} on failure.
|
|
260
309
|
*/
|
|
261
|
-
reserveTool(estimatedCost: number):
|
|
310
|
+
reserveTool(estimatedCost: number): ReservationHandle;
|
|
262
311
|
/**
|
|
263
312
|
* Release a reservation and record a tool call's actual cost.
|
|
264
313
|
*
|
|
@@ -274,7 +323,7 @@ declare class BudgetGuard {
|
|
|
274
323
|
* Returns `costUsd`.
|
|
275
324
|
*/
|
|
276
325
|
settleTool(tool: string, costUsd: number, options?: {
|
|
277
|
-
reserved?:
|
|
326
|
+
reserved?: ReservationHandle;
|
|
278
327
|
label?: string;
|
|
279
328
|
}): number;
|
|
280
329
|
/**
|
|
@@ -292,7 +341,7 @@ declare class BudgetGuard {
|
|
|
292
341
|
* Drop an in-flight reservation without recording spend (e.g. the call failed
|
|
293
342
|
* before producing usage). Safe to call with `0`.
|
|
294
343
|
*/
|
|
295
|
-
release(reserved:
|
|
344
|
+
release(reserved: ReservationHandle): void;
|
|
296
345
|
/** USD left before the ceiling, net of in-flight reservations (never negative). */
|
|
297
346
|
get remainingUsd(): number;
|
|
298
347
|
/**
|
|
@@ -338,6 +387,50 @@ declare class BudgetGuard {
|
|
|
338
387
|
* responsibility.
|
|
339
388
|
*/
|
|
340
389
|
private consumeReservation;
|
|
390
|
+
/**
|
|
391
|
+
* The USD amount of a handle, validated. Both shapes are checked — a raw
|
|
392
|
+
* number and a {@link BudgetReservation}'s `usd`/`tokens` fields — so a bad
|
|
393
|
+
* hand-rolled handle can't corrupt the in-flight tally.
|
|
394
|
+
*/
|
|
395
|
+
/**
|
|
396
|
+
* Validate a caller-supplied token estimate. Rejects a fraction, NaN,
|
|
397
|
+
* Infinity, or boolean (via `Number.isInteger`) so it can't disable the
|
|
398
|
+
* integer token hard-stops or corrupt the in-flight token tally. `undefined`
|
|
399
|
+
* (the default) is fine; a negative integer is clamped by `Math.max(0, ...)`,
|
|
400
|
+
* matching the lenient USD estimate. Mirrors Python's `_validate_token_estimate`.
|
|
401
|
+
*/
|
|
402
|
+
private validateTokenEstimate;
|
|
403
|
+
private reservedUsdOf;
|
|
404
|
+
/**
|
|
405
|
+
* Accrue a settled call into the innermost active step (no-op when none).
|
|
406
|
+
* Sequential-loop contract: the innermost step owns the call.
|
|
407
|
+
*/
|
|
408
|
+
private accrueStep;
|
|
409
|
+
/**
|
|
410
|
+
* The ONE choke point, across two dimensions and two scopes. Returns the first
|
|
411
|
+
* ceiling that blocks as `[dimension, scope]` — dimension `"usd" | "tokens"`,
|
|
412
|
+
* scope `"aggregate" | "step"` — or `null` if the call fits everywhere.
|
|
413
|
+
* Aggregate is checked before step (the guard-wide ceiling is the hard limit).
|
|
414
|
+
*/
|
|
415
|
+
private blockingCross;
|
|
416
|
+
/** Notify + throw the right error for a [dimension, scope] block. */
|
|
417
|
+
private raiseBlock;
|
|
418
|
+
/**
|
|
419
|
+
* Scope a per-step USD and/or token cap for a **sequential agent loop**.
|
|
420
|
+
*
|
|
421
|
+
* Runs `fn` with a step pushed onto the guard's stack; the
|
|
422
|
+
* enforcement/accrual path honours the innermost active step *on top of* the
|
|
423
|
+
* aggregate ceilings. A call that would cross the step's `maxUsd` / `maxTokens`
|
|
424
|
+
* is hard-blocked ({@link BudgetExceeded} / {@link TokenBudgetExceeded} with
|
|
425
|
+
* `scope: "step"`) even if the aggregate budget has room. `fn` receives the
|
|
426
|
+
* SAME guard, so no adapter needs to know about steps. The step is popped when
|
|
427
|
+
* `fn` settles or throws. **Not for concurrent parallel steps on one guard** —
|
|
428
|
+
* that's out of scope for issue #46; use one guard per parallel branch.
|
|
429
|
+
*/
|
|
430
|
+
step<T>(options: {
|
|
431
|
+
maxUsd?: number;
|
|
432
|
+
maxTokens?: number;
|
|
433
|
+
}, fn: (guard: BudgetGuard) => T): T;
|
|
341
434
|
private appendEvent;
|
|
342
435
|
/**
|
|
343
436
|
* Context-aware spend advisory for this budget — see {@link BudgetAdvisory}.
|
|
@@ -442,7 +535,25 @@ declare class FloeGuardError extends Error {
|
|
|
442
535
|
declare class BudgetExceeded extends FloeGuardError {
|
|
443
536
|
readonly spentUsd: number;
|
|
444
537
|
readonly limitUsd: number;
|
|
445
|
-
constructor(spentUsd: number, limitUsd: number);
|
|
538
|
+
constructor(spentUsd: number, limitUsd: number, message?: string);
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Thrown before a call that would cross a token ceiling (aggregate or step).
|
|
542
|
+
*
|
|
543
|
+
* The token twin of {@link BudgetExceeded} — it extends it so the same retry
|
|
544
|
+
* logic that treats a USD block as terminal (`!(error instanceof
|
|
545
|
+
* BudgetExceeded)`) treats a token block as terminal too, with no extra wiring.
|
|
546
|
+
* `spentUsd` / `limitUsd` are inherited but not meaningful here; the token
|
|
547
|
+
* fields are the payload.
|
|
548
|
+
*
|
|
549
|
+
* `scope` is `"aggregate"` (the guard-wide `tokenLimit`) or `"step"` (the
|
|
550
|
+
* innermost active {@link BudgetGuard.step} cap).
|
|
551
|
+
*/
|
|
552
|
+
declare class TokenBudgetExceeded extends BudgetExceeded {
|
|
553
|
+
readonly spentTokens: number;
|
|
554
|
+
readonly limitTokens: number;
|
|
555
|
+
readonly scope: "aggregate" | "step";
|
|
556
|
+
constructor(spentTokens: number, limitTokens: number, scope: "aggregate" | "step");
|
|
446
557
|
}
|
|
447
558
|
/**
|
|
448
559
|
* Thrown when a model cannot be priced and the guard is fail-closed.
|
|
@@ -559,4 +670,4 @@ interface BudgetRetryOptions<T> {
|
|
|
559
670
|
*/
|
|
560
671
|
declare function withBudgetRetry<T>(guard: BudgetGuard, call: () => T | Promise<T>, options?: BudgetRetryOptions<T>): Promise<T>;
|
|
561
672
|
|
|
562
|
-
export { type BudgetAdvisory, BudgetExceeded, BudgetGuard, type BudgetGuardMiddleware, type BudgetGuardOptions, type BudgetRetryOptions, DeadlineExceeded, FloeGuardError, type LatencyAdvisory, LatencyBudget, type LatencyBudgetOptions, type ManualPrice, type PricedModel, type RetryPlan, type SpendEvent, UnpriceableModelError, budgetGuardMiddleware, priceTokens, pricing, resolvePrice, withBudgetRetry };
|
|
673
|
+
export { type BudgetAdvisory, BudgetExceeded, BudgetGuard, type BudgetGuardMiddleware, type BudgetGuardOptions, type BudgetReservation, type BudgetRetryOptions, DeadlineExceeded, FloeGuardError, type LatencyAdvisory, LatencyBudget, type LatencyBudgetOptions, type ManualPrice, type PricedModel, type ReservationHandle, type RetryPlan, type SpendEvent, TokenBudgetExceeded, UnpriceableModelError, budgetGuardMiddleware, priceTokens, pricing, resolvePrice, withBudgetRetry };
|
package/dist/index.d.ts
CHANGED
|
@@ -64,6 +64,23 @@ declare namespace pricing {
|
|
|
64
64
|
* same epsilon handling, same fail-closed default.
|
|
65
65
|
*/
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* A two-dimensional in-flight hold (USD + tokens) returned by
|
|
69
|
+
* {@link BudgetGuard.reserve} when a token ceiling or an active
|
|
70
|
+
* {@link BudgetGuard.step} is involved. A dumb value handle — pass it straight
|
|
71
|
+
* back to {@link BudgetGuard.settle} / {@link BudgetGuard.release}. When neither
|
|
72
|
+
* tokens nor a step are involved, `reserve` returns a plain `number` instead
|
|
73
|
+
* (byte-for-byte the old behaviour), so {@link ReservationHandle} is the union.
|
|
74
|
+
*/
|
|
75
|
+
interface BudgetReservation {
|
|
76
|
+
readonly usd: number;
|
|
77
|
+
readonly tokens: number;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* A plain `number` when USD-only (backward compatible); a
|
|
81
|
+
* {@link BudgetReservation} when a token ceiling or an active step is in play.
|
|
82
|
+
*/
|
|
83
|
+
type ReservationHandle = number | BudgetReservation;
|
|
67
84
|
/**
|
|
68
85
|
* One priced spend event in the guard's per-call ledger.
|
|
69
86
|
*
|
|
@@ -103,7 +120,9 @@ interface BudgetGuardOptions {
|
|
|
103
120
|
/**
|
|
104
121
|
* Optional callback invoked with `(spentUsd, limitUsd)` right before
|
|
105
122
|
* {@link BudgetExceeded} is thrown. Defaults to printing the
|
|
106
|
-
* `BUDGET EXCEEDED — call blocked` banner to stderr.
|
|
123
|
+
* `BUDGET EXCEEDED — call blocked` banner to stderr. Fires on **USD** ceiling
|
|
124
|
+
* crossings only; a token-ceiling block ({@link TokenBudgetExceeded}, aggregate
|
|
125
|
+
* or step) is thrown without invoking it, since the callback is dollar-shaped.
|
|
107
126
|
*/
|
|
108
127
|
onBlock?: (spentUsd: number, limitUsd: number) => void;
|
|
109
128
|
/**
|
|
@@ -118,6 +137,11 @@ interface BudgetGuardOptions {
|
|
|
118
137
|
* unaffected. Default: keep every event.
|
|
119
138
|
*/
|
|
120
139
|
maxLogEvents?: number;
|
|
140
|
+
/**
|
|
141
|
+
* Aggregate token ceiling. `null`/undefined disables the token dimension
|
|
142
|
+
* entirely (a pure USD guard, unchanged). `0` blocks the first token.
|
|
143
|
+
*/
|
|
144
|
+
tokenLimit?: number;
|
|
121
145
|
}
|
|
122
146
|
/**
|
|
123
147
|
* A context-aware spend signal for the single local budget.
|
|
@@ -158,6 +182,19 @@ interface BudgetAdvisory {
|
|
|
158
182
|
* expectedCost; `advisory()` always sets it.
|
|
159
183
|
*/
|
|
160
184
|
estCallsRemaining?: number | null;
|
|
185
|
+
/**
|
|
186
|
+
* Aggregate token utilization in basis points (0..10000), mirroring usedBps
|
|
187
|
+
* for the token ceiling. null when no `tokenLimit` is set (nothing to signal).
|
|
188
|
+
*/
|
|
189
|
+
tokenUsedBps?: number | null;
|
|
190
|
+
/** Tokens left before the aggregate token ceiling. null when no `tokenLimit`. */
|
|
191
|
+
remainingTokens?: number | null;
|
|
192
|
+
/**
|
|
193
|
+
* Per-step headroom for the innermost active step — present (non-null) ONLY
|
|
194
|
+
* while a step() is active AND that dimension is capped. null otherwise.
|
|
195
|
+
*/
|
|
196
|
+
stepRemainingUsd?: number | null;
|
|
197
|
+
stepRemainingTokens?: number | null;
|
|
161
198
|
}
|
|
162
199
|
declare class BudgetGuard {
|
|
163
200
|
readonly limitUsd: number;
|
|
@@ -165,6 +202,14 @@ declare class BudgetGuard {
|
|
|
165
202
|
priceOverrides?: Record<string, ManualPrice>;
|
|
166
203
|
failClosed: boolean;
|
|
167
204
|
nearLimitBps: number;
|
|
205
|
+
/** Aggregate token ceiling, or null when the token dimension is disabled. */
|
|
206
|
+
readonly tokenLimit: number | null;
|
|
207
|
+
/** Aggregate tokens accrued (prompt + completion + cache buckets). */
|
|
208
|
+
spentTokens: number;
|
|
209
|
+
/** Tokens held in-flight — the token twin of `reserved`. */
|
|
210
|
+
private reservedTokens;
|
|
211
|
+
/** Step stack: innermost step is last. Empty when no step() is active. */
|
|
212
|
+
private readonly steps;
|
|
168
213
|
private readonly onBlock;
|
|
169
214
|
/**
|
|
170
215
|
* Costs of the most recent priced LLM call and tool call, tracked
|
|
@@ -203,7 +248,9 @@ declare class BudgetGuard {
|
|
|
203
248
|
* Note: `check` is a non-binding peek. For parallel calls, use `reserve()` /
|
|
204
249
|
* `settle()`, which hold the estimate across the await.
|
|
205
250
|
*/
|
|
206
|
-
check(estimatedNextCost?: number
|
|
251
|
+
check(estimatedNextCost?: number, options?: {
|
|
252
|
+
estimatedTokens?: number;
|
|
253
|
+
}): void;
|
|
207
254
|
/**
|
|
208
255
|
* Atomically check the ceiling AND hold the estimated cost in flight.
|
|
209
256
|
*
|
|
@@ -215,7 +262,9 @@ declare class BudgetGuard {
|
|
|
215
262
|
* `estimatedCost` defaults to the costlier of the last LLM call and the last
|
|
216
263
|
* tool call.
|
|
217
264
|
*/
|
|
218
|
-
reserve(estimatedCost?: number
|
|
265
|
+
reserve(estimatedCost?: number, options?: {
|
|
266
|
+
estimatedTokens?: number;
|
|
267
|
+
}): ReservationHandle;
|
|
219
268
|
/**
|
|
220
269
|
* Release a reservation and record the actual cost. `record` is `settle` with
|
|
221
270
|
* no reservation. Returns the USD cost of this call; unpriceable-model handling
|
|
@@ -226,7 +275,7 @@ declare class BudgetGuard {
|
|
|
226
275
|
* in lockstep with `spentUsd`.
|
|
227
276
|
*/
|
|
228
277
|
settle(model: string, promptTokens: number, completionTokens: number, options?: {
|
|
229
|
-
reserved?:
|
|
278
|
+
reserved?: ReservationHandle;
|
|
230
279
|
price?: ManualPrice;
|
|
231
280
|
label?: string;
|
|
232
281
|
}): number;
|
|
@@ -258,7 +307,7 @@ declare class BudgetGuard {
|
|
|
258
307
|
* worth falling back to. Pass the returned handle to
|
|
259
308
|
* {@link BudgetGuard.settleTool}, or {@link BudgetGuard.release} on failure.
|
|
260
309
|
*/
|
|
261
|
-
reserveTool(estimatedCost: number):
|
|
310
|
+
reserveTool(estimatedCost: number): ReservationHandle;
|
|
262
311
|
/**
|
|
263
312
|
* Release a reservation and record a tool call's actual cost.
|
|
264
313
|
*
|
|
@@ -274,7 +323,7 @@ declare class BudgetGuard {
|
|
|
274
323
|
* Returns `costUsd`.
|
|
275
324
|
*/
|
|
276
325
|
settleTool(tool: string, costUsd: number, options?: {
|
|
277
|
-
reserved?:
|
|
326
|
+
reserved?: ReservationHandle;
|
|
278
327
|
label?: string;
|
|
279
328
|
}): number;
|
|
280
329
|
/**
|
|
@@ -292,7 +341,7 @@ declare class BudgetGuard {
|
|
|
292
341
|
* Drop an in-flight reservation without recording spend (e.g. the call failed
|
|
293
342
|
* before producing usage). Safe to call with `0`.
|
|
294
343
|
*/
|
|
295
|
-
release(reserved:
|
|
344
|
+
release(reserved: ReservationHandle): void;
|
|
296
345
|
/** USD left before the ceiling, net of in-flight reservations (never negative). */
|
|
297
346
|
get remainingUsd(): number;
|
|
298
347
|
/**
|
|
@@ -338,6 +387,50 @@ declare class BudgetGuard {
|
|
|
338
387
|
* responsibility.
|
|
339
388
|
*/
|
|
340
389
|
private consumeReservation;
|
|
390
|
+
/**
|
|
391
|
+
* The USD amount of a handle, validated. Both shapes are checked — a raw
|
|
392
|
+
* number and a {@link BudgetReservation}'s `usd`/`tokens` fields — so a bad
|
|
393
|
+
* hand-rolled handle can't corrupt the in-flight tally.
|
|
394
|
+
*/
|
|
395
|
+
/**
|
|
396
|
+
* Validate a caller-supplied token estimate. Rejects a fraction, NaN,
|
|
397
|
+
* Infinity, or boolean (via `Number.isInteger`) so it can't disable the
|
|
398
|
+
* integer token hard-stops or corrupt the in-flight token tally. `undefined`
|
|
399
|
+
* (the default) is fine; a negative integer is clamped by `Math.max(0, ...)`,
|
|
400
|
+
* matching the lenient USD estimate. Mirrors Python's `_validate_token_estimate`.
|
|
401
|
+
*/
|
|
402
|
+
private validateTokenEstimate;
|
|
403
|
+
private reservedUsdOf;
|
|
404
|
+
/**
|
|
405
|
+
* Accrue a settled call into the innermost active step (no-op when none).
|
|
406
|
+
* Sequential-loop contract: the innermost step owns the call.
|
|
407
|
+
*/
|
|
408
|
+
private accrueStep;
|
|
409
|
+
/**
|
|
410
|
+
* The ONE choke point, across two dimensions and two scopes. Returns the first
|
|
411
|
+
* ceiling that blocks as `[dimension, scope]` — dimension `"usd" | "tokens"`,
|
|
412
|
+
* scope `"aggregate" | "step"` — or `null` if the call fits everywhere.
|
|
413
|
+
* Aggregate is checked before step (the guard-wide ceiling is the hard limit).
|
|
414
|
+
*/
|
|
415
|
+
private blockingCross;
|
|
416
|
+
/** Notify + throw the right error for a [dimension, scope] block. */
|
|
417
|
+
private raiseBlock;
|
|
418
|
+
/**
|
|
419
|
+
* Scope a per-step USD and/or token cap for a **sequential agent loop**.
|
|
420
|
+
*
|
|
421
|
+
* Runs `fn` with a step pushed onto the guard's stack; the
|
|
422
|
+
* enforcement/accrual path honours the innermost active step *on top of* the
|
|
423
|
+
* aggregate ceilings. A call that would cross the step's `maxUsd` / `maxTokens`
|
|
424
|
+
* is hard-blocked ({@link BudgetExceeded} / {@link TokenBudgetExceeded} with
|
|
425
|
+
* `scope: "step"`) even if the aggregate budget has room. `fn` receives the
|
|
426
|
+
* SAME guard, so no adapter needs to know about steps. The step is popped when
|
|
427
|
+
* `fn` settles or throws. **Not for concurrent parallel steps on one guard** —
|
|
428
|
+
* that's out of scope for issue #46; use one guard per parallel branch.
|
|
429
|
+
*/
|
|
430
|
+
step<T>(options: {
|
|
431
|
+
maxUsd?: number;
|
|
432
|
+
maxTokens?: number;
|
|
433
|
+
}, fn: (guard: BudgetGuard) => T): T;
|
|
341
434
|
private appendEvent;
|
|
342
435
|
/**
|
|
343
436
|
* Context-aware spend advisory for this budget — see {@link BudgetAdvisory}.
|
|
@@ -442,7 +535,25 @@ declare class FloeGuardError extends Error {
|
|
|
442
535
|
declare class BudgetExceeded extends FloeGuardError {
|
|
443
536
|
readonly spentUsd: number;
|
|
444
537
|
readonly limitUsd: number;
|
|
445
|
-
constructor(spentUsd: number, limitUsd: number);
|
|
538
|
+
constructor(spentUsd: number, limitUsd: number, message?: string);
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Thrown before a call that would cross a token ceiling (aggregate or step).
|
|
542
|
+
*
|
|
543
|
+
* The token twin of {@link BudgetExceeded} — it extends it so the same retry
|
|
544
|
+
* logic that treats a USD block as terminal (`!(error instanceof
|
|
545
|
+
* BudgetExceeded)`) treats a token block as terminal too, with no extra wiring.
|
|
546
|
+
* `spentUsd` / `limitUsd` are inherited but not meaningful here; the token
|
|
547
|
+
* fields are the payload.
|
|
548
|
+
*
|
|
549
|
+
* `scope` is `"aggregate"` (the guard-wide `tokenLimit`) or `"step"` (the
|
|
550
|
+
* innermost active {@link BudgetGuard.step} cap).
|
|
551
|
+
*/
|
|
552
|
+
declare class TokenBudgetExceeded extends BudgetExceeded {
|
|
553
|
+
readonly spentTokens: number;
|
|
554
|
+
readonly limitTokens: number;
|
|
555
|
+
readonly scope: "aggregate" | "step";
|
|
556
|
+
constructor(spentTokens: number, limitTokens: number, scope: "aggregate" | "step");
|
|
446
557
|
}
|
|
447
558
|
/**
|
|
448
559
|
* Thrown when a model cannot be priced and the guard is fail-closed.
|
|
@@ -559,4 +670,4 @@ interface BudgetRetryOptions<T> {
|
|
|
559
670
|
*/
|
|
560
671
|
declare function withBudgetRetry<T>(guard: BudgetGuard, call: () => T | Promise<T>, options?: BudgetRetryOptions<T>): Promise<T>;
|
|
561
672
|
|
|
562
|
-
export { type BudgetAdvisory, BudgetExceeded, BudgetGuard, type BudgetGuardMiddleware, type BudgetGuardOptions, type BudgetRetryOptions, DeadlineExceeded, FloeGuardError, type LatencyAdvisory, LatencyBudget, type LatencyBudgetOptions, type ManualPrice, type PricedModel, type RetryPlan, type SpendEvent, UnpriceableModelError, budgetGuardMiddleware, priceTokens, pricing, resolvePrice, withBudgetRetry };
|
|
673
|
+
export { type BudgetAdvisory, BudgetExceeded, BudgetGuard, type BudgetGuardMiddleware, type BudgetGuardOptions, type BudgetReservation, type BudgetRetryOptions, DeadlineExceeded, FloeGuardError, type LatencyAdvisory, LatencyBudget, type LatencyBudgetOptions, type ManualPrice, type PricedModel, type ReservationHandle, type RetryPlan, type SpendEvent, TokenBudgetExceeded, UnpriceableModelError, budgetGuardMiddleware, priceTokens, pricing, resolvePrice, withBudgetRetry };
|