floe-guard 0.2.0 → 0.2.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/dist/index.cjs +109 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +109 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/cost_map.json +60 -0
package/dist/index.cjs
CHANGED
|
@@ -209,6 +209,12 @@ var cost_map_default = {
|
|
|
209
209
|
litellm_provider: "anthropic",
|
|
210
210
|
mode: "chat"
|
|
211
211
|
},
|
|
212
|
+
"claude-sonnet-5": {
|
|
213
|
+
input_cost_per_token: 2e-6,
|
|
214
|
+
output_cost_per_token: 1e-5,
|
|
215
|
+
litellm_provider: "anthropic",
|
|
216
|
+
mode: "chat"
|
|
217
|
+
},
|
|
212
218
|
"ft:gpt-3.5-turbo": {
|
|
213
219
|
input_cost_per_token: 3e-6,
|
|
214
220
|
output_cost_per_token: 6e-6,
|
|
@@ -659,6 +665,30 @@ var cost_map_default = {
|
|
|
659
665
|
litellm_provider: "openai",
|
|
660
666
|
mode: "chat"
|
|
661
667
|
},
|
|
668
|
+
"gpt-5.6": {
|
|
669
|
+
input_cost_per_token: 5e-6,
|
|
670
|
+
output_cost_per_token: 3e-5,
|
|
671
|
+
litellm_provider: "openai",
|
|
672
|
+
mode: "chat"
|
|
673
|
+
},
|
|
674
|
+
"gpt-5.6-luna": {
|
|
675
|
+
input_cost_per_token: 1e-6,
|
|
676
|
+
output_cost_per_token: 6e-6,
|
|
677
|
+
litellm_provider: "openai",
|
|
678
|
+
mode: "chat"
|
|
679
|
+
},
|
|
680
|
+
"gpt-5.6-sol": {
|
|
681
|
+
input_cost_per_token: 5e-6,
|
|
682
|
+
output_cost_per_token: 3e-5,
|
|
683
|
+
litellm_provider: "openai",
|
|
684
|
+
mode: "chat"
|
|
685
|
+
},
|
|
686
|
+
"gpt-5.6-terra": {
|
|
687
|
+
input_cost_per_token: 25e-7,
|
|
688
|
+
output_cost_per_token: 15e-6,
|
|
689
|
+
litellm_provider: "openai",
|
|
690
|
+
mode: "chat"
|
|
691
|
+
},
|
|
662
692
|
"gpt-audio": {
|
|
663
693
|
input_cost_per_token: 25e-7,
|
|
664
694
|
output_cost_per_token: 1e-5,
|
|
@@ -713,6 +743,18 @@ var cost_map_default = {
|
|
|
713
743
|
litellm_provider: "openai",
|
|
714
744
|
mode: "chat"
|
|
715
745
|
},
|
|
746
|
+
"gpt-realtime-2.1": {
|
|
747
|
+
input_cost_per_token: 4e-6,
|
|
748
|
+
output_cost_per_token: 24e-6,
|
|
749
|
+
litellm_provider: "openai",
|
|
750
|
+
mode: "chat"
|
|
751
|
+
},
|
|
752
|
+
"gpt-realtime-2.1-mini": {
|
|
753
|
+
input_cost_per_token: 6e-7,
|
|
754
|
+
output_cost_per_token: 24e-7,
|
|
755
|
+
litellm_provider: "openai",
|
|
756
|
+
mode: "chat"
|
|
757
|
+
},
|
|
716
758
|
"gpt-realtime-2025-08-28": {
|
|
717
759
|
input_cost_per_token: 4e-6,
|
|
718
760
|
output_cost_per_token: 16e-6,
|
|
@@ -803,6 +845,24 @@ var cost_map_default = {
|
|
|
803
845
|
litellm_provider: "openai",
|
|
804
846
|
mode: "chat"
|
|
805
847
|
},
|
|
848
|
+
"openai/gpt-oss-120b": {
|
|
849
|
+
input_cost_per_token: 15e-8,
|
|
850
|
+
output_cost_per_token: 6e-7,
|
|
851
|
+
litellm_provider: "groq",
|
|
852
|
+
mode: "chat"
|
|
853
|
+
},
|
|
854
|
+
"openai/gpt-oss-20b": {
|
|
855
|
+
input_cost_per_token: 75e-9,
|
|
856
|
+
output_cost_per_token: 3e-7,
|
|
857
|
+
litellm_provider: "groq",
|
|
858
|
+
mode: "chat"
|
|
859
|
+
},
|
|
860
|
+
"openai/gpt-oss-safeguard-20b": {
|
|
861
|
+
input_cost_per_token: 75e-9,
|
|
862
|
+
output_cost_per_token: 3e-7,
|
|
863
|
+
litellm_provider: "groq",
|
|
864
|
+
mode: "chat"
|
|
865
|
+
},
|
|
806
866
|
"qwen/qwen3-32b": {
|
|
807
867
|
input_cost_per_token: 29e-8,
|
|
808
868
|
output_cost_per_token: 59e-8,
|
|
@@ -837,39 +897,64 @@ var cost_map_default = {
|
|
|
837
897
|
|
|
838
898
|
// src/pricing.ts
|
|
839
899
|
var COST_MAP = cost_map_default;
|
|
840
|
-
|
|
900
|
+
var PROVIDER_PREFIXES = /* @__PURE__ */ new Set(["groq"]);
|
|
901
|
+
var DATE_SUFFIX = /-(?:\d{8}|\d{4}-\d{2}-\d{2})$/;
|
|
902
|
+
function candidateGroups(model) {
|
|
841
903
|
const m = model.trim();
|
|
842
|
-
const
|
|
843
|
-
|
|
904
|
+
const base = [m];
|
|
905
|
+
const firstSlash = m.indexOf("/");
|
|
906
|
+
if (firstSlash !== -1 && PROVIDER_PREFIXES.has(m.slice(0, firstSlash))) {
|
|
907
|
+
base.push(m.slice(firstSlash + 1));
|
|
908
|
+
}
|
|
909
|
+
const lastSlash = m.lastIndexOf("/");
|
|
910
|
+
if (lastSlash !== -1) {
|
|
911
|
+
base.push(m.slice(lastSlash + 1));
|
|
912
|
+
}
|
|
913
|
+
const exact = [];
|
|
914
|
+
for (const cand of base) {
|
|
915
|
+
if (cand && !exact.includes(cand)) exact.push(cand);
|
|
916
|
+
}
|
|
917
|
+
const stripped = [];
|
|
918
|
+
for (const cand of exact) {
|
|
919
|
+
const c = cand.replace(DATE_SUFFIX, "");
|
|
920
|
+
if (c && !exact.includes(c) && !stripped.includes(c)) stripped.push(c);
|
|
921
|
+
}
|
|
922
|
+
return [exact, stripped];
|
|
844
923
|
}
|
|
845
924
|
function bothFinite(a, b) {
|
|
846
925
|
return typeof a === "number" && typeof b === "number" && Number.isFinite(a) && Number.isFinite(b);
|
|
847
926
|
}
|
|
848
927
|
function resolvePrice(model, overrides) {
|
|
849
|
-
const
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
928
|
+
for (const cands of candidateGroups(model)) {
|
|
929
|
+
if (overrides) {
|
|
930
|
+
for (const cand of cands) {
|
|
931
|
+
const ov = Object.prototype.hasOwnProperty.call(overrides, cand) ? overrides[cand] : void 0;
|
|
932
|
+
if (ov !== void 0) {
|
|
933
|
+
if (bothFinite(ov.inputCostPerToken, ov.outputCostPerToken)) {
|
|
934
|
+
return {
|
|
935
|
+
inputCostPerToken: ov.inputCostPerToken,
|
|
936
|
+
outputCostPerToken: ov.outputCostPerToken,
|
|
937
|
+
source: "override"
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
return null;
|
|
941
|
+
}
|
|
859
942
|
}
|
|
860
|
-
|
|
943
|
+
}
|
|
944
|
+
for (const cand of cands) {
|
|
945
|
+
const entry = Object.prototype.hasOwnProperty.call(COST_MAP, cand) ? COST_MAP[cand] : void 0;
|
|
946
|
+
if (!entry) continue;
|
|
947
|
+
const input = entry.input_cost_per_token;
|
|
948
|
+
const output = entry.output_cost_per_token;
|
|
949
|
+
if (!bothFinite(input, output)) return null;
|
|
950
|
+
return {
|
|
951
|
+
inputCostPerToken: input,
|
|
952
|
+
outputCostPerToken: output,
|
|
953
|
+
source: "cost_map"
|
|
954
|
+
};
|
|
861
955
|
}
|
|
862
956
|
}
|
|
863
|
-
|
|
864
|
-
if (!entry) return null;
|
|
865
|
-
const input = entry.input_cost_per_token;
|
|
866
|
-
const output = entry.output_cost_per_token;
|
|
867
|
-
if (!bothFinite(input, output)) return null;
|
|
868
|
-
return {
|
|
869
|
-
inputCostPerToken: input,
|
|
870
|
-
outputCostPerToken: output,
|
|
871
|
-
source: "cost_map"
|
|
872
|
-
};
|
|
957
|
+
return null;
|
|
873
958
|
}
|
|
874
959
|
function priceTokens(priced, promptTokens, completionTokens) {
|
|
875
960
|
const p = Math.max(0, promptTokens);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/pricing.ts","../src/cost_map.json","../src/guard.ts","../src/middleware.ts"],"sourcesContent":["/**\n * floe-guard — a local budget guardrail for AI agents.\n *\n * Hard-stops your agent before its next LLM call when it would cross a USD spend\n * ceiling. This package is the Vercel AI SDK (TypeScript) adapter; the Python\n * package `floe-guard` (pip) carries the LiteLLM / CrewAI / LangChain adapters.\n */\n\nexport {\n BudgetGuard,\n type BudgetGuardOptions,\n type BudgetAdvisory,\n} from \"./guard.js\";\nexport {\n FloeGuardError,\n BudgetExceeded,\n UnpriceableModelError,\n} from \"./errors.js\";\nexport {\n budgetGuardMiddleware,\n type BudgetGuardMiddleware,\n} from \"./middleware.js\";\nexport {\n type ManualPrice,\n type PricedModel,\n resolvePrice,\n priceTokens,\n} from \"./pricing.js\";\n\nexport * as pricing from \"./pricing.js\";\n","/**\n * Exceptions for floe-guard.\n *\n * Everything derives from {@link FloeGuardError} (the package-root base) so callers\n * can catch the whole family with a single `catch (e) { if (e instanceof FloeGuardError) ... }`.\n *\n * Mirrors `src/floe_guard/errors.py` in the Python package — message formats are\n * kept byte-for-byte identical so both adapters read the same.\n */\n\n/** Base class for every error raised by floe-guard. */\nexport class FloeGuardError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FloeGuardError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown before an LLM call that would cross the configured spend ceiling.\n *\n * The guard throws this *instead of* letting the next call run, so a runaway loop\n * stops here rather than burning more money.\n */\nexport class BudgetExceeded extends FloeGuardError {\n readonly spentUsd: number;\n readonly limitUsd: number;\n\n constructor(spentUsd: number, limitUsd: number) {\n super(\n `BUDGET EXCEEDED — call blocked (spent $${spentUsd.toFixed(6)} of $${limitUsd.toFixed(6)} ceiling)`,\n );\n this.name = \"BudgetExceeded\";\n this.spentUsd = spentUsd;\n this.limitUsd = limitUsd;\n }\n}\n\n/**\n * Thrown when a model cannot be priced and the guard is fail-closed.\n *\n * We refuse rather than silently accrue $0 — \"we cannot cap what we cannot price\".\n * Pass a manual price (`priceOverrides` or `record(..., { price })`) to make the\n * model enforceable.\n */\nexport class UnpriceableModelError extends FloeGuardError {\n readonly model: string;\n\n constructor(model: string) {\n super(\n `Cannot price model '${model}': not in the bundled cost map and no ` +\n `manual price was given. The guard cannot enforce a budget on spend ` +\n `it cannot measure. Pass a price override to enable enforcement.`,\n );\n this.name = \"UnpriceableModelError\";\n this.model = model;\n }\n}\n","/**\n * Offline token pricing from a vendored LiteLLM cost map.\n *\n * Mirrors `src/floe_guard/pricing.py`: BOTH the input and output per-token prices\n * must be finite numbers, otherwise the model is treated as unpriceable. A\n * half-valid entry would silently undercharge — so we refuse it (fail-closed).\n *\n * No network. The cost map (`cost_map.json`) is a snapshot of LiteLLM's\n * `model_prices_and_context_window.json`; refresh it on a schedule or estimates\n * drift as vendors change prices.\n */\n\nimport costMapJson from \"./cost_map.json\";\n\n/** A user-supplied per-token price, in USD, for a model the map cannot price. */\nexport interface ManualPrice {\n inputCostPerToken: number;\n outputCostPerToken: number;\n}\n\n/** A resolved per-token price plus where it came from. */\nexport interface PricedModel {\n inputCostPerToken: number;\n outputCostPerToken: number;\n source: \"override\" | \"cost_map\";\n}\n\ninterface CostMapEntry {\n input_cost_per_token?: unknown;\n output_cost_per_token?: unknown;\n}\n\nconst COST_MAP = costMapJson as Record<string, CostMapEntry>;\n\n/** Strip an optional `provider/` prefix (LiteLLM convention, e.g. `openai/gpt-4o`). */\nfunction bareModel(model: string): string {\n const m = model.trim();\n const slash = m.lastIndexOf(\"/\");\n return slash === -1 ? m : m.slice(slash + 1);\n}\n\nfunction bothFinite(a: unknown, b: unknown): boolean {\n return (\n typeof a === \"number\" &&\n typeof b === \"number\" &&\n Number.isFinite(a) &&\n Number.isFinite(b)\n );\n}\n\n/**\n * Resolve a model to its per-token price, or `null` if it cannot be priced.\n *\n * Overrides win, then the bundled cost map (looked up by bare name, then the raw\n * field). Fail-closed: both prices must be finite, else `null`.\n */\nexport function resolvePrice(\n model: string,\n overrides?: Record<string, ManualPrice>,\n): PricedModel | null {\n const bare = bareModel(model);\n\n if (overrides) {\n const ov = overrides[bare] ?? overrides[model.trim()];\n if (ov !== undefined) {\n if (bothFinite(ov.inputCostPerToken, ov.outputCostPerToken)) {\n return {\n inputCostPerToken: ov.inputCostPerToken,\n outputCostPerToken: ov.outputCostPerToken,\n source: \"override\",\n };\n }\n return null;\n }\n }\n\n const entry = COST_MAP[bare] ?? COST_MAP[model.trim()];\n if (!entry) return null;\n\n const input = entry.input_cost_per_token;\n const output = entry.output_cost_per_token;\n if (!bothFinite(input, output)) return null;\n\n return {\n inputCostPerToken: input as number,\n outputCostPerToken: output as number,\n source: \"cost_map\",\n };\n}\n\n/** USD cost for token usage. Negative counts are clamped to zero. */\nexport function priceTokens(\n priced: PricedModel,\n promptTokens: number,\n completionTokens: number,\n): number {\n const p = Math.max(0, promptTokens);\n const c = Math.max(0, completionTokens);\n const cost = p * priced.inputCostPerToken + c * priced.outputCostPerToken;\n if (!Number.isFinite(cost)) {\n // Defense-in-depth: resolvePrice already guarantees finite rates.\n throw new Error(\"Non-finite LLM cost — pricing entry is invalid\");\n }\n return Math.max(0, cost);\n}\n","{\n \"chatgpt-4o-latest\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"claude-3-7-sonnet-20250219\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-3-haiku-20240307\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-3-opus-20240229\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-4-opus-20250514\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-4-sonnet-20250514\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-fable-5\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-haiku-4-5\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-haiku-4-5-20251001\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-1\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-1-20250805\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-20250514\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-5\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-5-20251101\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-6\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-6-20260205\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-7\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-7-20260416\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-8\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-20250514\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-5\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-5-20250929\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-6\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-0125\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-0613\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-1106\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4-0613\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-2025-04-14\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000012,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-mini-2025-04-14\": {\n \"input_cost_per_token\": 8e-7,\n \"output_cost_per_token\": 0.0000032,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-nano-2025-04-14\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 8e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-2024-08-06\": {\n \"input_cost_per_token\": 0.00000375,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-2024-11-20\": {\n \"input_cost_per_token\": 0.00000375,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-mini-2024-07-18\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000012,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:o4-mini-2025-04-16\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo\": {\n \"input_cost_per_token\": 5e-7,\n \"output_cost_per_token\": 0.0000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-0125\": {\n \"input_cost_per_token\": 5e-7,\n \"output_cost_per_token\": 0.0000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-1106\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-16k\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000004,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0125-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0314\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0613\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-1106-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo-2024-04-09\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-2025-04-14\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-mini\": {\n \"input_cost_per_token\": 4e-7,\n \"output_cost_per_token\": 0.0000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-mini-2025-04-14\": {\n \"input_cost_per_token\": 4e-7,\n \"output_cost_per_token\": 0.0000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-nano\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-nano-2025-04-14\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-05-13\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-08-06\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-11-20\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview-2024-12-17\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview-2025-06-03\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-2024-07-18\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-audio-preview\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-audio-preview-2024-12-17\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-realtime-preview\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-realtime-preview-2024-12-17\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-search-preview\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-search-preview-2025-03-11\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-realtime-preview\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-realtime-preview-2024-12-17\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-realtime-preview-2025-06-03\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-search-preview\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-search-preview-2025-03-11\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-2025-08-07\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-chat\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-chat-latest\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-mini\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-mini-2025-08-07\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-nano\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-nano-2025-08-07\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-search-api\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-search-api-2025-10-14\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1-2025-11-13\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1-chat-latest\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2-2025-12-11\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2-chat-latest\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.3-chat-latest\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-2026-03-05\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-mini\": {\n \"input_cost_per_token\": 7.5e-7,\n \"output_cost_per_token\": 0.0000045,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-mini-2026-03-17\": {\n \"input_cost_per_token\": 7.5e-7,\n \"output_cost_per_token\": 0.0000045,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-nano\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-nano-2026-03-17\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.5\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.5-2026-04-23\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-1.5\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-2025-08-28\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini-2025-10-06\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini-2025-12-15\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-1.5\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-2\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-2025-08-28\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-mini\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-mini-2025-10-06\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-mini-2025-12-15\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"llama-3.1-8b-instant\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 8e-8,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"llama-3.3-70b-versatile\": {\n \"input_cost_per_token\": 5.9e-7,\n \"output_cost_per_token\": 7.9e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"meta-llama/llama-4-scout-17b-16e-instruct\": {\n \"input_cost_per_token\": 1.1e-7,\n \"output_cost_per_token\": 3.4e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"o1\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o1-2024-12-17\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-2025-04-16\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-mini\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-mini-2025-01-31\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o4-mini\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o4-mini-2025-04-16\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"qwen/qwen3-32b\": {\n \"input_cost_per_token\": 2.9e-7,\n \"output_cost_per_token\": 5.9e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"text-embedding-3-large\": {\n \"input_cost_per_token\": 1.3e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-3-small\": {\n \"input_cost_per_token\": 2e-8,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-ada-002\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-ada-002-v2\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n }\n}\n","/**\n * The local, in-process budget guard.\n *\n * `BudgetGuard` is a kill-switch that lives in the LLM call path. The contract:\n *\n * 1. Call {@link BudgetGuard.check} BEFORE every LLM call. If the *next* call\n * would cross the ceiling, it throws {@link BudgetExceeded} and the call never\n * runs.\n * 2. Call {@link BudgetGuard.record} AFTER every response, with the token usage.\n * It prices the tokens offline and accrues the USD into a running total.\n *\n * **Concurrency.** `check()` then `record()` is a check-then-act with an `await`\n * in between. Fire several model calls at once (e.g. `Promise.all`) and they all\n * `check()` against the same under-limit total before any `record()` lands, so\n * the ceiling is blown (see issue #18). {@link BudgetGuard.reserve} /\n * {@link BudgetGuard.settle} close that gap: `reserve()` holds the estimated cost\n * in flight (synchronously, before the await), so parallel callers each take\n * their own slice of the ceiling. JS is single-threaded, so an in-flight counter\n * is enough — no lock needed. The middleware uses it; `check`/`record` are\n * unchanged.\n *\n * This is a faithful port of `src/floe_guard/guard.py` — same prediction logic,\n * same epsilon handling, same fail-closed default.\n */\n\nimport { BudgetExceeded, UnpriceableModelError } from \"./errors.js\";\nimport {\n type ManualPrice,\n priceTokens,\n resolvePrice,\n} from \"./pricing.js\";\n\n/** Tolerance for float rounding in the running spend total (well below $0.000001). */\nconst EPS = 1e-12;\n\nexport interface BudgetGuardOptions {\n /** Per-model manual prices for models the bundled cost map cannot price. */\n priceOverrides?: Record<string, ManualPrice>;\n /**\n * When `true` (default), recording an unpriceable model without a manual price\n * warns loudly AND throws {@link UnpriceableModelError}. When `false`, it warns\n * and skips accrual (you have opted into un-enforced spend for that model).\n */\n failClosed?: boolean;\n /**\n * Optional callback invoked with `(spentUsd, limitUsd)` right before\n * {@link BudgetExceeded} is thrown. Defaults to printing the\n * `BUDGET EXCEEDED — call blocked` banner to stderr.\n */\n onBlock?: (spentUsd: number, limitUsd: number) => void;\n /**\n * Utilization (basis points, 0..10000) at which {@link BudgetGuard.advisory}\n * flags `nearLimit` so an agent can taper before the hard-stop. Default 8000.\n */\n nearLimitBps?: number;\n}\n\n/**\n * A context-aware spend signal for the single local budget.\n *\n * Mirrors the core fields of hosted Floe's `X-Floe-Budget-Advisory` header, so\n * agent logic that reads it (taper as you approach the cap, stop at it) ports\n * unchanged to the hosted path. Hosted adds what a local, single-budget guard\n * cannot know: which of several caps is tightest (`scope` across\n * `credit_line | session | task | api | vendor`), cross-vendor reasoning,\n * server-truth balances, and rolling-window reset timing.\n *\n * This is a **soft** signal — the model may ignore it. The hard-stop\n * ({@link BudgetGuard.check}) is what enforces the ceiling; the advisory is\n * upside (let the agent finish on budget rather than be cut off).\n */\nexport interface BudgetAdvisory {\n nearLimit: boolean;\n /** Utilization in basis points, 0..10000 (8500 = 85%). */\n usedBps: number;\n remainingUsd: number;\n limitUsd: number;\n spentUsd: number;\n /** Hosted reports the tightest cap across all scopes; local is always \"local\". */\n scope: \"local\";\n}\n\nexport class BudgetGuard {\n readonly limitUsd: number;\n spentUsd = 0;\n priceOverrides?: Record<string, ManualPrice>;\n failClosed: boolean;\n nearLimitBps: number;\n\n private readonly onBlock: (spentUsd: number, limitUsd: number) => void;\n /** Cost of the most recent priced call, used to predict the next one. */\n private lastCost = 0;\n /** USD held for in-flight calls (reserved, not yet settled). Counts toward the ceiling. */\n private reserved = 0;\n\n /**\n * @param limitUsd the spend ceiling, in USD. `0` blocks the very first call.\n */\n constructor(limitUsd: number, options: BudgetGuardOptions = {}) {\n if (!Number.isFinite(limitUsd) || limitUsd < 0) {\n // NaN/Infinity would make every check() comparison fail-open, silently\n // disabling the guard — reject them up front.\n throw new RangeError(\n `limitUsd must be a finite, non-negative number, got ${limitUsd}`,\n );\n }\n // `=== undefined` (not `??`) so an explicit null is rejected by validation\n // rather than silently defaulting — matches Python, which rejects None.\n const nearLimitBps = options.nearLimitBps === undefined ? 8000 : options.nearLimitBps;\n if (!Number.isInteger(nearLimitBps) || nearLimitBps < 0 || nearLimitBps > 10000) {\n throw new RangeError(\n `nearLimitBps must be an integer in 0..10000, got ${nearLimitBps}`,\n );\n }\n this.limitUsd = limitUsd;\n this.priceOverrides = options.priceOverrides;\n this.failClosed = options.failClosed ?? true;\n this.onBlock = options.onBlock ?? defaultOnBlock;\n this.nearLimitBps = nearLimitBps;\n }\n\n /**\n * Throw {@link BudgetExceeded} if the next call would cross the ceiling.\n *\n * Call this immediately before each LLM request. The \"next call\" is estimated\n * from the last recorded call's cost (override with `estimatedNextCost`); the\n * first call is always allowed unless the ceiling is already met. In-flight\n * reservations count toward the total, so this stays correct alongside\n * {@link BudgetGuard.reserve}.\n *\n * Note: `check` is a non-binding peek. For parallel calls, use `reserve()` /\n * `settle()`, which hold the estimate across the await.\n */\n check(estimatedNextCost?: number): void {\n const rawEstimate =\n estimatedNextCost === undefined ? this.lastCost : estimatedNextCost;\n if (!Number.isFinite(rawEstimate)) {\n // NaN/Infinity would poison the comparisons and fail-open — reject it\n // (parity with the constructor's Number.isFinite guard).\n throw new RangeError(\n `estimatedNextCost must be a finite number, got ${rawEstimate}`,\n );\n }\n const estimate = Math.max(0, rawEstimate);\n const committed = this.spentUsd + this.reserved;\n if (committed > this.limitUsd - EPS || committed + estimate > this.limitUsd + EPS) {\n this.onBlock(this.spentUsd, this.limitUsd);\n throw new BudgetExceeded(this.spentUsd, this.limitUsd);\n }\n }\n\n /**\n * Atomically check the ceiling AND hold the estimated cost in flight.\n *\n * The concurrency-safe enforcement path: call before the request and hold the\n * returned reservation across the await, so parallel callers can't all clear\n * the same stale total. Throws {@link BudgetExceeded} (without reserving) if\n * the reservation would cross the ceiling. Returns the reservation handle to\n * pass to {@link BudgetGuard.settle} (or {@link BudgetGuard.release} on error).\n * `estimatedCost` defaults to the last call's cost.\n */\n reserve(estimatedCost?: number): number {\n const rawEstimate = estimatedCost === undefined ? this.lastCost : estimatedCost;\n if (!Number.isFinite(rawEstimate)) {\n // NaN would poison this.reserved and fail-open the ceiling — reject it.\n throw new RangeError(\n `estimatedCost must be a finite number, got ${rawEstimate}`,\n );\n }\n const estimate = Math.max(0, rawEstimate);\n const committed = this.spentUsd + this.reserved;\n if (committed > this.limitUsd - EPS || committed + estimate > this.limitUsd + EPS) {\n this.onBlock(this.spentUsd, this.limitUsd);\n throw new BudgetExceeded(this.spentUsd, this.limitUsd);\n }\n this.reserved += estimate;\n return estimate;\n }\n\n /**\n * Release a reservation and record the actual cost. `record` is `settle` with\n * no reservation. Returns the USD cost of this call; unpriceable-model handling\n * matches {@link BudgetGuard.record}, and any held reservation is released even\n * on the warn-and-skip path.\n */\n settle(\n model: string,\n promptTokens: number,\n completionTokens: number,\n options: { reserved?: number; price?: ManualPrice } = {},\n ): number {\n const reserved = options.reserved ?? 0;\n // A bad reserved handle would corrupt this.reserved and break the ceiling for\n // OTHER in-flight calls (negative → phantom hold; Infinity → clears all holds).\n if (!Number.isFinite(reserved) || reserved < 0) {\n throw new RangeError(`reserved must be a finite, non-negative number, got ${reserved}`);\n }\n let overrides = this.priceOverrides;\n if (options.price !== undefined) {\n overrides = { ...(overrides ?? {}), [model]: options.price };\n }\n\n const priced = resolvePrice(model, overrides);\n if (priced === null) {\n console.warn(\n `Cannot price model '${model}': not in the bundled cost map and no ` +\n `manual price given. The budget guard cannot enforce a ceiling on ` +\n `spend it cannot measure — pass { price } or set it in priceOverrides.`,\n );\n // Release any held reservation on BOTH paths. Fail-closed must not leak\n // the in-flight hold, or reserved grows permanently and remainingUsd\n // shrinks until reserve() starts blocking everything.\n this.release(reserved);\n if (this.failClosed) {\n throw new UnpriceableModelError(model);\n }\n return 0;\n }\n\n let cost: number;\n try {\n cost = priceTokens(priced, promptTokens, completionTokens);\n } catch (err) {\n // priceTokens can throw (e.g. non-finite costs). Release the in-flight\n // hold before re-throwing so `reserved` doesn't leak and shrink\n // remainingUsd permanently — same fail-safe as the unpriceable path above.\n this.release(reserved);\n throw err;\n }\n if (reserved) {\n this.reserved = Math.max(0, this.reserved - reserved);\n }\n this.spentUsd += cost;\n // Clamp a sub-epsilon float overshoot back to the limit so the running total\n // never reports as having crossed the ceiling by a rounding artifact.\n if (this.spentUsd - this.limitUsd > 0 && this.spentUsd - this.limitUsd < EPS) {\n this.spentUsd = this.limitUsd;\n }\n this.lastCost = cost;\n return cost;\n }\n\n /**\n * Price one response's tokens offline and add the cost to the total.\n *\n * Returns the USD cost of this call. If the model is unpriceable and no `price`\n * is given, behaviour depends on `failClosed`: warn + throw (default), or\n * warn + skip accrual.\n */\n record(\n model: string,\n promptTokens: number,\n completionTokens: number,\n options: { price?: ManualPrice } = {},\n ): number {\n return this.settle(model, promptTokens, completionTokens, {\n reserved: 0,\n price: options.price,\n });\n }\n\n /**\n * Drop an in-flight reservation without recording spend (e.g. the call failed\n * before producing usage). Safe to call with `0`.\n */\n release(reserved: number): void {\n // Validate before the zero-check so a NaN handle throws instead of being\n // silently dropped (a leak); a bad handle corrupts the in-flight tally.\n if (!Number.isFinite(reserved) || reserved < 0) {\n throw new RangeError(`reserved must be a finite, non-negative number, got ${reserved}`);\n }\n if (!reserved) return;\n this.reserved = Math.max(0, this.reserved - reserved);\n }\n\n /** USD left before the ceiling, net of in-flight reservations (never negative). */\n get remainingUsd(): number {\n return Math.max(0, this.limitUsd - this.spentUsd - this.reserved);\n }\n\n /**\n * Context-aware spend advisory for this budget — see {@link BudgetAdvisory}.\n *\n * `nearLimit` flips once utilization reaches `nearLimitBps` (default 80%), so an\n * agent can taper *before* the hard-stop. Advisory only: read it to adapt;\n * {@link BudgetGuard.check} is what enforces the ceiling.\n */\n advisory(): BudgetAdvisory {\n // Floor (not round) so usedBps never over-reports utilization and nearLimit\n // flips exactly when the threshold is reached; the epsilon absorbs float noise\n // and Math.floor matches Python's int() exactly (round() would diverge).\n const usedBps =\n this.limitUsd <= 0\n ? 10000\n : Math.max(0, Math.min(10000, Math.floor((this.spentUsd / this.limitUsd) * 10000 + 1e-9)));\n return {\n nearLimit: usedBps >= this.nearLimitBps,\n usedBps,\n // Settled budget: limit minus accrued spend, deliberately NOT net of\n // in-flight reservations. Unlike the remainingUsd getter (which subtracts\n // `reserved`), the advisory is a soft utilization signal about money already\n // spent, while the getter reports what a new call can still claim.\n remainingUsd: Math.max(0, this.limitUsd - this.spentUsd),\n limitUsd: this.limitUsd,\n spentUsd: this.spentUsd,\n scope: \"local\",\n };\n }\n}\n\nfunction defaultOnBlock(spentUsd: number, limitUsd: number): void {\n console.error(\n \"BUDGET EXCEEDED — call blocked\\n\" +\n ` spent so far: $${spentUsd.toFixed(6)} | ceiling: $${limitUsd.toFixed(6)}\\n` +\n \" The next call would cross your budget; floe-guard stopped your agent \" +\n \"before it ran.\",\n );\n}\n","/**\n * Vercel AI SDK middleware that enforces a {@link BudgetGuard} in the call path.\n *\n * This is the TypeScript counterpart to the Python framework adapters. The AI SDK\n * is TypeScript-only, so it ships as its own npm package.\n *\n * Works with BOTH `ai@4` (`LanguageModelV1Middleware`) and `ai@5`\n * (`LanguageModelV2Middleware`). The two majors renamed the middleware type and\n * the usage fields (`promptTokens`/`completionTokens` → `inputTokens`/\n * `outputTokens`), so this module deliberately imports nothing from `ai`: the\n * middleware is typed structurally against the surface both majors share, and\n * usage is read from whichever field pair the installed SDK reports.\n *\n * - `wrapGenerate({ doGenerate, model })` — we `reserve()` (throws to hard-stop)\n * BEFORE calling `doGenerate()`, hold the reservation across the await, then\n * `settle()` from `result.usage`.\n * - `wrapStream({ doStream, model })` — we `reserve()` BEFORE `doStream()`, then\n * `settle()` from the `finish` part as the stream drains.\n *\n * Reserving before the await is what makes parallel calls (`Promise.all` over\n * several generations) honour the ceiling: each holds its slice instead of all\n * reading the same stale total (issue #18). The reservation is released if the\n * call throws, or if a stream ends without reporting usage.\n *\n * The model id used for pricing comes from `model.modelId`.\n */\n\nimport type { BudgetGuard } from \"./guard.js\";\n\n/**\n * The middleware call surface shared by `ai@4` and `ai@5`. Both majors invoke\n * `wrapGenerate`/`wrapStream` with an options object carrying these members\n * (plus richer `model` fields we don't read). `doGenerate`/`doStream` are\n * declared optional so every 4.x/5.x minor's options type stays assignable —\n * the SDK always provides the one each hook actually calls.\n */\ninterface MiddlewareCallOptions {\n doGenerate?: () => PromiseLike<any>;\n doStream?: () => PromiseLike<any>;\n model: { modelId: string };\n params?: unknown;\n}\n\n/**\n * Structural stand-in for `LanguageModelV1Middleware` (ai@4) and\n * `LanguageModelV2Middleware` (ai@5) — assignable to the `middleware` option of\n * `wrapLanguageModel` on either major.\n */\nexport interface BudgetGuardMiddleware {\n wrapGenerate: (options: MiddlewareCallOptions) => Promise<any>;\n wrapStream: (options: MiddlewareCallOptions) => Promise<any>;\n}\n\n/**\n * Read prompt/completion token counts from an ai@4 usage object\n * (`promptTokens`/`completionTokens`) or an ai@5 one (`inputTokens`/\n * `outputTokens`). Throws when either count is missing or non-numeric: the guard\n * cannot meter spend it cannot see, and treating it as $0 would fail open.\n */\nfunction usageTokens(\n modelId: string,\n usage: unknown,\n): { promptTokens: number; completionTokens: number } {\n const u = usage as\n | {\n promptTokens?: unknown;\n completionTokens?: unknown;\n inputTokens?: unknown;\n outputTokens?: unknown;\n }\n | null\n | undefined;\n const promptTokens = u?.promptTokens ?? u?.inputTokens;\n const completionTokens = u?.completionTokens ?? u?.outputTokens;\n if (typeof promptTokens !== \"number\" || typeof completionTokens !== \"number\") {\n throw new Error(\n `Model '${modelId}' reported no token usage — the budget guard cannot ` +\n `meter spend it cannot see, so this call is rejected rather than ` +\n `treated as free.`,\n );\n }\n return { promptTokens, completionTokens };\n}\n\n/**\n * Build a budget-guard middleware that hard-stops the model before a call\n * crosses the guard's USD ceiling, and records priced token usage after.\n * Compatible with `wrapLanguageModel` from both `ai@4` and `ai@5`.\n *\n * @example\n * import { wrapLanguageModel } from \"ai\";\n * import { openai } from \"@ai-sdk/openai\";\n * import { BudgetGuard, budgetGuardMiddleware } from \"floe-guard\";\n *\n * const guard = new BudgetGuard(5.00);\n * const model = wrapLanguageModel({\n * model: openai(\"gpt-4o\"),\n * middleware: budgetGuardMiddleware(guard),\n * });\n */\nexport function budgetGuardMiddleware(guard: BudgetGuard): BudgetGuardMiddleware {\n return {\n async wrapGenerate({ doGenerate, model }) {\n const reserved = guard.reserve(); // throws BudgetExceeded before the call runs\n let result: any;\n try {\n result = await doGenerate!();\n } catch (err) {\n guard.release(reserved); // the call failed before settle() took ownership\n throw err;\n }\n // From here settle() OWNS the reservation: it releases the hold on its own\n // throw (unpriceable / non-finite cost) and consumes it on success. Releasing\n // again would double-subtract and clear a concurrent call's in-flight hold.\n let handled = false;\n try {\n const { promptTokens, completionTokens } = usageTokens(\n model.modelId,\n result?.usage,\n );\n handled = true;\n guard.settle(model.modelId, promptTokens, completionTokens, { reserved });\n return result;\n } catch (err) {\n if (!handled) guard.release(reserved); // failed reading usage, before settle()\n throw err;\n }\n },\n\n async wrapStream({ doStream, model }) {\n const reserved = guard.reserve(); // throws BudgetExceeded before the stream starts\n let streamResult: any;\n try {\n streamResult = await doStream!();\n } catch (err) {\n guard.release(reserved); // the call failed before settle() took ownership\n throw err;\n }\n const { stream, ...rest } = streamResult as {\n stream: ReadableStream<any>;\n } & Record<string, unknown>;\n\n // `handled` flips once the reservation is disposed — settled on the finish\n // part, or released exactly once if the stream produced no usage (flush) or\n // ended early via error/cancellation (cancel). settle() owns disposal once\n // called, so nothing else may release after `handled` is set, or we'd\n // double-subtract and clear a concurrent call's hold.\n let handled = false;\n const guarded = stream.pipeThrough(\n new TransformStream<any, any>({\n transform(chunk, controller) {\n if (chunk?.type === \"finish\" && !handled) {\n try {\n const { promptTokens, completionTokens } = usageTokens(\n model.modelId,\n chunk.usage,\n );\n handled = true;\n guard.settle(model.modelId, promptTokens, completionTokens, { reserved });\n } catch (err) {\n // Release only if we never reached settle() (e.g. usage missing).\n // If settle() itself threw, it already released its own hold.\n if (!handled) {\n handled = true;\n guard.release(reserved);\n }\n throw err;\n }\n }\n controller.enqueue(chunk);\n },\n flush() {\n // Clean close with no finish/usage part — free the held budget.\n if (!handled) {\n handled = true;\n guard.release(reserved);\n }\n },\n cancel() {\n // Upstream error or consumer cancellation: flush() does not run here\n // (Web Streams: flush and cancel are mutually exclusive), so release\n // the still-held reservation.\n if (!handled) {\n handled = true;\n guard.release(reserved);\n }\n },\n // `cancel` is valid per the Streams spec and supported in Node 18+, but\n // TS's Transformer lib type lags and omits it — cast to keep the type check.\n } as Transformer<any, any>),\n );\n\n return { stream: guarded, ...rest };\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/pricing.ts","../src/cost_map.json","../src/guard.ts","../src/middleware.ts"],"sourcesContent":["/**\n * floe-guard — a local budget guardrail for AI agents.\n *\n * Hard-stops your agent before its next LLM call when it would cross a USD spend\n * ceiling. This package is the Vercel AI SDK (TypeScript) adapter; the Python\n * package `floe-guard` (pip) carries the LiteLLM / CrewAI / LangChain adapters.\n */\n\nexport {\n BudgetGuard,\n type BudgetGuardOptions,\n type BudgetAdvisory,\n} from \"./guard.js\";\nexport {\n FloeGuardError,\n BudgetExceeded,\n UnpriceableModelError,\n} from \"./errors.js\";\nexport {\n budgetGuardMiddleware,\n type BudgetGuardMiddleware,\n} from \"./middleware.js\";\nexport {\n type ManualPrice,\n type PricedModel,\n resolvePrice,\n priceTokens,\n} from \"./pricing.js\";\n\nexport * as pricing from \"./pricing.js\";\n","/**\n * Exceptions for floe-guard.\n *\n * Everything derives from {@link FloeGuardError} (the package-root base) so callers\n * can catch the whole family with a single `catch (e) { if (e instanceof FloeGuardError) ... }`.\n *\n * Mirrors `src/floe_guard/errors.py` in the Python package — message formats are\n * kept byte-for-byte identical so both adapters read the same.\n */\n\n/** Base class for every error raised by floe-guard. */\nexport class FloeGuardError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FloeGuardError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown before an LLM call that would cross the configured spend ceiling.\n *\n * The guard throws this *instead of* letting the next call run, so a runaway loop\n * stops here rather than burning more money.\n */\nexport class BudgetExceeded extends FloeGuardError {\n readonly spentUsd: number;\n readonly limitUsd: number;\n\n constructor(spentUsd: number, limitUsd: number) {\n super(\n `BUDGET EXCEEDED — call blocked (spent $${spentUsd.toFixed(6)} of $${limitUsd.toFixed(6)} ceiling)`,\n );\n this.name = \"BudgetExceeded\";\n this.spentUsd = spentUsd;\n this.limitUsd = limitUsd;\n }\n}\n\n/**\n * Thrown when a model cannot be priced and the guard is fail-closed.\n *\n * We refuse rather than silently accrue $0 — \"we cannot cap what we cannot price\".\n * Pass a manual price (`priceOverrides` or `record(..., { price })`) to make the\n * model enforceable.\n */\nexport class UnpriceableModelError extends FloeGuardError {\n readonly model: string;\n\n constructor(model: string) {\n super(\n `Cannot price model '${model}': not in the bundled cost map and no ` +\n `manual price was given. The guard cannot enforce a budget on spend ` +\n `it cannot measure. Pass a price override to enable enforcement.`,\n );\n this.name = \"UnpriceableModelError\";\n this.model = model;\n }\n}\n","/**\n * Offline token pricing from a vendored LiteLLM cost map.\n *\n * Mirrors `src/floe_guard/pricing.py`: BOTH the input and output per-token prices\n * must be finite numbers, otherwise the model is treated as unpriceable. A\n * half-valid entry would silently undercharge — so we refuse it (fail-closed).\n *\n * No network. The cost map (`cost_map.json`) is a snapshot of LiteLLM's\n * `model_prices_and_context_window.json`; refresh it on a schedule or estimates\n * drift as vendors change prices.\n */\n\nimport costMapJson from \"./cost_map.json\";\n\n/** A user-supplied per-token price, in USD, for a model the map cannot price. */\nexport interface ManualPrice {\n inputCostPerToken: number;\n outputCostPerToken: number;\n}\n\n/** A resolved per-token price plus where it came from. */\nexport interface PricedModel {\n inputCostPerToken: number;\n outputCostPerToken: number;\n source: \"override\" | \"cost_map\";\n}\n\ninterface CostMapEntry {\n input_cost_per_token?: unknown;\n output_cost_per_token?: unknown;\n}\n\nconst COST_MAP = costMapJson as Record<string, CostMapEntry>;\n\n/**\n * The one `<provider>/` prefix that is safe to strip: the remainder of a\n * `groq/…` id is the ChatGroq id the map vendors (e.g. `groq/qwen/qwen3-32b` →\n * `qwen/qwen3-32b`). `openai/` and `anthropic/` are deliberately excluded:\n * their own model ids never contain slashes (single-segment remainders are\n * already covered by the bare-last-segment fallback), so a multi-segment\n * remainder under those prefixes is some OTHER vendor's model behind an\n * OpenAI-compatible endpoint (vLLM, OpenRouter, …) — bridging it into a\n * Groq-priced key would under-meter. Unknown prefixes fail closed the same way.\n */\nconst PROVIDER_PREFIXES = new Set([\"groq\"]);\n\n/**\n * A trailing dated-snapshot suffix: Anthropic's `-20250929` or OpenAI's\n * `-2024-08-06`. Vendors resolve alias ids to dated snapshots in responses, so a\n * snapshot the map doesn't list yet prices at its alias entry (same model, same\n * rate) instead of failing closed. (`\\d` is ASCII-only in JS; the Python regex\n * uses re.ASCII to match.)\n */\nconst DATE_SUFFIX = /-(?:\\d{8}|\\d{4}-\\d{2}-\\d{2})$/;\n\n/**\n * Lookup keys for a model id in two specificity groups, deduplicated.\n *\n * Group 1 (exact): the raw id, the id with a known `provider/` first segment\n * stripped, the bare last segment. Group 2 (date-stripped): the same forms\n * with a trailing dated-snapshot suffix removed. Kept separate so a\n * less-specific date-stripped key (in overrides OR the map) can never shadow\n * an exact dated entry — e.g. an alias override must not absorb a snapshot\n * the map prices differently.\n */\nfunction candidateGroups(model: string): [string[], string[]] {\n const m = model.trim();\n const base = [m];\n const firstSlash = m.indexOf(\"/\");\n if (firstSlash !== -1 && PROVIDER_PREFIXES.has(m.slice(0, firstSlash))) {\n base.push(m.slice(firstSlash + 1));\n }\n const lastSlash = m.lastIndexOf(\"/\");\n if (lastSlash !== -1) {\n base.push(m.slice(lastSlash + 1));\n }\n const exact: string[] = [];\n for (const cand of base) {\n if (cand && !exact.includes(cand)) exact.push(cand);\n }\n const stripped: string[] = [];\n for (const cand of exact) {\n const c = cand.replace(DATE_SUFFIX, \"\");\n if (c && !exact.includes(c) && !stripped.includes(c)) stripped.push(c);\n }\n return [exact, stripped];\n}\n\nfunction bothFinite(a: unknown, b: unknown): boolean {\n return (\n typeof a === \"number\" &&\n typeof b === \"number\" &&\n Number.isFinite(a) &&\n Number.isFinite(b)\n );\n}\n\n/**\n * Resolve a model to its per-token price, or `null` if it cannot be priced.\n *\n * Per specificity group (exact forms first, date-stripped fallbacks second):\n * overrides win, then the bundled cost map. Fail-closed: the first matching\n * entry must have finite prices, else `null`.\n */\nexport function resolvePrice(\n model: string,\n overrides?: Record<string, ManualPrice>,\n): PricedModel | null {\n for (const cands of candidateGroups(model)) {\n if (overrides) {\n for (const cand of cands) {\n // Own-property check so a key like \"constructor\" can't pull a function\n // off Object.prototype and be treated as a price entry.\n const ov = Object.prototype.hasOwnProperty.call(overrides, cand)\n ? overrides[cand]\n : undefined;\n if (ov !== undefined) {\n if (bothFinite(ov.inputCostPerToken, ov.outputCostPerToken)) {\n return {\n inputCostPerToken: ov.inputCostPerToken,\n outputCostPerToken: ov.outputCostPerToken,\n source: \"override\",\n };\n }\n return null;\n }\n }\n }\n\n for (const cand of cands) {\n const entry = Object.prototype.hasOwnProperty.call(COST_MAP, cand)\n ? COST_MAP[cand]\n : undefined;\n if (!entry) continue;\n\n const input = entry.input_cost_per_token;\n const output = entry.output_cost_per_token;\n if (!bothFinite(input, output)) return null;\n\n return {\n inputCostPerToken: input as number,\n outputCostPerToken: output as number,\n source: \"cost_map\",\n };\n }\n }\n return null;\n}\n\n/** USD cost for token usage. Negative counts are clamped to zero. */\nexport function priceTokens(\n priced: PricedModel,\n promptTokens: number,\n completionTokens: number,\n): number {\n const p = Math.max(0, promptTokens);\n const c = Math.max(0, completionTokens);\n const cost = p * priced.inputCostPerToken + c * priced.outputCostPerToken;\n if (!Number.isFinite(cost)) {\n // Defense-in-depth: resolvePrice already guarantees finite rates.\n throw new Error(\"Non-finite LLM cost — pricing entry is invalid\");\n }\n return Math.max(0, cost);\n}\n","{\n \"chatgpt-4o-latest\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"claude-3-7-sonnet-20250219\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-3-haiku-20240307\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-3-opus-20240229\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-4-opus-20250514\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-4-sonnet-20250514\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-fable-5\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-haiku-4-5\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-haiku-4-5-20251001\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-1\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-1-20250805\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-20250514\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-5\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-5-20251101\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-6\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-6-20260205\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-7\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-7-20260416\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-8\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-20250514\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-5\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-5-20250929\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-6\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-5\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-0125\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-0613\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-1106\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4-0613\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-2025-04-14\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000012,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-mini-2025-04-14\": {\n \"input_cost_per_token\": 8e-7,\n \"output_cost_per_token\": 0.0000032,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-nano-2025-04-14\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 8e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-2024-08-06\": {\n \"input_cost_per_token\": 0.00000375,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-2024-11-20\": {\n \"input_cost_per_token\": 0.00000375,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-mini-2024-07-18\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000012,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:o4-mini-2025-04-16\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo\": {\n \"input_cost_per_token\": 5e-7,\n \"output_cost_per_token\": 0.0000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-0125\": {\n \"input_cost_per_token\": 5e-7,\n \"output_cost_per_token\": 0.0000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-1106\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-16k\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000004,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0125-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0314\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0613\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-1106-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo-2024-04-09\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-2025-04-14\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-mini\": {\n \"input_cost_per_token\": 4e-7,\n \"output_cost_per_token\": 0.0000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-mini-2025-04-14\": {\n \"input_cost_per_token\": 4e-7,\n \"output_cost_per_token\": 0.0000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-nano\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-nano-2025-04-14\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-05-13\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-08-06\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-11-20\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview-2024-12-17\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview-2025-06-03\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-2024-07-18\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-audio-preview\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-audio-preview-2024-12-17\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-realtime-preview\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-realtime-preview-2024-12-17\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-search-preview\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-search-preview-2025-03-11\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-realtime-preview\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-realtime-preview-2024-12-17\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-realtime-preview-2025-06-03\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-search-preview\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-search-preview-2025-03-11\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-2025-08-07\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-chat\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-chat-latest\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-mini\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-mini-2025-08-07\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-nano\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-nano-2025-08-07\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-search-api\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-search-api-2025-10-14\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1-2025-11-13\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1-chat-latest\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2-2025-12-11\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2-chat-latest\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.3-chat-latest\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-2026-03-05\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-mini\": {\n \"input_cost_per_token\": 7.5e-7,\n \"output_cost_per_token\": 0.0000045,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-mini-2026-03-17\": {\n \"input_cost_per_token\": 7.5e-7,\n \"output_cost_per_token\": 0.0000045,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-nano\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-nano-2026-03-17\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.5\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.5-2026-04-23\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.6\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.6-luna\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.6-sol\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.6-terra\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-1.5\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-2025-08-28\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini-2025-10-06\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini-2025-12-15\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-1.5\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-2\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-2.1\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-2.1-mini\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-2025-08-28\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-mini\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-mini-2025-10-06\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-mini-2025-12-15\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"llama-3.1-8b-instant\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 8e-8,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"llama-3.3-70b-versatile\": {\n \"input_cost_per_token\": 5.9e-7,\n \"output_cost_per_token\": 7.9e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"meta-llama/llama-4-scout-17b-16e-instruct\": {\n \"input_cost_per_token\": 1.1e-7,\n \"output_cost_per_token\": 3.4e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"o1\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o1-2024-12-17\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-2025-04-16\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-mini\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-mini-2025-01-31\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o4-mini\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o4-mini-2025-04-16\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"openai/gpt-oss-120b\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"openai/gpt-oss-20b\": {\n \"input_cost_per_token\": 7.5e-8,\n \"output_cost_per_token\": 3e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"openai/gpt-oss-safeguard-20b\": {\n \"input_cost_per_token\": 7.5e-8,\n \"output_cost_per_token\": 3e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"qwen/qwen3-32b\": {\n \"input_cost_per_token\": 2.9e-7,\n \"output_cost_per_token\": 5.9e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"text-embedding-3-large\": {\n \"input_cost_per_token\": 1.3e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-3-small\": {\n \"input_cost_per_token\": 2e-8,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-ada-002\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-ada-002-v2\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n }\n}\n","/**\n * The local, in-process budget guard.\n *\n * `BudgetGuard` is a kill-switch that lives in the LLM call path. The contract:\n *\n * 1. Call {@link BudgetGuard.check} BEFORE every LLM call. If the *next* call\n * would cross the ceiling, it throws {@link BudgetExceeded} and the call never\n * runs.\n * 2. Call {@link BudgetGuard.record} AFTER every response, with the token usage.\n * It prices the tokens offline and accrues the USD into a running total.\n *\n * **Concurrency.** `check()` then `record()` is a check-then-act with an `await`\n * in between. Fire several model calls at once (e.g. `Promise.all`) and they all\n * `check()` against the same under-limit total before any `record()` lands, so\n * the ceiling is blown (see issue #18). {@link BudgetGuard.reserve} /\n * {@link BudgetGuard.settle} close that gap: `reserve()` holds the estimated cost\n * in flight (synchronously, before the await), so parallel callers each take\n * their own slice of the ceiling. JS is single-threaded, so an in-flight counter\n * is enough — no lock needed. The middleware uses it; `check`/`record` are\n * unchanged.\n *\n * This is a faithful port of `src/floe_guard/guard.py` — same prediction logic,\n * same epsilon handling, same fail-closed default.\n */\n\nimport { BudgetExceeded, UnpriceableModelError } from \"./errors.js\";\nimport {\n type ManualPrice,\n priceTokens,\n resolvePrice,\n} from \"./pricing.js\";\n\n/** Tolerance for float rounding in the running spend total (well below $0.000001). */\nconst EPS = 1e-12;\n\nexport interface BudgetGuardOptions {\n /** Per-model manual prices for models the bundled cost map cannot price. */\n priceOverrides?: Record<string, ManualPrice>;\n /**\n * When `true` (default), recording an unpriceable model without a manual price\n * warns loudly AND throws {@link UnpriceableModelError}. When `false`, it warns\n * and skips accrual (you have opted into un-enforced spend for that model).\n */\n failClosed?: boolean;\n /**\n * Optional callback invoked with `(spentUsd, limitUsd)` right before\n * {@link BudgetExceeded} is thrown. Defaults to printing the\n * `BUDGET EXCEEDED — call blocked` banner to stderr.\n */\n onBlock?: (spentUsd: number, limitUsd: number) => void;\n /**\n * Utilization (basis points, 0..10000) at which {@link BudgetGuard.advisory}\n * flags `nearLimit` so an agent can taper before the hard-stop. Default 8000.\n */\n nearLimitBps?: number;\n}\n\n/**\n * A context-aware spend signal for the single local budget.\n *\n * Mirrors the core fields of hosted Floe's `X-Floe-Budget-Advisory` header, so\n * agent logic that reads it (taper as you approach the cap, stop at it) ports\n * unchanged to the hosted path. Hosted adds what a local, single-budget guard\n * cannot know: which of several caps is tightest (`scope` across\n * `credit_line | session | task | api | vendor`), cross-vendor reasoning,\n * server-truth balances, and rolling-window reset timing.\n *\n * This is a **soft** signal — the model may ignore it. The hard-stop\n * ({@link BudgetGuard.check}) is what enforces the ceiling; the advisory is\n * upside (let the agent finish on budget rather than be cut off).\n */\nexport interface BudgetAdvisory {\n nearLimit: boolean;\n /** Utilization in basis points, 0..10000 (8500 = 85%). */\n usedBps: number;\n remainingUsd: number;\n limitUsd: number;\n spentUsd: number;\n /** Hosted reports the tightest cap across all scopes; local is always \"local\". */\n scope: \"local\";\n}\n\nexport class BudgetGuard {\n readonly limitUsd: number;\n spentUsd = 0;\n priceOverrides?: Record<string, ManualPrice>;\n failClosed: boolean;\n nearLimitBps: number;\n\n private readonly onBlock: (spentUsd: number, limitUsd: number) => void;\n /** Cost of the most recent priced call, used to predict the next one. */\n private lastCost = 0;\n /** USD held for in-flight calls (reserved, not yet settled). Counts toward the ceiling. */\n private reserved = 0;\n\n /**\n * @param limitUsd the spend ceiling, in USD. `0` blocks the very first call.\n */\n constructor(limitUsd: number, options: BudgetGuardOptions = {}) {\n if (!Number.isFinite(limitUsd) || limitUsd < 0) {\n // NaN/Infinity would make every check() comparison fail-open, silently\n // disabling the guard — reject them up front.\n throw new RangeError(\n `limitUsd must be a finite, non-negative number, got ${limitUsd}`,\n );\n }\n // `=== undefined` (not `??`) so an explicit null is rejected by validation\n // rather than silently defaulting — matches Python, which rejects None.\n const nearLimitBps = options.nearLimitBps === undefined ? 8000 : options.nearLimitBps;\n if (!Number.isInteger(nearLimitBps) || nearLimitBps < 0 || nearLimitBps > 10000) {\n throw new RangeError(\n `nearLimitBps must be an integer in 0..10000, got ${nearLimitBps}`,\n );\n }\n this.limitUsd = limitUsd;\n this.priceOverrides = options.priceOverrides;\n this.failClosed = options.failClosed ?? true;\n this.onBlock = options.onBlock ?? defaultOnBlock;\n this.nearLimitBps = nearLimitBps;\n }\n\n /**\n * Throw {@link BudgetExceeded} if the next call would cross the ceiling.\n *\n * Call this immediately before each LLM request. The \"next call\" is estimated\n * from the last recorded call's cost (override with `estimatedNextCost`); the\n * first call is always allowed unless the ceiling is already met. In-flight\n * reservations count toward the total, so this stays correct alongside\n * {@link BudgetGuard.reserve}.\n *\n * Note: `check` is a non-binding peek. For parallel calls, use `reserve()` /\n * `settle()`, which hold the estimate across the await.\n */\n check(estimatedNextCost?: number): void {\n const rawEstimate =\n estimatedNextCost === undefined ? this.lastCost : estimatedNextCost;\n if (!Number.isFinite(rawEstimate)) {\n // NaN/Infinity would poison the comparisons and fail-open — reject it\n // (parity with the constructor's Number.isFinite guard).\n throw new RangeError(\n `estimatedNextCost must be a finite number, got ${rawEstimate}`,\n );\n }\n const estimate = Math.max(0, rawEstimate);\n const committed = this.spentUsd + this.reserved;\n if (committed > this.limitUsd - EPS || committed + estimate > this.limitUsd + EPS) {\n this.onBlock(this.spentUsd, this.limitUsd);\n throw new BudgetExceeded(this.spentUsd, this.limitUsd);\n }\n }\n\n /**\n * Atomically check the ceiling AND hold the estimated cost in flight.\n *\n * The concurrency-safe enforcement path: call before the request and hold the\n * returned reservation across the await, so parallel callers can't all clear\n * the same stale total. Throws {@link BudgetExceeded} (without reserving) if\n * the reservation would cross the ceiling. Returns the reservation handle to\n * pass to {@link BudgetGuard.settle} (or {@link BudgetGuard.release} on error).\n * `estimatedCost` defaults to the last call's cost.\n */\n reserve(estimatedCost?: number): number {\n const rawEstimate = estimatedCost === undefined ? this.lastCost : estimatedCost;\n if (!Number.isFinite(rawEstimate)) {\n // NaN would poison this.reserved and fail-open the ceiling — reject it.\n throw new RangeError(\n `estimatedCost must be a finite number, got ${rawEstimate}`,\n );\n }\n const estimate = Math.max(0, rawEstimate);\n const committed = this.spentUsd + this.reserved;\n if (committed > this.limitUsd - EPS || committed + estimate > this.limitUsd + EPS) {\n this.onBlock(this.spentUsd, this.limitUsd);\n throw new BudgetExceeded(this.spentUsd, this.limitUsd);\n }\n this.reserved += estimate;\n return estimate;\n }\n\n /**\n * Release a reservation and record the actual cost. `record` is `settle` with\n * no reservation. Returns the USD cost of this call; unpriceable-model handling\n * matches {@link BudgetGuard.record}, and any held reservation is released even\n * on the warn-and-skip path.\n */\n settle(\n model: string,\n promptTokens: number,\n completionTokens: number,\n options: { reserved?: number; price?: ManualPrice } = {},\n ): number {\n const reserved = options.reserved ?? 0;\n // A bad reserved handle would corrupt this.reserved and break the ceiling for\n // OTHER in-flight calls (negative → phantom hold; Infinity → clears all holds).\n if (!Number.isFinite(reserved) || reserved < 0) {\n throw new RangeError(`reserved must be a finite, non-negative number, got ${reserved}`);\n }\n let overrides = this.priceOverrides;\n if (options.price !== undefined) {\n overrides = { ...(overrides ?? {}), [model]: options.price };\n }\n\n const priced = resolvePrice(model, overrides);\n if (priced === null) {\n console.warn(\n `Cannot price model '${model}': not in the bundled cost map and no ` +\n `manual price given. The budget guard cannot enforce a ceiling on ` +\n `spend it cannot measure — pass { price } or set it in priceOverrides.`,\n );\n // Release any held reservation on BOTH paths. Fail-closed must not leak\n // the in-flight hold, or reserved grows permanently and remainingUsd\n // shrinks until reserve() starts blocking everything.\n this.release(reserved);\n if (this.failClosed) {\n throw new UnpriceableModelError(model);\n }\n return 0;\n }\n\n let cost: number;\n try {\n cost = priceTokens(priced, promptTokens, completionTokens);\n } catch (err) {\n // priceTokens can throw (e.g. non-finite costs). Release the in-flight\n // hold before re-throwing so `reserved` doesn't leak and shrink\n // remainingUsd permanently — same fail-safe as the unpriceable path above.\n this.release(reserved);\n throw err;\n }\n if (reserved) {\n this.reserved = Math.max(0, this.reserved - reserved);\n }\n this.spentUsd += cost;\n // Clamp a sub-epsilon float overshoot back to the limit so the running total\n // never reports as having crossed the ceiling by a rounding artifact.\n if (this.spentUsd - this.limitUsd > 0 && this.spentUsd - this.limitUsd < EPS) {\n this.spentUsd = this.limitUsd;\n }\n this.lastCost = cost;\n return cost;\n }\n\n /**\n * Price one response's tokens offline and add the cost to the total.\n *\n * Returns the USD cost of this call. If the model is unpriceable and no `price`\n * is given, behaviour depends on `failClosed`: warn + throw (default), or\n * warn + skip accrual.\n */\n record(\n model: string,\n promptTokens: number,\n completionTokens: number,\n options: { price?: ManualPrice } = {},\n ): number {\n return this.settle(model, promptTokens, completionTokens, {\n reserved: 0,\n price: options.price,\n });\n }\n\n /**\n * Drop an in-flight reservation without recording spend (e.g. the call failed\n * before producing usage). Safe to call with `0`.\n */\n release(reserved: number): void {\n // Validate before the zero-check so a NaN handle throws instead of being\n // silently dropped (a leak); a bad handle corrupts the in-flight tally.\n if (!Number.isFinite(reserved) || reserved < 0) {\n throw new RangeError(`reserved must be a finite, non-negative number, got ${reserved}`);\n }\n if (!reserved) return;\n this.reserved = Math.max(0, this.reserved - reserved);\n }\n\n /** USD left before the ceiling, net of in-flight reservations (never negative). */\n get remainingUsd(): number {\n return Math.max(0, this.limitUsd - this.spentUsd - this.reserved);\n }\n\n /**\n * Context-aware spend advisory for this budget — see {@link BudgetAdvisory}.\n *\n * `nearLimit` flips once utilization reaches `nearLimitBps` (default 80%), so an\n * agent can taper *before* the hard-stop. Advisory only: read it to adapt;\n * {@link BudgetGuard.check} is what enforces the ceiling.\n */\n advisory(): BudgetAdvisory {\n // Floor (not round) so usedBps never over-reports utilization and nearLimit\n // flips exactly when the threshold is reached; the epsilon absorbs float noise\n // and Math.floor matches Python's int() exactly (round() would diverge).\n const usedBps =\n this.limitUsd <= 0\n ? 10000\n : Math.max(0, Math.min(10000, Math.floor((this.spentUsd / this.limitUsd) * 10000 + 1e-9)));\n return {\n nearLimit: usedBps >= this.nearLimitBps,\n usedBps,\n // Settled budget: limit minus accrued spend, deliberately NOT net of\n // in-flight reservations. Unlike the remainingUsd getter (which subtracts\n // `reserved`), the advisory is a soft utilization signal about money already\n // spent, while the getter reports what a new call can still claim.\n remainingUsd: Math.max(0, this.limitUsd - this.spentUsd),\n limitUsd: this.limitUsd,\n spentUsd: this.spentUsd,\n scope: \"local\",\n };\n }\n}\n\nfunction defaultOnBlock(spentUsd: number, limitUsd: number): void {\n console.error(\n \"BUDGET EXCEEDED — call blocked\\n\" +\n ` spent so far: $${spentUsd.toFixed(6)} | ceiling: $${limitUsd.toFixed(6)}\\n` +\n \" The next call would cross your budget; floe-guard stopped your agent \" +\n \"before it ran.\",\n );\n}\n","/**\n * Vercel AI SDK middleware that enforces a {@link BudgetGuard} in the call path.\n *\n * This is the TypeScript counterpart to the Python framework adapters. The AI SDK\n * is TypeScript-only, so it ships as its own npm package.\n *\n * Works with BOTH `ai@4` (`LanguageModelV1Middleware`) and `ai@5`\n * (`LanguageModelV2Middleware`). The two majors renamed the middleware type and\n * the usage fields (`promptTokens`/`completionTokens` → `inputTokens`/\n * `outputTokens`), so this module deliberately imports nothing from `ai`: the\n * middleware is typed structurally against the surface both majors share, and\n * usage is read from whichever field pair the installed SDK reports.\n *\n * - `wrapGenerate({ doGenerate, model })` — we `reserve()` (throws to hard-stop)\n * BEFORE calling `doGenerate()`, hold the reservation across the await, then\n * `settle()` from `result.usage`.\n * - `wrapStream({ doStream, model })` — we `reserve()` BEFORE `doStream()`, then\n * `settle()` from the `finish` part as the stream drains.\n *\n * Reserving before the await is what makes parallel calls (`Promise.all` over\n * several generations) honour the ceiling: each holds its slice instead of all\n * reading the same stale total (issue #18). The reservation is released if the\n * call throws, or if a stream ends without reporting usage.\n *\n * The model id used for pricing comes from `model.modelId`.\n */\n\nimport type { BudgetGuard } from \"./guard.js\";\n\n/**\n * The middleware call surface shared by `ai@4` and `ai@5`. Both majors invoke\n * `wrapGenerate`/`wrapStream` with an options object carrying these members\n * (plus richer `model` fields we don't read). `doGenerate`/`doStream` are\n * declared optional so every 4.x/5.x minor's options type stays assignable —\n * the SDK always provides the one each hook actually calls.\n */\ninterface MiddlewareCallOptions {\n doGenerate?: () => PromiseLike<any>;\n doStream?: () => PromiseLike<any>;\n model: { modelId: string };\n params?: unknown;\n}\n\n/**\n * Structural stand-in for `LanguageModelV1Middleware` (ai@4) and\n * `LanguageModelV2Middleware` (ai@5) — assignable to the `middleware` option of\n * `wrapLanguageModel` on either major.\n */\nexport interface BudgetGuardMiddleware {\n wrapGenerate: (options: MiddlewareCallOptions) => Promise<any>;\n wrapStream: (options: MiddlewareCallOptions) => Promise<any>;\n}\n\n/**\n * Read prompt/completion token counts from an ai@4 usage object\n * (`promptTokens`/`completionTokens`) or an ai@5 one (`inputTokens`/\n * `outputTokens`). Throws when either count is missing or non-numeric: the guard\n * cannot meter spend it cannot see, and treating it as $0 would fail open.\n */\nfunction usageTokens(\n modelId: string,\n usage: unknown,\n): { promptTokens: number; completionTokens: number } {\n const u = usage as\n | {\n promptTokens?: unknown;\n completionTokens?: unknown;\n inputTokens?: unknown;\n outputTokens?: unknown;\n }\n | null\n | undefined;\n const promptTokens = u?.promptTokens ?? u?.inputTokens;\n const completionTokens = u?.completionTokens ?? u?.outputTokens;\n if (typeof promptTokens !== \"number\" || typeof completionTokens !== \"number\") {\n throw new Error(\n `Model '${modelId}' reported no token usage — the budget guard cannot ` +\n `meter spend it cannot see, so this call is rejected rather than ` +\n `treated as free.`,\n );\n }\n return { promptTokens, completionTokens };\n}\n\n/**\n * Build a budget-guard middleware that hard-stops the model before a call\n * crosses the guard's USD ceiling, and records priced token usage after.\n * Compatible with `wrapLanguageModel` from both `ai@4` and `ai@5`.\n *\n * @example\n * import { wrapLanguageModel } from \"ai\";\n * import { openai } from \"@ai-sdk/openai\";\n * import { BudgetGuard, budgetGuardMiddleware } from \"floe-guard\";\n *\n * const guard = new BudgetGuard(5.00);\n * const model = wrapLanguageModel({\n * model: openai(\"gpt-4o\"),\n * middleware: budgetGuardMiddleware(guard),\n * });\n */\nexport function budgetGuardMiddleware(guard: BudgetGuard): BudgetGuardMiddleware {\n return {\n async wrapGenerate({ doGenerate, model }) {\n const reserved = guard.reserve(); // throws BudgetExceeded before the call runs\n let result: any;\n try {\n result = await doGenerate!();\n } catch (err) {\n guard.release(reserved); // the call failed before settle() took ownership\n throw err;\n }\n // From here settle() OWNS the reservation: it releases the hold on its own\n // throw (unpriceable / non-finite cost) and consumes it on success. Releasing\n // again would double-subtract and clear a concurrent call's in-flight hold.\n let handled = false;\n try {\n const { promptTokens, completionTokens } = usageTokens(\n model.modelId,\n result?.usage,\n );\n handled = true;\n guard.settle(model.modelId, promptTokens, completionTokens, { reserved });\n return result;\n } catch (err) {\n if (!handled) guard.release(reserved); // failed reading usage, before settle()\n throw err;\n }\n },\n\n async wrapStream({ doStream, model }) {\n const reserved = guard.reserve(); // throws BudgetExceeded before the stream starts\n let streamResult: any;\n try {\n streamResult = await doStream!();\n } catch (err) {\n guard.release(reserved); // the call failed before settle() took ownership\n throw err;\n }\n const { stream, ...rest } = streamResult as {\n stream: ReadableStream<any>;\n } & Record<string, unknown>;\n\n // `handled` flips once the reservation is disposed — settled on the finish\n // part, or released exactly once if the stream produced no usage (flush) or\n // ended early via error/cancellation (cancel). settle() owns disposal once\n // called, so nothing else may release after `handled` is set, or we'd\n // double-subtract and clear a concurrent call's hold.\n let handled = false;\n const guarded = stream.pipeThrough(\n new TransformStream<any, any>({\n transform(chunk, controller) {\n if (chunk?.type === \"finish\" && !handled) {\n try {\n const { promptTokens, completionTokens } = usageTokens(\n model.modelId,\n chunk.usage,\n );\n handled = true;\n guard.settle(model.modelId, promptTokens, completionTokens, { reserved });\n } catch (err) {\n // Release only if we never reached settle() (e.g. usage missing).\n // If settle() itself threw, it already released its own hold.\n if (!handled) {\n handled = true;\n guard.release(reserved);\n }\n throw err;\n }\n }\n controller.enqueue(chunk);\n },\n flush() {\n // Clean close with no finish/usage part — free the held budget.\n if (!handled) {\n handled = true;\n guard.release(reserved);\n }\n },\n cancel() {\n // Upstream error or consumer cancellation: flush() does not run here\n // (Web Streams: flush and cancel are mutually exclusive), so release\n // the still-held reservation.\n if (!handled) {\n handled = true;\n guard.release(reserved);\n }\n },\n // `cancel` is valid per the Streams spec and supported in Node 18+, but\n // TS's Transformer lib type lags and omits it — cast to keep the type check.\n } as Transformer<any, any>),\n );\n\n return { stream: guarded, ...rest };\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -23,8 +23,9 @@ interface PricedModel {
|
|
|
23
23
|
/**
|
|
24
24
|
* Resolve a model to its per-token price, or `null` if it cannot be priced.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
26
|
+
* Per specificity group (exact forms first, date-stripped fallbacks second):
|
|
27
|
+
* overrides win, then the bundled cost map. Fail-closed: the first matching
|
|
28
|
+
* entry must have finite prices, else `null`.
|
|
28
29
|
*/
|
|
29
30
|
declare function resolvePrice(model: string, overrides?: Record<string, ManualPrice>): PricedModel | null;
|
|
30
31
|
/** USD cost for token usage. Negative counts are clamped to zero. */
|
package/dist/index.d.ts
CHANGED
|
@@ -23,8 +23,9 @@ interface PricedModel {
|
|
|
23
23
|
/**
|
|
24
24
|
* Resolve a model to its per-token price, or `null` if it cannot be priced.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
26
|
+
* Per specificity group (exact forms first, date-stripped fallbacks second):
|
|
27
|
+
* overrides win, then the bundled cost map. Fail-closed: the first matching
|
|
28
|
+
* entry must have finite prices, else `null`.
|
|
28
29
|
*/
|
|
29
30
|
declare function resolvePrice(model: string, overrides?: Record<string, ManualPrice>): PricedModel | null;
|
|
30
31
|
/** USD cost for token usage. Negative counts are clamped to zero. */
|
package/dist/index.js
CHANGED
|
@@ -182,6 +182,12 @@ var cost_map_default = {
|
|
|
182
182
|
litellm_provider: "anthropic",
|
|
183
183
|
mode: "chat"
|
|
184
184
|
},
|
|
185
|
+
"claude-sonnet-5": {
|
|
186
|
+
input_cost_per_token: 2e-6,
|
|
187
|
+
output_cost_per_token: 1e-5,
|
|
188
|
+
litellm_provider: "anthropic",
|
|
189
|
+
mode: "chat"
|
|
190
|
+
},
|
|
185
191
|
"ft:gpt-3.5-turbo": {
|
|
186
192
|
input_cost_per_token: 3e-6,
|
|
187
193
|
output_cost_per_token: 6e-6,
|
|
@@ -632,6 +638,30 @@ var cost_map_default = {
|
|
|
632
638
|
litellm_provider: "openai",
|
|
633
639
|
mode: "chat"
|
|
634
640
|
},
|
|
641
|
+
"gpt-5.6": {
|
|
642
|
+
input_cost_per_token: 5e-6,
|
|
643
|
+
output_cost_per_token: 3e-5,
|
|
644
|
+
litellm_provider: "openai",
|
|
645
|
+
mode: "chat"
|
|
646
|
+
},
|
|
647
|
+
"gpt-5.6-luna": {
|
|
648
|
+
input_cost_per_token: 1e-6,
|
|
649
|
+
output_cost_per_token: 6e-6,
|
|
650
|
+
litellm_provider: "openai",
|
|
651
|
+
mode: "chat"
|
|
652
|
+
},
|
|
653
|
+
"gpt-5.6-sol": {
|
|
654
|
+
input_cost_per_token: 5e-6,
|
|
655
|
+
output_cost_per_token: 3e-5,
|
|
656
|
+
litellm_provider: "openai",
|
|
657
|
+
mode: "chat"
|
|
658
|
+
},
|
|
659
|
+
"gpt-5.6-terra": {
|
|
660
|
+
input_cost_per_token: 25e-7,
|
|
661
|
+
output_cost_per_token: 15e-6,
|
|
662
|
+
litellm_provider: "openai",
|
|
663
|
+
mode: "chat"
|
|
664
|
+
},
|
|
635
665
|
"gpt-audio": {
|
|
636
666
|
input_cost_per_token: 25e-7,
|
|
637
667
|
output_cost_per_token: 1e-5,
|
|
@@ -686,6 +716,18 @@ var cost_map_default = {
|
|
|
686
716
|
litellm_provider: "openai",
|
|
687
717
|
mode: "chat"
|
|
688
718
|
},
|
|
719
|
+
"gpt-realtime-2.1": {
|
|
720
|
+
input_cost_per_token: 4e-6,
|
|
721
|
+
output_cost_per_token: 24e-6,
|
|
722
|
+
litellm_provider: "openai",
|
|
723
|
+
mode: "chat"
|
|
724
|
+
},
|
|
725
|
+
"gpt-realtime-2.1-mini": {
|
|
726
|
+
input_cost_per_token: 6e-7,
|
|
727
|
+
output_cost_per_token: 24e-7,
|
|
728
|
+
litellm_provider: "openai",
|
|
729
|
+
mode: "chat"
|
|
730
|
+
},
|
|
689
731
|
"gpt-realtime-2025-08-28": {
|
|
690
732
|
input_cost_per_token: 4e-6,
|
|
691
733
|
output_cost_per_token: 16e-6,
|
|
@@ -776,6 +818,24 @@ var cost_map_default = {
|
|
|
776
818
|
litellm_provider: "openai",
|
|
777
819
|
mode: "chat"
|
|
778
820
|
},
|
|
821
|
+
"openai/gpt-oss-120b": {
|
|
822
|
+
input_cost_per_token: 15e-8,
|
|
823
|
+
output_cost_per_token: 6e-7,
|
|
824
|
+
litellm_provider: "groq",
|
|
825
|
+
mode: "chat"
|
|
826
|
+
},
|
|
827
|
+
"openai/gpt-oss-20b": {
|
|
828
|
+
input_cost_per_token: 75e-9,
|
|
829
|
+
output_cost_per_token: 3e-7,
|
|
830
|
+
litellm_provider: "groq",
|
|
831
|
+
mode: "chat"
|
|
832
|
+
},
|
|
833
|
+
"openai/gpt-oss-safeguard-20b": {
|
|
834
|
+
input_cost_per_token: 75e-9,
|
|
835
|
+
output_cost_per_token: 3e-7,
|
|
836
|
+
litellm_provider: "groq",
|
|
837
|
+
mode: "chat"
|
|
838
|
+
},
|
|
779
839
|
"qwen/qwen3-32b": {
|
|
780
840
|
input_cost_per_token: 29e-8,
|
|
781
841
|
output_cost_per_token: 59e-8,
|
|
@@ -810,39 +870,64 @@ var cost_map_default = {
|
|
|
810
870
|
|
|
811
871
|
// src/pricing.ts
|
|
812
872
|
var COST_MAP = cost_map_default;
|
|
813
|
-
|
|
873
|
+
var PROVIDER_PREFIXES = /* @__PURE__ */ new Set(["groq"]);
|
|
874
|
+
var DATE_SUFFIX = /-(?:\d{8}|\d{4}-\d{2}-\d{2})$/;
|
|
875
|
+
function candidateGroups(model) {
|
|
814
876
|
const m = model.trim();
|
|
815
|
-
const
|
|
816
|
-
|
|
877
|
+
const base = [m];
|
|
878
|
+
const firstSlash = m.indexOf("/");
|
|
879
|
+
if (firstSlash !== -1 && PROVIDER_PREFIXES.has(m.slice(0, firstSlash))) {
|
|
880
|
+
base.push(m.slice(firstSlash + 1));
|
|
881
|
+
}
|
|
882
|
+
const lastSlash = m.lastIndexOf("/");
|
|
883
|
+
if (lastSlash !== -1) {
|
|
884
|
+
base.push(m.slice(lastSlash + 1));
|
|
885
|
+
}
|
|
886
|
+
const exact = [];
|
|
887
|
+
for (const cand of base) {
|
|
888
|
+
if (cand && !exact.includes(cand)) exact.push(cand);
|
|
889
|
+
}
|
|
890
|
+
const stripped = [];
|
|
891
|
+
for (const cand of exact) {
|
|
892
|
+
const c = cand.replace(DATE_SUFFIX, "");
|
|
893
|
+
if (c && !exact.includes(c) && !stripped.includes(c)) stripped.push(c);
|
|
894
|
+
}
|
|
895
|
+
return [exact, stripped];
|
|
817
896
|
}
|
|
818
897
|
function bothFinite(a, b) {
|
|
819
898
|
return typeof a === "number" && typeof b === "number" && Number.isFinite(a) && Number.isFinite(b);
|
|
820
899
|
}
|
|
821
900
|
function resolvePrice(model, overrides) {
|
|
822
|
-
const
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
901
|
+
for (const cands of candidateGroups(model)) {
|
|
902
|
+
if (overrides) {
|
|
903
|
+
for (const cand of cands) {
|
|
904
|
+
const ov = Object.prototype.hasOwnProperty.call(overrides, cand) ? overrides[cand] : void 0;
|
|
905
|
+
if (ov !== void 0) {
|
|
906
|
+
if (bothFinite(ov.inputCostPerToken, ov.outputCostPerToken)) {
|
|
907
|
+
return {
|
|
908
|
+
inputCostPerToken: ov.inputCostPerToken,
|
|
909
|
+
outputCostPerToken: ov.outputCostPerToken,
|
|
910
|
+
source: "override"
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
return null;
|
|
914
|
+
}
|
|
832
915
|
}
|
|
833
|
-
|
|
916
|
+
}
|
|
917
|
+
for (const cand of cands) {
|
|
918
|
+
const entry = Object.prototype.hasOwnProperty.call(COST_MAP, cand) ? COST_MAP[cand] : void 0;
|
|
919
|
+
if (!entry) continue;
|
|
920
|
+
const input = entry.input_cost_per_token;
|
|
921
|
+
const output = entry.output_cost_per_token;
|
|
922
|
+
if (!bothFinite(input, output)) return null;
|
|
923
|
+
return {
|
|
924
|
+
inputCostPerToken: input,
|
|
925
|
+
outputCostPerToken: output,
|
|
926
|
+
source: "cost_map"
|
|
927
|
+
};
|
|
834
928
|
}
|
|
835
929
|
}
|
|
836
|
-
|
|
837
|
-
if (!entry) return null;
|
|
838
|
-
const input = entry.input_cost_per_token;
|
|
839
|
-
const output = entry.output_cost_per_token;
|
|
840
|
-
if (!bothFinite(input, output)) return null;
|
|
841
|
-
return {
|
|
842
|
-
inputCostPerToken: input,
|
|
843
|
-
outputCostPerToken: output,
|
|
844
|
-
source: "cost_map"
|
|
845
|
-
};
|
|
930
|
+
return null;
|
|
846
931
|
}
|
|
847
932
|
function priceTokens(priced, promptTokens, completionTokens) {
|
|
848
933
|
const p = Math.max(0, promptTokens);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/pricing.ts","../src/cost_map.json","../src/guard.ts","../src/middleware.ts"],"sourcesContent":["/**\n * Exceptions for floe-guard.\n *\n * Everything derives from {@link FloeGuardError} (the package-root base) so callers\n * can catch the whole family with a single `catch (e) { if (e instanceof FloeGuardError) ... }`.\n *\n * Mirrors `src/floe_guard/errors.py` in the Python package — message formats are\n * kept byte-for-byte identical so both adapters read the same.\n */\n\n/** Base class for every error raised by floe-guard. */\nexport class FloeGuardError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FloeGuardError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown before an LLM call that would cross the configured spend ceiling.\n *\n * The guard throws this *instead of* letting the next call run, so a runaway loop\n * stops here rather than burning more money.\n */\nexport class BudgetExceeded extends FloeGuardError {\n readonly spentUsd: number;\n readonly limitUsd: number;\n\n constructor(spentUsd: number, limitUsd: number) {\n super(\n `BUDGET EXCEEDED — call blocked (spent $${spentUsd.toFixed(6)} of $${limitUsd.toFixed(6)} ceiling)`,\n );\n this.name = \"BudgetExceeded\";\n this.spentUsd = spentUsd;\n this.limitUsd = limitUsd;\n }\n}\n\n/**\n * Thrown when a model cannot be priced and the guard is fail-closed.\n *\n * We refuse rather than silently accrue $0 — \"we cannot cap what we cannot price\".\n * Pass a manual price (`priceOverrides` or `record(..., { price })`) to make the\n * model enforceable.\n */\nexport class UnpriceableModelError extends FloeGuardError {\n readonly model: string;\n\n constructor(model: string) {\n super(\n `Cannot price model '${model}': not in the bundled cost map and no ` +\n `manual price was given. The guard cannot enforce a budget on spend ` +\n `it cannot measure. Pass a price override to enable enforcement.`,\n );\n this.name = \"UnpriceableModelError\";\n this.model = model;\n }\n}\n","/**\n * Offline token pricing from a vendored LiteLLM cost map.\n *\n * Mirrors `src/floe_guard/pricing.py`: BOTH the input and output per-token prices\n * must be finite numbers, otherwise the model is treated as unpriceable. A\n * half-valid entry would silently undercharge — so we refuse it (fail-closed).\n *\n * No network. The cost map (`cost_map.json`) is a snapshot of LiteLLM's\n * `model_prices_and_context_window.json`; refresh it on a schedule or estimates\n * drift as vendors change prices.\n */\n\nimport costMapJson from \"./cost_map.json\";\n\n/** A user-supplied per-token price, in USD, for a model the map cannot price. */\nexport interface ManualPrice {\n inputCostPerToken: number;\n outputCostPerToken: number;\n}\n\n/** A resolved per-token price plus where it came from. */\nexport interface PricedModel {\n inputCostPerToken: number;\n outputCostPerToken: number;\n source: \"override\" | \"cost_map\";\n}\n\ninterface CostMapEntry {\n input_cost_per_token?: unknown;\n output_cost_per_token?: unknown;\n}\n\nconst COST_MAP = costMapJson as Record<string, CostMapEntry>;\n\n/** Strip an optional `provider/` prefix (LiteLLM convention, e.g. `openai/gpt-4o`). */\nfunction bareModel(model: string): string {\n const m = model.trim();\n const slash = m.lastIndexOf(\"/\");\n return slash === -1 ? m : m.slice(slash + 1);\n}\n\nfunction bothFinite(a: unknown, b: unknown): boolean {\n return (\n typeof a === \"number\" &&\n typeof b === \"number\" &&\n Number.isFinite(a) &&\n Number.isFinite(b)\n );\n}\n\n/**\n * Resolve a model to its per-token price, or `null` if it cannot be priced.\n *\n * Overrides win, then the bundled cost map (looked up by bare name, then the raw\n * field). Fail-closed: both prices must be finite, else `null`.\n */\nexport function resolvePrice(\n model: string,\n overrides?: Record<string, ManualPrice>,\n): PricedModel | null {\n const bare = bareModel(model);\n\n if (overrides) {\n const ov = overrides[bare] ?? overrides[model.trim()];\n if (ov !== undefined) {\n if (bothFinite(ov.inputCostPerToken, ov.outputCostPerToken)) {\n return {\n inputCostPerToken: ov.inputCostPerToken,\n outputCostPerToken: ov.outputCostPerToken,\n source: \"override\",\n };\n }\n return null;\n }\n }\n\n const entry = COST_MAP[bare] ?? COST_MAP[model.trim()];\n if (!entry) return null;\n\n const input = entry.input_cost_per_token;\n const output = entry.output_cost_per_token;\n if (!bothFinite(input, output)) return null;\n\n return {\n inputCostPerToken: input as number,\n outputCostPerToken: output as number,\n source: \"cost_map\",\n };\n}\n\n/** USD cost for token usage. Negative counts are clamped to zero. */\nexport function priceTokens(\n priced: PricedModel,\n promptTokens: number,\n completionTokens: number,\n): number {\n const p = Math.max(0, promptTokens);\n const c = Math.max(0, completionTokens);\n const cost = p * priced.inputCostPerToken + c * priced.outputCostPerToken;\n if (!Number.isFinite(cost)) {\n // Defense-in-depth: resolvePrice already guarantees finite rates.\n throw new Error(\"Non-finite LLM cost — pricing entry is invalid\");\n }\n return Math.max(0, cost);\n}\n","{\n \"chatgpt-4o-latest\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"claude-3-7-sonnet-20250219\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-3-haiku-20240307\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-3-opus-20240229\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-4-opus-20250514\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-4-sonnet-20250514\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-fable-5\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-haiku-4-5\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-haiku-4-5-20251001\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-1\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-1-20250805\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-20250514\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-5\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-5-20251101\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-6\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-6-20260205\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-7\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-7-20260416\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-8\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-20250514\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-5\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-5-20250929\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-6\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-0125\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-0613\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-1106\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4-0613\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-2025-04-14\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000012,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-mini-2025-04-14\": {\n \"input_cost_per_token\": 8e-7,\n \"output_cost_per_token\": 0.0000032,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-nano-2025-04-14\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 8e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-2024-08-06\": {\n \"input_cost_per_token\": 0.00000375,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-2024-11-20\": {\n \"input_cost_per_token\": 0.00000375,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-mini-2024-07-18\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000012,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:o4-mini-2025-04-16\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo\": {\n \"input_cost_per_token\": 5e-7,\n \"output_cost_per_token\": 0.0000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-0125\": {\n \"input_cost_per_token\": 5e-7,\n \"output_cost_per_token\": 0.0000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-1106\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-16k\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000004,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0125-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0314\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0613\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-1106-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo-2024-04-09\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-2025-04-14\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-mini\": {\n \"input_cost_per_token\": 4e-7,\n \"output_cost_per_token\": 0.0000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-mini-2025-04-14\": {\n \"input_cost_per_token\": 4e-7,\n \"output_cost_per_token\": 0.0000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-nano\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-nano-2025-04-14\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-05-13\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-08-06\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-11-20\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview-2024-12-17\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview-2025-06-03\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-2024-07-18\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-audio-preview\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-audio-preview-2024-12-17\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-realtime-preview\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-realtime-preview-2024-12-17\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-search-preview\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-search-preview-2025-03-11\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-realtime-preview\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-realtime-preview-2024-12-17\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-realtime-preview-2025-06-03\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-search-preview\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-search-preview-2025-03-11\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-2025-08-07\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-chat\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-chat-latest\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-mini\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-mini-2025-08-07\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-nano\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-nano-2025-08-07\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-search-api\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-search-api-2025-10-14\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1-2025-11-13\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1-chat-latest\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2-2025-12-11\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2-chat-latest\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.3-chat-latest\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-2026-03-05\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-mini\": {\n \"input_cost_per_token\": 7.5e-7,\n \"output_cost_per_token\": 0.0000045,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-mini-2026-03-17\": {\n \"input_cost_per_token\": 7.5e-7,\n \"output_cost_per_token\": 0.0000045,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-nano\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-nano-2026-03-17\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.5\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.5-2026-04-23\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-1.5\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-2025-08-28\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini-2025-10-06\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini-2025-12-15\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-1.5\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-2\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-2025-08-28\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-mini\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-mini-2025-10-06\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-mini-2025-12-15\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"llama-3.1-8b-instant\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 8e-8,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"llama-3.3-70b-versatile\": {\n \"input_cost_per_token\": 5.9e-7,\n \"output_cost_per_token\": 7.9e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"meta-llama/llama-4-scout-17b-16e-instruct\": {\n \"input_cost_per_token\": 1.1e-7,\n \"output_cost_per_token\": 3.4e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"o1\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o1-2024-12-17\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-2025-04-16\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-mini\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-mini-2025-01-31\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o4-mini\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o4-mini-2025-04-16\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"qwen/qwen3-32b\": {\n \"input_cost_per_token\": 2.9e-7,\n \"output_cost_per_token\": 5.9e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"text-embedding-3-large\": {\n \"input_cost_per_token\": 1.3e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-3-small\": {\n \"input_cost_per_token\": 2e-8,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-ada-002\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-ada-002-v2\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n }\n}\n","/**\n * The local, in-process budget guard.\n *\n * `BudgetGuard` is a kill-switch that lives in the LLM call path. The contract:\n *\n * 1. Call {@link BudgetGuard.check} BEFORE every LLM call. If the *next* call\n * would cross the ceiling, it throws {@link BudgetExceeded} and the call never\n * runs.\n * 2. Call {@link BudgetGuard.record} AFTER every response, with the token usage.\n * It prices the tokens offline and accrues the USD into a running total.\n *\n * **Concurrency.** `check()` then `record()` is a check-then-act with an `await`\n * in between. Fire several model calls at once (e.g. `Promise.all`) and they all\n * `check()` against the same under-limit total before any `record()` lands, so\n * the ceiling is blown (see issue #18). {@link BudgetGuard.reserve} /\n * {@link BudgetGuard.settle} close that gap: `reserve()` holds the estimated cost\n * in flight (synchronously, before the await), so parallel callers each take\n * their own slice of the ceiling. JS is single-threaded, so an in-flight counter\n * is enough — no lock needed. The middleware uses it; `check`/`record` are\n * unchanged.\n *\n * This is a faithful port of `src/floe_guard/guard.py` — same prediction logic,\n * same epsilon handling, same fail-closed default.\n */\n\nimport { BudgetExceeded, UnpriceableModelError } from \"./errors.js\";\nimport {\n type ManualPrice,\n priceTokens,\n resolvePrice,\n} from \"./pricing.js\";\n\n/** Tolerance for float rounding in the running spend total (well below $0.000001). */\nconst EPS = 1e-12;\n\nexport interface BudgetGuardOptions {\n /** Per-model manual prices for models the bundled cost map cannot price. */\n priceOverrides?: Record<string, ManualPrice>;\n /**\n * When `true` (default), recording an unpriceable model without a manual price\n * warns loudly AND throws {@link UnpriceableModelError}. When `false`, it warns\n * and skips accrual (you have opted into un-enforced spend for that model).\n */\n failClosed?: boolean;\n /**\n * Optional callback invoked with `(spentUsd, limitUsd)` right before\n * {@link BudgetExceeded} is thrown. Defaults to printing the\n * `BUDGET EXCEEDED — call blocked` banner to stderr.\n */\n onBlock?: (spentUsd: number, limitUsd: number) => void;\n /**\n * Utilization (basis points, 0..10000) at which {@link BudgetGuard.advisory}\n * flags `nearLimit` so an agent can taper before the hard-stop. Default 8000.\n */\n nearLimitBps?: number;\n}\n\n/**\n * A context-aware spend signal for the single local budget.\n *\n * Mirrors the core fields of hosted Floe's `X-Floe-Budget-Advisory` header, so\n * agent logic that reads it (taper as you approach the cap, stop at it) ports\n * unchanged to the hosted path. Hosted adds what a local, single-budget guard\n * cannot know: which of several caps is tightest (`scope` across\n * `credit_line | session | task | api | vendor`), cross-vendor reasoning,\n * server-truth balances, and rolling-window reset timing.\n *\n * This is a **soft** signal — the model may ignore it. The hard-stop\n * ({@link BudgetGuard.check}) is what enforces the ceiling; the advisory is\n * upside (let the agent finish on budget rather than be cut off).\n */\nexport interface BudgetAdvisory {\n nearLimit: boolean;\n /** Utilization in basis points, 0..10000 (8500 = 85%). */\n usedBps: number;\n remainingUsd: number;\n limitUsd: number;\n spentUsd: number;\n /** Hosted reports the tightest cap across all scopes; local is always \"local\". */\n scope: \"local\";\n}\n\nexport class BudgetGuard {\n readonly limitUsd: number;\n spentUsd = 0;\n priceOverrides?: Record<string, ManualPrice>;\n failClosed: boolean;\n nearLimitBps: number;\n\n private readonly onBlock: (spentUsd: number, limitUsd: number) => void;\n /** Cost of the most recent priced call, used to predict the next one. */\n private lastCost = 0;\n /** USD held for in-flight calls (reserved, not yet settled). Counts toward the ceiling. */\n private reserved = 0;\n\n /**\n * @param limitUsd the spend ceiling, in USD. `0` blocks the very first call.\n */\n constructor(limitUsd: number, options: BudgetGuardOptions = {}) {\n if (!Number.isFinite(limitUsd) || limitUsd < 0) {\n // NaN/Infinity would make every check() comparison fail-open, silently\n // disabling the guard — reject them up front.\n throw new RangeError(\n `limitUsd must be a finite, non-negative number, got ${limitUsd}`,\n );\n }\n // `=== undefined` (not `??`) so an explicit null is rejected by validation\n // rather than silently defaulting — matches Python, which rejects None.\n const nearLimitBps = options.nearLimitBps === undefined ? 8000 : options.nearLimitBps;\n if (!Number.isInteger(nearLimitBps) || nearLimitBps < 0 || nearLimitBps > 10000) {\n throw new RangeError(\n `nearLimitBps must be an integer in 0..10000, got ${nearLimitBps}`,\n );\n }\n this.limitUsd = limitUsd;\n this.priceOverrides = options.priceOverrides;\n this.failClosed = options.failClosed ?? true;\n this.onBlock = options.onBlock ?? defaultOnBlock;\n this.nearLimitBps = nearLimitBps;\n }\n\n /**\n * Throw {@link BudgetExceeded} if the next call would cross the ceiling.\n *\n * Call this immediately before each LLM request. The \"next call\" is estimated\n * from the last recorded call's cost (override with `estimatedNextCost`); the\n * first call is always allowed unless the ceiling is already met. In-flight\n * reservations count toward the total, so this stays correct alongside\n * {@link BudgetGuard.reserve}.\n *\n * Note: `check` is a non-binding peek. For parallel calls, use `reserve()` /\n * `settle()`, which hold the estimate across the await.\n */\n check(estimatedNextCost?: number): void {\n const rawEstimate =\n estimatedNextCost === undefined ? this.lastCost : estimatedNextCost;\n if (!Number.isFinite(rawEstimate)) {\n // NaN/Infinity would poison the comparisons and fail-open — reject it\n // (parity with the constructor's Number.isFinite guard).\n throw new RangeError(\n `estimatedNextCost must be a finite number, got ${rawEstimate}`,\n );\n }\n const estimate = Math.max(0, rawEstimate);\n const committed = this.spentUsd + this.reserved;\n if (committed > this.limitUsd - EPS || committed + estimate > this.limitUsd + EPS) {\n this.onBlock(this.spentUsd, this.limitUsd);\n throw new BudgetExceeded(this.spentUsd, this.limitUsd);\n }\n }\n\n /**\n * Atomically check the ceiling AND hold the estimated cost in flight.\n *\n * The concurrency-safe enforcement path: call before the request and hold the\n * returned reservation across the await, so parallel callers can't all clear\n * the same stale total. Throws {@link BudgetExceeded} (without reserving) if\n * the reservation would cross the ceiling. Returns the reservation handle to\n * pass to {@link BudgetGuard.settle} (or {@link BudgetGuard.release} on error).\n * `estimatedCost` defaults to the last call's cost.\n */\n reserve(estimatedCost?: number): number {\n const rawEstimate = estimatedCost === undefined ? this.lastCost : estimatedCost;\n if (!Number.isFinite(rawEstimate)) {\n // NaN would poison this.reserved and fail-open the ceiling — reject it.\n throw new RangeError(\n `estimatedCost must be a finite number, got ${rawEstimate}`,\n );\n }\n const estimate = Math.max(0, rawEstimate);\n const committed = this.spentUsd + this.reserved;\n if (committed > this.limitUsd - EPS || committed + estimate > this.limitUsd + EPS) {\n this.onBlock(this.spentUsd, this.limitUsd);\n throw new BudgetExceeded(this.spentUsd, this.limitUsd);\n }\n this.reserved += estimate;\n return estimate;\n }\n\n /**\n * Release a reservation and record the actual cost. `record` is `settle` with\n * no reservation. Returns the USD cost of this call; unpriceable-model handling\n * matches {@link BudgetGuard.record}, and any held reservation is released even\n * on the warn-and-skip path.\n */\n settle(\n model: string,\n promptTokens: number,\n completionTokens: number,\n options: { reserved?: number; price?: ManualPrice } = {},\n ): number {\n const reserved = options.reserved ?? 0;\n // A bad reserved handle would corrupt this.reserved and break the ceiling for\n // OTHER in-flight calls (negative → phantom hold; Infinity → clears all holds).\n if (!Number.isFinite(reserved) || reserved < 0) {\n throw new RangeError(`reserved must be a finite, non-negative number, got ${reserved}`);\n }\n let overrides = this.priceOverrides;\n if (options.price !== undefined) {\n overrides = { ...(overrides ?? {}), [model]: options.price };\n }\n\n const priced = resolvePrice(model, overrides);\n if (priced === null) {\n console.warn(\n `Cannot price model '${model}': not in the bundled cost map and no ` +\n `manual price given. The budget guard cannot enforce a ceiling on ` +\n `spend it cannot measure — pass { price } or set it in priceOverrides.`,\n );\n // Release any held reservation on BOTH paths. Fail-closed must not leak\n // the in-flight hold, or reserved grows permanently and remainingUsd\n // shrinks until reserve() starts blocking everything.\n this.release(reserved);\n if (this.failClosed) {\n throw new UnpriceableModelError(model);\n }\n return 0;\n }\n\n let cost: number;\n try {\n cost = priceTokens(priced, promptTokens, completionTokens);\n } catch (err) {\n // priceTokens can throw (e.g. non-finite costs). Release the in-flight\n // hold before re-throwing so `reserved` doesn't leak and shrink\n // remainingUsd permanently — same fail-safe as the unpriceable path above.\n this.release(reserved);\n throw err;\n }\n if (reserved) {\n this.reserved = Math.max(0, this.reserved - reserved);\n }\n this.spentUsd += cost;\n // Clamp a sub-epsilon float overshoot back to the limit so the running total\n // never reports as having crossed the ceiling by a rounding artifact.\n if (this.spentUsd - this.limitUsd > 0 && this.spentUsd - this.limitUsd < EPS) {\n this.spentUsd = this.limitUsd;\n }\n this.lastCost = cost;\n return cost;\n }\n\n /**\n * Price one response's tokens offline and add the cost to the total.\n *\n * Returns the USD cost of this call. If the model is unpriceable and no `price`\n * is given, behaviour depends on `failClosed`: warn + throw (default), or\n * warn + skip accrual.\n */\n record(\n model: string,\n promptTokens: number,\n completionTokens: number,\n options: { price?: ManualPrice } = {},\n ): number {\n return this.settle(model, promptTokens, completionTokens, {\n reserved: 0,\n price: options.price,\n });\n }\n\n /**\n * Drop an in-flight reservation without recording spend (e.g. the call failed\n * before producing usage). Safe to call with `0`.\n */\n release(reserved: number): void {\n // Validate before the zero-check so a NaN handle throws instead of being\n // silently dropped (a leak); a bad handle corrupts the in-flight tally.\n if (!Number.isFinite(reserved) || reserved < 0) {\n throw new RangeError(`reserved must be a finite, non-negative number, got ${reserved}`);\n }\n if (!reserved) return;\n this.reserved = Math.max(0, this.reserved - reserved);\n }\n\n /** USD left before the ceiling, net of in-flight reservations (never negative). */\n get remainingUsd(): number {\n return Math.max(0, this.limitUsd - this.spentUsd - this.reserved);\n }\n\n /**\n * Context-aware spend advisory for this budget — see {@link BudgetAdvisory}.\n *\n * `nearLimit` flips once utilization reaches `nearLimitBps` (default 80%), so an\n * agent can taper *before* the hard-stop. Advisory only: read it to adapt;\n * {@link BudgetGuard.check} is what enforces the ceiling.\n */\n advisory(): BudgetAdvisory {\n // Floor (not round) so usedBps never over-reports utilization and nearLimit\n // flips exactly when the threshold is reached; the epsilon absorbs float noise\n // and Math.floor matches Python's int() exactly (round() would diverge).\n const usedBps =\n this.limitUsd <= 0\n ? 10000\n : Math.max(0, Math.min(10000, Math.floor((this.spentUsd / this.limitUsd) * 10000 + 1e-9)));\n return {\n nearLimit: usedBps >= this.nearLimitBps,\n usedBps,\n // Settled budget: limit minus accrued spend, deliberately NOT net of\n // in-flight reservations. Unlike the remainingUsd getter (which subtracts\n // `reserved`), the advisory is a soft utilization signal about money already\n // spent, while the getter reports what a new call can still claim.\n remainingUsd: Math.max(0, this.limitUsd - this.spentUsd),\n limitUsd: this.limitUsd,\n spentUsd: this.spentUsd,\n scope: \"local\",\n };\n }\n}\n\nfunction defaultOnBlock(spentUsd: number, limitUsd: number): void {\n console.error(\n \"BUDGET EXCEEDED — call blocked\\n\" +\n ` spent so far: $${spentUsd.toFixed(6)} | ceiling: $${limitUsd.toFixed(6)}\\n` +\n \" The next call would cross your budget; floe-guard stopped your agent \" +\n \"before it ran.\",\n );\n}\n","/**\n * Vercel AI SDK middleware that enforces a {@link BudgetGuard} in the call path.\n *\n * This is the TypeScript counterpart to the Python framework adapters. The AI SDK\n * is TypeScript-only, so it ships as its own npm package.\n *\n * Works with BOTH `ai@4` (`LanguageModelV1Middleware`) and `ai@5`\n * (`LanguageModelV2Middleware`). The two majors renamed the middleware type and\n * the usage fields (`promptTokens`/`completionTokens` → `inputTokens`/\n * `outputTokens`), so this module deliberately imports nothing from `ai`: the\n * middleware is typed structurally against the surface both majors share, and\n * usage is read from whichever field pair the installed SDK reports.\n *\n * - `wrapGenerate({ doGenerate, model })` — we `reserve()` (throws to hard-stop)\n * BEFORE calling `doGenerate()`, hold the reservation across the await, then\n * `settle()` from `result.usage`.\n * - `wrapStream({ doStream, model })` — we `reserve()` BEFORE `doStream()`, then\n * `settle()` from the `finish` part as the stream drains.\n *\n * Reserving before the await is what makes parallel calls (`Promise.all` over\n * several generations) honour the ceiling: each holds its slice instead of all\n * reading the same stale total (issue #18). The reservation is released if the\n * call throws, or if a stream ends without reporting usage.\n *\n * The model id used for pricing comes from `model.modelId`.\n */\n\nimport type { BudgetGuard } from \"./guard.js\";\n\n/**\n * The middleware call surface shared by `ai@4` and `ai@5`. Both majors invoke\n * `wrapGenerate`/`wrapStream` with an options object carrying these members\n * (plus richer `model` fields we don't read). `doGenerate`/`doStream` are\n * declared optional so every 4.x/5.x minor's options type stays assignable —\n * the SDK always provides the one each hook actually calls.\n */\ninterface MiddlewareCallOptions {\n doGenerate?: () => PromiseLike<any>;\n doStream?: () => PromiseLike<any>;\n model: { modelId: string };\n params?: unknown;\n}\n\n/**\n * Structural stand-in for `LanguageModelV1Middleware` (ai@4) and\n * `LanguageModelV2Middleware` (ai@5) — assignable to the `middleware` option of\n * `wrapLanguageModel` on either major.\n */\nexport interface BudgetGuardMiddleware {\n wrapGenerate: (options: MiddlewareCallOptions) => Promise<any>;\n wrapStream: (options: MiddlewareCallOptions) => Promise<any>;\n}\n\n/**\n * Read prompt/completion token counts from an ai@4 usage object\n * (`promptTokens`/`completionTokens`) or an ai@5 one (`inputTokens`/\n * `outputTokens`). Throws when either count is missing or non-numeric: the guard\n * cannot meter spend it cannot see, and treating it as $0 would fail open.\n */\nfunction usageTokens(\n modelId: string,\n usage: unknown,\n): { promptTokens: number; completionTokens: number } {\n const u = usage as\n | {\n promptTokens?: unknown;\n completionTokens?: unknown;\n inputTokens?: unknown;\n outputTokens?: unknown;\n }\n | null\n | undefined;\n const promptTokens = u?.promptTokens ?? u?.inputTokens;\n const completionTokens = u?.completionTokens ?? u?.outputTokens;\n if (typeof promptTokens !== \"number\" || typeof completionTokens !== \"number\") {\n throw new Error(\n `Model '${modelId}' reported no token usage — the budget guard cannot ` +\n `meter spend it cannot see, so this call is rejected rather than ` +\n `treated as free.`,\n );\n }\n return { promptTokens, completionTokens };\n}\n\n/**\n * Build a budget-guard middleware that hard-stops the model before a call\n * crosses the guard's USD ceiling, and records priced token usage after.\n * Compatible with `wrapLanguageModel` from both `ai@4` and `ai@5`.\n *\n * @example\n * import { wrapLanguageModel } from \"ai\";\n * import { openai } from \"@ai-sdk/openai\";\n * import { BudgetGuard, budgetGuardMiddleware } from \"floe-guard\";\n *\n * const guard = new BudgetGuard(5.00);\n * const model = wrapLanguageModel({\n * model: openai(\"gpt-4o\"),\n * middleware: budgetGuardMiddleware(guard),\n * });\n */\nexport function budgetGuardMiddleware(guard: BudgetGuard): BudgetGuardMiddleware {\n return {\n async wrapGenerate({ doGenerate, model }) {\n const reserved = guard.reserve(); // throws BudgetExceeded before the call runs\n let result: any;\n try {\n result = await doGenerate!();\n } catch (err) {\n guard.release(reserved); // the call failed before settle() took ownership\n throw err;\n }\n // From here settle() OWNS the reservation: it releases the hold on its own\n // throw (unpriceable / non-finite cost) and consumes it on success. Releasing\n // again would double-subtract and clear a concurrent call's in-flight hold.\n let handled = false;\n try {\n const { promptTokens, completionTokens } = usageTokens(\n model.modelId,\n result?.usage,\n );\n handled = true;\n guard.settle(model.modelId, promptTokens, completionTokens, { reserved });\n return result;\n } catch (err) {\n if (!handled) guard.release(reserved); // failed reading usage, before settle()\n throw err;\n }\n },\n\n async wrapStream({ doStream, model }) {\n const reserved = guard.reserve(); // throws BudgetExceeded before the stream starts\n let streamResult: any;\n try {\n streamResult = await doStream!();\n } catch (err) {\n guard.release(reserved); // the call failed before settle() took ownership\n throw err;\n }\n const { stream, ...rest } = streamResult as {\n stream: ReadableStream<any>;\n } & Record<string, unknown>;\n\n // `handled` flips once the reservation is disposed — settled on the finish\n // part, or released exactly once if the stream produced no usage (flush) or\n // ended early via error/cancellation (cancel). settle() owns disposal once\n // called, so nothing else may release after `handled` is set, or we'd\n // double-subtract and clear a concurrent call's hold.\n let handled = false;\n const guarded = stream.pipeThrough(\n new TransformStream<any, any>({\n transform(chunk, controller) {\n if (chunk?.type === \"finish\" && !handled) {\n try {\n const { promptTokens, completionTokens } = usageTokens(\n model.modelId,\n chunk.usage,\n );\n handled = true;\n guard.settle(model.modelId, promptTokens, completionTokens, { reserved });\n } catch (err) {\n // Release only if we never reached settle() (e.g. usage missing).\n // If settle() itself threw, it already released its own hold.\n if (!handled) {\n handled = true;\n guard.release(reserved);\n }\n throw err;\n }\n }\n controller.enqueue(chunk);\n },\n flush() {\n // Clean close with no finish/usage part — free the held budget.\n if (!handled) {\n handled = true;\n guard.release(reserved);\n }\n },\n cancel() {\n // Upstream error or consumer cancellation: flush() does not run here\n // (Web Streams: flush and cancel are mutually exclusive), so release\n // the still-held reservation.\n if (!handled) {\n handled = true;\n guard.release(reserved);\n }\n },\n // `cancel` is valid per the Streams spec and supported in Node 18+, but\n // TS's Transformer lib type lags and omits it — cast to keep the type check.\n } as Transformer<any, any>),\n );\n\n return { stream: guarded, ...rest };\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/pricing.ts","../src/cost_map.json","../src/guard.ts","../src/middleware.ts"],"sourcesContent":["/**\n * Exceptions for floe-guard.\n *\n * Everything derives from {@link FloeGuardError} (the package-root base) so callers\n * can catch the whole family with a single `catch (e) { if (e instanceof FloeGuardError) ... }`.\n *\n * Mirrors `src/floe_guard/errors.py` in the Python package — message formats are\n * kept byte-for-byte identical so both adapters read the same.\n */\n\n/** Base class for every error raised by floe-guard. */\nexport class FloeGuardError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FloeGuardError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown before an LLM call that would cross the configured spend ceiling.\n *\n * The guard throws this *instead of* letting the next call run, so a runaway loop\n * stops here rather than burning more money.\n */\nexport class BudgetExceeded extends FloeGuardError {\n readonly spentUsd: number;\n readonly limitUsd: number;\n\n constructor(spentUsd: number, limitUsd: number) {\n super(\n `BUDGET EXCEEDED — call blocked (spent $${spentUsd.toFixed(6)} of $${limitUsd.toFixed(6)} ceiling)`,\n );\n this.name = \"BudgetExceeded\";\n this.spentUsd = spentUsd;\n this.limitUsd = limitUsd;\n }\n}\n\n/**\n * Thrown when a model cannot be priced and the guard is fail-closed.\n *\n * We refuse rather than silently accrue $0 — \"we cannot cap what we cannot price\".\n * Pass a manual price (`priceOverrides` or `record(..., { price })`) to make the\n * model enforceable.\n */\nexport class UnpriceableModelError extends FloeGuardError {\n readonly model: string;\n\n constructor(model: string) {\n super(\n `Cannot price model '${model}': not in the bundled cost map and no ` +\n `manual price was given. The guard cannot enforce a budget on spend ` +\n `it cannot measure. Pass a price override to enable enforcement.`,\n );\n this.name = \"UnpriceableModelError\";\n this.model = model;\n }\n}\n","/**\n * Offline token pricing from a vendored LiteLLM cost map.\n *\n * Mirrors `src/floe_guard/pricing.py`: BOTH the input and output per-token prices\n * must be finite numbers, otherwise the model is treated as unpriceable. A\n * half-valid entry would silently undercharge — so we refuse it (fail-closed).\n *\n * No network. The cost map (`cost_map.json`) is a snapshot of LiteLLM's\n * `model_prices_and_context_window.json`; refresh it on a schedule or estimates\n * drift as vendors change prices.\n */\n\nimport costMapJson from \"./cost_map.json\";\n\n/** A user-supplied per-token price, in USD, for a model the map cannot price. */\nexport interface ManualPrice {\n inputCostPerToken: number;\n outputCostPerToken: number;\n}\n\n/** A resolved per-token price plus where it came from. */\nexport interface PricedModel {\n inputCostPerToken: number;\n outputCostPerToken: number;\n source: \"override\" | \"cost_map\";\n}\n\ninterface CostMapEntry {\n input_cost_per_token?: unknown;\n output_cost_per_token?: unknown;\n}\n\nconst COST_MAP = costMapJson as Record<string, CostMapEntry>;\n\n/**\n * The one `<provider>/` prefix that is safe to strip: the remainder of a\n * `groq/…` id is the ChatGroq id the map vendors (e.g. `groq/qwen/qwen3-32b` →\n * `qwen/qwen3-32b`). `openai/` and `anthropic/` are deliberately excluded:\n * their own model ids never contain slashes (single-segment remainders are\n * already covered by the bare-last-segment fallback), so a multi-segment\n * remainder under those prefixes is some OTHER vendor's model behind an\n * OpenAI-compatible endpoint (vLLM, OpenRouter, …) — bridging it into a\n * Groq-priced key would under-meter. Unknown prefixes fail closed the same way.\n */\nconst PROVIDER_PREFIXES = new Set([\"groq\"]);\n\n/**\n * A trailing dated-snapshot suffix: Anthropic's `-20250929` or OpenAI's\n * `-2024-08-06`. Vendors resolve alias ids to dated snapshots in responses, so a\n * snapshot the map doesn't list yet prices at its alias entry (same model, same\n * rate) instead of failing closed. (`\\d` is ASCII-only in JS; the Python regex\n * uses re.ASCII to match.)\n */\nconst DATE_SUFFIX = /-(?:\\d{8}|\\d{4}-\\d{2}-\\d{2})$/;\n\n/**\n * Lookup keys for a model id in two specificity groups, deduplicated.\n *\n * Group 1 (exact): the raw id, the id with a known `provider/` first segment\n * stripped, the bare last segment. Group 2 (date-stripped): the same forms\n * with a trailing dated-snapshot suffix removed. Kept separate so a\n * less-specific date-stripped key (in overrides OR the map) can never shadow\n * an exact dated entry — e.g. an alias override must not absorb a snapshot\n * the map prices differently.\n */\nfunction candidateGroups(model: string): [string[], string[]] {\n const m = model.trim();\n const base = [m];\n const firstSlash = m.indexOf(\"/\");\n if (firstSlash !== -1 && PROVIDER_PREFIXES.has(m.slice(0, firstSlash))) {\n base.push(m.slice(firstSlash + 1));\n }\n const lastSlash = m.lastIndexOf(\"/\");\n if (lastSlash !== -1) {\n base.push(m.slice(lastSlash + 1));\n }\n const exact: string[] = [];\n for (const cand of base) {\n if (cand && !exact.includes(cand)) exact.push(cand);\n }\n const stripped: string[] = [];\n for (const cand of exact) {\n const c = cand.replace(DATE_SUFFIX, \"\");\n if (c && !exact.includes(c) && !stripped.includes(c)) stripped.push(c);\n }\n return [exact, stripped];\n}\n\nfunction bothFinite(a: unknown, b: unknown): boolean {\n return (\n typeof a === \"number\" &&\n typeof b === \"number\" &&\n Number.isFinite(a) &&\n Number.isFinite(b)\n );\n}\n\n/**\n * Resolve a model to its per-token price, or `null` if it cannot be priced.\n *\n * Per specificity group (exact forms first, date-stripped fallbacks second):\n * overrides win, then the bundled cost map. Fail-closed: the first matching\n * entry must have finite prices, else `null`.\n */\nexport function resolvePrice(\n model: string,\n overrides?: Record<string, ManualPrice>,\n): PricedModel | null {\n for (const cands of candidateGroups(model)) {\n if (overrides) {\n for (const cand of cands) {\n // Own-property check so a key like \"constructor\" can't pull a function\n // off Object.prototype and be treated as a price entry.\n const ov = Object.prototype.hasOwnProperty.call(overrides, cand)\n ? overrides[cand]\n : undefined;\n if (ov !== undefined) {\n if (bothFinite(ov.inputCostPerToken, ov.outputCostPerToken)) {\n return {\n inputCostPerToken: ov.inputCostPerToken,\n outputCostPerToken: ov.outputCostPerToken,\n source: \"override\",\n };\n }\n return null;\n }\n }\n }\n\n for (const cand of cands) {\n const entry = Object.prototype.hasOwnProperty.call(COST_MAP, cand)\n ? COST_MAP[cand]\n : undefined;\n if (!entry) continue;\n\n const input = entry.input_cost_per_token;\n const output = entry.output_cost_per_token;\n if (!bothFinite(input, output)) return null;\n\n return {\n inputCostPerToken: input as number,\n outputCostPerToken: output as number,\n source: \"cost_map\",\n };\n }\n }\n return null;\n}\n\n/** USD cost for token usage. Negative counts are clamped to zero. */\nexport function priceTokens(\n priced: PricedModel,\n promptTokens: number,\n completionTokens: number,\n): number {\n const p = Math.max(0, promptTokens);\n const c = Math.max(0, completionTokens);\n const cost = p * priced.inputCostPerToken + c * priced.outputCostPerToken;\n if (!Number.isFinite(cost)) {\n // Defense-in-depth: resolvePrice already guarantees finite rates.\n throw new Error(\"Non-finite LLM cost — pricing entry is invalid\");\n }\n return Math.max(0, cost);\n}\n","{\n \"chatgpt-4o-latest\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"claude-3-7-sonnet-20250219\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-3-haiku-20240307\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-3-opus-20240229\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-4-opus-20250514\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-4-sonnet-20250514\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-fable-5\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-haiku-4-5\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-haiku-4-5-20251001\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000005,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-1\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-1-20250805\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-20250514\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.000075,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-5\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-5-20251101\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-6\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-6-20260205\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-7\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-7-20260416\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-opus-4-8\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000025,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-20250514\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-5\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-5-20250929\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-4-6\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"claude-sonnet-5\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"anthropic\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-0125\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-0613\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-3.5-turbo-1106\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4-0613\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-2025-04-14\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000012,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-mini-2025-04-14\": {\n \"input_cost_per_token\": 8e-7,\n \"output_cost_per_token\": 0.0000032,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4.1-nano-2025-04-14\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 8e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-2024-08-06\": {\n \"input_cost_per_token\": 0.00000375,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-2024-11-20\": {\n \"input_cost_per_token\": 0.00000375,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:gpt-4o-mini-2024-07-18\": {\n \"input_cost_per_token\": 3e-7,\n \"output_cost_per_token\": 0.0000012,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"ft:o4-mini-2025-04-16\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo\": {\n \"input_cost_per_token\": 5e-7,\n \"output_cost_per_token\": 0.0000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-0125\": {\n \"input_cost_per_token\": 5e-7,\n \"output_cost_per_token\": 0.0000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-1106\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-3.5-turbo-16k\": {\n \"input_cost_per_token\": 0.000003,\n \"output_cost_per_token\": 0.000004,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0125-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0314\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-0613\": {\n \"input_cost_per_token\": 0.00003,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-1106-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo-2024-04-09\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4-turbo-preview\": {\n \"input_cost_per_token\": 0.00001,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-2025-04-14\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-mini\": {\n \"input_cost_per_token\": 4e-7,\n \"output_cost_per_token\": 0.0000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-mini-2025-04-14\": {\n \"input_cost_per_token\": 4e-7,\n \"output_cost_per_token\": 0.0000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-nano\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4.1-nano-2025-04-14\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-05-13\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-08-06\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-2024-11-20\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview-2024-12-17\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-audio-preview-2025-06-03\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-2024-07-18\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-audio-preview\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-audio-preview-2024-12-17\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-realtime-preview\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-realtime-preview-2024-12-17\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-search-preview\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-mini-search-preview-2025-03-11\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-realtime-preview\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-realtime-preview-2024-12-17\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-realtime-preview-2025-06-03\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-search-preview\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-4o-search-preview-2025-03-11\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-2025-08-07\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-chat\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-chat-latest\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-mini\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-mini-2025-08-07\": {\n \"input_cost_per_token\": 2.5e-7,\n \"output_cost_per_token\": 0.000002,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-nano\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-nano-2025-08-07\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 4e-7,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-search-api\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5-search-api-2025-10-14\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1-2025-11-13\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.1-chat-latest\": {\n \"input_cost_per_token\": 0.00000125,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2-2025-12-11\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.2-chat-latest\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.3-chat-latest\": {\n \"input_cost_per_token\": 0.00000175,\n \"output_cost_per_token\": 0.000014,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-2026-03-05\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-mini\": {\n \"input_cost_per_token\": 7.5e-7,\n \"output_cost_per_token\": 0.0000045,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-mini-2026-03-17\": {\n \"input_cost_per_token\": 7.5e-7,\n \"output_cost_per_token\": 0.0000045,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-nano\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.4-nano-2026-03-17\": {\n \"input_cost_per_token\": 2e-7,\n \"output_cost_per_token\": 0.00000125,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.5\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.5-2026-04-23\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.6\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.6-luna\": {\n \"input_cost_per_token\": 0.000001,\n \"output_cost_per_token\": 0.000006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.6-sol\": {\n \"input_cost_per_token\": 0.000005,\n \"output_cost_per_token\": 0.00003,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-5.6-terra\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.000015,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-1.5\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-2025-08-28\": {\n \"input_cost_per_token\": 0.0000025,\n \"output_cost_per_token\": 0.00001,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini-2025-10-06\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-audio-mini-2025-12-15\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-1.5\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-2\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-2.1\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-2.1-mini\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-2025-08-28\": {\n \"input_cost_per_token\": 0.000004,\n \"output_cost_per_token\": 0.000016,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-mini\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-mini-2025-10-06\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"gpt-realtime-mini-2025-12-15\": {\n \"input_cost_per_token\": 6e-7,\n \"output_cost_per_token\": 0.0000024,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"llama-3.1-8b-instant\": {\n \"input_cost_per_token\": 5e-8,\n \"output_cost_per_token\": 8e-8,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"llama-3.3-70b-versatile\": {\n \"input_cost_per_token\": 5.9e-7,\n \"output_cost_per_token\": 7.9e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"meta-llama/llama-4-scout-17b-16e-instruct\": {\n \"input_cost_per_token\": 1.1e-7,\n \"output_cost_per_token\": 3.4e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"o1\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o1-2024-12-17\": {\n \"input_cost_per_token\": 0.000015,\n \"output_cost_per_token\": 0.00006,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-2025-04-16\": {\n \"input_cost_per_token\": 0.000002,\n \"output_cost_per_token\": 0.000008,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-mini\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o3-mini-2025-01-31\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o4-mini\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"o4-mini-2025-04-16\": {\n \"input_cost_per_token\": 0.0000011,\n \"output_cost_per_token\": 0.0000044,\n \"litellm_provider\": \"openai\",\n \"mode\": \"chat\"\n },\n \"openai/gpt-oss-120b\": {\n \"input_cost_per_token\": 1.5e-7,\n \"output_cost_per_token\": 6e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"openai/gpt-oss-20b\": {\n \"input_cost_per_token\": 7.5e-8,\n \"output_cost_per_token\": 3e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"openai/gpt-oss-safeguard-20b\": {\n \"input_cost_per_token\": 7.5e-8,\n \"output_cost_per_token\": 3e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"qwen/qwen3-32b\": {\n \"input_cost_per_token\": 2.9e-7,\n \"output_cost_per_token\": 5.9e-7,\n \"litellm_provider\": \"groq\",\n \"mode\": \"chat\"\n },\n \"text-embedding-3-large\": {\n \"input_cost_per_token\": 1.3e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-3-small\": {\n \"input_cost_per_token\": 2e-8,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-ada-002\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n },\n \"text-embedding-ada-002-v2\": {\n \"input_cost_per_token\": 1e-7,\n \"output_cost_per_token\": 0,\n \"litellm_provider\": \"openai\",\n \"mode\": \"embedding\"\n }\n}\n","/**\n * The local, in-process budget guard.\n *\n * `BudgetGuard` is a kill-switch that lives in the LLM call path. The contract:\n *\n * 1. Call {@link BudgetGuard.check} BEFORE every LLM call. If the *next* call\n * would cross the ceiling, it throws {@link BudgetExceeded} and the call never\n * runs.\n * 2. Call {@link BudgetGuard.record} AFTER every response, with the token usage.\n * It prices the tokens offline and accrues the USD into a running total.\n *\n * **Concurrency.** `check()` then `record()` is a check-then-act with an `await`\n * in between. Fire several model calls at once (e.g. `Promise.all`) and they all\n * `check()` against the same under-limit total before any `record()` lands, so\n * the ceiling is blown (see issue #18). {@link BudgetGuard.reserve} /\n * {@link BudgetGuard.settle} close that gap: `reserve()` holds the estimated cost\n * in flight (synchronously, before the await), so parallel callers each take\n * their own slice of the ceiling. JS is single-threaded, so an in-flight counter\n * is enough — no lock needed. The middleware uses it; `check`/`record` are\n * unchanged.\n *\n * This is a faithful port of `src/floe_guard/guard.py` — same prediction logic,\n * same epsilon handling, same fail-closed default.\n */\n\nimport { BudgetExceeded, UnpriceableModelError } from \"./errors.js\";\nimport {\n type ManualPrice,\n priceTokens,\n resolvePrice,\n} from \"./pricing.js\";\n\n/** Tolerance for float rounding in the running spend total (well below $0.000001). */\nconst EPS = 1e-12;\n\nexport interface BudgetGuardOptions {\n /** Per-model manual prices for models the bundled cost map cannot price. */\n priceOverrides?: Record<string, ManualPrice>;\n /**\n * When `true` (default), recording an unpriceable model without a manual price\n * warns loudly AND throws {@link UnpriceableModelError}. When `false`, it warns\n * and skips accrual (you have opted into un-enforced spend for that model).\n */\n failClosed?: boolean;\n /**\n * Optional callback invoked with `(spentUsd, limitUsd)` right before\n * {@link BudgetExceeded} is thrown. Defaults to printing the\n * `BUDGET EXCEEDED — call blocked` banner to stderr.\n */\n onBlock?: (spentUsd: number, limitUsd: number) => void;\n /**\n * Utilization (basis points, 0..10000) at which {@link BudgetGuard.advisory}\n * flags `nearLimit` so an agent can taper before the hard-stop. Default 8000.\n */\n nearLimitBps?: number;\n}\n\n/**\n * A context-aware spend signal for the single local budget.\n *\n * Mirrors the core fields of hosted Floe's `X-Floe-Budget-Advisory` header, so\n * agent logic that reads it (taper as you approach the cap, stop at it) ports\n * unchanged to the hosted path. Hosted adds what a local, single-budget guard\n * cannot know: which of several caps is tightest (`scope` across\n * `credit_line | session | task | api | vendor`), cross-vendor reasoning,\n * server-truth balances, and rolling-window reset timing.\n *\n * This is a **soft** signal — the model may ignore it. The hard-stop\n * ({@link BudgetGuard.check}) is what enforces the ceiling; the advisory is\n * upside (let the agent finish on budget rather than be cut off).\n */\nexport interface BudgetAdvisory {\n nearLimit: boolean;\n /** Utilization in basis points, 0..10000 (8500 = 85%). */\n usedBps: number;\n remainingUsd: number;\n limitUsd: number;\n spentUsd: number;\n /** Hosted reports the tightest cap across all scopes; local is always \"local\". */\n scope: \"local\";\n}\n\nexport class BudgetGuard {\n readonly limitUsd: number;\n spentUsd = 0;\n priceOverrides?: Record<string, ManualPrice>;\n failClosed: boolean;\n nearLimitBps: number;\n\n private readonly onBlock: (spentUsd: number, limitUsd: number) => void;\n /** Cost of the most recent priced call, used to predict the next one. */\n private lastCost = 0;\n /** USD held for in-flight calls (reserved, not yet settled). Counts toward the ceiling. */\n private reserved = 0;\n\n /**\n * @param limitUsd the spend ceiling, in USD. `0` blocks the very first call.\n */\n constructor(limitUsd: number, options: BudgetGuardOptions = {}) {\n if (!Number.isFinite(limitUsd) || limitUsd < 0) {\n // NaN/Infinity would make every check() comparison fail-open, silently\n // disabling the guard — reject them up front.\n throw new RangeError(\n `limitUsd must be a finite, non-negative number, got ${limitUsd}`,\n );\n }\n // `=== undefined` (not `??`) so an explicit null is rejected by validation\n // rather than silently defaulting — matches Python, which rejects None.\n const nearLimitBps = options.nearLimitBps === undefined ? 8000 : options.nearLimitBps;\n if (!Number.isInteger(nearLimitBps) || nearLimitBps < 0 || nearLimitBps > 10000) {\n throw new RangeError(\n `nearLimitBps must be an integer in 0..10000, got ${nearLimitBps}`,\n );\n }\n this.limitUsd = limitUsd;\n this.priceOverrides = options.priceOverrides;\n this.failClosed = options.failClosed ?? true;\n this.onBlock = options.onBlock ?? defaultOnBlock;\n this.nearLimitBps = nearLimitBps;\n }\n\n /**\n * Throw {@link BudgetExceeded} if the next call would cross the ceiling.\n *\n * Call this immediately before each LLM request. The \"next call\" is estimated\n * from the last recorded call's cost (override with `estimatedNextCost`); the\n * first call is always allowed unless the ceiling is already met. In-flight\n * reservations count toward the total, so this stays correct alongside\n * {@link BudgetGuard.reserve}.\n *\n * Note: `check` is a non-binding peek. For parallel calls, use `reserve()` /\n * `settle()`, which hold the estimate across the await.\n */\n check(estimatedNextCost?: number): void {\n const rawEstimate =\n estimatedNextCost === undefined ? this.lastCost : estimatedNextCost;\n if (!Number.isFinite(rawEstimate)) {\n // NaN/Infinity would poison the comparisons and fail-open — reject it\n // (parity with the constructor's Number.isFinite guard).\n throw new RangeError(\n `estimatedNextCost must be a finite number, got ${rawEstimate}`,\n );\n }\n const estimate = Math.max(0, rawEstimate);\n const committed = this.spentUsd + this.reserved;\n if (committed > this.limitUsd - EPS || committed + estimate > this.limitUsd + EPS) {\n this.onBlock(this.spentUsd, this.limitUsd);\n throw new BudgetExceeded(this.spentUsd, this.limitUsd);\n }\n }\n\n /**\n * Atomically check the ceiling AND hold the estimated cost in flight.\n *\n * The concurrency-safe enforcement path: call before the request and hold the\n * returned reservation across the await, so parallel callers can't all clear\n * the same stale total. Throws {@link BudgetExceeded} (without reserving) if\n * the reservation would cross the ceiling. Returns the reservation handle to\n * pass to {@link BudgetGuard.settle} (or {@link BudgetGuard.release} on error).\n * `estimatedCost` defaults to the last call's cost.\n */\n reserve(estimatedCost?: number): number {\n const rawEstimate = estimatedCost === undefined ? this.lastCost : estimatedCost;\n if (!Number.isFinite(rawEstimate)) {\n // NaN would poison this.reserved and fail-open the ceiling — reject it.\n throw new RangeError(\n `estimatedCost must be a finite number, got ${rawEstimate}`,\n );\n }\n const estimate = Math.max(0, rawEstimate);\n const committed = this.spentUsd + this.reserved;\n if (committed > this.limitUsd - EPS || committed + estimate > this.limitUsd + EPS) {\n this.onBlock(this.spentUsd, this.limitUsd);\n throw new BudgetExceeded(this.spentUsd, this.limitUsd);\n }\n this.reserved += estimate;\n return estimate;\n }\n\n /**\n * Release a reservation and record the actual cost. `record` is `settle` with\n * no reservation. Returns the USD cost of this call; unpriceable-model handling\n * matches {@link BudgetGuard.record}, and any held reservation is released even\n * on the warn-and-skip path.\n */\n settle(\n model: string,\n promptTokens: number,\n completionTokens: number,\n options: { reserved?: number; price?: ManualPrice } = {},\n ): number {\n const reserved = options.reserved ?? 0;\n // A bad reserved handle would corrupt this.reserved and break the ceiling for\n // OTHER in-flight calls (negative → phantom hold; Infinity → clears all holds).\n if (!Number.isFinite(reserved) || reserved < 0) {\n throw new RangeError(`reserved must be a finite, non-negative number, got ${reserved}`);\n }\n let overrides = this.priceOverrides;\n if (options.price !== undefined) {\n overrides = { ...(overrides ?? {}), [model]: options.price };\n }\n\n const priced = resolvePrice(model, overrides);\n if (priced === null) {\n console.warn(\n `Cannot price model '${model}': not in the bundled cost map and no ` +\n `manual price given. The budget guard cannot enforce a ceiling on ` +\n `spend it cannot measure — pass { price } or set it in priceOverrides.`,\n );\n // Release any held reservation on BOTH paths. Fail-closed must not leak\n // the in-flight hold, or reserved grows permanently and remainingUsd\n // shrinks until reserve() starts blocking everything.\n this.release(reserved);\n if (this.failClosed) {\n throw new UnpriceableModelError(model);\n }\n return 0;\n }\n\n let cost: number;\n try {\n cost = priceTokens(priced, promptTokens, completionTokens);\n } catch (err) {\n // priceTokens can throw (e.g. non-finite costs). Release the in-flight\n // hold before re-throwing so `reserved` doesn't leak and shrink\n // remainingUsd permanently — same fail-safe as the unpriceable path above.\n this.release(reserved);\n throw err;\n }\n if (reserved) {\n this.reserved = Math.max(0, this.reserved - reserved);\n }\n this.spentUsd += cost;\n // Clamp a sub-epsilon float overshoot back to the limit so the running total\n // never reports as having crossed the ceiling by a rounding artifact.\n if (this.spentUsd - this.limitUsd > 0 && this.spentUsd - this.limitUsd < EPS) {\n this.spentUsd = this.limitUsd;\n }\n this.lastCost = cost;\n return cost;\n }\n\n /**\n * Price one response's tokens offline and add the cost to the total.\n *\n * Returns the USD cost of this call. If the model is unpriceable and no `price`\n * is given, behaviour depends on `failClosed`: warn + throw (default), or\n * warn + skip accrual.\n */\n record(\n model: string,\n promptTokens: number,\n completionTokens: number,\n options: { price?: ManualPrice } = {},\n ): number {\n return this.settle(model, promptTokens, completionTokens, {\n reserved: 0,\n price: options.price,\n });\n }\n\n /**\n * Drop an in-flight reservation without recording spend (e.g. the call failed\n * before producing usage). Safe to call with `0`.\n */\n release(reserved: number): void {\n // Validate before the zero-check so a NaN handle throws instead of being\n // silently dropped (a leak); a bad handle corrupts the in-flight tally.\n if (!Number.isFinite(reserved) || reserved < 0) {\n throw new RangeError(`reserved must be a finite, non-negative number, got ${reserved}`);\n }\n if (!reserved) return;\n this.reserved = Math.max(0, this.reserved - reserved);\n }\n\n /** USD left before the ceiling, net of in-flight reservations (never negative). */\n get remainingUsd(): number {\n return Math.max(0, this.limitUsd - this.spentUsd - this.reserved);\n }\n\n /**\n * Context-aware spend advisory for this budget — see {@link BudgetAdvisory}.\n *\n * `nearLimit` flips once utilization reaches `nearLimitBps` (default 80%), so an\n * agent can taper *before* the hard-stop. Advisory only: read it to adapt;\n * {@link BudgetGuard.check} is what enforces the ceiling.\n */\n advisory(): BudgetAdvisory {\n // Floor (not round) so usedBps never over-reports utilization and nearLimit\n // flips exactly when the threshold is reached; the epsilon absorbs float noise\n // and Math.floor matches Python's int() exactly (round() would diverge).\n const usedBps =\n this.limitUsd <= 0\n ? 10000\n : Math.max(0, Math.min(10000, Math.floor((this.spentUsd / this.limitUsd) * 10000 + 1e-9)));\n return {\n nearLimit: usedBps >= this.nearLimitBps,\n usedBps,\n // Settled budget: limit minus accrued spend, deliberately NOT net of\n // in-flight reservations. Unlike the remainingUsd getter (which subtracts\n // `reserved`), the advisory is a soft utilization signal about money already\n // spent, while the getter reports what a new call can still claim.\n remainingUsd: Math.max(0, this.limitUsd - this.spentUsd),\n limitUsd: this.limitUsd,\n spentUsd: this.spentUsd,\n scope: \"local\",\n };\n }\n}\n\nfunction defaultOnBlock(spentUsd: number, limitUsd: number): void {\n console.error(\n \"BUDGET EXCEEDED — call blocked\\n\" +\n ` spent so far: $${spentUsd.toFixed(6)} | ceiling: $${limitUsd.toFixed(6)}\\n` +\n \" The next call would cross your budget; floe-guard stopped your agent \" +\n \"before it ran.\",\n );\n}\n","/**\n * Vercel AI SDK middleware that enforces a {@link BudgetGuard} in the call path.\n *\n * This is the TypeScript counterpart to the Python framework adapters. The AI SDK\n * is TypeScript-only, so it ships as its own npm package.\n *\n * Works with BOTH `ai@4` (`LanguageModelV1Middleware`) and `ai@5`\n * (`LanguageModelV2Middleware`). The two majors renamed the middleware type and\n * the usage fields (`promptTokens`/`completionTokens` → `inputTokens`/\n * `outputTokens`), so this module deliberately imports nothing from `ai`: the\n * middleware is typed structurally against the surface both majors share, and\n * usage is read from whichever field pair the installed SDK reports.\n *\n * - `wrapGenerate({ doGenerate, model })` — we `reserve()` (throws to hard-stop)\n * BEFORE calling `doGenerate()`, hold the reservation across the await, then\n * `settle()` from `result.usage`.\n * - `wrapStream({ doStream, model })` — we `reserve()` BEFORE `doStream()`, then\n * `settle()` from the `finish` part as the stream drains.\n *\n * Reserving before the await is what makes parallel calls (`Promise.all` over\n * several generations) honour the ceiling: each holds its slice instead of all\n * reading the same stale total (issue #18). The reservation is released if the\n * call throws, or if a stream ends without reporting usage.\n *\n * The model id used for pricing comes from `model.modelId`.\n */\n\nimport type { BudgetGuard } from \"./guard.js\";\n\n/**\n * The middleware call surface shared by `ai@4` and `ai@5`. Both majors invoke\n * `wrapGenerate`/`wrapStream` with an options object carrying these members\n * (plus richer `model` fields we don't read). `doGenerate`/`doStream` are\n * declared optional so every 4.x/5.x minor's options type stays assignable —\n * the SDK always provides the one each hook actually calls.\n */\ninterface MiddlewareCallOptions {\n doGenerate?: () => PromiseLike<any>;\n doStream?: () => PromiseLike<any>;\n model: { modelId: string };\n params?: unknown;\n}\n\n/**\n * Structural stand-in for `LanguageModelV1Middleware` (ai@4) and\n * `LanguageModelV2Middleware` (ai@5) — assignable to the `middleware` option of\n * `wrapLanguageModel` on either major.\n */\nexport interface BudgetGuardMiddleware {\n wrapGenerate: (options: MiddlewareCallOptions) => Promise<any>;\n wrapStream: (options: MiddlewareCallOptions) => Promise<any>;\n}\n\n/**\n * Read prompt/completion token counts from an ai@4 usage object\n * (`promptTokens`/`completionTokens`) or an ai@5 one (`inputTokens`/\n * `outputTokens`). Throws when either count is missing or non-numeric: the guard\n * cannot meter spend it cannot see, and treating it as $0 would fail open.\n */\nfunction usageTokens(\n modelId: string,\n usage: unknown,\n): { promptTokens: number; completionTokens: number } {\n const u = usage as\n | {\n promptTokens?: unknown;\n completionTokens?: unknown;\n inputTokens?: unknown;\n outputTokens?: unknown;\n }\n | null\n | undefined;\n const promptTokens = u?.promptTokens ?? u?.inputTokens;\n const completionTokens = u?.completionTokens ?? u?.outputTokens;\n if (typeof promptTokens !== \"number\" || typeof completionTokens !== \"number\") {\n throw new Error(\n `Model '${modelId}' reported no token usage — the budget guard cannot ` +\n `meter spend it cannot see, so this call is rejected rather than ` +\n `treated as free.`,\n );\n }\n return { promptTokens, completionTokens };\n}\n\n/**\n * Build a budget-guard middleware that hard-stops the model before a call\n * crosses the guard's USD ceiling, and records priced token usage after.\n * Compatible with `wrapLanguageModel` from both `ai@4` and `ai@5`.\n *\n * @example\n * import { wrapLanguageModel } from \"ai\";\n * import { openai } from \"@ai-sdk/openai\";\n * import { BudgetGuard, budgetGuardMiddleware } from \"floe-guard\";\n *\n * const guard = new BudgetGuard(5.00);\n * const model = wrapLanguageModel({\n * model: openai(\"gpt-4o\"),\n * middleware: budgetGuardMiddleware(guard),\n * });\n */\nexport function budgetGuardMiddleware(guard: BudgetGuard): BudgetGuardMiddleware {\n return {\n async wrapGenerate({ doGenerate, model }) {\n const reserved = guard.reserve(); // throws BudgetExceeded before the call runs\n let result: any;\n try {\n result = await doGenerate!();\n } catch (err) {\n guard.release(reserved); // the call failed before settle() took ownership\n throw err;\n }\n // From here settle() OWNS the reservation: it releases the hold on its own\n // throw (unpriceable / non-finite cost) and consumes it on success. Releasing\n // again would double-subtract and clear a concurrent call's in-flight hold.\n let handled = false;\n try {\n const { promptTokens, completionTokens } = usageTokens(\n model.modelId,\n result?.usage,\n );\n handled = true;\n guard.settle(model.modelId, promptTokens, completionTokens, { reserved });\n return result;\n } catch (err) {\n if (!handled) guard.release(reserved); // failed reading usage, before settle()\n throw err;\n }\n },\n\n async wrapStream({ doStream, model }) {\n const reserved = guard.reserve(); // throws BudgetExceeded before the stream starts\n let streamResult: any;\n try {\n streamResult = await doStream!();\n } catch (err) {\n guard.release(reserved); // the call failed before settle() took ownership\n throw err;\n }\n const { stream, ...rest } = streamResult as {\n stream: ReadableStream<any>;\n } & Record<string, unknown>;\n\n // `handled` flips once the reservation is disposed — settled on the finish\n // part, or released exactly once if the stream produced no usage (flush) or\n // ended early via error/cancellation (cancel). settle() owns disposal once\n // called, so nothing else may release after `handled` is set, or we'd\n // double-subtract and clear a concurrent call's hold.\n let handled = false;\n const guarded = stream.pipeThrough(\n new TransformStream<any, any>({\n transform(chunk, controller) {\n if (chunk?.type === \"finish\" && !handled) {\n try {\n const { promptTokens, completionTokens } = usageTokens(\n model.modelId,\n chunk.usage,\n );\n handled = true;\n guard.settle(model.modelId, promptTokens, completionTokens, { reserved });\n } catch (err) {\n // Release only if we never reached settle() (e.g. usage missing).\n // If settle() itself threw, it already released its own hold.\n if (!handled) {\n handled = true;\n guard.release(reserved);\n }\n throw err;\n }\n }\n controller.enqueue(chunk);\n },\n flush() {\n // Clean close with no finish/usage part — free the held budget.\n if (!handled) {\n handled = true;\n guard.release(reserved);\n }\n },\n cancel() {\n // Upstream error or consumer cancellation: flush() does not run here\n // (Web Streams: flush and cancel are mutually exclusive), so release\n // the still-held reservation.\n if (!handled) {\n handled = true;\n guard.release(reserved);\n }\n },\n // `cancel` is valid per the Streams spec and supported in Node 18+, but\n // TS's Transformer lib type lags and omits it — cast to keep the type check.\n } as Transformer<any, any>),\n );\n\n return { stream: guarded, ...rest };\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
package/src/cost_map.json
CHANGED
|
@@ -137,6 +137,12 @@
|
|
|
137
137
|
"litellm_provider": "anthropic",
|
|
138
138
|
"mode": "chat"
|
|
139
139
|
},
|
|
140
|
+
"claude-sonnet-5": {
|
|
141
|
+
"input_cost_per_token": 0.000002,
|
|
142
|
+
"output_cost_per_token": 0.00001,
|
|
143
|
+
"litellm_provider": "anthropic",
|
|
144
|
+
"mode": "chat"
|
|
145
|
+
},
|
|
140
146
|
"ft:gpt-3.5-turbo": {
|
|
141
147
|
"input_cost_per_token": 0.000003,
|
|
142
148
|
"output_cost_per_token": 0.000006,
|
|
@@ -587,6 +593,30 @@
|
|
|
587
593
|
"litellm_provider": "openai",
|
|
588
594
|
"mode": "chat"
|
|
589
595
|
},
|
|
596
|
+
"gpt-5.6": {
|
|
597
|
+
"input_cost_per_token": 0.000005,
|
|
598
|
+
"output_cost_per_token": 0.00003,
|
|
599
|
+
"litellm_provider": "openai",
|
|
600
|
+
"mode": "chat"
|
|
601
|
+
},
|
|
602
|
+
"gpt-5.6-luna": {
|
|
603
|
+
"input_cost_per_token": 0.000001,
|
|
604
|
+
"output_cost_per_token": 0.000006,
|
|
605
|
+
"litellm_provider": "openai",
|
|
606
|
+
"mode": "chat"
|
|
607
|
+
},
|
|
608
|
+
"gpt-5.6-sol": {
|
|
609
|
+
"input_cost_per_token": 0.000005,
|
|
610
|
+
"output_cost_per_token": 0.00003,
|
|
611
|
+
"litellm_provider": "openai",
|
|
612
|
+
"mode": "chat"
|
|
613
|
+
},
|
|
614
|
+
"gpt-5.6-terra": {
|
|
615
|
+
"input_cost_per_token": 0.0000025,
|
|
616
|
+
"output_cost_per_token": 0.000015,
|
|
617
|
+
"litellm_provider": "openai",
|
|
618
|
+
"mode": "chat"
|
|
619
|
+
},
|
|
590
620
|
"gpt-audio": {
|
|
591
621
|
"input_cost_per_token": 0.0000025,
|
|
592
622
|
"output_cost_per_token": 0.00001,
|
|
@@ -641,6 +671,18 @@
|
|
|
641
671
|
"litellm_provider": "openai",
|
|
642
672
|
"mode": "chat"
|
|
643
673
|
},
|
|
674
|
+
"gpt-realtime-2.1": {
|
|
675
|
+
"input_cost_per_token": 0.000004,
|
|
676
|
+
"output_cost_per_token": 0.000024,
|
|
677
|
+
"litellm_provider": "openai",
|
|
678
|
+
"mode": "chat"
|
|
679
|
+
},
|
|
680
|
+
"gpt-realtime-2.1-mini": {
|
|
681
|
+
"input_cost_per_token": 6e-7,
|
|
682
|
+
"output_cost_per_token": 0.0000024,
|
|
683
|
+
"litellm_provider": "openai",
|
|
684
|
+
"mode": "chat"
|
|
685
|
+
},
|
|
644
686
|
"gpt-realtime-2025-08-28": {
|
|
645
687
|
"input_cost_per_token": 0.000004,
|
|
646
688
|
"output_cost_per_token": 0.000016,
|
|
@@ -731,6 +773,24 @@
|
|
|
731
773
|
"litellm_provider": "openai",
|
|
732
774
|
"mode": "chat"
|
|
733
775
|
},
|
|
776
|
+
"openai/gpt-oss-120b": {
|
|
777
|
+
"input_cost_per_token": 1.5e-7,
|
|
778
|
+
"output_cost_per_token": 6e-7,
|
|
779
|
+
"litellm_provider": "groq",
|
|
780
|
+
"mode": "chat"
|
|
781
|
+
},
|
|
782
|
+
"openai/gpt-oss-20b": {
|
|
783
|
+
"input_cost_per_token": 7.5e-8,
|
|
784
|
+
"output_cost_per_token": 3e-7,
|
|
785
|
+
"litellm_provider": "groq",
|
|
786
|
+
"mode": "chat"
|
|
787
|
+
},
|
|
788
|
+
"openai/gpt-oss-safeguard-20b": {
|
|
789
|
+
"input_cost_per_token": 7.5e-8,
|
|
790
|
+
"output_cost_per_token": 3e-7,
|
|
791
|
+
"litellm_provider": "groq",
|
|
792
|
+
"mode": "chat"
|
|
793
|
+
},
|
|
734
794
|
"qwen/qwen3-32b": {
|
|
735
795
|
"input_cost_per_token": 2.9e-7,
|
|
736
796
|
"output_cost_per_token": 5.9e-7,
|