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,658 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite-backed persistence store for routing state.
|
|
3
|
+
*
|
|
4
|
+
* Implements StorePort from domain types, plus token-bucket rate limiting.
|
|
5
|
+
* Uses WAL journal mode for concurrent reads and BEGIN IMMEDIATE for
|
|
6
|
+
* atomic token-bucket operations (prevents TOCTOU on rate_limits table).
|
|
7
|
+
*
|
|
8
|
+
* Maps to T013 in the routing pipeline spec.
|
|
9
|
+
*/
|
|
10
|
+
import { renameSync } from 'node:fs';
|
|
11
|
+
import Database from 'better-sqlite3';
|
|
12
|
+
import { MemoryStore } from './memory-store.js';
|
|
13
|
+
import { DEFAULT_HISTORY_LIMIT, MAX_HISTORY_LIMIT, TELEMETRY_MAX_ENTRIES, TELEMETRY_WINDOW_MS, } from '../telemetry/telemetry-limits.js';
|
|
14
|
+
import { DATASET_MAX_ENTRIES, DATASET_WINDOW_MS, } from '../telemetry/dataset-limits.js';
|
|
15
|
+
import { OUTCOME_MAX_ENTRIES, OUTCOME_WINDOW_MS, } from '../telemetry/outcome-limits.js';
|
|
16
|
+
// ─── Schema version & migrations ────────────────────────────────────────────
|
|
17
|
+
const CURRENT_SCHEMA_VERSION = 5;
|
|
18
|
+
const MIGRATION_V1 = `
|
|
19
|
+
CREATE TABLE IF NOT EXISTS pins (
|
|
20
|
+
session_id TEXT PRIMARY KEY,
|
|
21
|
+
pinned_model_id TEXT NOT NULL,
|
|
22
|
+
pin_reason TEXT NOT NULL CHECK (pin_reason IN ('initial','user_forced','loop_escalation','compaction','cache_economics','context_overflow')),
|
|
23
|
+
has_ever_switched INTEGER NOT NULL DEFAULT 0,
|
|
24
|
+
consecutive_upstream_errors INTEGER NOT NULL DEFAULT 0,
|
|
25
|
+
consecutive_tool_failures INTEGER NOT NULL DEFAULT 0,
|
|
26
|
+
last_tool_failure_signature TEXT,
|
|
27
|
+
created_at TEXT NOT NULL,
|
|
28
|
+
updated_at TEXT NOT NULL
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
CREATE TABLE IF NOT EXISTS rate_limits (
|
|
32
|
+
bucket_key TEXT PRIMARY KEY,
|
|
33
|
+
tokens REAL NOT NULL,
|
|
34
|
+
max_tokens REAL NOT NULL,
|
|
35
|
+
refill_rate REAL NOT NULL,
|
|
36
|
+
last_refill_at TEXT NOT NULL
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
CREATE TABLE IF NOT EXISTS price_cache (
|
|
40
|
+
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
41
|
+
registry_snapshot TEXT NOT NULL,
|
|
42
|
+
user_overrides TEXT NOT NULL,
|
|
43
|
+
last_updated TEXT NOT NULL,
|
|
44
|
+
source TEXT NOT NULL CHECK (source IN ('override','registry','yaml_fallback'))
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
CREATE TABLE IF NOT EXISTS telemetry (
|
|
48
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
49
|
+
timestamp TEXT NOT NULL,
|
|
50
|
+
session_id TEXT NOT NULL,
|
|
51
|
+
request_id TEXT NOT NULL,
|
|
52
|
+
turn_type TEXT NOT NULL,
|
|
53
|
+
stage TEXT NOT NULL,
|
|
54
|
+
reason_code TEXT NOT NULL,
|
|
55
|
+
selected_model_id TEXT NOT NULL,
|
|
56
|
+
estimated_cost_usd REAL NOT NULL,
|
|
57
|
+
routing_latency_ms REAL NOT NULL,
|
|
58
|
+
pin_reason TEXT
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
CREATE INDEX IF NOT EXISTS idx_telemetry_session ON telemetry(session_id);
|
|
62
|
+
CREATE INDEX IF NOT EXISTS idx_telemetry_timestamp ON telemetry(timestamp);
|
|
63
|
+
`;
|
|
64
|
+
const MIGRATION_V2 = `
|
|
65
|
+
CREATE TABLE IF NOT EXISTS dataset (
|
|
66
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
67
|
+
request_id TEXT NOT NULL,
|
|
68
|
+
timestamp TEXT NOT NULL,
|
|
69
|
+
turn_type TEXT NOT NULL,
|
|
70
|
+
stage TEXT NOT NULL,
|
|
71
|
+
reason_code TEXT NOT NULL,
|
|
72
|
+
selected_model_id TEXT NOT NULL,
|
|
73
|
+
tier TEXT NOT NULL,
|
|
74
|
+
candidates_json TEXT,
|
|
75
|
+
prompt_length_chars INTEGER NOT NULL,
|
|
76
|
+
estimated_input_tokens INTEGER,
|
|
77
|
+
message_count INTEGER NOT NULL,
|
|
78
|
+
has_tool_context INTEGER NOT NULL,
|
|
79
|
+
compaction_flag INTEGER NOT NULL,
|
|
80
|
+
triage_verdict TEXT,
|
|
81
|
+
triage_reason_code TEXT,
|
|
82
|
+
triage_cyclomatic_score REAL,
|
|
83
|
+
triage_trivial_hits INTEGER,
|
|
84
|
+
triage_complex_hits INTEGER,
|
|
85
|
+
triage_sanitized_length_delta INTEGER,
|
|
86
|
+
requirement_reasoning REAL,
|
|
87
|
+
requirement_code_gen REAL,
|
|
88
|
+
requirement_tool_use REAL,
|
|
89
|
+
routing_latency_ms REAL NOT NULL,
|
|
90
|
+
estimated_cost_usd REAL
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
CREATE INDEX IF NOT EXISTS idx_dataset_timestamp ON dataset(timestamp);
|
|
94
|
+
CREATE INDEX IF NOT EXISTS idx_dataset_request ON dataset(request_id);
|
|
95
|
+
`;
|
|
96
|
+
const MIGRATION_V3 = `
|
|
97
|
+
ALTER TABLE dataset ADD COLUMN prompt_fingerprint TEXT;
|
|
98
|
+
`;
|
|
99
|
+
const MIGRATION_V4 = `
|
|
100
|
+
CREATE TABLE IF NOT EXISTS outcomes (
|
|
101
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
102
|
+
request_id TEXT NOT NULL,
|
|
103
|
+
session_id TEXT NOT NULL,
|
|
104
|
+
timestamp TEXT NOT NULL,
|
|
105
|
+
signal_type TEXT NOT NULL CHECK (signal_type IN ('model_override','compaction_pin_break','feedback_good','feedback_bad')),
|
|
106
|
+
routed_model_id TEXT,
|
|
107
|
+
override_model_id TEXT
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
CREATE INDEX IF NOT EXISTS idx_outcomes_timestamp ON outcomes(timestamp);
|
|
111
|
+
CREATE INDEX IF NOT EXISTS idx_outcomes_request ON outcomes(request_id);
|
|
112
|
+
CREATE INDEX IF NOT EXISTS idx_outcomes_session ON outcomes(session_id);
|
|
113
|
+
`;
|
|
114
|
+
const MIGRATION_V5 = `
|
|
115
|
+
CREATE TABLE pins_v5 (
|
|
116
|
+
session_id TEXT PRIMARY KEY,
|
|
117
|
+
pinned_model_id TEXT NOT NULL,
|
|
118
|
+
pin_reason TEXT NOT NULL CHECK (pin_reason IN ('initial','user_forced','loop_escalation','compaction','cache_economics','context_overflow')),
|
|
119
|
+
has_ever_switched INTEGER NOT NULL DEFAULT 0,
|
|
120
|
+
consecutive_upstream_errors INTEGER NOT NULL DEFAULT 0,
|
|
121
|
+
consecutive_tool_failures INTEGER NOT NULL DEFAULT 0,
|
|
122
|
+
last_tool_failure_signature TEXT,
|
|
123
|
+
created_at TEXT NOT NULL,
|
|
124
|
+
updated_at TEXT NOT NULL
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
INSERT INTO pins_v5 (
|
|
128
|
+
session_id, pinned_model_id, pin_reason,
|
|
129
|
+
has_ever_switched, consecutive_upstream_errors,
|
|
130
|
+
consecutive_tool_failures, last_tool_failure_signature,
|
|
131
|
+
created_at, updated_at
|
|
132
|
+
)
|
|
133
|
+
SELECT
|
|
134
|
+
session_id, pinned_model_id, pin_reason,
|
|
135
|
+
has_ever_switched, consecutive_upstream_errors,
|
|
136
|
+
consecutive_tool_failures, last_tool_failure_signature,
|
|
137
|
+
created_at, updated_at
|
|
138
|
+
FROM pins;
|
|
139
|
+
|
|
140
|
+
DROP TABLE pins;
|
|
141
|
+
ALTER TABLE pins_v5 RENAME TO pins;
|
|
142
|
+
`;
|
|
143
|
+
/**
|
|
144
|
+
* Create a persistence store with corrupt-DB recovery.
|
|
145
|
+
*
|
|
146
|
+
* Strategy:
|
|
147
|
+
* 1. Attempt to open the SQLite DB and run migrations.
|
|
148
|
+
* 2. On failure (corrupt/locked): rename the file, try fresh creation.
|
|
149
|
+
* 3. If recreation also fails: fall back to MemoryStore.
|
|
150
|
+
*
|
|
151
|
+
* Never throws — the host agent must not crash due to persistence issues.
|
|
152
|
+
*/
|
|
153
|
+
export function createResilientStore(options) {
|
|
154
|
+
if (options.dbPath === ':memory:') {
|
|
155
|
+
return { store: new SqliteStore(options), degraded: false };
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
return { store: new SqliteStore(options), degraded: false };
|
|
159
|
+
}
|
|
160
|
+
catch (firstError) {
|
|
161
|
+
console.warn('SQLite store open failed; attempting corrupt-DB recovery', firstError);
|
|
162
|
+
try {
|
|
163
|
+
const corruptPath = `${options.dbPath}.corrupt.${Date.now()}`;
|
|
164
|
+
renameSync(options.dbPath, corruptPath);
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// Rename may fail if the file doesn't exist or permissions issue — continue to recreate attempt
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
return { store: new SqliteStore(options), degraded: false };
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return { store: new MemoryStore(options.models), degraded: true };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// ─── SqliteStore ────────────────────────────────────────────────────────────
|
|
178
|
+
export class SqliteStore {
|
|
179
|
+
db;
|
|
180
|
+
models;
|
|
181
|
+
consumeTokenTx;
|
|
182
|
+
constructor(options) {
|
|
183
|
+
this.db = new Database(options.dbPath);
|
|
184
|
+
this.models = options.models;
|
|
185
|
+
this.initialize();
|
|
186
|
+
this.consumeTokenTx = this.buildConsumeTokenTx();
|
|
187
|
+
}
|
|
188
|
+
// ─── StorePort: SessionPin ──────────────────────────────────────────────
|
|
189
|
+
async getSessionPin(sessionId) {
|
|
190
|
+
const row = this.db
|
|
191
|
+
.prepare('SELECT * FROM pins WHERE session_id = ?')
|
|
192
|
+
.get(sessionId);
|
|
193
|
+
return row ? pinRowToEntity(row) : null;
|
|
194
|
+
}
|
|
195
|
+
async putSessionPin(pin) {
|
|
196
|
+
this.db
|
|
197
|
+
.prepare(`INSERT INTO pins (
|
|
198
|
+
session_id, pinned_model_id, pin_reason,
|
|
199
|
+
has_ever_switched, consecutive_upstream_errors,
|
|
200
|
+
consecutive_tool_failures, last_tool_failure_signature,
|
|
201
|
+
created_at, updated_at
|
|
202
|
+
) VALUES (
|
|
203
|
+
@session_id, @pinned_model_id, @pin_reason,
|
|
204
|
+
@has_ever_switched, @consecutive_upstream_errors,
|
|
205
|
+
@consecutive_tool_failures, @last_tool_failure_signature,
|
|
206
|
+
@created_at, @updated_at
|
|
207
|
+
)
|
|
208
|
+
ON CONFLICT(session_id) DO UPDATE SET
|
|
209
|
+
pinned_model_id = excluded.pinned_model_id,
|
|
210
|
+
pin_reason = excluded.pin_reason,
|
|
211
|
+
has_ever_switched = excluded.has_ever_switched,
|
|
212
|
+
consecutive_upstream_errors = excluded.consecutive_upstream_errors,
|
|
213
|
+
consecutive_tool_failures = excluded.consecutive_tool_failures,
|
|
214
|
+
last_tool_failure_signature = excluded.last_tool_failure_signature,
|
|
215
|
+
updated_at = excluded.updated_at`)
|
|
216
|
+
.run({
|
|
217
|
+
session_id: pin.session_id,
|
|
218
|
+
pinned_model_id: pin.pinned_model_id,
|
|
219
|
+
pin_reason: pin.pin_reason,
|
|
220
|
+
has_ever_switched: pin.has_ever_switched ? 1 : 0,
|
|
221
|
+
consecutive_upstream_errors: pin.consecutive_upstream_errors,
|
|
222
|
+
consecutive_tool_failures: pin.consecutive_tool_failures,
|
|
223
|
+
last_tool_failure_signature: pin.last_tool_failure_signature,
|
|
224
|
+
created_at: pin.created_at,
|
|
225
|
+
updated_at: pin.updated_at,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
async deleteSessionPin(sessionId) {
|
|
229
|
+
this.db.prepare('DELETE FROM pins WHERE session_id = ?').run(sessionId);
|
|
230
|
+
}
|
|
231
|
+
// ─── StorePort: ModelProfile (read-only, from fleet catalog) ────────────
|
|
232
|
+
async getModelProfiles() {
|
|
233
|
+
return this.models;
|
|
234
|
+
}
|
|
235
|
+
// ─── StorePort: PriceCatalog ────────────────────────────────────────────
|
|
236
|
+
async getPriceCatalog() {
|
|
237
|
+
const row = this.db
|
|
238
|
+
.prepare('SELECT * FROM price_cache WHERE id = 1')
|
|
239
|
+
.get();
|
|
240
|
+
if (!row)
|
|
241
|
+
return null;
|
|
242
|
+
return {
|
|
243
|
+
registry_snapshot: JSON.parse(row.registry_snapshot),
|
|
244
|
+
user_overrides: JSON.parse(row.user_overrides),
|
|
245
|
+
last_updated: row.last_updated,
|
|
246
|
+
source: row.source,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
async putPriceCatalog(catalog) {
|
|
250
|
+
this.db
|
|
251
|
+
.prepare(`INSERT INTO price_cache (id, registry_snapshot, user_overrides, last_updated, source)
|
|
252
|
+
VALUES (1, @registry_snapshot, @user_overrides, @last_updated, @source)
|
|
253
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
254
|
+
registry_snapshot = excluded.registry_snapshot,
|
|
255
|
+
user_overrides = excluded.user_overrides,
|
|
256
|
+
last_updated = excluded.last_updated,
|
|
257
|
+
source = excluded.source`)
|
|
258
|
+
.run({
|
|
259
|
+
registry_snapshot: JSON.stringify(catalog.registry_snapshot),
|
|
260
|
+
user_overrides: JSON.stringify(catalog.user_overrides),
|
|
261
|
+
last_updated: catalog.last_updated,
|
|
262
|
+
source: catalog.source,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
// ─── Telemetry (append-only) ────────────────────────────────────────────
|
|
266
|
+
appendTelemetry(entry) {
|
|
267
|
+
this.db
|
|
268
|
+
.prepare(`INSERT INTO telemetry (
|
|
269
|
+
timestamp, session_id, request_id, turn_type,
|
|
270
|
+
stage, reason_code, selected_model_id,
|
|
271
|
+
estimated_cost_usd, routing_latency_ms, pin_reason
|
|
272
|
+
) VALUES (
|
|
273
|
+
@timestamp, @session_id, @request_id, @turn_type,
|
|
274
|
+
@stage, @reason_code, @selected_model_id,
|
|
275
|
+
@estimated_cost_usd, @routing_latency_ms, @pin_reason
|
|
276
|
+
)`)
|
|
277
|
+
.run(entry);
|
|
278
|
+
this.evictTelemetryRows();
|
|
279
|
+
}
|
|
280
|
+
async listTelemetry(options) {
|
|
281
|
+
const limit = clampHistoryLimit(options?.limit);
|
|
282
|
+
const sessionId = options?.sessionId;
|
|
283
|
+
const rows = sessionId
|
|
284
|
+
? this.db
|
|
285
|
+
.prepare(`SELECT * FROM telemetry
|
|
286
|
+
WHERE session_id = ?
|
|
287
|
+
ORDER BY id DESC
|
|
288
|
+
LIMIT ?`)
|
|
289
|
+
.all(sessionId, limit)
|
|
290
|
+
: this.db
|
|
291
|
+
.prepare(`SELECT * FROM telemetry
|
|
292
|
+
ORDER BY id DESC
|
|
293
|
+
LIMIT ?`)
|
|
294
|
+
.all(limit);
|
|
295
|
+
return rows.map(telemetryRowToEntity);
|
|
296
|
+
}
|
|
297
|
+
evictTelemetryRows() {
|
|
298
|
+
const cutoff = new Date(Date.now() - TELEMETRY_WINDOW_MS).toISOString();
|
|
299
|
+
this.db.prepare('DELETE FROM telemetry WHERE timestamp < ?').run(cutoff);
|
|
300
|
+
const countRow = this.db
|
|
301
|
+
.prepare('SELECT COUNT(*) AS count FROM telemetry')
|
|
302
|
+
.get();
|
|
303
|
+
const excess = countRow.count - TELEMETRY_MAX_ENTRIES;
|
|
304
|
+
if (excess <= 0) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
this.db
|
|
308
|
+
.prepare(`DELETE FROM telemetry
|
|
309
|
+
WHERE id IN (
|
|
310
|
+
SELECT id FROM telemetry
|
|
311
|
+
ORDER BY id ASC
|
|
312
|
+
LIMIT ?
|
|
313
|
+
)`)
|
|
314
|
+
.run(excess);
|
|
315
|
+
}
|
|
316
|
+
// ─── Dataset (append-only, privacy-safe) ────────────────────────────────
|
|
317
|
+
appendDatasetRecord(entry) {
|
|
318
|
+
this.db
|
|
319
|
+
.prepare(`INSERT INTO dataset (
|
|
320
|
+
request_id, timestamp, turn_type, stage, reason_code,
|
|
321
|
+
selected_model_id, tier, candidates_json,
|
|
322
|
+
prompt_length_chars, estimated_input_tokens, message_count,
|
|
323
|
+
has_tool_context, compaction_flag,
|
|
324
|
+
triage_verdict, triage_reason_code, triage_cyclomatic_score,
|
|
325
|
+
triage_trivial_hits, triage_complex_hits, triage_sanitized_length_delta,
|
|
326
|
+
requirement_reasoning, requirement_code_gen, requirement_tool_use,
|
|
327
|
+
routing_latency_ms, estimated_cost_usd, prompt_fingerprint
|
|
328
|
+
) VALUES (
|
|
329
|
+
@request_id, @timestamp, @turn_type, @stage, @reason_code,
|
|
330
|
+
@selected_model_id, @tier, @candidates_json,
|
|
331
|
+
@prompt_length_chars, @estimated_input_tokens, @message_count,
|
|
332
|
+
@has_tool_context, @compaction_flag,
|
|
333
|
+
@triage_verdict, @triage_reason_code, @triage_cyclomatic_score,
|
|
334
|
+
@triage_trivial_hits, @triage_complex_hits, @triage_sanitized_length_delta,
|
|
335
|
+
@requirement_reasoning, @requirement_code_gen, @requirement_tool_use,
|
|
336
|
+
@routing_latency_ms, @estimated_cost_usd, @prompt_fingerprint
|
|
337
|
+
)`)
|
|
338
|
+
.run({
|
|
339
|
+
request_id: entry.request_id,
|
|
340
|
+
timestamp: entry.timestamp,
|
|
341
|
+
turn_type: entry.turn_type,
|
|
342
|
+
stage: entry.stage,
|
|
343
|
+
reason_code: entry.reason_code,
|
|
344
|
+
selected_model_id: entry.selected_model_id,
|
|
345
|
+
tier: entry.tier,
|
|
346
|
+
candidates_json: entry.candidates_json,
|
|
347
|
+
prompt_length_chars: entry.prompt_length_chars,
|
|
348
|
+
estimated_input_tokens: entry.estimated_input_tokens,
|
|
349
|
+
message_count: entry.message_count,
|
|
350
|
+
has_tool_context: entry.has_tool_context ? 1 : 0,
|
|
351
|
+
compaction_flag: entry.compaction_flag ? 1 : 0,
|
|
352
|
+
triage_verdict: entry.triage_verdict,
|
|
353
|
+
triage_reason_code: entry.triage_reason_code,
|
|
354
|
+
triage_cyclomatic_score: entry.triage_cyclomatic_score,
|
|
355
|
+
triage_trivial_hits: entry.triage_trivial_hits,
|
|
356
|
+
triage_complex_hits: entry.triage_complex_hits,
|
|
357
|
+
triage_sanitized_length_delta: entry.triage_sanitized_length_delta,
|
|
358
|
+
requirement_reasoning: entry.requirement_reasoning,
|
|
359
|
+
requirement_code_gen: entry.requirement_code_gen,
|
|
360
|
+
requirement_tool_use: entry.requirement_tool_use,
|
|
361
|
+
routing_latency_ms: entry.routing_latency_ms,
|
|
362
|
+
estimated_cost_usd: entry.estimated_cost_usd,
|
|
363
|
+
prompt_fingerprint: entry.prompt_fingerprint,
|
|
364
|
+
});
|
|
365
|
+
this.evictDatasetRows();
|
|
366
|
+
}
|
|
367
|
+
async listDatasetRecords(options) {
|
|
368
|
+
const limit = clampHistoryLimit(options?.limit);
|
|
369
|
+
const rows = this.db
|
|
370
|
+
.prepare(`SELECT * FROM dataset
|
|
371
|
+
ORDER BY id DESC
|
|
372
|
+
LIMIT ?`)
|
|
373
|
+
.all(limit);
|
|
374
|
+
return rows.map(datasetRowToEntity);
|
|
375
|
+
}
|
|
376
|
+
evictDatasetRows() {
|
|
377
|
+
const cutoff = new Date(Date.now() - DATASET_WINDOW_MS).toISOString();
|
|
378
|
+
this.db.prepare('DELETE FROM dataset WHERE timestamp < ?').run(cutoff);
|
|
379
|
+
const countRow = this.db
|
|
380
|
+
.prepare('SELECT COUNT(*) AS count FROM dataset')
|
|
381
|
+
.get();
|
|
382
|
+
const excess = countRow.count - DATASET_MAX_ENTRIES;
|
|
383
|
+
if (excess <= 0) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
this.db
|
|
387
|
+
.prepare(`DELETE FROM dataset
|
|
388
|
+
WHERE id IN (
|
|
389
|
+
SELECT id FROM dataset
|
|
390
|
+
ORDER BY id ASC
|
|
391
|
+
LIMIT ?
|
|
392
|
+
)`)
|
|
393
|
+
.run(excess);
|
|
394
|
+
}
|
|
395
|
+
// ─── Outcomes (append-only, privacy-safe) ───────────────────────────────
|
|
396
|
+
appendOutcomeRecord(entry) {
|
|
397
|
+
this.db
|
|
398
|
+
.prepare(`INSERT INTO outcomes (
|
|
399
|
+
request_id, session_id, timestamp, signal_type,
|
|
400
|
+
routed_model_id, override_model_id
|
|
401
|
+
) VALUES (
|
|
402
|
+
@request_id, @session_id, @timestamp, @signal_type,
|
|
403
|
+
@routed_model_id, @override_model_id
|
|
404
|
+
)`)
|
|
405
|
+
.run({
|
|
406
|
+
request_id: entry.request_id,
|
|
407
|
+
session_id: entry.session_id,
|
|
408
|
+
timestamp: entry.timestamp,
|
|
409
|
+
signal_type: entry.signal_type,
|
|
410
|
+
routed_model_id: entry.routed_model_id,
|
|
411
|
+
override_model_id: entry.override_model_id,
|
|
412
|
+
});
|
|
413
|
+
this.evictOutcomeRows();
|
|
414
|
+
}
|
|
415
|
+
async listOutcomeRecords(options) {
|
|
416
|
+
const limit = clampHistoryLimit(options?.limit);
|
|
417
|
+
const requestId = options?.requestId;
|
|
418
|
+
const sessionId = options?.sessionId;
|
|
419
|
+
const rows = requestId
|
|
420
|
+
? this.db
|
|
421
|
+
.prepare(`SELECT * FROM outcomes
|
|
422
|
+
WHERE request_id = ?
|
|
423
|
+
ORDER BY id DESC
|
|
424
|
+
LIMIT ?`)
|
|
425
|
+
.all(requestId, limit)
|
|
426
|
+
: sessionId
|
|
427
|
+
? this.db
|
|
428
|
+
.prepare(`SELECT * FROM outcomes
|
|
429
|
+
WHERE session_id = ?
|
|
430
|
+
ORDER BY id DESC
|
|
431
|
+
LIMIT ?`)
|
|
432
|
+
.all(sessionId, limit)
|
|
433
|
+
: this.db
|
|
434
|
+
.prepare(`SELECT * FROM outcomes
|
|
435
|
+
ORDER BY id DESC
|
|
436
|
+
LIMIT ?`)
|
|
437
|
+
.all(limit);
|
|
438
|
+
return rows.map(outcomeRowToEntity);
|
|
439
|
+
}
|
|
440
|
+
evictOutcomeRows() {
|
|
441
|
+
const cutoff = new Date(Date.now() - OUTCOME_WINDOW_MS).toISOString();
|
|
442
|
+
this.db.prepare('DELETE FROM outcomes WHERE timestamp < ?').run(cutoff);
|
|
443
|
+
const countRow = this.db
|
|
444
|
+
.prepare('SELECT COUNT(*) AS count FROM outcomes')
|
|
445
|
+
.get();
|
|
446
|
+
const excess = countRow.count - OUTCOME_MAX_ENTRIES;
|
|
447
|
+
if (excess <= 0) {
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
this.db
|
|
451
|
+
.prepare(`DELETE FROM outcomes
|
|
452
|
+
WHERE id IN (
|
|
453
|
+
SELECT id FROM outcomes
|
|
454
|
+
ORDER BY id ASC
|
|
455
|
+
LIMIT ?
|
|
456
|
+
)`)
|
|
457
|
+
.run(excess);
|
|
458
|
+
}
|
|
459
|
+
// ─── Token bucket (BEGIN IMMEDIATE) ─────────────────────────────────────
|
|
460
|
+
/**
|
|
461
|
+
* Initialize a token bucket. Idempotent — existing buckets are unchanged.
|
|
462
|
+
*/
|
|
463
|
+
initBucket(key, maxTokens, refillRate) {
|
|
464
|
+
this.db
|
|
465
|
+
.prepare(`INSERT OR IGNORE INTO rate_limits (bucket_key, tokens, max_tokens, refill_rate, last_refill_at)
|
|
466
|
+
VALUES (?, ?, ?, ?, ?)`)
|
|
467
|
+
.run(key, maxTokens, maxTokens, refillRate, new Date().toISOString());
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Atomically attempt to consume tokens from a bucket.
|
|
471
|
+
*
|
|
472
|
+
* Uses BEGIN IMMEDIATE to acquire a reserved lock before reading,
|
|
473
|
+
* preventing TOCTOU races between concurrent consumers.
|
|
474
|
+
*/
|
|
475
|
+
consumeToken(key, cost = 1) {
|
|
476
|
+
return this.consumeTokenTx(key, cost);
|
|
477
|
+
}
|
|
478
|
+
/** Run PRAGMA integrity_check. Returns true if the database is healthy. */
|
|
479
|
+
checkHealth() {
|
|
480
|
+
try {
|
|
481
|
+
const result = this.db.pragma('integrity_check', { simple: true });
|
|
482
|
+
return result === 'ok';
|
|
483
|
+
}
|
|
484
|
+
catch {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
/** Close the database connection. */
|
|
489
|
+
close() {
|
|
490
|
+
this.db.close();
|
|
491
|
+
}
|
|
492
|
+
// ─── Internals ──────────────────────────────────────────────────────────
|
|
493
|
+
initialize() {
|
|
494
|
+
this.db.pragma('journal_mode = WAL');
|
|
495
|
+
this.db.pragma('busy_timeout = 5000');
|
|
496
|
+
this.db.pragma('foreign_keys = ON');
|
|
497
|
+
this.runMigrations();
|
|
498
|
+
}
|
|
499
|
+
runMigrations() {
|
|
500
|
+
let version = this.db.pragma('user_version', { simple: true });
|
|
501
|
+
if (version < 1) {
|
|
502
|
+
this.db.exec(MIGRATION_V1);
|
|
503
|
+
version = 1;
|
|
504
|
+
this.db.pragma('user_version = 1');
|
|
505
|
+
}
|
|
506
|
+
if (version < 2) {
|
|
507
|
+
this.db.exec(MIGRATION_V2);
|
|
508
|
+
version = 2;
|
|
509
|
+
this.db.pragma('user_version = 2');
|
|
510
|
+
}
|
|
511
|
+
if (version < 3) {
|
|
512
|
+
this.db.exec(MIGRATION_V3);
|
|
513
|
+
version = 3;
|
|
514
|
+
this.db.pragma('user_version = 3');
|
|
515
|
+
}
|
|
516
|
+
if (version < 4) {
|
|
517
|
+
this.db.exec(MIGRATION_V4);
|
|
518
|
+
version = 4;
|
|
519
|
+
this.db.pragma('user_version = 4');
|
|
520
|
+
}
|
|
521
|
+
if (version < 5) {
|
|
522
|
+
this.db.exec(MIGRATION_V5);
|
|
523
|
+
this.db.pragma(`user_version = ${CURRENT_SCHEMA_VERSION}`);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
buildConsumeTokenTx() {
|
|
527
|
+
const selectBucket = this.db.prepare('SELECT * FROM rate_limits WHERE bucket_key = ?');
|
|
528
|
+
const updateBucket = this.db.prepare('UPDATE rate_limits SET tokens = ?, last_refill_at = ? WHERE bucket_key = ?');
|
|
529
|
+
return this.db.transaction((key, cost) => {
|
|
530
|
+
const row = selectBucket.get(key);
|
|
531
|
+
if (!row) {
|
|
532
|
+
throw new SqliteStoreError(`Token bucket not found: ${key}`);
|
|
533
|
+
}
|
|
534
|
+
const now = Date.now();
|
|
535
|
+
const lastRefill = new Date(row.last_refill_at).getTime();
|
|
536
|
+
const elapsedSeconds = Math.max(0, (now - lastRefill) / 1000);
|
|
537
|
+
const refilled = Math.min(row.max_tokens, row.tokens + elapsedSeconds * row.refill_rate);
|
|
538
|
+
if (refilled >= cost) {
|
|
539
|
+
const remaining = refilled - cost;
|
|
540
|
+
updateBucket.run(remaining, new Date(now).toISOString(), key);
|
|
541
|
+
return { allowed: true, remaining, retryAfterSeconds: null };
|
|
542
|
+
}
|
|
543
|
+
updateBucket.run(refilled, new Date(now).toISOString(), key);
|
|
544
|
+
const deficit = cost - refilled;
|
|
545
|
+
const retryAfterSeconds = Math.ceil(deficit / row.refill_rate);
|
|
546
|
+
return { allowed: false, remaining: refilled, retryAfterSeconds };
|
|
547
|
+
}).immediate;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
// ─── Error type ───────────────────────────────────────────────────────────
|
|
551
|
+
export class SqliteStoreError extends Error {
|
|
552
|
+
name = 'SqliteStoreError';
|
|
553
|
+
constructor(message, options) {
|
|
554
|
+
super(message, options);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
// ─── Row mappers ──────────────────────────────────────────────────────────
|
|
558
|
+
function clampHistoryLimit(limit) {
|
|
559
|
+
if (limit === undefined) {
|
|
560
|
+
return DEFAULT_HISTORY_LIMIT;
|
|
561
|
+
}
|
|
562
|
+
return Math.min(Math.max(1, Math.floor(limit)), MAX_HISTORY_LIMIT);
|
|
563
|
+
}
|
|
564
|
+
function telemetryRowToEntity(row) {
|
|
565
|
+
return {
|
|
566
|
+
timestamp: row.timestamp,
|
|
567
|
+
session_id: row.session_id,
|
|
568
|
+
request_id: row.request_id,
|
|
569
|
+
turn_type: row.turn_type,
|
|
570
|
+
stage: row.stage,
|
|
571
|
+
reason_code: row.reason_code,
|
|
572
|
+
selected_model_id: row.selected_model_id,
|
|
573
|
+
estimated_cost_usd: row.estimated_cost_usd,
|
|
574
|
+
routing_latency_ms: row.routing_latency_ms,
|
|
575
|
+
pin_reason: row.pin_reason,
|
|
576
|
+
estimated_input_tokens: null,
|
|
577
|
+
context_fit_viable_count: null,
|
|
578
|
+
context_fit_rejected_json: null,
|
|
579
|
+
context_overflow_pin_break: false,
|
|
580
|
+
selected_model_max_input_tokens: null,
|
|
581
|
+
context_fit_reason_code: null,
|
|
582
|
+
cluster_id: null,
|
|
583
|
+
cluster_similarity: null,
|
|
584
|
+
cluster_margin: null,
|
|
585
|
+
low_intensity_score: null,
|
|
586
|
+
tier_hint: null,
|
|
587
|
+
p_success_cheap: null,
|
|
588
|
+
local_eligible_reason: null,
|
|
589
|
+
tier_selection_reason_code: null,
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
function datasetRowToEntity(row) {
|
|
593
|
+
return {
|
|
594
|
+
request_id: row.request_id,
|
|
595
|
+
timestamp: row.timestamp,
|
|
596
|
+
turn_type: row.turn_type,
|
|
597
|
+
stage: row.stage,
|
|
598
|
+
reason_code: row.reason_code,
|
|
599
|
+
selected_model_id: row.selected_model_id,
|
|
600
|
+
tier: row.tier,
|
|
601
|
+
candidates_json: row.candidates_json,
|
|
602
|
+
prompt_length_chars: row.prompt_length_chars,
|
|
603
|
+
estimated_input_tokens: row.estimated_input_tokens,
|
|
604
|
+
message_count: row.message_count,
|
|
605
|
+
has_tool_context: row.has_tool_context === 1,
|
|
606
|
+
compaction_flag: row.compaction_flag === 1,
|
|
607
|
+
triage_verdict: row.triage_verdict,
|
|
608
|
+
triage_reason_code: row.triage_reason_code,
|
|
609
|
+
triage_cyclomatic_score: row.triage_cyclomatic_score,
|
|
610
|
+
triage_trivial_hits: row.triage_trivial_hits,
|
|
611
|
+
triage_complex_hits: row.triage_complex_hits,
|
|
612
|
+
triage_sanitized_length_delta: row.triage_sanitized_length_delta,
|
|
613
|
+
requirement_reasoning: row.requirement_reasoning,
|
|
614
|
+
requirement_code_gen: row.requirement_code_gen,
|
|
615
|
+
requirement_tool_use: row.requirement_tool_use,
|
|
616
|
+
routing_latency_ms: row.routing_latency_ms,
|
|
617
|
+
estimated_cost_usd: row.estimated_cost_usd,
|
|
618
|
+
prompt_fingerprint: row.prompt_fingerprint,
|
|
619
|
+
estimated_input_tokens_gate: null,
|
|
620
|
+
context_fit_viable_count: null,
|
|
621
|
+
context_fit_rejected_json: null,
|
|
622
|
+
context_overflow_pin_break: false,
|
|
623
|
+
selected_model_max_input_tokens: null,
|
|
624
|
+
context_fit_reason_code: null,
|
|
625
|
+
cluster_id: null,
|
|
626
|
+
cluster_similarity: null,
|
|
627
|
+
cluster_margin: null,
|
|
628
|
+
low_intensity_score: null,
|
|
629
|
+
tier_hint: null,
|
|
630
|
+
p_success_cheap: null,
|
|
631
|
+
local_eligible_reason: null,
|
|
632
|
+
tier_selection_reason_code: null,
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
function outcomeRowToEntity(row) {
|
|
636
|
+
return {
|
|
637
|
+
request_id: row.request_id,
|
|
638
|
+
session_id: row.session_id,
|
|
639
|
+
timestamp: row.timestamp,
|
|
640
|
+
signal_type: row.signal_type,
|
|
641
|
+
routed_model_id: row.routed_model_id,
|
|
642
|
+
override_model_id: row.override_model_id,
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
function pinRowToEntity(row) {
|
|
646
|
+
return {
|
|
647
|
+
session_id: row.session_id,
|
|
648
|
+
pinned_model_id: row.pinned_model_id,
|
|
649
|
+
pin_reason: row.pin_reason,
|
|
650
|
+
has_ever_switched: row.has_ever_switched === 1,
|
|
651
|
+
consecutive_upstream_errors: row.consecutive_upstream_errors,
|
|
652
|
+
consecutive_tool_failures: row.consecutive_tool_failures,
|
|
653
|
+
last_tool_failure_signature: row.last_tool_failure_signature,
|
|
654
|
+
created_at: row.created_at,
|
|
655
|
+
updated_at: row.updated_at,
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
//# sourceMappingURL=sqlite-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-store.js","sourceRoot":"","sources":["../../../src/infrastructure/persistence/sqlite-store.ts"],"names":[],"mappings":"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"}
|