Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@routerlab/core

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@routerlab/core - npm Package Compare versions

Comparing version
1.0.2
to
1.1.0
+57
dist/budget-router.d.ts
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

@@ -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"}

@@ -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"}
{
"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"
}
}

@@ -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