pi-smart-router 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.pi/extensions/smart-router/command-formatters.ts +167 -0
- package/.pi/extensions/smart-router/commands.ts +242 -0
- package/.pi/extensions/smart-router/dataset-export.ts +142 -0
- package/.pi/extensions/smart-router/delegate-stream.ts +105 -0
- package/.pi/extensions/smart-router/delegation-runtime.ts +355 -0
- package/.pi/extensions/smart-router/extension-setup.ts +115 -0
- package/.pi/extensions/smart-router/fleet-bootstrap.ts +244 -0
- package/.pi/extensions/smart-router/index.ts +115 -0
- package/.pi/extensions/smart-router/package.json +3 -0
- package/.pi/extensions/smart-router/pi-model-scope.ts +55 -0
- package/.pi/extensions/smart-router/pricing-lifecycle.ts +43 -0
- package/.pi/extensions/smart-router/route-and-delegate.ts +562 -0
- package/.pi/extensions/smart-router/routing-context.ts +171 -0
- package/.pi/extensions/smart-router/routing-outcomes.ts +44 -0
- package/.pi/extensions/smart-router/session-lifecycle.ts +140 -0
- package/.pi/extensions/smart-router/stream-delegation.ts +75 -0
- package/.pi/extensions/smart-router/types.ts +90 -0
- package/.pi/extensions/smart-router/utils.ts +58 -0
- package/README.md +593 -0
- package/bin/pi-smart-router.mjs +79 -0
- package/config/.gitkeep +0 -0
- package/config/hydra-projection-weights.json.example +1169 -0
- package/config/models.yaml.example +58 -0
- package/config/p-success-weights.json.example +19 -0
- package/config/routing-calibration.json.example +1605 -0
- package/config/routing-centroids.json.example +1570 -0
- package/config/routing-clusters.yaml.example +41 -0
- package/data/contrib/example.json +25 -0
- package/dist/api/explain/router-explain.d.ts +47 -0
- package/dist/api/explain/router-explain.d.ts.map +1 -0
- package/dist/api/explain/router-explain.js +101 -0
- package/dist/api/explain/router-explain.js.map +1 -0
- package/dist/api/middleware/pi-router-middleware.d.ts +86 -0
- package/dist/api/middleware/pi-router-middleware.d.ts.map +1 -0
- package/dist/api/middleware/pi-router-middleware.js +83 -0
- package/dist/api/middleware/pi-router-middleware.js.map +1 -0
- package/dist/cli/smart-router-cli.d.ts +85 -0
- package/dist/cli/smart-router-cli.d.ts.map +1 -0
- package/dist/cli/smart-router-cli.js +293 -0
- package/dist/cli/smart-router-cli.js.map +1 -0
- package/dist/config/defaults.d.ts +7 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +33 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/models-loader.d.ts +22 -0
- package/dist/config/models-loader.d.ts.map +1 -0
- package/dist/config/models-loader.js +51 -0
- package/dist/config/models-loader.js.map +1 -0
- package/dist/config/pi-model-mapper.d.ts +40 -0
- package/dist/config/pi-model-mapper.d.ts.map +1 -0
- package/dist/config/pi-model-mapper.js +216 -0
- package/dist/config/pi-model-mapper.js.map +1 -0
- package/dist/config/routing-clusters-loader.d.ts +35 -0
- package/dist/config/routing-clusters-loader.d.ts.map +1 -0
- package/dist/config/routing-clusters-loader.js +100 -0
- package/dist/config/routing-clusters-loader.js.map +1 -0
- package/dist/domain/delegation/delegation-context.d.ts +23 -0
- package/dist/domain/delegation/delegation-context.d.ts.map +1 -0
- package/dist/domain/delegation/delegation-context.js +73 -0
- package/dist/domain/delegation/delegation-context.js.map +1 -0
- package/dist/domain/delegation/execution-ledger.d.ts +19 -0
- package/dist/domain/delegation/execution-ledger.d.ts.map +1 -0
- package/dist/domain/delegation/execution-ledger.js +23 -0
- package/dist/domain/delegation/execution-ledger.js.map +1 -0
- package/dist/domain/delegation/output-headroom.d.ts +39 -0
- package/dist/domain/delegation/output-headroom.d.ts.map +1 -0
- package/dist/domain/delegation/output-headroom.js +78 -0
- package/dist/domain/delegation/output-headroom.js.map +1 -0
- package/dist/domain/matching/cluster-matcher.d.ts +69 -0
- package/dist/domain/matching/cluster-matcher.d.ts.map +1 -0
- package/dist/domain/matching/cluster-matcher.js +294 -0
- package/dist/domain/matching/cluster-matcher.js.map +1 -0
- package/dist/domain/matching/embedding-provider.d.ts +21 -0
- package/dist/domain/matching/embedding-provider.d.ts.map +1 -0
- package/dist/domain/matching/embedding-provider.js +42 -0
- package/dist/domain/matching/embedding-provider.js.map +1 -0
- package/dist/domain/matching/hydra-input.d.ts +18 -0
- package/dist/domain/matching/hydra-input.d.ts.map +1 -0
- package/dist/domain/matching/hydra-input.js +40 -0
- package/dist/domain/matching/hydra-input.js.map +1 -0
- package/dist/domain/matching/hydra-matcher.d.ts +103 -0
- package/dist/domain/matching/hydra-matcher.d.ts.map +1 -0
- package/dist/domain/matching/hydra-matcher.js +275 -0
- package/dist/domain/matching/hydra-matcher.js.map +1 -0
- package/dist/domain/pinning/cache-economics.d.ts +53 -0
- package/dist/domain/pinning/cache-economics.d.ts.map +1 -0
- package/dist/domain/pinning/cache-economics.js +72 -0
- package/dist/domain/pinning/cache-economics.js.map +1 -0
- package/dist/domain/pinning/loop-escalation.d.ts +41 -0
- package/dist/domain/pinning/loop-escalation.d.ts.map +1 -0
- package/dist/domain/pinning/loop-escalation.js +137 -0
- package/dist/domain/pinning/loop-escalation.js.map +1 -0
- package/dist/domain/pinning/session-pinner.d.ts +81 -0
- package/dist/domain/pinning/session-pinner.d.ts.map +1 -0
- package/dist/domain/pinning/session-pinner.js +237 -0
- package/dist/domain/pinning/session-pinner.js.map +1 -0
- package/dist/domain/pinning/sub-route-policy.d.ts +41 -0
- package/dist/domain/pinning/sub-route-policy.d.ts.map +1 -0
- package/dist/domain/pinning/sub-route-policy.js +72 -0
- package/dist/domain/pinning/sub-route-policy.js.map +1 -0
- package/dist/domain/pipeline/router-pipeline.d.ts +180 -0
- package/dist/domain/pipeline/router-pipeline.d.ts.map +1 -0
- package/dist/domain/pipeline/router-pipeline.js +807 -0
- package/dist/domain/pipeline/router-pipeline.js.map +1 -0
- package/dist/domain/pipeline/safe-default.d.ts +25 -0
- package/dist/domain/pipeline/safe-default.d.ts.map +1 -0
- package/dist/domain/pipeline/safe-default.js +41 -0
- package/dist/domain/pipeline/safe-default.js.map +1 -0
- package/dist/domain/refactor-guardrails.d.ts +48 -0
- package/dist/domain/refactor-guardrails.d.ts.map +1 -0
- package/dist/domain/refactor-guardrails.js +129 -0
- package/dist/domain/refactor-guardrails.js.map +1 -0
- package/dist/domain/routing/context-fit.d.ts +53 -0
- package/dist/domain/routing/context-fit.d.ts.map +1 -0
- package/dist/domain/routing/context-fit.js +142 -0
- package/dist/domain/routing/context-fit.js.map +1 -0
- package/dist/domain/routing/expected-cost.d.ts +63 -0
- package/dist/domain/routing/expected-cost.d.ts.map +1 -0
- package/dist/domain/routing/expected-cost.js +177 -0
- package/dist/domain/routing/expected-cost.js.map +1 -0
- package/dist/domain/routing/p-success-classifier.d.ts +130 -0
- package/dist/domain/routing/p-success-classifier.d.ts.map +1 -0
- package/dist/domain/routing/p-success-classifier.js +350 -0
- package/dist/domain/routing/p-success-classifier.js.map +1 -0
- package/dist/domain/routing/tier-features.d.ts +70 -0
- package/dist/domain/routing/tier-features.d.ts.map +1 -0
- package/dist/domain/routing/tier-features.js +174 -0
- package/dist/domain/routing/tier-features.js.map +1 -0
- package/dist/domain/routing/tool-history-guard.d.ts +32 -0
- package/dist/domain/routing/tool-history-guard.d.ts.map +1 -0
- package/dist/domain/routing/tool-history-guard.js +110 -0
- package/dist/domain/routing/tool-history-guard.js.map +1 -0
- package/dist/domain/scoring/multi-objective.d.ts +48 -0
- package/dist/domain/scoring/multi-objective.d.ts.map +1 -0
- package/dist/domain/scoring/multi-objective.js +116 -0
- package/dist/domain/scoring/multi-objective.js.map +1 -0
- package/dist/domain/triage/triage-engine.d.ts +43 -0
- package/dist/domain/triage/triage-engine.d.ts.map +1 -0
- package/dist/domain/triage/triage-engine.js +317 -0
- package/dist/domain/triage/triage-engine.js.map +1 -0
- package/dist/domain/triage/turn-envelope.d.ts +17 -0
- package/dist/domain/triage/turn-envelope.d.ts.map +1 -0
- package/dist/domain/triage/turn-envelope.js +81 -0
- package/dist/domain/triage/turn-envelope.js.map +1 -0
- package/dist/domain/types/entities.d.ts +303 -0
- package/dist/domain/types/entities.d.ts.map +1 -0
- package/dist/domain/types/entities.js +6 -0
- package/dist/domain/types/entities.js.map +1 -0
- package/dist/domain/types/index.d.ts +4 -0
- package/dist/domain/types/index.d.ts.map +1 -0
- package/dist/domain/types/index.js +2 -0
- package/dist/domain/types/index.js.map +1 -0
- package/dist/domain/types/schemas.d.ts +346 -0
- package/dist/domain/types/schemas.d.ts.map +1 -0
- package/dist/domain/types/schemas.js +241 -0
- package/dist/domain/types/schemas.js.map +1 -0
- package/dist/domain/types/store-port.d.ts +44 -0
- package/dist/domain/types/store-port.d.ts.map +1 -0
- package/dist/domain/types/store-port.js +6 -0
- package/dist/domain/types/store-port.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/infra/gemini-provider.d.ts +28 -0
- package/dist/infra/gemini-provider.d.ts.map +1 -0
- package/dist/infra/gemini-provider.js +112 -0
- package/dist/infra/gemini-provider.js.map +1 -0
- package/dist/infra/telemetry.d.ts +51 -0
- package/dist/infra/telemetry.d.ts.map +1 -0
- package/dist/infra/telemetry.js +100 -0
- package/dist/infra/telemetry.js.map +1 -0
- package/dist/infrastructure/delegation/provider-error.d.ts +44 -0
- package/dist/infrastructure/delegation/provider-error.d.ts.map +1 -0
- package/dist/infrastructure/delegation/provider-error.js +179 -0
- package/dist/infrastructure/delegation/provider-error.js.map +1 -0
- package/dist/infrastructure/gateway/circuit-breaker.d.ts +68 -0
- package/dist/infrastructure/gateway/circuit-breaker.d.ts.map +1 -0
- package/dist/infrastructure/gateway/circuit-breaker.js +150 -0
- package/dist/infrastructure/gateway/circuit-breaker.js.map +1 -0
- package/dist/infrastructure/gateway/gateway-dispatch.d.ts +138 -0
- package/dist/infrastructure/gateway/gateway-dispatch.d.ts.map +1 -0
- package/dist/infrastructure/gateway/gateway-dispatch.js +308 -0
- package/dist/infrastructure/gateway/gateway-dispatch.js.map +1 -0
- package/dist/infrastructure/hardware/hardware-probe.d.ts +32 -0
- package/dist/infrastructure/hardware/hardware-probe.d.ts.map +1 -0
- package/dist/infrastructure/hardware/hardware-probe.js +199 -0
- package/dist/infrastructure/hardware/hardware-probe.js.map +1 -0
- package/dist/infrastructure/local/local-zero-tier.d.ts +47 -0
- package/dist/infrastructure/local/local-zero-tier.d.ts.map +1 -0
- package/dist/infrastructure/local/local-zero-tier.js +92 -0
- package/dist/infrastructure/local/local-zero-tier.js.map +1 -0
- package/dist/infrastructure/persistence/memory-store.d.ts +31 -0
- package/dist/infrastructure/persistence/memory-store.d.ts.map +1 -0
- package/dist/infrastructure/persistence/memory-store.js +87 -0
- package/dist/infrastructure/persistence/memory-store.js.map +1 -0
- package/dist/infrastructure/persistence/sqlite-store.d.ts +81 -0
- package/dist/infrastructure/persistence/sqlite-store.d.ts.map +1 -0
- package/dist/infrastructure/persistence/sqlite-store.js +658 -0
- package/dist/infrastructure/persistence/sqlite-store.js.map +1 -0
- package/dist/infrastructure/pricing/litellm-fetch.d.ts +46 -0
- package/dist/infrastructure/pricing/litellm-fetch.d.ts.map +1 -0
- package/dist/infrastructure/pricing/litellm-fetch.js +145 -0
- package/dist/infrastructure/pricing/litellm-fetch.js.map +1 -0
- package/dist/infrastructure/pricing/price-broker.d.ts +56 -0
- package/dist/infrastructure/pricing/price-broker.d.ts.map +1 -0
- package/dist/infrastructure/pricing/price-broker.js +133 -0
- package/dist/infrastructure/pricing/price-broker.js.map +1 -0
- package/dist/infrastructure/pricing/pricing-monitor.d.ts +27 -0
- package/dist/infrastructure/pricing/pricing-monitor.d.ts.map +1 -0
- package/dist/infrastructure/pricing/pricing-monitor.js +46 -0
- package/dist/infrastructure/pricing/pricing-monitor.js.map +1 -0
- package/dist/infrastructure/telemetry/dataset-limits.d.ts +13 -0
- package/dist/infrastructure/telemetry/dataset-limits.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/dataset-limits.js +28 -0
- package/dist/infrastructure/telemetry/dataset-limits.js.map +1 -0
- package/dist/infrastructure/telemetry/dataset-recorder.d.ts +48 -0
- package/dist/infrastructure/telemetry/dataset-recorder.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/dataset-recorder.js +154 -0
- package/dist/infrastructure/telemetry/dataset-recorder.js.map +1 -0
- package/dist/infrastructure/telemetry/outcome-limits.d.ts +12 -0
- package/dist/infrastructure/telemetry/outcome-limits.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/outcome-limits.js +28 -0
- package/dist/infrastructure/telemetry/outcome-limits.js.map +1 -0
- package/dist/infrastructure/telemetry/outcome-recorder.d.ts +29 -0
- package/dist/infrastructure/telemetry/outcome-recorder.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/outcome-recorder.js +49 -0
- package/dist/infrastructure/telemetry/outcome-recorder.js.map +1 -0
- package/dist/infrastructure/telemetry/routing-telemetry.d.ts +115 -0
- package/dist/infrastructure/telemetry/routing-telemetry.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/routing-telemetry.js +529 -0
- package/dist/infrastructure/telemetry/routing-telemetry.js.map +1 -0
- package/dist/infrastructure/telemetry/telemetry-limits.d.ts +16 -0
- package/dist/infrastructure/telemetry/telemetry-limits.d.ts.map +1 -0
- package/dist/infrastructure/telemetry/telemetry-limits.js +35 -0
- package/dist/infrastructure/telemetry/telemetry-limits.js.map +1 -0
- package/package.json +110 -0
- package/skills/router-backlog-orchestrator/SKILL.md +183 -0
- package/skills/router-backlog-orchestrator/references/github-router-issue-template.md +78 -0
- package/skills/router-backlog-orchestrator/references/packet-from-issue.md +99 -0
- package/skills/router-backlog-orchestrator/references/prioritization-rubric.md +65 -0
- package/skills/router-backlog-orchestrator/scripts/collect-backlog.sh +44 -0
- package/specs/001-build-smart-router/contracts/telemetry-contrib.schema.json +151 -0
- package/src/api/explain/.gitkeep +0 -0
- package/src/api/explain/router-explain.ts +146 -0
- package/src/api/middleware/.gitkeep +0 -0
- package/src/api/middleware/pi-router-middleware.ts +169 -0
- package/src/cli/smart-router-cli.ts +436 -0
- package/src/config/.gitkeep +0 -0
- package/src/config/defaults.ts +35 -0
- package/src/config/models-loader.ts +68 -0
- package/src/config/pi-model-mapper.ts +285 -0
- package/src/config/routing-clusters-loader.ts +148 -0
- package/src/domain/delegation/delegation-context.ts +111 -0
- package/src/domain/delegation/execution-ledger.ts +34 -0
- package/src/domain/delegation/output-headroom.ts +131 -0
- package/src/domain/matching/.gitkeep +0 -0
- package/src/domain/matching/cluster-matcher.ts +474 -0
- package/src/domain/matching/embedding-provider.ts +79 -0
- package/src/domain/matching/hydra-input.ts +53 -0
- package/src/domain/matching/hydra-matcher.ts +454 -0
- package/src/domain/pinning/.gitkeep +0 -0
- package/src/domain/pinning/cache-economics.ts +128 -0
- package/src/domain/pinning/loop-escalation.ts +181 -0
- package/src/domain/pinning/session-pinner.ts +388 -0
- package/src/domain/pinning/sub-route-policy.ts +119 -0
- package/src/domain/pipeline/.gitkeep +0 -0
- package/src/domain/pipeline/router-pipeline.ts +1139 -0
- package/src/domain/pipeline/safe-default.ts +70 -0
- package/src/domain/refactor-guardrails.ts +202 -0
- package/src/domain/routing/context-fit.ts +221 -0
- package/src/domain/routing/expected-cost.ts +320 -0
- package/src/domain/routing/p-success-classifier.ts +511 -0
- package/src/domain/routing/tier-features.ts +290 -0
- package/src/domain/routing/tool-history-guard.ts +159 -0
- package/src/domain/scoring/.gitkeep +0 -0
- package/src/domain/scoring/multi-objective.ts +175 -0
- package/src/domain/triage/.gitkeep +0 -0
- package/src/domain/triage/triage-engine.ts +373 -0
- package/src/domain/triage/turn-envelope.ts +104 -0
- package/src/domain/types/.gitkeep +0 -0
- package/src/domain/types/entities.ts +384 -0
- package/src/domain/types/index.ts +41 -0
- package/src/domain/types/schemas.ts +289 -0
- package/src/domain/types/store-port.ts +59 -0
- package/src/index.ts +103 -0
- package/src/infra/gemini-provider.ts +142 -0
- package/src/infra/telemetry.ts +169 -0
- package/src/infrastructure/delegation/provider-error.ts +251 -0
- package/src/infrastructure/gateway/.gitkeep +0 -0
- package/src/infrastructure/gateway/circuit-breaker.ts +196 -0
- package/src/infrastructure/gateway/gateway-dispatch.ts +444 -0
- package/src/infrastructure/hardware/.gitkeep +0 -0
- package/src/infrastructure/hardware/hardware-probe.ts +276 -0
- package/src/infrastructure/local/.gitkeep +0 -0
- package/src/infrastructure/local/local-zero-tier.ts +151 -0
- package/src/infrastructure/persistence/.gitkeep +0 -0
- package/src/infrastructure/persistence/memory-store.ts +122 -0
- package/src/infrastructure/persistence/sqlite-store.ts +900 -0
- package/src/infrastructure/pricing/.gitkeep +0 -0
- package/src/infrastructure/pricing/litellm-fetch.ts +215 -0
- package/src/infrastructure/pricing/price-broker.ts +183 -0
- package/src/infrastructure/pricing/pricing-monitor.ts +65 -0
- package/src/infrastructure/telemetry/.gitkeep +0 -0
- package/src/infrastructure/telemetry/dataset-limits.ts +39 -0
- package/src/infrastructure/telemetry/dataset-recorder.ts +215 -0
- package/src/infrastructure/telemetry/outcome-limits.ts +42 -0
- package/src/infrastructure/telemetry/outcome-recorder.ts +118 -0
- package/src/infrastructure/telemetry/routing-telemetry.ts +824 -0
- package/src/infrastructure/telemetry/telemetry-limits.ts +50 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LiteLLM pricing fetch — manual refresh path (SP-045).
|
|
3
|
+
*
|
|
4
|
+
* Fetches the public LiteLLM model pricing JSON and normalizes chat-model
|
|
5
|
+
* rates into PriceCatalog.registry_snapshot entries keyed by model id and
|
|
6
|
+
* provider/model aliases for tri-tier broker lookup.
|
|
7
|
+
*/
|
|
8
|
+
import type { ModelLimits, PriceCatalog } from '../../domain/types/index.js';
|
|
9
|
+
export declare const DEFAULT_LITELLM_PRICING_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json";
|
|
10
|
+
export interface LitellmFetchResult {
|
|
11
|
+
readonly registry_snapshot: Readonly<Record<string, number>>;
|
|
12
|
+
readonly registry_limits_snapshot: Readonly<Record<string, ModelLimits>>;
|
|
13
|
+
/** Number of LiteLLM chat/completion models normalized (before alias keys). */
|
|
14
|
+
readonly model_count: number;
|
|
15
|
+
}
|
|
16
|
+
export interface LitellmFetchDeps {
|
|
17
|
+
readonly fetchFn?: typeof fetch;
|
|
18
|
+
readonly pricingUrl?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare class LitellmFetchError extends Error {
|
|
21
|
+
readonly name = "LitellmFetchError";
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolve pricing URL from env with documented LiteLLM GitHub default.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getLitellmPricingUrl(env?: NodeJS.ProcessEnv): string;
|
|
27
|
+
/**
|
|
28
|
+
* Weighted blend of input/output per-token rates → USD per 1M tokens.
|
|
29
|
+
* Matches the registry-cost formula planned for SP-046.
|
|
30
|
+
*/
|
|
31
|
+
export declare function computeCostPer1MTokens(inputCostPerToken: number, outputCostPerToken: number): number;
|
|
32
|
+
/**
|
|
33
|
+
* Normalize LiteLLM pricing JSON into registry_snapshot rates.
|
|
34
|
+
* Validates shape and fails fast with actionable errors.
|
|
35
|
+
*/
|
|
36
|
+
export declare function normalizeLitellmPricing(raw: unknown): LitellmFetchResult;
|
|
37
|
+
export interface LitellmPriceCatalogResult {
|
|
38
|
+
readonly catalog: PriceCatalog;
|
|
39
|
+
/** Number of chat/completion models in the LiteLLM source payload. */
|
|
40
|
+
readonly model_count: number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Fetch LiteLLM pricing and build a PriceCatalog payload (does not persist).
|
|
44
|
+
*/
|
|
45
|
+
export declare function fetchLitellmPriceCatalog(deps?: LitellmFetchDeps): Promise<LitellmPriceCatalogResult>;
|
|
46
|
+
//# sourceMappingURL=litellm-fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"litellm-fetch.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/pricing/litellm-fetch.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE7E,eAAO,MAAM,2BAA2B,gGACuD,CAAC;AAIhG,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7D,QAAQ,CAAC,wBAAwB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IACzE,+EAA+E;IAC/E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,SAAkB,IAAI,uBAAuB;CAC9C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAGjF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,iBAAiB,EAAE,MAAM,EACzB,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAIR;AA4CD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,kBAAkB,CA8DxE;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,GAAE,gBAAqB,GAC1B,OAAO,CAAC,yBAAyB,CAAC,CAyCpC"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LiteLLM pricing fetch — manual refresh path (SP-045).
|
|
3
|
+
*
|
|
4
|
+
* Fetches the public LiteLLM model pricing JSON and normalizes chat-model
|
|
5
|
+
* rates into PriceCatalog.registry_snapshot entries keyed by model id and
|
|
6
|
+
* provider/model aliases for tri-tier broker lookup.
|
|
7
|
+
*/
|
|
8
|
+
export const DEFAULT_LITELLM_PRICING_URL = 'https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json';
|
|
9
|
+
const CHAT_MODES = new Set(['chat', 'completion']);
|
|
10
|
+
export class LitellmFetchError extends Error {
|
|
11
|
+
name = 'LitellmFetchError';
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resolve pricing URL from env with documented LiteLLM GitHub default.
|
|
15
|
+
*/
|
|
16
|
+
export function getLitellmPricingUrl(env = process.env) {
|
|
17
|
+
const configured = env.LITELLM_PRICING_URL?.trim();
|
|
18
|
+
return configured && configured.length > 0 ? configured : DEFAULT_LITELLM_PRICING_URL;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Weighted blend of input/output per-token rates → USD per 1M tokens.
|
|
22
|
+
* Matches the registry-cost formula planned for SP-046.
|
|
23
|
+
*/
|
|
24
|
+
export function computeCostPer1MTokens(inputCostPerToken, outputCostPerToken) {
|
|
25
|
+
const inputPer1M = inputCostPerToken * 1_000_000;
|
|
26
|
+
const outputPer1M = outputCostPerToken * 1_000_000;
|
|
27
|
+
return (inputPer1M + outputPer1M) / 2;
|
|
28
|
+
}
|
|
29
|
+
function isRecord(value) {
|
|
30
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
31
|
+
}
|
|
32
|
+
function readNumberField(entry, field) {
|
|
33
|
+
const value = entry[field];
|
|
34
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
35
|
+
}
|
|
36
|
+
function readStringField(entry, field) {
|
|
37
|
+
const value = entry[field];
|
|
38
|
+
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
|
|
39
|
+
}
|
|
40
|
+
function readPositiveIntField(entry, field) {
|
|
41
|
+
const value = entry[field];
|
|
42
|
+
return typeof value === 'number' && Number.isInteger(value) && value > 0 ? value : undefined;
|
|
43
|
+
}
|
|
44
|
+
function parseModelLimits(entry) {
|
|
45
|
+
const maxInputTokens = readPositiveIntField(entry, 'max_input_tokens');
|
|
46
|
+
const maxOutputTokens = readPositiveIntField(entry, 'max_output_tokens') ?? readPositiveIntField(entry, 'max_tokens');
|
|
47
|
+
if (maxInputTokens === undefined && maxOutputTokens === undefined) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
...(maxInputTokens !== undefined ? { max_input_tokens: maxInputTokens } : {}),
|
|
52
|
+
...(maxOutputTokens !== undefined ? { max_output_tokens: maxOutputTokens } : {}),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function storeLimitsAlias(registry_limits_snapshot, key, limits) {
|
|
56
|
+
registry_limits_snapshot[key] = limits;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Normalize LiteLLM pricing JSON into registry_snapshot rates.
|
|
60
|
+
* Validates shape and fails fast with actionable errors.
|
|
61
|
+
*/
|
|
62
|
+
export function normalizeLitellmPricing(raw) {
|
|
63
|
+
if (!isRecord(raw)) {
|
|
64
|
+
throw new LitellmFetchError('LiteLLM pricing response must be a JSON object. Check LITELLM_PRICING_URL points at model_prices_and_context_window.json.');
|
|
65
|
+
}
|
|
66
|
+
const registry_snapshot = {};
|
|
67
|
+
const registry_limits_snapshot = {};
|
|
68
|
+
let modelCount = 0;
|
|
69
|
+
for (const [modelKey, entry] of Object.entries(raw)) {
|
|
70
|
+
if (modelKey === 'sample_spec') {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (!isRecord(entry)) {
|
|
74
|
+
throw new LitellmFetchError(`LiteLLM pricing entry "${modelKey}" must be an object. Received ${typeof entry}.`);
|
|
75
|
+
}
|
|
76
|
+
const mode = readStringField(entry, 'mode');
|
|
77
|
+
if (mode !== undefined && !CHAT_MODES.has(mode)) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const inputCost = readNumberField(entry, 'input_cost_per_token');
|
|
81
|
+
const outputCost = readNumberField(entry, 'output_cost_per_token');
|
|
82
|
+
if (inputCost === undefined || outputCost === undefined) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const costPer1M = computeCostPer1MTokens(inputCost, outputCost);
|
|
86
|
+
registry_snapshot[modelKey] = costPer1M;
|
|
87
|
+
modelCount += 1;
|
|
88
|
+
const limits = parseModelLimits(entry);
|
|
89
|
+
if (limits !== undefined) {
|
|
90
|
+
storeLimitsAlias(registry_limits_snapshot, modelKey, limits);
|
|
91
|
+
}
|
|
92
|
+
const provider = readStringField(entry, 'litellm_provider');
|
|
93
|
+
if (provider !== undefined) {
|
|
94
|
+
registry_snapshot[`${provider}/${modelKey}`] = costPer1M;
|
|
95
|
+
if (limits !== undefined) {
|
|
96
|
+
storeLimitsAlias(registry_limits_snapshot, `${provider}/${modelKey}`, limits);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (Object.keys(registry_snapshot).length === 0) {
|
|
101
|
+
throw new LitellmFetchError('LiteLLM pricing response contained no chat models with input/output token costs.');
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
registry_snapshot,
|
|
105
|
+
registry_limits_snapshot,
|
|
106
|
+
model_count: modelCount,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Fetch LiteLLM pricing and build a PriceCatalog payload (does not persist).
|
|
111
|
+
*/
|
|
112
|
+
export async function fetchLitellmPriceCatalog(deps = {}) {
|
|
113
|
+
const fetchFn = deps.fetchFn ?? fetch;
|
|
114
|
+
const url = deps.pricingUrl ?? getLitellmPricingUrl();
|
|
115
|
+
let response;
|
|
116
|
+
try {
|
|
117
|
+
response = await fetchFn(url);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
121
|
+
throw new LitellmFetchError(`Failed to fetch LiteLLM pricing from ${url}: ${detail}`);
|
|
122
|
+
}
|
|
123
|
+
if (!response.ok) {
|
|
124
|
+
throw new LitellmFetchError(`LiteLLM pricing fetch failed (${response.status} ${response.statusText}) from ${url}`);
|
|
125
|
+
}
|
|
126
|
+
let raw;
|
|
127
|
+
try {
|
|
128
|
+
raw = await response.json();
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
throw new LitellmFetchError(`LiteLLM pricing response from ${url} is not valid JSON.`);
|
|
132
|
+
}
|
|
133
|
+
const normalized = normalizeLitellmPricing(raw);
|
|
134
|
+
return {
|
|
135
|
+
catalog: {
|
|
136
|
+
registry_snapshot: normalized.registry_snapshot,
|
|
137
|
+
registry_limits_snapshot: normalized.registry_limits_snapshot,
|
|
138
|
+
user_overrides: {},
|
|
139
|
+
last_updated: new Date().toISOString(),
|
|
140
|
+
source: 'registry',
|
|
141
|
+
},
|
|
142
|
+
model_count: normalized.model_count,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=litellm-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"litellm-fetch.js","sourceRoot":"","sources":["../../../src/infrastructure/pricing/litellm-fetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tri-tier price broker — FR-019 (T053).
|
|
3
|
+
*
|
|
4
|
+
* Resolves per-model pricing using a strict priority cascade:
|
|
5
|
+
* 1. Operator overrides (highest priority)
|
|
6
|
+
* 2. Registry snapshot (refreshed external data)
|
|
7
|
+
* 3. YAML/catalog fallback (ModelProfile.pricing.fallback_cost_per_1m)
|
|
8
|
+
*
|
|
9
|
+
* The broker is a pure function layer; it reads from the PriceCatalog
|
|
10
|
+
* and ModelProfile without side effects.
|
|
11
|
+
*/
|
|
12
|
+
import type { ModelProfile, ModelLimits, PriceCatalog, PriceSource } from '../../domain/types/index.js';
|
|
13
|
+
export interface ResolvedPrice {
|
|
14
|
+
readonly model_id: string;
|
|
15
|
+
readonly cost_per_1m_tokens: number;
|
|
16
|
+
readonly source: PriceSource;
|
|
17
|
+
}
|
|
18
|
+
export interface ResolvedLimits {
|
|
19
|
+
readonly model_id: string;
|
|
20
|
+
readonly limits: ModelLimits;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Resolve effective context limits for a model.
|
|
24
|
+
*
|
|
25
|
+
* Priority: YAML/profile override → LiteLLM registry snapshot → tier default.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveLimits(model: ModelProfile, catalog: PriceCatalog | null): ResolvedLimits;
|
|
28
|
+
/**
|
|
29
|
+
* Apply resolved context limits to fleet profiles for routing gates (SP-092).
|
|
30
|
+
*/
|
|
31
|
+
export declare function applyCatalogLimitsToFleet(fleet: readonly ModelProfile[], catalog: PriceCatalog | null): ModelProfile[];
|
|
32
|
+
/**
|
|
33
|
+
* Resolve the effective price for a single model.
|
|
34
|
+
*
|
|
35
|
+
* Priority: operator override → registry snapshot → catalog fallback.
|
|
36
|
+
* Always returns a price — the fallback from ModelProfile is guaranteed
|
|
37
|
+
* by schema to exist.
|
|
38
|
+
*/
|
|
39
|
+
export declare function resolvePrice(model: ModelProfile, catalog: PriceCatalog | null): ResolvedPrice;
|
|
40
|
+
/**
|
|
41
|
+
* Resolve prices for the entire fleet in a single pass.
|
|
42
|
+
*
|
|
43
|
+
* Returns a Map keyed by model ID for O(1) lookup during scoring.
|
|
44
|
+
*/
|
|
45
|
+
export declare function resolveFleetPrices(fleet: readonly ModelProfile[], catalog: PriceCatalog | null): ReadonlyMap<string, ResolvedPrice>;
|
|
46
|
+
/**
|
|
47
|
+
* Apply tri-tier resolved prices and context limits to fleet profiles.
|
|
48
|
+
* When no catalog is loaded, applies tier default limits only.
|
|
49
|
+
*/
|
|
50
|
+
export declare function applyCatalogPricesToFleet(fleet: readonly ModelProfile[], catalog: PriceCatalog | null): ModelProfile[];
|
|
51
|
+
/**
|
|
52
|
+
* Resolve per-request cost rate for frugality scoring and telemetry (SP-096).
|
|
53
|
+
* Subscription-quota virtual cost takes precedence over API/catalog rates.
|
|
54
|
+
*/
|
|
55
|
+
export declare function resolveFrugalityCostPer1M(model: ModelProfile, catalog: PriceCatalog | null): number;
|
|
56
|
+
//# sourceMappingURL=price-broker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"price-broker.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/pricing/price-broker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAGxG,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC9B;AAeD;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,YAAY,GAAG,IAAI,GAC3B,cAAc,CAkBhB;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,SAAS,YAAY,EAAE,EAC9B,OAAO,EAAE,YAAY,GAAG,IAAI,GAC3B,YAAY,EAAE,CAQhB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,YAAY,GAAG,IAAI,GAC3B,aAAa,CA2Bf;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,YAAY,EAAE,EAC9B,OAAO,EAAE,YAAY,GAAG,IAAI,GAC3B,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAMpC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,SAAS,YAAY,EAAE,EAC9B,OAAO,EAAE,YAAY,GAAG,IAAI,GAC3B,YAAY,EAAE,CAuBhB;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,YAAY,GAAG,IAAI,GAC3B,MAAM,CAKR"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tri-tier price broker — FR-019 (T053).
|
|
3
|
+
*
|
|
4
|
+
* Resolves per-model pricing using a strict priority cascade:
|
|
5
|
+
* 1. Operator overrides (highest priority)
|
|
6
|
+
* 2. Registry snapshot (refreshed external data)
|
|
7
|
+
* 3. YAML/catalog fallback (ModelProfile.pricing.fallback_cost_per_1m)
|
|
8
|
+
*
|
|
9
|
+
* The broker is a pure function layer; it reads from the PriceCatalog
|
|
10
|
+
* and ModelProfile without side effects.
|
|
11
|
+
*/
|
|
12
|
+
import { getDefaultLimitsForTier } from '../../config/pi-model-mapper.js';
|
|
13
|
+
function lookupRegistryLimits(model, catalog) {
|
|
14
|
+
const snapshot = catalog.registry_limits_snapshot;
|
|
15
|
+
if (!snapshot) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
const registryKey = model.pricing.registry_key ?? model.id;
|
|
19
|
+
return snapshot[registryKey] ?? snapshot[model.id];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Resolve effective context limits for a model.
|
|
23
|
+
*
|
|
24
|
+
* Priority: YAML/profile override → LiteLLM registry snapshot → tier default.
|
|
25
|
+
*/
|
|
26
|
+
export function resolveLimits(model, catalog) {
|
|
27
|
+
const yamlLimits = model.limits;
|
|
28
|
+
const registryLimits = catalog ? lookupRegistryLimits(model, catalog) : undefined;
|
|
29
|
+
const defaults = getDefaultLimitsForTier(model.tier);
|
|
30
|
+
return {
|
|
31
|
+
model_id: model.id,
|
|
32
|
+
limits: {
|
|
33
|
+
max_input_tokens: yamlLimits?.max_input_tokens ??
|
|
34
|
+
registryLimits?.max_input_tokens ??
|
|
35
|
+
defaults.max_input_tokens,
|
|
36
|
+
max_output_tokens: yamlLimits?.max_output_tokens ??
|
|
37
|
+
registryLimits?.max_output_tokens ??
|
|
38
|
+
defaults.max_output_tokens,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Apply resolved context limits to fleet profiles for routing gates (SP-092).
|
|
44
|
+
*/
|
|
45
|
+
export function applyCatalogLimitsToFleet(fleet, catalog) {
|
|
46
|
+
return fleet.map((profile) => {
|
|
47
|
+
const resolved = resolveLimits(profile, catalog);
|
|
48
|
+
return {
|
|
49
|
+
...profile,
|
|
50
|
+
limits: resolved.limits,
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Resolve the effective price for a single model.
|
|
56
|
+
*
|
|
57
|
+
* Priority: operator override → registry snapshot → catalog fallback.
|
|
58
|
+
* Always returns a price — the fallback from ModelProfile is guaranteed
|
|
59
|
+
* by schema to exist.
|
|
60
|
+
*/
|
|
61
|
+
export function resolvePrice(model, catalog) {
|
|
62
|
+
if (catalog) {
|
|
63
|
+
const override = catalog.user_overrides[model.id];
|
|
64
|
+
if (override !== undefined) {
|
|
65
|
+
return {
|
|
66
|
+
model_id: model.id,
|
|
67
|
+
cost_per_1m_tokens: override,
|
|
68
|
+
source: 'override',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const registryKey = model.pricing.registry_key ?? model.id;
|
|
72
|
+
const registryPrice = catalog.registry_snapshot[registryKey];
|
|
73
|
+
if (registryPrice !== undefined) {
|
|
74
|
+
return {
|
|
75
|
+
model_id: model.id,
|
|
76
|
+
cost_per_1m_tokens: registryPrice,
|
|
77
|
+
source: 'registry',
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
model_id: model.id,
|
|
83
|
+
cost_per_1m_tokens: model.pricing.fallback_cost_per_1m,
|
|
84
|
+
source: 'yaml_fallback',
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Resolve prices for the entire fleet in a single pass.
|
|
89
|
+
*
|
|
90
|
+
* Returns a Map keyed by model ID for O(1) lookup during scoring.
|
|
91
|
+
*/
|
|
92
|
+
export function resolveFleetPrices(fleet, catalog) {
|
|
93
|
+
const prices = new Map();
|
|
94
|
+
for (const model of fleet) {
|
|
95
|
+
prices.set(model.id, resolvePrice(model, catalog));
|
|
96
|
+
}
|
|
97
|
+
return prices;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Apply tri-tier resolved prices and context limits to fleet profiles.
|
|
101
|
+
* When no catalog is loaded, applies tier default limits only.
|
|
102
|
+
*/
|
|
103
|
+
export function applyCatalogPricesToFleet(fleet, catalog) {
|
|
104
|
+
if (!catalog) {
|
|
105
|
+
return applyCatalogLimitsToFleet(fleet, catalog);
|
|
106
|
+
}
|
|
107
|
+
const prices = resolveFleetPrices(fleet, catalog);
|
|
108
|
+
const priced = fleet.map((profile) => {
|
|
109
|
+
const resolved = prices.get(profile.id);
|
|
110
|
+
if (!resolved || resolved.source === 'yaml_fallback') {
|
|
111
|
+
return profile;
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
...profile,
|
|
115
|
+
pricing: {
|
|
116
|
+
...profile.pricing,
|
|
117
|
+
fallback_cost_per_1m: resolved.cost_per_1m_tokens,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
return applyCatalogLimitsToFleet(priced, catalog);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Resolve per-request cost rate for frugality scoring and telemetry (SP-096).
|
|
125
|
+
* Subscription-quota virtual cost takes precedence over API/catalog rates.
|
|
126
|
+
*/
|
|
127
|
+
export function resolveFrugalityCostPer1M(model, catalog) {
|
|
128
|
+
if (model.pricing.quota_cost_per_1m !== undefined) {
|
|
129
|
+
return model.pricing.quota_cost_per_1m;
|
|
130
|
+
}
|
|
131
|
+
return resolvePrice(model, catalog).cost_per_1m_tokens;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=price-broker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"price-broker.js","sourceRoot":"","sources":["../../../src/infrastructure/pricing/price-broker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pricing staleness monitor — FR-020 (T054).
|
|
3
|
+
*
|
|
4
|
+
* Checks whether the PriceCatalog's last_updated timestamp exceeds a
|
|
5
|
+
* configurable staleness threshold (default: 14 days). When stale,
|
|
6
|
+
* emits a structured warning for operator visibility.
|
|
7
|
+
*
|
|
8
|
+
* The monitor is stateless and side-effect-free beyond returning a
|
|
9
|
+
* diagnostic result. Callers (gateway, CLI, health-check) decide how
|
|
10
|
+
* to surface the warning.
|
|
11
|
+
*/
|
|
12
|
+
import type { PriceCatalog } from '../../domain/types/index.js';
|
|
13
|
+
export interface StalenessResult {
|
|
14
|
+
readonly stale: boolean;
|
|
15
|
+
readonly age_days: number;
|
|
16
|
+
readonly threshold_days: number;
|
|
17
|
+
readonly warning?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Evaluate pricing freshness against the configured threshold.
|
|
21
|
+
*
|
|
22
|
+
* @param catalog Current price catalog, or null if none loaded.
|
|
23
|
+
* @param stalenessDays Operator-configured threshold (default 14).
|
|
24
|
+
* @param now Reference time for testability.
|
|
25
|
+
*/
|
|
26
|
+
export declare function checkStaleness(catalog: PriceCatalog | null, stalenessDays?: number, now?: Date): StalenessResult;
|
|
27
|
+
//# sourceMappingURL=pricing-monitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing-monitor.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/pricing/pricing-monitor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAIhE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,YAAY,GAAG,IAAI,EAC5B,aAAa,GAAE,MAAW,EAC1B,GAAG,GAAE,IAAiB,GACrB,eAAe,CA8BjB"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pricing staleness monitor — FR-020 (T054).
|
|
3
|
+
*
|
|
4
|
+
* Checks whether the PriceCatalog's last_updated timestamp exceeds a
|
|
5
|
+
* configurable staleness threshold (default: 14 days). When stale,
|
|
6
|
+
* emits a structured warning for operator visibility.
|
|
7
|
+
*
|
|
8
|
+
* The monitor is stateless and side-effect-free beyond returning a
|
|
9
|
+
* diagnostic result. Callers (gateway, CLI, health-check) decide how
|
|
10
|
+
* to surface the warning.
|
|
11
|
+
*/
|
|
12
|
+
const MS_PER_DAY = 86_400_000;
|
|
13
|
+
/**
|
|
14
|
+
* Evaluate pricing freshness against the configured threshold.
|
|
15
|
+
*
|
|
16
|
+
* @param catalog Current price catalog, or null if none loaded.
|
|
17
|
+
* @param stalenessDays Operator-configured threshold (default 14).
|
|
18
|
+
* @param now Reference time for testability.
|
|
19
|
+
*/
|
|
20
|
+
export function checkStaleness(catalog, stalenessDays = 14, now = new Date()) {
|
|
21
|
+
if (!catalog) {
|
|
22
|
+
return {
|
|
23
|
+
stale: true,
|
|
24
|
+
age_days: Infinity,
|
|
25
|
+
threshold_days: stalenessDays,
|
|
26
|
+
warning: 'No pricing catalog loaded. Model costs will use YAML fallback values.',
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const lastUpdated = new Date(catalog.last_updated);
|
|
30
|
+
const ageDays = (now.getTime() - lastUpdated.getTime()) / MS_PER_DAY;
|
|
31
|
+
if (ageDays > stalenessDays) {
|
|
32
|
+
return {
|
|
33
|
+
stale: true,
|
|
34
|
+
age_days: Math.round(ageDays * 10) / 10,
|
|
35
|
+
threshold_days: stalenessDays,
|
|
36
|
+
warning: `Pricing data is ${Math.round(ageDays)} days old (threshold: ${stalenessDays} days). ` +
|
|
37
|
+
'Consider refreshing registry rates to ensure accurate cost estimation.',
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
stale: false,
|
|
42
|
+
age_days: Math.round(ageDays * 10) / 10,
|
|
43
|
+
threshold_days: stalenessDays,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=pricing-monitor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing-monitor.js","sourceRoot":"","sources":["../../../src/infrastructure/pricing/pricing-monitor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,MAAM,UAAU,GAAG,UAAU,CAAC;AAS9B;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,OAA4B,EAC5B,gBAAwB,EAAE,EAC1B,MAAY,IAAI,IAAI,EAAE;IAEtB,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;YACL,KAAK,EAAE,IAAI;YACX,QAAQ,EAAE,QAAQ;YAClB,cAAc,EAAE,aAAa;YAC7B,OAAO,EACL,uEAAuE;SAC1E,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,GAAG,UAAU,CAAC;IAErE,IAAI,OAAO,GAAG,aAAa,EAAE,CAAC;QAC5B,OAAO;YACL,KAAK,EAAE,IAAI;YACX,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,GAAG,EAAE;YACvC,cAAc,EAAE,aAAa;YAC7B,OAAO,EACL,mBAAmB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,yBAAyB,aAAa,UAAU;gBACtF,wEAAwE;SAC3E,CAAC;IACJ,CAAC;IAED,OAAO;QACL,KAAK,EAAE,KAAK;QACZ,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,GAAG,EAAE;QACvC,cAAc,EAAE,aAAa;KAC9B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared retention bounds for routing dataset records (in-memory and SQLite).
|
|
3
|
+
* GitHub #8: 30 days / 10k rows.
|
|
4
|
+
*/
|
|
5
|
+
import type { RoutingDatasetRecord } from '../../domain/types/index.js';
|
|
6
|
+
export declare const DATASET_WINDOW_DAYS = 30;
|
|
7
|
+
export declare const DATASET_WINDOW_MS: number;
|
|
8
|
+
export declare const DATASET_MAX_ENTRIES = 10000;
|
|
9
|
+
/** Remove dataset entries older than the rolling window. */
|
|
10
|
+
export declare function evictExpiredDatasetEntries(entries: RoutingDatasetRecord[], windowMs?: number): void;
|
|
11
|
+
/** Make room for one more dataset entry before append. */
|
|
12
|
+
export declare function makeDatasetRoom(entries: RoutingDatasetRecord[], maxEntries?: number, windowMs?: number): void;
|
|
13
|
+
//# sourceMappingURL=dataset-limits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataset-limits.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/telemetry/dataset-limits.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAExE,eAAO,MAAM,mBAAmB,KAAK,CAAC;AACtC,eAAO,MAAM,iBAAiB,QAA4C,CAAC;AAC3E,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAE1C,4DAA4D;AAC5D,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,oBAAoB,EAAE,EAC/B,QAAQ,GAAE,MAA0B,GACnC,IAAI,CAWN;AAED,0DAA0D;AAC1D,wBAAgB,eAAe,CAC7B,OAAO,EAAE,oBAAoB,EAAE,EAC/B,UAAU,GAAE,MAA4B,EACxC,QAAQ,GAAE,MAA0B,GACnC,IAAI,CAKN"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared retention bounds for routing dataset records (in-memory and SQLite).
|
|
3
|
+
* GitHub #8: 30 days / 10k rows.
|
|
4
|
+
*/
|
|
5
|
+
export const DATASET_WINDOW_DAYS = 30;
|
|
6
|
+
export const DATASET_WINDOW_MS = DATASET_WINDOW_DAYS * 24 * 60 * 60 * 1000;
|
|
7
|
+
export const DATASET_MAX_ENTRIES = 10_000;
|
|
8
|
+
/** Remove dataset entries older than the rolling window. */
|
|
9
|
+
export function evictExpiredDatasetEntries(entries, windowMs = DATASET_WINDOW_MS) {
|
|
10
|
+
const cutoff = Date.now() - windowMs;
|
|
11
|
+
while (entries.length > 0) {
|
|
12
|
+
const oldest = entries[0];
|
|
13
|
+
if (new Date(oldest.timestamp).getTime() < cutoff) {
|
|
14
|
+
entries.shift();
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Make room for one more dataset entry before append. */
|
|
22
|
+
export function makeDatasetRoom(entries, maxEntries = DATASET_MAX_ENTRIES, windowMs = DATASET_WINDOW_MS) {
|
|
23
|
+
evictExpiredDatasetEntries(entries, windowMs);
|
|
24
|
+
while (entries.length >= maxEntries) {
|
|
25
|
+
entries.shift();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=dataset-limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataset-limits.js","sourceRoot":"","sources":["../../../src/infrastructure/telemetry/dataset-limits.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AACtC,MAAM,CAAC,MAAM,iBAAiB,GAAG,mBAAmB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAC3E,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAE1C,4DAA4D;AAC5D,MAAM,UAAU,0BAA0B,CACxC,OAA+B,EAC/B,WAAmB,iBAAiB;IAEpC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC;IAErC,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC;QAC3B,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC;YAClD,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,MAAM;QACR,CAAC;IACH,CAAC;AACH,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,eAAe,CAC7B,OAA+B,EAC/B,aAAqB,mBAAmB,EACxC,WAAmB,iBAAiB;IAEpC,0BAA0B,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC9C,OAAO,OAAO,CAAC,MAAM,IAAI,UAAU,EAAE,CAAC;QACpC,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Privacy-safe routing dataset recorder (SP-058).
|
|
3
|
+
*
|
|
4
|
+
* Maps routing decisions and feature sidecars to RoutingDatasetRecord when
|
|
5
|
+
* SMART_ROUTER_DATASET=1. Never stores prompt text, messages, or tool arguments.
|
|
6
|
+
*
|
|
7
|
+
* Optional install-local prompt fingerprints (SP-061) when
|
|
8
|
+
* SMART_ROUTER_DATASET_FINGERPRINT=1.
|
|
9
|
+
*/
|
|
10
|
+
import type { RoutingDatasetRecord, RoutingDecision, RoutingRequest } from '../../domain/types/index.js';
|
|
11
|
+
import type { TierFeatureDatasetScalars } from '../../domain/routing/tier-features.js';
|
|
12
|
+
import { type ContextFitObservabilityInput } from './routing-telemetry.js';
|
|
13
|
+
export declare const DATASET_ENABLED_NOTIFY_MESSAGE = "Smart Router dataset mode is enabled. Recording routing metadata and feature fields only \u2014 prompt text, messages, and tool arguments are never stored.";
|
|
14
|
+
export declare const DATASET_STATE_DIR = ".pi-smart-router";
|
|
15
|
+
export declare const DATASET_PEPPER_FILENAME = ".dataset-key";
|
|
16
|
+
export declare function isDatasetRecordingEnabled(): boolean;
|
|
17
|
+
export declare function isDatasetFingerprintEnabled(): boolean;
|
|
18
|
+
export declare function getDatasetPepperPath(cwd?: string): string;
|
|
19
|
+
/** Load or create the install-local dataset pepper (never exported). */
|
|
20
|
+
export declare function loadOrCreateDatasetPepper(cwd?: string): Buffer;
|
|
21
|
+
/** Collapse whitespace and trim for stable duplicate detection. */
|
|
22
|
+
export declare function normalizePromptForFingerprint(prompt: string): string;
|
|
23
|
+
export declare function computePromptFingerprint(pepper: Buffer, prompt: string): string;
|
|
24
|
+
export interface DatasetRecorderOptions {
|
|
25
|
+
readonly clock?: () => string;
|
|
26
|
+
readonly onRecord?: (record: RoutingDatasetRecord) => void;
|
|
27
|
+
readonly onFirstEnable?: () => void;
|
|
28
|
+
readonly cwd?: string;
|
|
29
|
+
readonly loadPepper?: (cwd: string) => Buffer;
|
|
30
|
+
readonly contextFitInput?: Omit<ContextFitObservabilityInput, 'request' | 'decision'>;
|
|
31
|
+
}
|
|
32
|
+
/** Map a completed routing decision to a privacy-safe dataset row. */
|
|
33
|
+
export declare function buildDatasetRecord(request: RoutingRequest, decision: RoutingDecision, timestamp: string, promptFingerprint?: string | null, tierScalars?: TierFeatureDatasetScalars, contextFitInput?: Omit<ContextFitObservabilityInput, 'request' | 'decision'>): RoutingDatasetRecord;
|
|
34
|
+
export declare class DatasetRecorder {
|
|
35
|
+
private readonly clock;
|
|
36
|
+
private readonly onRecord;
|
|
37
|
+
private readonly onFirstEnable;
|
|
38
|
+
private readonly cwd;
|
|
39
|
+
private readonly loadPepper;
|
|
40
|
+
private readonly contextFitInput;
|
|
41
|
+
private enabledNotified;
|
|
42
|
+
private pepper;
|
|
43
|
+
constructor(options?: DatasetRecorderOptions);
|
|
44
|
+
private getPepper;
|
|
45
|
+
/** Record a routing decision when dataset mode is enabled; no-op when off. */
|
|
46
|
+
record(request: RoutingRequest, decision: RoutingDecision): RoutingDatasetRecord | null;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=dataset-recorder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataset-recorder.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/telemetry/dataset-recorder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EACV,oBAAoB,EACpB,eAAe,EACf,cAAc,EACf,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,EAGL,KAAK,4BAA4B,EAClC,MAAM,wBAAwB,CAAC;AAEhC,eAAO,MAAM,8BAA8B,gKAC+G,CAAC;AAE3J,eAAO,MAAM,iBAAiB,qBAAqB,CAAC;AACpD,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AAItD,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAED,wBAAgB,2BAA2B,IAAI,OAAO,CAKrD;AAED,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAExE;AAED,wEAAwE;AACxE,wBAAgB,yBAAyB,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAY7E;AAED,mEAAmE;AACnE,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAI/E;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC3D,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IACpC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9C,QAAQ,CAAC,eAAe,CAAC,EAAE,IAAI,CAAC,4BAA4B,EAAE,SAAS,GAAG,UAAU,CAAC,CAAC;CACvF;AAmBD,sEAAsE;AACtE,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,eAAe,EACzB,SAAS,EAAE,MAAM,EACjB,iBAAiB,GAAE,MAAM,GAAG,IAAW,EACvC,WAAW,CAAC,EAAE,yBAAyB,EACvC,eAAe,CAAC,EAAE,IAAI,CAAC,4BAA4B,EAAE,SAAS,GAAG,UAAU,CAAC,GAC3E,oBAAoB,CAmDtB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuD;IAChF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA2B;IACzD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0B;IACrD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAyE;IACzG,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,MAAM,CAAuB;gBAEzB,OAAO,CAAC,EAAE,sBAAsB;IAS5C,OAAO,CAAC,SAAS;IAOjB,8EAA8E;IAC9E,MAAM,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,eAAe,GAAG,oBAAoB,GAAG,IAAI;CAyBxF"}
|