floe-guard 0.15.0 → 0.15.1

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
@@ -64,6 +64,24 @@ const adv = guard.advisory();
64
64
  const model = adv.nearLimit ? openai("gpt-4o-mini") : openai("gpt-4o");
65
65
  ```
66
66
 
67
+ ## Request-sized estimates
68
+
69
+ To ensure the ceiling is enforced on the first run or for a call much larger than the previous one, you can price the actual incoming request using `estimateCall()` and pass the estimate to `reserve()` or `check()`:
70
+
71
+ ```ts
72
+ const est = guard.estimateCall("gpt-4o", 12_000, 4_096);
73
+ const handle = guard.reserve(est); // throws BudgetExceeded NOW if this call alone would cross
74
+ try {
75
+ const response = await callYourLlm({ model: "gpt-4o", ... });
76
+ guard.settle("gpt-4o", response.usage.promptTokens, response.usage.completionTokens, { reserved: handle });
77
+ } catch (err) {
78
+ guard.release(handle);
79
+ throw err;
80
+ }
81
+ ```
82
+
83
+ If the model is unpriceable, `estimateCall()` returns `undefined` and `reserve(undefined)` / `check(undefined)` fall back gracefully to the last-cost prediction.
84
+
67
85
  ## Tool spend under the same ceiling
68
86
 
69
87
  Paid tool calls (Apollo, Exa, scrapers) burn the same budget as tokens. The
@@ -1,4 +1,4 @@
1
- import { B as BudgetGuard, a as BudgetExceeded } from '../guard-CJWReYhA.cjs';
1
+ import { B as BudgetGuard, a as BudgetExceeded } from '../guard-B05gDZ3g.cjs';
2
2
 
3
3
  /**
4
4
  * LiveKit Agents adapter (optional peer: `npm i @livekit/agents`).
@@ -1,4 +1,4 @@
1
- import { B as BudgetGuard, a as BudgetExceeded } from '../guard-CJWReYhA.js';
1
+ import { B as BudgetGuard, a as BudgetExceeded } from '../guard-B05gDZ3g.js';
2
2
 
3
3
  /**
4
4
  * LiveKit Agents adapter (optional peer: `npm i @livekit/agents`).
@@ -1,4 +1,4 @@
1
- import { B as BudgetGuard, a as BudgetExceeded } from '../guard-CJWReYhA.cjs';
1
+ import { B as BudgetGuard, a as BudgetExceeded } from '../guard-B05gDZ3g.cjs';
2
2
 
3
3
  /**
4
4
  * Retell custom-LLM WebSocket adapter (optional peer: the `ws` server your custom
@@ -1,4 +1,4 @@
1
- import { B as BudgetGuard, a as BudgetExceeded } from '../guard-CJWReYhA.js';
1
+ import { B as BudgetGuard, a as BudgetExceeded } from '../guard-B05gDZ3g.js';
2
2
 
3
3
  /**
4
4
  * Retell custom-LLM WebSocket adapter (optional peer: the `ws` server your custom
@@ -1,5 +1,5 @@
1
- import { B as BudgetGuard, F as FloeGuardError } from '../guard-CJWReYhA.cjs';
2
- export { a as BudgetExceeded } from '../guard-CJWReYhA.cjs';
1
+ import { B as BudgetGuard, F as FloeGuardError } from '../guard-B05gDZ3g.cjs';
2
+ export { a as BudgetExceeded } from '../guard-B05gDZ3g.cjs';
3
3
 
4
4
  /**
5
5
  * Vapi custom-LLM adapter (no SDK dependency — typed structurally).
@@ -1,5 +1,5 @@
1
- import { B as BudgetGuard, F as FloeGuardError } from '../guard-CJWReYhA.js';
2
- export { a as BudgetExceeded } from '../guard-CJWReYhA.js';
1
+ import { B as BudgetGuard, F as FloeGuardError } from '../guard-B05gDZ3g.js';
2
+ export { a as BudgetExceeded } from '../guard-B05gDZ3g.js';
3
3
 
4
4
  /**
5
5
  * Vapi custom-LLM adapter (no SDK dependency — typed structurally).
@@ -412,6 +412,27 @@ declare class BudgetGuard {
412
412
  price?: ManualPrice;
413
413
  label?: string;
414
414
  }): number;
415
+ /**
416
+ * Price the ACTUAL incoming request, for a request-sized {@link reserve} / {@link check}.
417
+ *
418
+ * {@link check} and {@link reserve} default to predicting the next call
419
+ * from the LAST call's cost — which is blind on the first call and wrong
420
+ * for a call much larger than the previous one. Feed this the request you
421
+ * are about to send (its real prompt size and output cap) and pass the
422
+ * result straight through:
423
+ *
424
+ * const est = guard.estimateCall("gpt-4o", promptTokens, maxCompletionTokens);
425
+ * const handle = guard.reserve(est); // blocks NOW if this call alone would cross
426
+ *
427
+ * The estimate is worst-case on output (the model may stop well short of
428
+ * `maxCompletionTokens`); the hold is corrected to actual cost at
429
+ * {@link settle}. Returns `undefined` when the model is unpriceable — and
430
+ * `reserve(undefined)` / `check(undefined)` fall back to the last-cost
431
+ * prediction, so the wiring degrades gracefully instead of failing.
432
+ */
433
+ estimateCall(model: string, promptTokens: number, maxCompletionTokens?: number, options?: {
434
+ price?: ManualPrice;
435
+ }): number | undefined;
415
436
  /**
416
437
  * Atomically check the ceiling AND hold a tool call's cost in flight.
417
438
  *
@@ -412,6 +412,27 @@ declare class BudgetGuard {
412
412
  price?: ManualPrice;
413
413
  label?: string;
414
414
  }): number;
415
+ /**
416
+ * Price the ACTUAL incoming request, for a request-sized {@link reserve} / {@link check}.
417
+ *
418
+ * {@link check} and {@link reserve} default to predicting the next call
419
+ * from the LAST call's cost — which is blind on the first call and wrong
420
+ * for a call much larger than the previous one. Feed this the request you
421
+ * are about to send (its real prompt size and output cap) and pass the
422
+ * result straight through:
423
+ *
424
+ * const est = guard.estimateCall("gpt-4o", promptTokens, maxCompletionTokens);
425
+ * const handle = guard.reserve(est); // blocks NOW if this call alone would cross
426
+ *
427
+ * The estimate is worst-case on output (the model may stop well short of
428
+ * `maxCompletionTokens`); the hold is corrected to actual cost at
429
+ * {@link settle}. Returns `undefined` when the model is unpriceable — and
430
+ * `reserve(undefined)` / `check(undefined)` fall back to the last-cost
431
+ * prediction, so the wiring degrades gracefully instead of failing.
432
+ */
433
+ estimateCall(model: string, promptTokens: number, maxCompletionTokens?: number, options?: {
434
+ price?: ManualPrice;
435
+ }): number | undefined;
415
436
  /**
416
437
  * Atomically check the ceiling AND hold a tool call's cost in flight.
417
438
  *
package/dist/index.cjs CHANGED
@@ -1855,6 +1855,35 @@ var BudgetGuard = class {
1855
1855
  label: options.label
1856
1856
  });
1857
1857
  }
1858
+ /**
1859
+ * Price the ACTUAL incoming request, for a request-sized {@link reserve} / {@link check}.
1860
+ *
1861
+ * {@link check} and {@link reserve} default to predicting the next call
1862
+ * from the LAST call's cost — which is blind on the first call and wrong
1863
+ * for a call much larger than the previous one. Feed this the request you
1864
+ * are about to send (its real prompt size and output cap) and pass the
1865
+ * result straight through:
1866
+ *
1867
+ * const est = guard.estimateCall("gpt-4o", promptTokens, maxCompletionTokens);
1868
+ * const handle = guard.reserve(est); // blocks NOW if this call alone would cross
1869
+ *
1870
+ * The estimate is worst-case on output (the model may stop well short of
1871
+ * `maxCompletionTokens`); the hold is corrected to actual cost at
1872
+ * {@link settle}. Returns `undefined` when the model is unpriceable — and
1873
+ * `reserve(undefined)` / `check(undefined)` fall back to the last-cost
1874
+ * prediction, so the wiring degrades gracefully instead of failing.
1875
+ */
1876
+ estimateCall(model, promptTokens, maxCompletionTokens = 0, options = {}) {
1877
+ let overrides = this.priceOverrides;
1878
+ if (options.price !== void 0) {
1879
+ overrides = { ...overrides ?? {}, [model]: options.price };
1880
+ }
1881
+ const priced = resolvePrice(model, overrides);
1882
+ if (priced === null) {
1883
+ return void 0;
1884
+ }
1885
+ return priceTokens(priced, promptTokens, maxCompletionTokens);
1886
+ }
1858
1887
  /**
1859
1888
  * Atomically check the ceiling AND hold a tool call's cost in flight.
1860
1889
  *