@routerlab/core
Advanced tools
| import { type UsageTokens } from "@tokenometer/core"; | ||
| import type { ModelCandidate, RouteDecision, RouteRequest } from "./types.ts"; | ||
| export type BudgetState = "ok" | "warn" | "exhausted"; | ||
| export type BudgetStepSource = "actual" | "estimated"; | ||
| export interface BudgetAwareRouterOptions { | ||
| maxBudgetUsd: number; | ||
| /** Fraction of budget at which routing enters warn/degraded mode. Default 0.8. */ | ||
| warnAt?: number; | ||
| /** Optional lower quality bar used once the chain reaches warnAt. */ | ||
| degradedQualityBar?: number; | ||
| } | ||
| export interface BudgetStepRecord { | ||
| source: BudgetStepSource; | ||
| model: ModelCandidate; | ||
| totalUsd: number; | ||
| inputUsd: number; | ||
| cachedInputUsd: number; | ||
| outputUsd: number; | ||
| usage?: UsageTokens; | ||
| } | ||
| export interface BudgetSnapshot { | ||
| maxBudgetUsd: number; | ||
| spentUsd: number; | ||
| remainingUsd: number; | ||
| percentUsed: number; | ||
| state: BudgetState; | ||
| steps: BudgetStepRecord[]; | ||
| } | ||
| export interface BudgetRouteStepRequest extends Omit<RouteRequest, "maxCostUsd"> { | ||
| /** Optional per-step cap. The effective cap is min(remaining budget, this value). */ | ||
| maxStepCostUsd?: number; | ||
| } | ||
| export interface BudgetRouteStepResult { | ||
| decision: RouteDecision; | ||
| snapshotBefore: BudgetSnapshot; | ||
| effectiveQualityBar: number; | ||
| maxCostUsd: number; | ||
| } | ||
| export interface RecordActualUsageInput { | ||
| model: ModelCandidate; | ||
| usage: UsageTokens; | ||
| } | ||
| export declare class BudgetAwareRouter { | ||
| readonly maxBudgetUsd: number; | ||
| readonly warnAt: number; | ||
| readonly degradedQualityBar?: number; | ||
| private spentUsd; | ||
| private steps; | ||
| constructor(options: BudgetAwareRouterOptions); | ||
| routeStep(request: BudgetRouteStepRequest): BudgetRouteStepResult; | ||
| recordActualUsage(input: RecordActualUsageInput): BudgetStepRecord; | ||
| recordEstimatedStep(decision: RouteDecision): BudgetStepRecord; | ||
| getSnapshot(): BudgetSnapshot; | ||
| reset(): void; | ||
| private record; | ||
| } | ||
| //# sourceMappingURL=budget-router.d.ts.map |
| {"version":3,"file":"budget-router.d.ts","sourceRoot":"","sources":["../src/budget-router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEjE,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE9E,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,MAAM,GAAG,WAAW,CAAC;AACtD,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEtD,MAAM,WAAW,wBAAwB;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,gBAAgB,CAAC;IACzB,KAAK,EAAE,cAAc,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC;IAC9E,qFAAqF;IACrF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,aAAa,CAAC;IACxB,cAAc,EAAE,cAAc,CAAC;IAC/B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,EAAE,WAAW,CAAC;CACpB;AAgBD,qBAAa,iBAAiB;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,KAAK,CAA0B;gBAE3B,OAAO,EAAE,wBAAwB;IAsB7C,SAAS,CAAC,OAAO,EAAE,sBAAsB,GAAG,qBAAqB;IAwBjE,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,gBAAgB;IAmBlE,mBAAmB,CAAC,QAAQ,EAAE,aAAa,GAAG,gBAAgB;IAW9D,WAAW,IAAI,cAAc;IAgB7B,KAAK,IAAI,IAAI;IAKb,OAAO,CAAC,MAAM;CAMf"} |
| import { priceUsage } from "@tokenometer/core"; | ||
| import { route } from "./router.js"; | ||
| const DEFAULT_WARN_AT = 0.8; | ||
| const assertNonNegativeFinite = (field, value) => { | ||
| if (!Number.isFinite(value) || value < 0) { | ||
| throw new Error(`BudgetAwareRouter: ${field} must be a non-negative finite number`); | ||
| } | ||
| }; | ||
| const cloneStep = (step) => ({ | ||
| ...step, | ||
| model: { ...step.model, pricing: { ...step.model.pricing } }, | ||
| ...(step.usage !== undefined ? { usage: { ...step.usage } } : {}), | ||
| }); | ||
| export class BudgetAwareRouter { | ||
| maxBudgetUsd; | ||
| warnAt; | ||
| degradedQualityBar; | ||
| spentUsd = 0; | ||
| steps = []; | ||
| constructor(options) { | ||
| assertNonNegativeFinite("maxBudgetUsd", options.maxBudgetUsd); | ||
| if (options.maxBudgetUsd === 0) { | ||
| throw new Error("BudgetAwareRouter: maxBudgetUsd must be greater than 0"); | ||
| } | ||
| this.maxBudgetUsd = options.maxBudgetUsd; | ||
| this.warnAt = options.warnAt ?? DEFAULT_WARN_AT; | ||
| if (!Number.isFinite(this.warnAt) || this.warnAt < 0 || this.warnAt > 1) { | ||
| throw new Error("BudgetAwareRouter: warnAt must be in [0, 1]"); | ||
| } | ||
| if (options.degradedQualityBar !== undefined) { | ||
| if (!Number.isFinite(options.degradedQualityBar) || | ||
| options.degradedQualityBar < 0 || | ||
| options.degradedQualityBar > 1) { | ||
| throw new Error("BudgetAwareRouter: degradedQualityBar must be in [0, 1]"); | ||
| } | ||
| this.degradedQualityBar = options.degradedQualityBar; | ||
| } | ||
| } | ||
| routeStep(request) { | ||
| const snapshotBefore = this.getSnapshot(); | ||
| if (snapshotBefore.remainingUsd <= 0) { | ||
| throw new Error("BudgetAwareRouter: budget is exhausted"); | ||
| } | ||
| const effectiveQualityBar = snapshotBefore.state === "warn" && this.degradedQualityBar !== undefined | ||
| ? Math.min(request.qualityBar, this.degradedQualityBar) | ||
| : request.qualityBar; | ||
| const maxCostUsd = request.maxStepCostUsd !== undefined | ||
| ? Math.min(snapshotBefore.remainingUsd, request.maxStepCostUsd) | ||
| : snapshotBefore.remainingUsd; | ||
| const decision = route({ | ||
| ...request, | ||
| maxCostUsd, | ||
| qualityBar: effectiveQualityBar, | ||
| }); | ||
| return { decision, effectiveQualityBar, maxCostUsd, snapshotBefore }; | ||
| } | ||
| recordActualUsage(input) { | ||
| const priced = priceUsage({ | ||
| pricing: { | ||
| inputUsdPerMtok: input.model.pricing.inputUsdPerMtok, | ||
| outputUsdPerMtok: input.model.pricing.outputUsdPerMtok, | ||
| }, | ||
| usage: input.usage, | ||
| }); | ||
| return this.record({ | ||
| cachedInputUsd: priced.cachedInputUsd, | ||
| inputUsd: priced.inputUsd, | ||
| model: input.model, | ||
| outputUsd: priced.outputUsd, | ||
| source: "actual", | ||
| totalUsd: priced.totalUsd, | ||
| usage: input.usage, | ||
| }); | ||
| } | ||
| recordEstimatedStep(decision) { | ||
| return this.record({ | ||
| cachedInputUsd: 0, | ||
| inputUsd: decision.chosen.expectedCost, | ||
| model: decision.chosen.model, | ||
| outputUsd: 0, | ||
| source: "estimated", | ||
| totalUsd: decision.chosen.expectedCost, | ||
| }); | ||
| } | ||
| getSnapshot() { | ||
| const remainingUsd = this.maxBudgetUsd - this.spentUsd; | ||
| const percentUsed = this.spentUsd / this.maxBudgetUsd; | ||
| let state = "ok"; | ||
| if (remainingUsd <= 0) | ||
| state = "exhausted"; | ||
| else if (percentUsed >= this.warnAt) | ||
| state = "warn"; | ||
| return { | ||
| maxBudgetUsd: this.maxBudgetUsd, | ||
| percentUsed, | ||
| remainingUsd, | ||
| spentUsd: this.spentUsd, | ||
| state, | ||
| steps: this.steps.map(cloneStep), | ||
| }; | ||
| } | ||
| reset() { | ||
| this.spentUsd = 0; | ||
| this.steps = []; | ||
| } | ||
| record(step) { | ||
| const cloned = cloneStep(step); | ||
| this.steps.push(cloned); | ||
| this.spentUsd += cloned.totalUsd; | ||
| return cloneStep(cloned); | ||
| } | ||
| } | ||
| //# sourceMappingURL=budget-router.js.map |
| {"version":3,"file":"budget-router.js","sourceRoot":"","sources":["../src/budget-router.ts"],"names":[],"mappings":"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"} |
+2
-0
| export declare const version: string; | ||
| export { route, getDefaultCandidates } from "./router.ts"; | ||
| export { BudgetAwareRouter } from "./budget-router.ts"; | ||
| export type { BudgetAwareRouterOptions, BudgetRouteStepRequest, BudgetRouteStepResult, BudgetSnapshot, BudgetState, BudgetStepRecord, BudgetStepSource, RecordActualUsageInput, } from "./budget-router.ts"; | ||
| export { __resetQualityCacheForTest, getQualitySourceInfo, PRIOR_N, predictQuality, predictQualityWithCI, wilsonScore95, } from "./quality_predictor.ts"; | ||
@@ -4,0 +6,0 @@ export type { QualityWithCI } from "./quality_predictor.ts"; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,OAAO,QAAuB,CAAC;AAE5C,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAM1D,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,EACpB,OAAO,EACP,cAAc,EACd,oBAAoB,EACpB,aAAa,GACd,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,YAAY,EACV,cAAc,EACd,YAAY,EACZ,QAAQ,EACR,aAAa,EACb,aAAa,EACb,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,SAAS,GACV,MAAM,YAAY,CAAC;AAOpB,OAAO,EACL,mBAAmB,EACnB,8BAA8B,EAC9B,YAAY,EACZ,iBAAiB,GAClB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,UAAU,EACV,YAAY,EACZ,qBAAqB,EACrB,SAAS,EACT,WAAW,EACX,YAAY,EACZ,WAAW,GACZ,MAAM,WAAW,CAAC"} | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,OAAO,QAAuB,CAAC;AAE5C,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,YAAY,EACV,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAM5B,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,EACpB,OAAO,EACP,cAAc,EACd,oBAAoB,EACpB,aAAa,GACd,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,YAAY,EACV,cAAc,EACd,YAAY,EACZ,QAAQ,EACR,aAAa,EACb,aAAa,EACb,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,SAAS,GACV,MAAM,YAAY,CAAC;AAOpB,OAAO,EACL,mBAAmB,EACnB,8BAA8B,EAC9B,YAAY,EACZ,iBAAiB,GAClB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,UAAU,EACV,YAAY,EACZ,qBAAqB,EACrB,SAAS,EACT,WAAW,EACX,YAAY,EACZ,WAAW,GACZ,MAAM,WAAW,CAAC"} |
+1
-0
@@ -16,2 +16,3 @@ // @routerlab/core — public entrypoint. | ||
| export { route, getDefaultCandidates } from "./router.js"; | ||
| export { BudgetAwareRouter } from "./budget-router.js"; | ||
| // Quality predictor: serves measured eval data when present, falls | ||
@@ -18,0 +19,0 @@ // back to the seeded prior table from `quality_prior.ts` otherwise. |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,EAAE;AACF,uEAAuE;AACvE,gEAAgE;AAChE,sEAAsE;AACtE,iEAAiE;AACjE,mEAAmE;AAEnE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,SAAS,kBAAkB;IACzB,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,MAAM,CAAC,CAAyB,CAAC;IAC7F,OAAO,WAAW,CAAC,OAAO,IAAI,OAAO,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;AAE5C,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAE1D,mEAAmE;AACnE,oEAAoE;AACpE,qEAAqE;AACrE,sEAAsE;AACtE,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,EACpB,OAAO,EACP,cAAc,EACd,oBAAoB,EACpB,aAAa,GACd,MAAM,wBAAwB,CAAC;AAehC,mEAAmE;AACnE,6EAA6E;AAC7E,0EAA0E;AAC1E,yEAAyE;AACzE,wCAAwC;AACxC,OAAO,EACL,mBAAmB,EACnB,8BAA8B,EAC9B,YAAY,EACZ,iBAAiB,GAClB,MAAM,WAAW,CAAC"} | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,EAAE;AACF,uEAAuE;AACvE,gEAAgE;AAChE,sEAAsE;AACtE,iEAAiE;AACjE,mEAAmE;AAEnE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,SAAS,kBAAkB;IACzB,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,MAAM,CAAC,CAAyB,CAAC;IAC7F,OAAO,WAAW,CAAC,OAAO,IAAI,OAAO,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;AAE5C,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAYvD,mEAAmE;AACnE,oEAAoE;AACpE,qEAAqE;AACrE,sEAAsE;AACtE,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,EACpB,OAAO,EACP,cAAc,EACd,oBAAoB,EACpB,aAAa,GACd,MAAM,wBAAwB,CAAC;AAehC,mEAAmE;AACnE,6EAA6E;AAC7E,0EAA0E;AAC1E,yEAAyE;AACzE,wCAAwC;AACxC,OAAO,EACL,mBAAmB,EACnB,8BAA8B,EAC9B,YAAY,EACZ,iBAAiB,GAClB,MAAM,WAAW,CAAC"} |
+2
-2
| { | ||
| "name": "@routerlab/core", | ||
| "version": "1.0.2", | ||
| "version": "1.1.0", | ||
| "description": "Routing engine for cost-quality LLM model selection.", | ||
@@ -29,4 +29,4 @@ "license": "Apache-2.0", | ||
| "dependencies": { | ||
| "@tokenometer/core": "1.0.1" | ||
| "@tokenometer/core": "2.1.0" | ||
| } | ||
| } |
+39
-3
@@ -26,3 +26,3 @@ # `@routerlab/core` | ||
| ```ts | ||
| import { route, predictQuality, estimateCost } from "@routerlab/core"; | ||
| import { BudgetAwareRouter, route, predictQuality, estimateCost } from "@routerlab/core"; | ||
@@ -40,6 +40,39 @@ const decision = await route({ | ||
| for (const fb of decision.fallback) console.log("fallback:", fb.model.model); | ||
| for (const fb of decision.fallbacks) console.log("fallback:", fb.model.model); | ||
| for (const sk of decision.skipped) console.log("skipped:", sk.model.model, sk.reason); | ||
| ``` | ||
| ### Budget-aware agent loops | ||
| ```ts | ||
| const budget = new BudgetAwareRouter({ | ||
| maxBudgetUsd: 0.25, | ||
| warnAt: 0.8, | ||
| degradedQualityBar: 0.65, | ||
| }); | ||
| while (!done) { | ||
| const step = budget.routeStep({ | ||
| task: "reasoning", | ||
| prompt: agentContext, | ||
| qualityBar: 0.85, | ||
| }); | ||
| const response = await callYourModel(step.decision.chosen.model, agentContext); | ||
| budget.recordActualUsage({ | ||
| model: step.decision.chosen.model, | ||
| usage: { | ||
| inputTokens: response.usage.prompt_tokens, | ||
| outputTokens: response.usage.completion_tokens, | ||
| }, | ||
| }); | ||
| } | ||
| ``` | ||
| `routeStep()` caps the next decision by the remaining chain budget. After the | ||
| provider call, `recordActualUsage()` prices the real usage with Tokenometer's | ||
| runtime usage-pricing primitive. If a provider does not return usage, call | ||
| `recordEstimatedStep(step.decision)` to account for the selected estimate. | ||
| ### `RouteDecision` shape | ||
@@ -50,3 +83,3 @@ | ||
| chosen: RoutePick | null; // null when no candidate passes the filters | ||
| fallback: RouteFallback[]; // ordered cheapest-next | ||
| fallbacks: RouteFallback[]; // ordered cheapest-next | ||
| skipped: RouteSkipped[]; // every dropped candidate, with a reason | ||
@@ -64,2 +97,5 @@ request: RouteRequest; // echoed | ||
| - **`route(req)`** — top-level routing entry point. | ||
| - **`BudgetAwareRouter`** — stateful task budget controller for multi-step | ||
| agent loops. It preflights each step with routerlab and records actual or | ||
| estimated spend after each call. | ||
| - **`predictQuality` / `predictQualityWithCI`** — quality predictor; serves | ||
@@ -66,0 +102,0 @@ measured eval data when present, falls back to the seeded prior table |
131334
11.15%32
14.29%1752
10.82%129
38.71%+ Added
- Removed
Updated