open-multi-agent-kit 0.95.1 → 0.95.2
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/CHANGELOG.md +17 -0
- package/README.md +1 -1
- package/dist/approvals/approval-receipt-store.d.ts +18 -0
- package/dist/approvals/approval-receipt-store.d.ts.map +1 -0
- package/dist/approvals/approval-receipt-store.js +169 -0
- package/dist/approvals/approval-receipt-store.js.map +1 -0
- package/dist/approvals/approval-receipt.d.ts +43 -0
- package/dist/approvals/approval-receipt.d.ts.map +1 -0
- package/dist/approvals/approval-receipt.js +208 -0
- package/dist/approvals/approval-receipt.js.map +1 -0
- package/dist/approvals/approval-verifier.d.ts +17 -0
- package/dist/approvals/approval-verifier.d.ts.map +1 -0
- package/dist/approvals/approval-verifier.js +23 -0
- package/dist/approvals/approval-verifier.js.map +1 -0
- package/dist/approvals/plannotator-approval-bridge.d.ts +58 -0
- package/dist/approvals/plannotator-approval-bridge.d.ts.map +1 -0
- package/dist/approvals/plannotator-approval-bridge.js +169 -0
- package/dist/approvals/plannotator-approval-bridge.js.map +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +2 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/commands/package-doctor-cli.d.ts +13 -0
- package/dist/commands/package-doctor-cli.d.ts.map +1 -0
- package/dist/commands/package-doctor-cli.js +80 -0
- package/dist/commands/package-doctor-cli.js.map +1 -0
- package/dist/commands/router-feedback-cli.d.ts +11 -0
- package/dist/commands/router-feedback-cli.d.ts.map +1 -0
- package/dist/commands/router-feedback-cli.js +99 -0
- package/dist/commands/router-feedback-cli.js.map +1 -0
- package/dist/commands/stats-cli.d.ts +20 -0
- package/dist/commands/stats-cli.d.ts.map +1 -0
- package/dist/commands/stats-cli.js +99 -0
- package/dist/commands/stats-cli.js.map +1 -0
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +4 -1
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +97 -29
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +583 -199
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +8 -2
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/transaction.d.ts +9 -0
- package/dist/core/compaction/transaction.d.ts.map +1 -1
- package/dist/core/compaction/transaction.js +17 -2
- package/dist/core/compaction/transaction.js.map +1 -1
- package/dist/core/context-budget-compressors.d.ts +50 -0
- package/dist/core/context-budget-compressors.d.ts.map +1 -0
- package/dist/core/context-budget-compressors.js +166 -0
- package/dist/core/context-budget-compressors.js.map +1 -0
- package/dist/core/context-budget-governor-v2.d.ts +1 -1
- package/dist/core/context-budget-governor-v2.d.ts.map +1 -1
- package/dist/core/context-budget-governor-v2.js +1 -1
- package/dist/core/context-budget-governor-v2.js.map +1 -1
- package/dist/core/context-budget-system-prompt.d.ts.map +1 -1
- package/dist/core/context-budget-system-prompt.js +18 -2
- package/dist/core/context-budget-system-prompt.js.map +1 -1
- package/dist/core/context-budget-v2-cache-disk.d.ts +109 -0
- package/dist/core/context-budget-v2-cache-disk.d.ts.map +1 -0
- package/dist/core/context-budget-v2-cache-disk.js +343 -0
- package/dist/core/context-budget-v2-cache-disk.js.map +1 -0
- package/dist/core/context-budget-v2-cache-keys.d.ts +22 -0
- package/dist/core/context-budget-v2-cache-keys.d.ts.map +1 -1
- package/dist/core/context-budget-v2-cache-keys.js +4 -4
- package/dist/core/context-budget-v2-cache-keys.js.map +1 -1
- package/dist/core/context-budget-v2-cache.d.ts +1 -0
- package/dist/core/context-budget-v2-cache.d.ts.map +1 -1
- package/dist/core/context-budget-v2-cache.js +1 -0
- package/dist/core/context-budget-v2-cache.js.map +1 -1
- package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
- package/dist/core/context-budget-v2-planner.js +17 -14
- package/dist/core/context-budget-v2-planner.js.map +1 -1
- package/dist/core/context-budget-v2-types.d.ts +1 -0
- package/dist/core/context-budget-v2-types.d.ts.map +1 -1
- package/dist/core/context-budget-v2-types.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +45 -22
- package/dist/core/extensions/loader.js.bak-sharedjiti-20260812-111246 +553 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +4 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/mcp/client.d.ts +105 -0
- package/dist/core/mcp/client.d.ts.map +1 -0
- package/dist/core/mcp/client.js +198 -0
- package/dist/core/mcp/client.js.map +1 -0
- package/dist/core/mcp/config.d.ts +23 -0
- package/dist/core/mcp/config.d.ts.map +1 -0
- package/dist/core/mcp/config.js +89 -0
- package/dist/core/mcp/config.js.map +1 -0
- package/dist/core/mcp/index.d.ts +15 -0
- package/dist/core/mcp/index.d.ts.map +1 -0
- package/dist/core/mcp/index.js +15 -0
- package/dist/core/mcp/index.js.map +1 -0
- package/dist/core/mcp/manager.d.ts +84 -0
- package/dist/core/mcp/manager.d.ts.map +1 -0
- package/dist/core/mcp/manager.js +173 -0
- package/dist/core/mcp/manager.js.map +1 -0
- package/dist/core/mcp/protocol.d.ts +59 -0
- package/dist/core/mcp/protocol.d.ts.map +1 -0
- package/dist/core/mcp/protocol.js +103 -0
- package/dist/core/mcp/protocol.js.map +1 -0
- package/dist/core/mcp/stdio-transport.d.ts +63 -0
- package/dist/core/mcp/stdio-transport.d.ts.map +1 -0
- package/dist/core/mcp/stdio-transport.js +132 -0
- package/dist/core/mcp/stdio-transport.js.map +1 -0
- package/dist/core/mcp/tools.d.ts +47 -0
- package/dist/core/mcp/tools.d.ts.map +1 -0
- package/dist/core/mcp/tools.js +102 -0
- package/dist/core/mcp/tools.js.map +1 -0
- package/dist/core/package-archive.d.ts +3 -0
- package/dist/core/package-archive.d.ts.map +1 -0
- package/dist/core/package-archive.js +161 -0
- package/dist/core/package-archive.js.map +1 -0
- package/dist/core/package-doctor-source-scan.d.ts +13 -0
- package/dist/core/package-doctor-source-scan.d.ts.map +1 -0
- package/dist/core/package-doctor-source-scan.js +124 -0
- package/dist/core/package-doctor-source-scan.js.map +1 -0
- package/dist/core/package-doctor.d.ts +41 -0
- package/dist/core/package-doctor.d.ts.map +1 -0
- package/dist/core/package-doctor.js +145 -0
- package/dist/core/package-doctor.js.map +1 -0
- package/dist/core/package-manager.d.ts +10 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +175 -42
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/package-manifest.d.ts +26 -0
- package/dist/core/package-manifest.d.ts.map +1 -0
- package/dist/core/package-manifest.js +85 -0
- package/dist/core/package-manifest.js.map +1 -0
- package/dist/core/pi-compat.d.ts +5 -0
- package/dist/core/pi-compat.d.ts.map +1 -0
- package/dist/core/pi-compat.js +18 -0
- package/dist/core/pi-compat.js.map +1 -0
- package/dist/core/reasoning-router-bias.d.ts +10 -14
- package/dist/core/reasoning-router-bias.d.ts.map +1 -1
- package/dist/core/reasoning-router-bias.js +22 -15
- package/dist/core/reasoning-router-bias.js.map +1 -1
- package/dist/core/reasoning-router-v4.d.ts +9 -1
- package/dist/core/reasoning-router-v4.d.ts.map +1 -1
- package/dist/core/reasoning-router-v4.js +20 -5
- package/dist/core/reasoning-router-v4.js.map +1 -1
- package/dist/core/redaction.d.ts +2 -5
- package/dist/core/redaction.d.ts.map +1 -1
- package/dist/core/redaction.js +14 -1
- package/dist/core/redaction.js.map +1 -1
- package/dist/core/repository-learning-scope.d.ts +10 -0
- package/dist/core/repository-learning-scope.d.ts.map +1 -0
- package/dist/core/repository-learning-scope.js +42 -0
- package/dist/core/repository-learning-scope.js.map +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +16 -1
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/router-feedback-collector.d.ts +2 -1
- package/dist/core/router-feedback-collector.d.ts.map +1 -1
- package/dist/core/router-feedback-collector.js +2 -2
- package/dist/core/router-feedback-collector.js.map +1 -1
- package/dist/core/runtime-provenance.d.ts +54 -0
- package/dist/core/runtime-provenance.d.ts.map +1 -0
- package/dist/core/runtime-provenance.js +115 -0
- package/dist/core/runtime-provenance.js.map +1 -0
- package/dist/core/sandbox/backend.d.ts.map +1 -1
- package/dist/core/sandbox/backend.js +39 -21
- package/dist/core/sandbox/backend.js.map +1 -1
- package/dist/core/sandbox/default-policy.d.ts +4 -5
- package/dist/core/sandbox/default-policy.d.ts.map +1 -1
- package/dist/core/sandbox/default-policy.js +9 -11
- package/dist/core/sandbox/default-policy.js.map +1 -1
- package/dist/core/session-bash-runtime.d.ts +4 -4
- package/dist/core/session-bash-runtime.d.ts.map +1 -1
- package/dist/core/session-bash-runtime.js +6 -5
- package/dist/core/session-bash-runtime.js.map +1 -1
- package/dist/core/session-compaction-service.d.ts.map +1 -1
- package/dist/core/session-compaction-service.js +7 -7
- package/dist/core/session-compaction-service.js.map +1 -1
- package/dist/core/session-manager.d.ts +4 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +47 -7
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +7 -4
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +11 -3
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts +9 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +10 -4
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -2
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +2 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +15 -0
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/turn-metrics.d.ts +135 -0
- package/dist/core/turn-metrics.d.ts.map +1 -0
- package/dist/core/turn-metrics.js +261 -0
- package/dist/core/turn-metrics.js.map +1 -0
- package/dist/core/verified-bash-runtime.d.ts.map +1 -1
- package/dist/core/verified-bash-runtime.js +10 -4
- package/dist/core/verified-bash-runtime.js.map +1 -1
- package/dist/guardrails/replay-ledger-lock-owner.d.ts +7 -0
- package/dist/guardrails/replay-ledger-lock-owner.d.ts.map +1 -1
- package/dist/guardrails/replay-ledger-lock-owner.js +39 -0
- package/dist/guardrails/replay-ledger-lock-owner.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +18 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/control-panel-layout.d.ts.map +1 -1
- package/dist/modes/interactive/components/control-panel-layout.js +2 -2
- package/dist/modes/interactive/components/control-panel-layout.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +3 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +40 -12
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +10 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/status-sidebar.d.ts +14 -2
- package/dist/modes/interactive/components/status-sidebar.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-sidebar.js +106 -19
- package/dist/modes/interactive/components/status-sidebar.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +10 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +104 -17
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/dark.json +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +1 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +1 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/docs/compaction.md +25 -3
- package/docs/containerization.md +14 -2
- package/docs/docs.json +8 -0
- package/docs/environment-variables.md +1 -1
- package/docs/extensions.md +75 -16
- package/docs/mcp.md +97 -0
- package/docs/metrics.md +87 -0
- package/docs/packages.md +25 -4
- package/docs/providers.md +1 -1
- package/docs/sdk.md +25 -4
- package/docs/settings.md +8 -7
- package/docs/usage.md +13 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/plannotator-approval-bridge.ts +83 -0
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/subagent/README.md +21 -11
- package/examples/extensions/subagent/adaptive-agent-runtime.ts +9 -3
- package/examples/extensions/subagent/agents/planner.md +0 -2
- package/examples/extensions/subagent/agents/reviewer.md +0 -2
- package/examples/extensions/subagent/agents/scout.md +0 -2
- package/examples/extensions/subagent/agents/worker.md +0 -1
- package/examples/extensions/subagent/agents.test.ts +9 -0
- package/examples/extensions/subagent/agents.ts +11 -4
- package/examples/extensions/subagent/deadline-budget.test.ts +32 -0
- package/examples/extensions/subagent/deadline-budget.ts +25 -1
- package/examples/extensions/subagent/fixtures/fake-omk-json.mjs +10 -0
- package/examples/extensions/subagent/index.ts +234 -55
- package/examples/extensions/subagent/subagent-execution-policy.test.ts +27 -0
- package/examples/extensions/subagent/subagent-extension-smoke.test.ts +167 -2
- package/examples/extensions/subagent/workflow-graph.test.ts +80 -0
- package/examples/extensions/subagent/workflow-graph.ts +89 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +253 -439
- package/package.json +8 -8
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace-layer disk persistence for the context-budget-v2 representation
|
|
3
|
+
* cache.
|
|
4
|
+
*
|
|
5
|
+
* The in-memory provider (`context-budget-v2-cache-provider.ts`) dies with the
|
|
6
|
+
* process, so every new session re-renders and re-compresses context it already
|
|
7
|
+
* paid for. This provider keeps the same synchronous
|
|
8
|
+
* `ContextBudgetCacheProviderV2` contract and adds a bounded, atomically
|
|
9
|
+
* written JSON snapshot on disk.
|
|
10
|
+
*
|
|
11
|
+
* Scope: representation entries and negative entries only. Plan entries stay in
|
|
12
|
+
* memory on purpose — a plan is session-scoped (its key folds in the
|
|
13
|
+
* invalidation snapshot), so persisting it would only ever store misses.
|
|
14
|
+
*
|
|
15
|
+
* Safety: reads go through the same validator as the memory provider
|
|
16
|
+
* (`validateContextBudgetRepresentationCacheEntryV2`), which re-checks source
|
|
17
|
+
* hash, representation fingerprint, model, tokenizer, policy version and TTL.
|
|
18
|
+
* A corrupt, truncated, oversized, or schema-mismatched snapshot is discarded
|
|
19
|
+
* and the cache simply starts empty; a cache is never load-bearing for
|
|
20
|
+
* correctness.
|
|
21
|
+
*/
|
|
22
|
+
import fs from "node:fs";
|
|
23
|
+
import path from "node:path";
|
|
24
|
+
import { containsCredentialShape } from "./compaction/transaction.js";
|
|
25
|
+
import { createContextCacheInvalidationSnapshot, } from "./context-budget-v2-cache-invalidation.js";
|
|
26
|
+
export const CONTEXT_BUDGET_DISK_CACHE_SCHEMA_VERSION = "context-budget-v2-diskcache-1";
|
|
27
|
+
/** Default cap on persisted representation entries. */
|
|
28
|
+
export const DEFAULT_DISK_CACHE_MAX_ENTRIES = 2048;
|
|
29
|
+
/** Default cap on the persisted snapshot size. Oversized snapshots are dropped on load. */
|
|
30
|
+
export const DEFAULT_DISK_CACHE_MAX_BYTES = 32 * 1024 * 1024;
|
|
31
|
+
/** Default write-behind debounce. Collapses a burst of writes into a single flush. */
|
|
32
|
+
export const DEFAULT_DISK_CACHE_FLUSH_DEBOUNCE_MS = 750;
|
|
33
|
+
/** Default cap on a single persisted representation's text length. */
|
|
34
|
+
export const DEFAULT_DISK_CACHE_MAX_ENTRY_TEXT_LENGTH = 512 * 1024;
|
|
35
|
+
function isRecord(value) {
|
|
36
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37
|
+
}
|
|
38
|
+
function containsCredentialShapeInValue(value) {
|
|
39
|
+
const pending = [value];
|
|
40
|
+
const seen = new Set();
|
|
41
|
+
while (pending.length > 0) {
|
|
42
|
+
const current = pending.pop();
|
|
43
|
+
if (typeof current === "string") {
|
|
44
|
+
if (containsCredentialShape(current))
|
|
45
|
+
return true;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (typeof current !== "object" || current === null || seen.has(current))
|
|
49
|
+
continue;
|
|
50
|
+
seen.add(current);
|
|
51
|
+
if (Array.isArray(current)) {
|
|
52
|
+
pending.push(...current);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
for (const [key, nested] of Object.entries(current)) {
|
|
56
|
+
if (containsCredentialShape(key))
|
|
57
|
+
return true;
|
|
58
|
+
pending.push(nested);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
function isPersistableRepresentation(value, maxEntryTextLength) {
|
|
64
|
+
if (!isRecord(value))
|
|
65
|
+
return false;
|
|
66
|
+
if (typeof value.kind !== "string")
|
|
67
|
+
return false;
|
|
68
|
+
if (typeof value.text !== "string" || value.text.length > maxEntryTextLength)
|
|
69
|
+
return false;
|
|
70
|
+
if (containsCredentialShapeInValue(value))
|
|
71
|
+
return false;
|
|
72
|
+
const estimated = value.estimatedTokens;
|
|
73
|
+
if (typeof estimated !== "number" || !Number.isFinite(estimated) || estimated < 0)
|
|
74
|
+
return false;
|
|
75
|
+
if (typeof value.fidelity !== "string")
|
|
76
|
+
return false;
|
|
77
|
+
if (typeof value.sourceHash !== "string" || value.sourceHash.length === 0)
|
|
78
|
+
return false;
|
|
79
|
+
if (typeof value.representationFingerprint !== "string")
|
|
80
|
+
return false;
|
|
81
|
+
if (typeof value.modelId !== "string")
|
|
82
|
+
return false;
|
|
83
|
+
if (typeof value.tokenizerId !== "string")
|
|
84
|
+
return false;
|
|
85
|
+
if (typeof value.policyVersion !== "string")
|
|
86
|
+
return false;
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
function isPersistableNegative(value) {
|
|
90
|
+
return isRecord(value) && typeof value.reason === "string" && !containsCredentialShapeInValue(value);
|
|
91
|
+
}
|
|
92
|
+
function readLru(store, key) {
|
|
93
|
+
const entry = store.get(key);
|
|
94
|
+
if (entry === undefined)
|
|
95
|
+
return undefined;
|
|
96
|
+
store.delete(key);
|
|
97
|
+
store.set(key, entry);
|
|
98
|
+
return entry;
|
|
99
|
+
}
|
|
100
|
+
function writeLru(store, key, entry, maxEntries) {
|
|
101
|
+
store.delete(key);
|
|
102
|
+
store.set(key, entry);
|
|
103
|
+
while (store.size > maxEntries) {
|
|
104
|
+
const oldestKey = store.keys().next().value;
|
|
105
|
+
if (oldestKey === undefined)
|
|
106
|
+
return;
|
|
107
|
+
store.delete(oldestKey);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Create a disk backed workspace cache provider. Loading is synchronous and
|
|
112
|
+
* best-effort: any failure yields an empty in-memory cache rather than throwing,
|
|
113
|
+
* because a cache miss is always a legal outcome.
|
|
114
|
+
*/
|
|
115
|
+
export function createDiskContextBudgetCacheProviderV2(options) {
|
|
116
|
+
return new DiskContextBudgetCacheProviderV2(options);
|
|
117
|
+
}
|
|
118
|
+
export class DiskContextBudgetCacheProviderV2 {
|
|
119
|
+
representations = new Map();
|
|
120
|
+
negatives = new Map();
|
|
121
|
+
/** Plans stay in memory: their keys are session-scoped, so persisting them stores only misses. */
|
|
122
|
+
plans = new Map();
|
|
123
|
+
layer;
|
|
124
|
+
maxEntries;
|
|
125
|
+
maxBytes;
|
|
126
|
+
maxEntryTextLength;
|
|
127
|
+
flushDebounceMs;
|
|
128
|
+
now;
|
|
129
|
+
snapshotPath;
|
|
130
|
+
invalidationSnapshot;
|
|
131
|
+
dirty = false;
|
|
132
|
+
flushTimer;
|
|
133
|
+
loadError;
|
|
134
|
+
constructor(options) {
|
|
135
|
+
this.layer = options.layer ?? "workspace";
|
|
136
|
+
this.maxEntries = Math.max(1, options.maxEntries ?? DEFAULT_DISK_CACHE_MAX_ENTRIES);
|
|
137
|
+
this.maxBytes = Math.max(1024, options.maxBytes ?? DEFAULT_DISK_CACHE_MAX_BYTES);
|
|
138
|
+
this.maxEntryTextLength = Math.max(1, options.maxEntryTextLength ?? DEFAULT_DISK_CACHE_MAX_ENTRY_TEXT_LENGTH);
|
|
139
|
+
this.flushDebounceMs = Math.max(0, options.flushDebounceMs ?? DEFAULT_DISK_CACHE_FLUSH_DEBOUNCE_MS);
|
|
140
|
+
this.now = options.now ?? Date.now;
|
|
141
|
+
this.snapshotPath = path.join(options.dir, "representations.json");
|
|
142
|
+
this.load();
|
|
143
|
+
}
|
|
144
|
+
/** Absolute path of the persisted snapshot. */
|
|
145
|
+
get snapshotFilePath() {
|
|
146
|
+
return this.snapshotPath;
|
|
147
|
+
}
|
|
148
|
+
/** Reason the on-disk snapshot was rejected, if it was. `undefined` on a clean load or a cold start. */
|
|
149
|
+
get lastLoadError() {
|
|
150
|
+
return this.loadError;
|
|
151
|
+
}
|
|
152
|
+
/** Number of representation entries currently held. */
|
|
153
|
+
get size() {
|
|
154
|
+
return this.representations.size;
|
|
155
|
+
}
|
|
156
|
+
load() {
|
|
157
|
+
let raw;
|
|
158
|
+
try {
|
|
159
|
+
const stat = fs.statSync(this.snapshotPath);
|
|
160
|
+
if (stat.size > this.maxBytes) {
|
|
161
|
+
this.loadError = `snapshot exceeds maxBytes (${stat.size} > ${this.maxBytes})`;
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
raw = fs.readFileSync(this.snapshotPath, "utf8");
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// Cold start: no snapshot yet, or it is unreadable. Both are normal.
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
let parsed;
|
|
171
|
+
try {
|
|
172
|
+
parsed = JSON.parse(raw);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
this.loadError = "snapshot is not valid JSON";
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (!isRecord(parsed) || parsed.schemaVersion !== CONTEXT_BUDGET_DISK_CACHE_SCHEMA_VERSION) {
|
|
179
|
+
this.loadError = "snapshot schema mismatch";
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (containsCredentialShapeInValue(parsed)) {
|
|
183
|
+
this.loadError = "snapshot contains credential-shaped text";
|
|
184
|
+
try {
|
|
185
|
+
fs.rmSync(this.snapshotPath, { force: true });
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// The unsafe snapshot remains unreadable to this provider.
|
|
189
|
+
}
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const representations = Array.isArray(parsed.representations) ? parsed.representations : [];
|
|
193
|
+
for (const pair of representations) {
|
|
194
|
+
if (!Array.isArray(pair) || pair.length !== 2)
|
|
195
|
+
continue;
|
|
196
|
+
const [key, entry] = pair;
|
|
197
|
+
if (typeof key !== "string" || key.length === 0)
|
|
198
|
+
continue;
|
|
199
|
+
if (!isPersistableRepresentation(entry, this.maxEntryTextLength))
|
|
200
|
+
continue;
|
|
201
|
+
writeLru(this.representations, key, entry, this.maxEntries);
|
|
202
|
+
}
|
|
203
|
+
const negatives = Array.isArray(parsed.negatives) ? parsed.negatives : [];
|
|
204
|
+
for (const pair of negatives) {
|
|
205
|
+
if (!Array.isArray(pair) || pair.length !== 2)
|
|
206
|
+
continue;
|
|
207
|
+
const [key, entry] = pair;
|
|
208
|
+
if (typeof key !== "string" || key.length === 0)
|
|
209
|
+
continue;
|
|
210
|
+
if (!isPersistableNegative(entry))
|
|
211
|
+
continue;
|
|
212
|
+
writeLru(this.negatives, key, entry, this.maxEntries);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
markDirty() {
|
|
216
|
+
this.dirty = true;
|
|
217
|
+
if (this.flushDebounceMs === 0) {
|
|
218
|
+
this.flush();
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
if (this.flushTimer !== undefined)
|
|
222
|
+
return;
|
|
223
|
+
this.flushTimer = setTimeout(() => {
|
|
224
|
+
this.flushTimer = undefined;
|
|
225
|
+
this.flush();
|
|
226
|
+
}, this.flushDebounceMs);
|
|
227
|
+
this.flushTimer.unref?.();
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Write the snapshot to disk atomically (temp file + rename). Best-effort:
|
|
231
|
+
* a failed flush leaves the previous snapshot intact and keeps the entries
|
|
232
|
+
* in memory. Returns `true` when a snapshot was written.
|
|
233
|
+
*/
|
|
234
|
+
flush() {
|
|
235
|
+
if (this.flushTimer !== undefined) {
|
|
236
|
+
clearTimeout(this.flushTimer);
|
|
237
|
+
this.flushTimer = undefined;
|
|
238
|
+
}
|
|
239
|
+
if (!this.dirty)
|
|
240
|
+
return false;
|
|
241
|
+
const snapshot = {
|
|
242
|
+
schemaVersion: CONTEXT_BUDGET_DISK_CACHE_SCHEMA_VERSION,
|
|
243
|
+
representations: [...this.representations.entries()]
|
|
244
|
+
.filter(([key, entry]) => !containsCredentialShape(key) && isPersistableRepresentation(entry, this.maxEntryTextLength))
|
|
245
|
+
.map(([key, entry]) => [key, entry]),
|
|
246
|
+
negatives: [...this.negatives.entries()]
|
|
247
|
+
.filter(([key, entry]) => !containsCredentialShape(key) && isPersistableNegative(entry))
|
|
248
|
+
.map(([key, entry]) => [key, entry]),
|
|
249
|
+
};
|
|
250
|
+
let serialized;
|
|
251
|
+
try {
|
|
252
|
+
serialized = JSON.stringify(snapshot);
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
if (Buffer.byteLength(serialized, "utf8") > this.maxBytes) {
|
|
258
|
+
// Drop the oldest half and retry once rather than growing forever.
|
|
259
|
+
const keys = [...this.representations.keys()];
|
|
260
|
+
if (keys.length === 0)
|
|
261
|
+
return false;
|
|
262
|
+
const dropCount = Math.max(1, Math.ceil(keys.length / 2));
|
|
263
|
+
for (const key of keys.slice(0, dropCount))
|
|
264
|
+
this.representations.delete(key);
|
|
265
|
+
return this.flush();
|
|
266
|
+
}
|
|
267
|
+
const tempPath = `${this.snapshotPath}.${process.pid}.tmp`;
|
|
268
|
+
try {
|
|
269
|
+
fs.mkdirSync(path.dirname(this.snapshotPath), { recursive: true });
|
|
270
|
+
fs.writeFileSync(tempPath, serialized, { encoding: "utf8", mode: 0o600 });
|
|
271
|
+
fs.renameSync(tempPath, this.snapshotPath);
|
|
272
|
+
this.dirty = false;
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
try {
|
|
277
|
+
fs.rmSync(tempPath, { force: true });
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
// The temp file is unlinkable; nothing further to do.
|
|
281
|
+
}
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/** Cancel any pending flush and persist immediately. Safe to call more than once. */
|
|
286
|
+
close() {
|
|
287
|
+
this.flush();
|
|
288
|
+
}
|
|
289
|
+
getInvalidationSnapshot() {
|
|
290
|
+
return this.invalidationSnapshot;
|
|
291
|
+
}
|
|
292
|
+
setInvalidationSnapshot(snapshot) {
|
|
293
|
+
this.invalidationSnapshot = createContextCacheInvalidationSnapshot({
|
|
294
|
+
forkId: snapshot.forkId,
|
|
295
|
+
worktreeFingerprint: snapshot.worktreeFingerprint,
|
|
296
|
+
activeModelId: snapshot.activeModelId,
|
|
297
|
+
compactionModelId: snapshot.compactionModelId,
|
|
298
|
+
globalEpoch: snapshot.globalEpoch,
|
|
299
|
+
transcriptRepair: snapshot.counters.transcriptRepair,
|
|
300
|
+
toolResultDisposition: snapshot.counters.toolResultDisposition,
|
|
301
|
+
evidenceReceipt: snapshot.counters.evidenceReceipt,
|
|
302
|
+
userSteering: snapshot.counters.userSteering,
|
|
303
|
+
settings: snapshot.counters.settings,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
readRepresentation(key) {
|
|
307
|
+
const entry = readLru(this.representations, key);
|
|
308
|
+
return entry ? { entry, layer: this.layer } : undefined;
|
|
309
|
+
}
|
|
310
|
+
writeRepresentation(input) {
|
|
311
|
+
writeLru(this.representations, input.key, input.entry, this.maxEntries);
|
|
312
|
+
if ((!containsCredentialShape(input.key) && isPersistableRepresentation(input.entry, this.maxEntryTextLength)) ||
|
|
313
|
+
fs.existsSync(this.snapshotPath)) {
|
|
314
|
+
this.markDirty();
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
deleteRepresentation(key) {
|
|
318
|
+
if (this.representations.delete(key))
|
|
319
|
+
this.markDirty();
|
|
320
|
+
}
|
|
321
|
+
readNegativeRepresentation(key) {
|
|
322
|
+
return readLru(this.negatives, key);
|
|
323
|
+
}
|
|
324
|
+
writeNegativeRepresentation(input) {
|
|
325
|
+
writeLru(this.negatives, input.key, { reason: input.reason, createdAtEpochMs: this.now(), layer: this.layer }, this.maxEntries);
|
|
326
|
+
this.markDirty();
|
|
327
|
+
}
|
|
328
|
+
deleteNegativeRepresentation(key) {
|
|
329
|
+
if (this.negatives.delete(key))
|
|
330
|
+
this.markDirty();
|
|
331
|
+
}
|
|
332
|
+
readPlan(key) {
|
|
333
|
+
const entry = readLru(this.plans, key);
|
|
334
|
+
return entry ? { entry, layer: "session" } : undefined;
|
|
335
|
+
}
|
|
336
|
+
writePlan(input) {
|
|
337
|
+
writeLru(this.plans, input.key, input.entry, this.maxEntries);
|
|
338
|
+
}
|
|
339
|
+
deletePlan(key) {
|
|
340
|
+
this.plans.delete(key);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
//# sourceMappingURL=context-budget-v2-cache-disk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-budget-v2-cache-disk.js","sourceRoot":"","sources":["../../src/core/context-budget-v2-cache-disk.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Workspace-layer disk persistence for the context-budget-v2 representation\n * cache.\n *\n * The in-memory provider (`context-budget-v2-cache-provider.ts`) dies with the\n * process, so every new session re-renders and re-compresses context it already\n * paid for. This provider keeps the same synchronous\n * `ContextBudgetCacheProviderV2` contract and adds a bounded, atomically\n * written JSON snapshot on disk.\n *\n * Scope: representation entries and negative entries only. Plan entries stay in\n * memory on purpose — a plan is session-scoped (its key folds in the\n * invalidation snapshot), so persisting it would only ever store misses.\n *\n * Safety: reads go through the same validator as the memory provider\n * (`validateContextBudgetRepresentationCacheEntryV2`), which re-checks source\n * hash, representation fingerprint, model, tokenizer, policy version and TTL.\n * A corrupt, truncated, oversized, or schema-mismatched snapshot is discarded\n * and the cache simply starts empty; a cache is never load-bearing for\n * correctness.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { containsCredentialShape } from \"./compaction/transaction.ts\";\nimport {\n\ttype ContextCacheInvalidationSnapshot,\n\tcreateContextCacheInvalidationSnapshot,\n} from \"./context-budget-v2-cache-invalidation.ts\";\nimport type {\n\tContextBudgetCacheLayerV2,\n\tContextBudgetCacheProviderV2,\n\tContextBudgetNegativeCacheEntryV2,\n\tContextBudgetPlanCacheEntryV2,\n\tContextBudgetPlanCacheReadV2,\n\tContextBudgetRepresentationCacheEntryV2,\n\tContextBudgetRepresentationCacheReadV2,\n} from \"./context-budget-v2-types.ts\";\n\nexport const CONTEXT_BUDGET_DISK_CACHE_SCHEMA_VERSION = \"context-budget-v2-diskcache-1\" as const;\n\n/** Default cap on persisted representation entries. */\nexport const DEFAULT_DISK_CACHE_MAX_ENTRIES = 2048;\n/** Default cap on the persisted snapshot size. Oversized snapshots are dropped on load. */\nexport const DEFAULT_DISK_CACHE_MAX_BYTES = 32 * 1024 * 1024;\n/** Default write-behind debounce. Collapses a burst of writes into a single flush. */\nexport const DEFAULT_DISK_CACHE_FLUSH_DEBOUNCE_MS = 750;\n/** Default cap on a single persisted representation's text length. */\nexport const DEFAULT_DISK_CACHE_MAX_ENTRY_TEXT_LENGTH = 512 * 1024;\n\nexport interface DiskContextBudgetCacheOptionsV2 {\n\t/** Directory holding the snapshot file. Created on first flush. */\n\treadonly dir: string;\n\t/** Cache layer reported on reads. Defaults to `workspace`. */\n\treadonly layer?: ContextBudgetCacheLayerV2;\n\t/** Max persisted representation entries (LRU). */\n\treadonly maxEntries?: number;\n\t/** Max accepted snapshot size in bytes. */\n\treadonly maxBytes?: number;\n\t/** Max persisted text length for a single entry. */\n\treadonly maxEntryTextLength?: number;\n\t/** Write-behind debounce in ms. `0` flushes synchronously on every write. */\n\treadonly flushDebounceMs?: number;\n\t/** Injectable clock, for tests. */\n\treadonly now?: () => number;\n}\n\ninterface DiskSnapshotFileV2 {\n\treadonly schemaVersion: typeof CONTEXT_BUDGET_DISK_CACHE_SCHEMA_VERSION;\n\treadonly representations: readonly (readonly [string, ContextBudgetRepresentationCacheEntryV2])[];\n\treadonly negatives: readonly (readonly [string, ContextBudgetNegativeCacheEntryV2])[];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction containsCredentialShapeInValue(value: unknown): boolean {\n\tconst pending: unknown[] = [value];\n\tconst seen = new Set<object>();\n\twhile (pending.length > 0) {\n\t\tconst current = pending.pop();\n\t\tif (typeof current === \"string\") {\n\t\t\tif (containsCredentialShape(current)) return true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof current !== \"object\" || current === null || seen.has(current)) continue;\n\t\tseen.add(current);\n\t\tif (Array.isArray(current)) {\n\t\t\tpending.push(...current);\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const [key, nested] of Object.entries(current)) {\n\t\t\tif (containsCredentialShape(key)) return true;\n\t\t\tpending.push(nested);\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction isPersistableRepresentation(\n\tvalue: unknown,\n\tmaxEntryTextLength: number,\n): value is ContextBudgetRepresentationCacheEntryV2 {\n\tif (!isRecord(value)) return false;\n\tif (typeof value.kind !== \"string\") return false;\n\tif (typeof value.text !== \"string\" || value.text.length > maxEntryTextLength) return false;\n\tif (containsCredentialShapeInValue(value)) return false;\n\tconst estimated = value.estimatedTokens;\n\tif (typeof estimated !== \"number\" || !Number.isFinite(estimated) || estimated < 0) return false;\n\tif (typeof value.fidelity !== \"string\") return false;\n\tif (typeof value.sourceHash !== \"string\" || value.sourceHash.length === 0) return false;\n\tif (typeof value.representationFingerprint !== \"string\") return false;\n\tif (typeof value.modelId !== \"string\") return false;\n\tif (typeof value.tokenizerId !== \"string\") return false;\n\tif (typeof value.policyVersion !== \"string\") return false;\n\treturn true;\n}\n\nfunction isPersistableNegative(value: unknown): value is ContextBudgetNegativeCacheEntryV2 {\n\treturn isRecord(value) && typeof value.reason === \"string\" && !containsCredentialShapeInValue(value);\n}\n\nfunction readLru<T>(store: Map<string, T>, key: string): T | undefined {\n\tconst entry = store.get(key);\n\tif (entry === undefined) return undefined;\n\tstore.delete(key);\n\tstore.set(key, entry);\n\treturn entry;\n}\n\nfunction writeLru<T>(store: Map<string, T>, key: string, entry: T, maxEntries: number): void {\n\tstore.delete(key);\n\tstore.set(key, entry);\n\twhile (store.size > maxEntries) {\n\t\tconst oldestKey = store.keys().next().value;\n\t\tif (oldestKey === undefined) return;\n\t\tstore.delete(oldestKey);\n\t}\n}\n\n/**\n * Create a disk backed workspace cache provider. Loading is synchronous and\n * best-effort: any failure yields an empty in-memory cache rather than throwing,\n * because a cache miss is always a legal outcome.\n */\nexport function createDiskContextBudgetCacheProviderV2(\n\toptions: DiskContextBudgetCacheOptionsV2,\n): DiskContextBudgetCacheProviderV2 {\n\treturn new DiskContextBudgetCacheProviderV2(options);\n}\n\nexport class DiskContextBudgetCacheProviderV2 implements ContextBudgetCacheProviderV2 {\n\tprivate readonly representations = new Map<string, ContextBudgetRepresentationCacheEntryV2>();\n\tprivate readonly negatives = new Map<string, ContextBudgetNegativeCacheEntryV2>();\n\t/** Plans stay in memory: their keys are session-scoped, so persisting them stores only misses. */\n\tprivate readonly plans = new Map<string, ContextBudgetPlanCacheEntryV2>();\n\tprivate readonly layer: ContextBudgetCacheLayerV2;\n\tprivate readonly maxEntries: number;\n\tprivate readonly maxBytes: number;\n\tprivate readonly maxEntryTextLength: number;\n\tprivate readonly flushDebounceMs: number;\n\tprivate readonly now: () => number;\n\tprivate readonly snapshotPath: string;\n\tprivate invalidationSnapshot: ContextCacheInvalidationSnapshot | undefined;\n\tprivate dirty = false;\n\tprivate flushTimer: ReturnType<typeof setTimeout> | undefined;\n\tprivate loadError: string | undefined;\n\n\tconstructor(options: DiskContextBudgetCacheOptionsV2) {\n\t\tthis.layer = options.layer ?? \"workspace\";\n\t\tthis.maxEntries = Math.max(1, options.maxEntries ?? DEFAULT_DISK_CACHE_MAX_ENTRIES);\n\t\tthis.maxBytes = Math.max(1024, options.maxBytes ?? DEFAULT_DISK_CACHE_MAX_BYTES);\n\t\tthis.maxEntryTextLength = Math.max(1, options.maxEntryTextLength ?? DEFAULT_DISK_CACHE_MAX_ENTRY_TEXT_LENGTH);\n\t\tthis.flushDebounceMs = Math.max(0, options.flushDebounceMs ?? DEFAULT_DISK_CACHE_FLUSH_DEBOUNCE_MS);\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.snapshotPath = path.join(options.dir, \"representations.json\");\n\t\tthis.load();\n\t}\n\n\t/** Absolute path of the persisted snapshot. */\n\tget snapshotFilePath(): string {\n\t\treturn this.snapshotPath;\n\t}\n\n\t/** Reason the on-disk snapshot was rejected, if it was. `undefined` on a clean load or a cold start. */\n\tget lastLoadError(): string | undefined {\n\t\treturn this.loadError;\n\t}\n\n\t/** Number of representation entries currently held. */\n\tget size(): number {\n\t\treturn this.representations.size;\n\t}\n\n\tprivate load(): void {\n\t\tlet raw: string;\n\t\ttry {\n\t\t\tconst stat = fs.statSync(this.snapshotPath);\n\t\t\tif (stat.size > this.maxBytes) {\n\t\t\t\tthis.loadError = `snapshot exceeds maxBytes (${stat.size} > ${this.maxBytes})`;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\traw = fs.readFileSync(this.snapshotPath, \"utf8\");\n\t\t} catch {\n\t\t\t// Cold start: no snapshot yet, or it is unreadable. Both are normal.\n\t\t\treturn;\n\t\t}\n\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = JSON.parse(raw);\n\t\t} catch {\n\t\t\tthis.loadError = \"snapshot is not valid JSON\";\n\t\t\treturn;\n\t\t}\n\t\tif (!isRecord(parsed) || parsed.schemaVersion !== CONTEXT_BUDGET_DISK_CACHE_SCHEMA_VERSION) {\n\t\t\tthis.loadError = \"snapshot schema mismatch\";\n\t\t\treturn;\n\t\t}\n\n\t\tif (containsCredentialShapeInValue(parsed)) {\n\t\t\tthis.loadError = \"snapshot contains credential-shaped text\";\n\t\t\ttry {\n\t\t\t\tfs.rmSync(this.snapshotPath, { force: true });\n\t\t\t} catch {\n\t\t\t\t// The unsafe snapshot remains unreadable to this provider.\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst representations = Array.isArray(parsed.representations) ? parsed.representations : [];\n\t\tfor (const pair of representations) {\n\t\t\tif (!Array.isArray(pair) || pair.length !== 2) continue;\n\t\t\tconst [key, entry] = pair as [unknown, unknown];\n\t\t\tif (typeof key !== \"string\" || key.length === 0) continue;\n\t\t\tif (!isPersistableRepresentation(entry, this.maxEntryTextLength)) continue;\n\t\t\twriteLru(this.representations, key, entry, this.maxEntries);\n\t\t}\n\n\t\tconst negatives = Array.isArray(parsed.negatives) ? parsed.negatives : [];\n\t\tfor (const pair of negatives) {\n\t\t\tif (!Array.isArray(pair) || pair.length !== 2) continue;\n\t\t\tconst [key, entry] = pair as [unknown, unknown];\n\t\t\tif (typeof key !== \"string\" || key.length === 0) continue;\n\t\t\tif (!isPersistableNegative(entry)) continue;\n\t\t\twriteLru(this.negatives, key, entry, this.maxEntries);\n\t\t}\n\t}\n\n\tprivate markDirty(): void {\n\t\tthis.dirty = true;\n\t\tif (this.flushDebounceMs === 0) {\n\t\t\tthis.flush();\n\t\t\treturn;\n\t\t}\n\t\tif (this.flushTimer !== undefined) return;\n\t\tthis.flushTimer = setTimeout(() => {\n\t\t\tthis.flushTimer = undefined;\n\t\t\tthis.flush();\n\t\t}, this.flushDebounceMs);\n\t\tthis.flushTimer.unref?.();\n\t}\n\n\t/**\n\t * Write the snapshot to disk atomically (temp file + rename). Best-effort:\n\t * a failed flush leaves the previous snapshot intact and keeps the entries\n\t * in memory. Returns `true` when a snapshot was written.\n\t */\n\tflush(): boolean {\n\t\tif (this.flushTimer !== undefined) {\n\t\t\tclearTimeout(this.flushTimer);\n\t\t\tthis.flushTimer = undefined;\n\t\t}\n\t\tif (!this.dirty) return false;\n\t\tconst snapshot: DiskSnapshotFileV2 = {\n\t\t\tschemaVersion: CONTEXT_BUDGET_DISK_CACHE_SCHEMA_VERSION,\n\t\t\trepresentations: [...this.representations.entries()]\n\t\t\t\t.filter(\n\t\t\t\t\t([key, entry]) =>\n\t\t\t\t\t\t!containsCredentialShape(key) && isPersistableRepresentation(entry, this.maxEntryTextLength),\n\t\t\t\t)\n\t\t\t\t.map(([key, entry]) => [key, entry] as const),\n\t\t\tnegatives: [...this.negatives.entries()]\n\t\t\t\t.filter(([key, entry]) => !containsCredentialShape(key) && isPersistableNegative(entry))\n\t\t\t\t.map(([key, entry]) => [key, entry] as const),\n\t\t};\n\t\tlet serialized: string;\n\t\ttry {\n\t\t\tserialized = JSON.stringify(snapshot);\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t\tif (Buffer.byteLength(serialized, \"utf8\") > this.maxBytes) {\n\t\t\t// Drop the oldest half and retry once rather than growing forever.\n\t\t\tconst keys = [...this.representations.keys()];\n\t\t\tif (keys.length === 0) return false;\n\t\t\tconst dropCount = Math.max(1, Math.ceil(keys.length / 2));\n\t\t\tfor (const key of keys.slice(0, dropCount)) this.representations.delete(key);\n\t\t\treturn this.flush();\n\t\t}\n\t\tconst tempPath = `${this.snapshotPath}.${process.pid}.tmp`;\n\t\ttry {\n\t\t\tfs.mkdirSync(path.dirname(this.snapshotPath), { recursive: true });\n\t\t\tfs.writeFileSync(tempPath, serialized, { encoding: \"utf8\", mode: 0o600 });\n\t\t\tfs.renameSync(tempPath, this.snapshotPath);\n\t\t\tthis.dirty = false;\n\t\t\treturn true;\n\t\t} catch {\n\t\t\ttry {\n\t\t\t\tfs.rmSync(tempPath, { force: true });\n\t\t\t} catch {\n\t\t\t\t// The temp file is unlinkable; nothing further to do.\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/** Cancel any pending flush and persist immediately. Safe to call more than once. */\n\tclose(): void {\n\t\tthis.flush();\n\t}\n\n\tgetInvalidationSnapshot(): ContextCacheInvalidationSnapshot | undefined {\n\t\treturn this.invalidationSnapshot;\n\t}\n\n\tsetInvalidationSnapshot(snapshot: ContextCacheInvalidationSnapshot): void {\n\t\tthis.invalidationSnapshot = createContextCacheInvalidationSnapshot({\n\t\t\tforkId: snapshot.forkId,\n\t\t\tworktreeFingerprint: snapshot.worktreeFingerprint,\n\t\t\tactiveModelId: snapshot.activeModelId,\n\t\t\tcompactionModelId: snapshot.compactionModelId,\n\t\t\tglobalEpoch: snapshot.globalEpoch,\n\t\t\ttranscriptRepair: snapshot.counters.transcriptRepair,\n\t\t\ttoolResultDisposition: snapshot.counters.toolResultDisposition,\n\t\t\tevidenceReceipt: snapshot.counters.evidenceReceipt,\n\t\t\tuserSteering: snapshot.counters.userSteering,\n\t\t\tsettings: snapshot.counters.settings,\n\t\t});\n\t}\n\n\treadRepresentation(key: string): ContextBudgetRepresentationCacheReadV2 | undefined {\n\t\tconst entry = readLru(this.representations, key);\n\t\treturn entry ? { entry, layer: this.layer } : undefined;\n\t}\n\n\twriteRepresentation(input: { readonly key: string; readonly entry: ContextBudgetRepresentationCacheEntryV2 }): void {\n\t\twriteLru(this.representations, input.key, input.entry, this.maxEntries);\n\t\tif (\n\t\t\t(!containsCredentialShape(input.key) && isPersistableRepresentation(input.entry, this.maxEntryTextLength)) ||\n\t\t\tfs.existsSync(this.snapshotPath)\n\t\t) {\n\t\t\tthis.markDirty();\n\t\t}\n\t}\n\n\tdeleteRepresentation(key: string): void {\n\t\tif (this.representations.delete(key)) this.markDirty();\n\t}\n\n\treadNegativeRepresentation(key: string): ContextBudgetNegativeCacheEntryV2 | undefined {\n\t\treturn readLru(this.negatives, key);\n\t}\n\n\twriteNegativeRepresentation(input: { readonly key: string; readonly reason: string }): void {\n\t\twriteLru(\n\t\t\tthis.negatives,\n\t\t\tinput.key,\n\t\t\t{ reason: input.reason, createdAtEpochMs: this.now(), layer: this.layer },\n\t\t\tthis.maxEntries,\n\t\t);\n\t\tthis.markDirty();\n\t}\n\n\tdeleteNegativeRepresentation(key: string): void {\n\t\tif (this.negatives.delete(key)) this.markDirty();\n\t}\n\n\treadPlan(key: string): ContextBudgetPlanCacheReadV2 | undefined {\n\t\tconst entry = readLru(this.plans, key);\n\t\treturn entry ? { entry, layer: \"session\" } : undefined;\n\t}\n\n\twritePlan(input: { readonly key: string; readonly entry: ContextBudgetPlanCacheEntryV2 }): void {\n\t\twriteLru(this.plans, input.key, input.entry, this.maxEntries);\n\t}\n\n\tdeletePlan(key: string): void {\n\t\tthis.plans.delete(key);\n\t}\n}\n"]}
|
|
@@ -3,6 +3,24 @@ import { type ContextCacheInvalidationSnapshot } from "./context-budget-v2-cache
|
|
|
3
3
|
export declare const DEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2 = "context-budget-v2-default-compressor";
|
|
4
4
|
export declare const DEFAULT_MATERIALIZED_QUALITY_POLICY_HASH_V2 = "context-budget-v2-default-quality";
|
|
5
5
|
type ContextBudgetRepresentationFingerprintInputV2 = Pick<ContextRepresentationCandidateV2, "compressorId" | "estimatedTokens" | "fidelity" | "kind" | "sourceRef" | "summaryHash" | "text">;
|
|
6
|
+
/**
|
|
7
|
+
* Cache-key inputs shared by the plan cache and the representation cache.
|
|
8
|
+
*
|
|
9
|
+
* Scope contract (deliberate asymmetry — see the two builders below):
|
|
10
|
+
* - **Plan keys are session-scoped.** A plan is a selection over the whole
|
|
11
|
+
* transcript and runtime state, so {@link invalidationSnapshotHash} (fork id,
|
|
12
|
+
* worktree fingerprint, steering/repair/settings counters) is part of the key.
|
|
13
|
+
* - **Representation keys are content-addressed.** A rendered representation is
|
|
14
|
+
* fully identified by its source content plus the rendering policy, so the
|
|
15
|
+
* invalidation snapshot is deliberately *excluded*. Folding a per-session
|
|
16
|
+
* `forkId` into representation keys made every new session miss every entry
|
|
17
|
+
* (structurally unreachable reuse, not a cold cache), while adding no safety:
|
|
18
|
+
* `validateContextBudgetRepresentationCacheEntryV2` independently re-checks
|
|
19
|
+
* source hash, fingerprint, model, tokenizer, policy version, and
|
|
20
|
+
* TTL on every read, and worktree/model/redaction/safety changes already move
|
|
21
|
+
* the key through `sourceHash` / `modelId` / `redactionPolicyHash` /
|
|
22
|
+
* `safetyProfileHash`.
|
|
23
|
+
*/
|
|
6
24
|
export interface ContextBudgetCacheKeyBaseV2 {
|
|
7
25
|
readonly namespace: string;
|
|
8
26
|
readonly modelId: string;
|
|
@@ -39,6 +57,10 @@ export declare function buildContextBudgetRepresentationCacheKeyV2(input: Contex
|
|
|
39
57
|
readonly representationFingerprint?: string;
|
|
40
58
|
readonly compressorId?: string;
|
|
41
59
|
}): string;
|
|
60
|
+
/**
|
|
61
|
+
* Exact representation key. Content-addressed: identical content + rendering
|
|
62
|
+
* policy yields one key across queries, budgets, sessions, forks, and worktrees.
|
|
63
|
+
*/
|
|
42
64
|
export declare function buildContextBudgetExactRepresentationCacheKeyV2(input: ContextBudgetCacheKeyBaseV2 & {
|
|
43
65
|
readonly representationKind: ContextRepresentationKindV2;
|
|
44
66
|
readonly sourceHash: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-budget-v2-cache-keys.d.ts","sourceRoot":"","sources":["../../src/core/context-budget-v2-cache-keys.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContextRepresentationCandidateV2, ContextRepresentationKindV2 } from \"./context-budget-headroom.ts\";\nimport { sha256Canonical, sha256Hex } from \"./context-budget-v2-cache-hash.ts\";\nimport {\n\ttype ContextCacheInvalidationSnapshot,\n\tserializeContextCacheSnapshot,\n} from \"./context-budget-v2-cache-invalidation.ts\";\n\nconst DEFAULT_CACHE_NAMESPACE = \"context-budget-v2\";\nconst DEFAULT_TOKENIZER_ID = \"heuristic-v1\";\nconst DEFAULT_REDACTION_POLICY_HASH = \"none\";\nconst DEFAULT_SAFETY_PROFILE_HASH = \"default\";\nconst NO_COMPRESSOR_ID = \"none\";\nexport const DEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2 = \"context-budget-v2-default-compressor\";\nexport const DEFAULT_MATERIALIZED_QUALITY_POLICY_HASH_V2 = \"context-budget-v2-default-quality\";\nconst MATERIALIZED_TARGET_TOKEN_BUCKET_SIZE = 100;\n\ntype ContextBudgetRepresentationFingerprintInputV2 = Pick<\n\tContextRepresentationCandidateV2,\n\t\"compressorId\" | \"estimatedTokens\" | \"fidelity\" | \"kind\" | \"sourceRef\" | \"summaryHash\" | \"text\"\n>;\n\nexport interface ContextBudgetCacheKeyBaseV2 {\n\treadonly namespace: string;\n\treadonly modelId: string;\n\treadonly tokenizerId: string;\n\treadonly policyVersion: string;\n\treadonly queryIntentHash: string;\n\treadonly queryIntentCluster?: string;\n\treadonly budgetBucket: string;\n\treadonly redactionPolicyHash: string;\n\treadonly safetyProfileHash: string;\n\treadonly compressorPolicyHash?: string;\n\treadonly qualityPolicyHash?: string;\n\treadonly invalidationSnapshotHash?: string;\n}\n\nexport function createContextBudgetCacheKeyBaseV2(input: {\n\treadonly namespace?: string;\n\treadonly modelId: string;\n\treadonly tokenizerId?: string;\n\treadonly policyVersion: string;\n\treadonly query?: string;\n\treadonly queryIntentHash?: string;\n\treadonly queryIntentCluster?: string;\n\treadonly budgetBucket?: string;\n\treadonly redactionPolicyHash?: string;\n\treadonly safetyProfileHash?: string;\n\treadonly compressorPolicyHash?: string;\n\treadonly qualityPolicyHash?: string;\n\treadonly cacheInvalidationSnapshot?: ContextCacheInvalidationSnapshot;\n}): ContextBudgetCacheKeyBaseV2 {\n\tconst queryIntentHash = input.queryIntentHash ?? computeContextBudgetQueryIntentHashV2(input.query);\n\treturn {\n\t\tnamespace: input.namespace ?? DEFAULT_CACHE_NAMESPACE,\n\t\tmodelId: input.modelId,\n\t\ttokenizerId: input.tokenizerId ?? DEFAULT_TOKENIZER_ID,\n\t\tpolicyVersion: input.policyVersion,\n\t\tqueryIntentHash,\n\t\tqueryIntentCluster: input.queryIntentCluster ?? queryIntentHash,\n\t\tbudgetBucket: input.budgetBucket ?? \"unknown\",\n\t\tredactionPolicyHash: input.redactionPolicyHash ?? DEFAULT_REDACTION_POLICY_HASH,\n\t\tsafetyProfileHash: input.safetyProfileHash ?? DEFAULT_SAFETY_PROFILE_HASH,\n\t\tcompressorPolicyHash: input.compressorPolicyHash ?? DEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2,\n\t\tqualityPolicyHash: input.qualityPolicyHash ?? DEFAULT_MATERIALIZED_QUALITY_POLICY_HASH_V2,\n\t\tinvalidationSnapshotHash:\n\t\t\tinput.cacheInvalidationSnapshot === undefined\n\t\t\t\t? \"none\"\n\t\t\t\t: sha256Hex(serializeContextCacheSnapshot(input.cacheInvalidationSnapshot)),\n\t};\n}\n\nexport function computeContextBudgetQueryIntentHashV2(query: string | undefined): string {\n\tconst normalized = (query ?? \"\")\n\t\t.toLowerCase()\n\t\t.split(/[\\s,.;:!?()[\\]{}\"'`]+/u)\n\t\t.map((term) => term.trim())\n\t\t.filter((term) => term.length > 0)\n\t\t.sort()\n\t\t.join(\" \");\n\treturn sha256Hex(normalized.length > 0 ? normalized : \"none\");\n}\n\nexport function buildContextBudgetRepresentationCacheKeyV2(\n\tinput: ContextBudgetCacheKeyBaseV2 & {\n\t\treadonly representationKind: ContextRepresentationKindV2;\n\t\treadonly sourceHash: string;\n\t\treadonly representationFingerprint?: string;\n\t\treadonly compressorId?: string;\n\t},\n): string {\n\treturn buildContextBudgetExactRepresentationCacheKeyV2(input);\n}\n\nexport function buildContextBudgetExactRepresentationCacheKeyV2(\n\tinput: ContextBudgetCacheKeyBaseV2 & {\n\t\treadonly representationKind: ContextRepresentationKindV2;\n\t\treadonly sourceHash: string;\n\t\treadonly representationFingerprint?: string;\n\t\treadonly compressorId?: string;\n\t},\n): string {\n\treturn `context-representation-exact:${sha256Canonical({\n\t\tbudgetBucket: input.budgetBucket,\n\t\tcompressorId: input.compressorId ?? NO_COMPRESSOR_ID,\n\t\tinvalidationSnapshotHash: input.invalidationSnapshotHash ?? \"none\",\n\t\tmodelId: input.modelId,\n\t\tnamespace: input.namespace,\n\t\tpolicyVersion: input.policyVersion,\n\t\tqueryIntentHash: input.queryIntentHash,\n\t\tredactionPolicyHash: input.redactionPolicyHash,\n\t\trepresentationFingerprint: input.representationFingerprint ?? \"none\",\n\t\trepresentationKind: input.representationKind,\n\t\tsafetyProfileHash: input.safetyProfileHash,\n\t\tsourceHash: input.sourceHash,\n\t\ttokenizerId: input.tokenizerId,\n\t})}`;\n}\n\nexport function buildContextBudgetMaterializedRepresentationCacheKeyV2(\n\tinput: ContextBudgetCacheKeyBaseV2 & {\n\t\treadonly representationKind: ContextRepresentationKindV2;\n\t\treadonly sourceHash: string;\n\t\treadonly compressorId?: string;\n\t\treadonly targetTokenBucket: number;\n\t},\n): string {\n\treturn `context-representation-materialized:${sha256Canonical({\n\t\tbudgetBucket: input.budgetBucket,\n\t\tcompressorId: input.compressorId ?? NO_COMPRESSOR_ID,\n\t\tcompressorPolicyHash: input.compressorPolicyHash ?? DEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2,\n\t\tinvalidationSnapshotHash: input.invalidationSnapshotHash ?? \"none\",\n\t\tmodelId: input.modelId,\n\t\tnamespace: input.namespace,\n\t\tpolicyVersion: input.policyVersion,\n\t\tqualityPolicyHash: input.qualityPolicyHash ?? DEFAULT_MATERIALIZED_QUALITY_POLICY_HASH_V2,\n\t\tqueryIntentCluster: input.queryIntentCluster ?? input.queryIntentHash,\n\t\tqueryIntentHash: input.queryIntentHash,\n\t\tredactionPolicyHash: input.redactionPolicyHash,\n\t\trepresentationKind: input.representationKind,\n\t\tsafetyProfileHash: input.safetyProfileHash,\n\t\tsourceHash: input.sourceHash,\n\t\ttargetTokenBucket: input.targetTokenBucket,\n\t\ttokenizerId: input.tokenizerId,\n\t})}`;\n}\n\nexport function computeContextBudgetRepresentationFingerprintV2(\n\tcandidate: ContextBudgetRepresentationFingerprintInputV2,\n): string {\n\treturn sha256Canonical({\n\t\tcompressorId: candidate.compressorId ?? NO_COMPRESSOR_ID,\n\t\testimatedTokens: candidate.estimatedTokens,\n\t\tfidelity: candidate.fidelity,\n\t\tkind: candidate.kind,\n\t\tsourceRef: fingerprintSourceRef(candidate.sourceRef),\n\t\tsummaryHash: candidate.summaryHash ?? null,\n\t\ttextHash: sha256Hex(candidate.text),\n\t});\n}\n\nexport function buildContextBudgetRepresentationCandidateKeyV2(\n\tkeyBase: ContextBudgetCacheKeyBaseV2,\n\tcandidate: ContextBudgetRepresentationFingerprintInputV2,\n\tsourceHash: string,\n): string {\n\treturn buildContextBudgetExactRepresentationCacheKeyV2({\n\t\t...keyBase,\n\t\tcompressorId: candidate.compressorId ?? NO_COMPRESSOR_ID,\n\t\trepresentationFingerprint: computeContextBudgetRepresentationFingerprintV2(candidate),\n\t\trepresentationKind: candidate.kind,\n\t\tsourceHash,\n\t});\n}\n\nexport function buildContextBudgetMaterializedRepresentationCandidateKeyV2(\n\tkeyBase: ContextBudgetCacheKeyBaseV2,\n\tcandidate: ContextBudgetRepresentationFingerprintInputV2,\n\tsourceHash: string,\n): string {\n\treturn buildContextBudgetMaterializedRepresentationCacheKeyV2({\n\t\t...keyBase,\n\t\tcompressorId: candidate.compressorId ?? NO_COMPRESSOR_ID,\n\t\trepresentationKind: candidate.kind,\n\t\tsourceHash,\n\t\ttargetTokenBucket: computeContextBudgetTargetTokenBucketV2(candidate.estimatedTokens),\n\t});\n}\n\nexport function computeContextBudgetTargetTokenBucketV2(tokens: number): number {\n\tif (!Number.isFinite(tokens) || tokens <= 0) {\n\t\treturn MATERIALIZED_TARGET_TOKEN_BUCKET_SIZE;\n\t}\n\treturn MATERIALIZED_TARGET_TOKEN_BUCKET_SIZE * Math.ceil(tokens / MATERIALIZED_TARGET_TOKEN_BUCKET_SIZE);\n}\n\nexport function computeContextBudgetOutputTextHashV2(text: string): string {\n\treturn sha256Hex(text);\n}\n\nexport function fingerprintSourceRef(sourceRef: ContextRepresentationCandidateV2[\"sourceRef\"]): unknown {\n\tif (!sourceRef) return null;\n\treturn {\n\t\tcontentHash: sourceRef.contentHash,\n\t\trange: sourceRef.range\n\t\t\t? {\n\t\t\t\t\tendLine: sourceRef.range.endLine,\n\t\t\t\t\tstartLine: sourceRef.range.startLine,\n\t\t\t\t}\n\t\t\t: null,\n\t\tretrievable: sourceRef.retrievable,\n\t\tsymbol: sourceRef.symbol ?? null,\n\t\turi: sourceRef.uri,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"context-budget-v2-cache-keys.d.ts","sourceRoot":"","sources":["../../src/core/context-budget-v2-cache-keys.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContextRepresentationCandidateV2, ContextRepresentationKindV2 } from \"./context-budget-headroom.ts\";\nimport { sha256Canonical, sha256Hex } from \"./context-budget-v2-cache-hash.ts\";\nimport {\n\ttype ContextCacheInvalidationSnapshot,\n\tserializeContextCacheSnapshot,\n} from \"./context-budget-v2-cache-invalidation.ts\";\n\nconst DEFAULT_CACHE_NAMESPACE = \"context-budget-v2\";\nconst DEFAULT_TOKENIZER_ID = \"heuristic-v1\";\nconst DEFAULT_REDACTION_POLICY_HASH = \"none\";\nconst DEFAULT_SAFETY_PROFILE_HASH = \"default\";\nconst NO_COMPRESSOR_ID = \"none\";\nexport const DEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2 = \"context-budget-v2-default-compressor\";\nexport const DEFAULT_MATERIALIZED_QUALITY_POLICY_HASH_V2 = \"context-budget-v2-default-quality\";\nconst MATERIALIZED_TARGET_TOKEN_BUCKET_SIZE = 100;\n\ntype ContextBudgetRepresentationFingerprintInputV2 = Pick<\n\tContextRepresentationCandidateV2,\n\t\"compressorId\" | \"estimatedTokens\" | \"fidelity\" | \"kind\" | \"sourceRef\" | \"summaryHash\" | \"text\"\n>;\n\n/**\n * Cache-key inputs shared by the plan cache and the representation cache.\n *\n * Scope contract (deliberate asymmetry — see the two builders below):\n * - **Plan keys are session-scoped.** A plan is a selection over the whole\n * transcript and runtime state, so {@link invalidationSnapshotHash} (fork id,\n * worktree fingerprint, steering/repair/settings counters) is part of the key.\n * - **Representation keys are content-addressed.** A rendered representation is\n * fully identified by its source content plus the rendering policy, so the\n * invalidation snapshot is deliberately *excluded*. Folding a per-session\n * `forkId` into representation keys made every new session miss every entry\n * (structurally unreachable reuse, not a cold cache), while adding no safety:\n * `validateContextBudgetRepresentationCacheEntryV2` independently re-checks\n * source hash, fingerprint, model, tokenizer, policy version, and\n * TTL on every read, and worktree/model/redaction/safety changes already move\n * the key through `sourceHash` / `modelId` / `redactionPolicyHash` /\n * `safetyProfileHash`.\n */\nexport interface ContextBudgetCacheKeyBaseV2 {\n\treadonly namespace: string;\n\treadonly modelId: string;\n\treadonly tokenizerId: string;\n\treadonly policyVersion: string;\n\treadonly queryIntentHash: string;\n\treadonly queryIntentCluster?: string;\n\treadonly budgetBucket: string;\n\treadonly redactionPolicyHash: string;\n\treadonly safetyProfileHash: string;\n\treadonly compressorPolicyHash?: string;\n\treadonly qualityPolicyHash?: string;\n\treadonly invalidationSnapshotHash?: string;\n}\n\nexport function createContextBudgetCacheKeyBaseV2(input: {\n\treadonly namespace?: string;\n\treadonly modelId: string;\n\treadonly tokenizerId?: string;\n\treadonly policyVersion: string;\n\treadonly query?: string;\n\treadonly queryIntentHash?: string;\n\treadonly queryIntentCluster?: string;\n\treadonly budgetBucket?: string;\n\treadonly redactionPolicyHash?: string;\n\treadonly safetyProfileHash?: string;\n\treadonly compressorPolicyHash?: string;\n\treadonly qualityPolicyHash?: string;\n\treadonly cacheInvalidationSnapshot?: ContextCacheInvalidationSnapshot;\n}): ContextBudgetCacheKeyBaseV2 {\n\tconst queryIntentHash = input.queryIntentHash ?? computeContextBudgetQueryIntentHashV2(input.query);\n\treturn {\n\t\tnamespace: input.namespace ?? DEFAULT_CACHE_NAMESPACE,\n\t\tmodelId: input.modelId,\n\t\ttokenizerId: input.tokenizerId ?? DEFAULT_TOKENIZER_ID,\n\t\tpolicyVersion: input.policyVersion,\n\t\tqueryIntentHash,\n\t\tqueryIntentCluster: input.queryIntentCluster ?? queryIntentHash,\n\t\tbudgetBucket: input.budgetBucket ?? \"unknown\",\n\t\tredactionPolicyHash: input.redactionPolicyHash ?? DEFAULT_REDACTION_POLICY_HASH,\n\t\tsafetyProfileHash: input.safetyProfileHash ?? DEFAULT_SAFETY_PROFILE_HASH,\n\t\tcompressorPolicyHash: input.compressorPolicyHash ?? DEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2,\n\t\tqualityPolicyHash: input.qualityPolicyHash ?? DEFAULT_MATERIALIZED_QUALITY_POLICY_HASH_V2,\n\t\tinvalidationSnapshotHash:\n\t\t\tinput.cacheInvalidationSnapshot === undefined\n\t\t\t\t? \"none\"\n\t\t\t\t: sha256Hex(serializeContextCacheSnapshot(input.cacheInvalidationSnapshot)),\n\t};\n}\n\nexport function computeContextBudgetQueryIntentHashV2(query: string | undefined): string {\n\tconst normalized = (query ?? \"\")\n\t\t.toLowerCase()\n\t\t.split(/[\\s,.;:!?()[\\]{}\"'`]+/u)\n\t\t.map((term) => term.trim())\n\t\t.filter((term) => term.length > 0)\n\t\t.sort()\n\t\t.join(\" \");\n\treturn sha256Hex(normalized.length > 0 ? normalized : \"none\");\n}\n\nexport function buildContextBudgetRepresentationCacheKeyV2(\n\tinput: ContextBudgetCacheKeyBaseV2 & {\n\t\treadonly representationKind: ContextRepresentationKindV2;\n\t\treadonly sourceHash: string;\n\t\treadonly representationFingerprint?: string;\n\t\treadonly compressorId?: string;\n\t},\n): string {\n\treturn buildContextBudgetExactRepresentationCacheKeyV2(input);\n}\n\n/**\n * Exact representation key. Content-addressed: identical content + rendering\n * policy yields one key across queries, budgets, sessions, forks, and worktrees.\n */\nexport function buildContextBudgetExactRepresentationCacheKeyV2(\n\tinput: ContextBudgetCacheKeyBaseV2 & {\n\t\treadonly representationKind: ContextRepresentationKindV2;\n\t\treadonly sourceHash: string;\n\t\treadonly representationFingerprint?: string;\n\t\treadonly compressorId?: string;\n\t},\n): string {\n\treturn `context-representation-exact:${sha256Canonical({\n\t\tcompressorId: input.compressorId ?? NO_COMPRESSOR_ID,\n\t\tmodelId: input.modelId,\n\t\tnamespace: input.namespace,\n\t\tpolicyVersion: input.policyVersion,\n\t\tredactionPolicyHash: input.redactionPolicyHash,\n\t\trepresentationFingerprint: input.representationFingerprint ?? \"none\",\n\t\trepresentationKind: input.representationKind,\n\t\tsafetyProfileHash: input.safetyProfileHash,\n\t\tsourceHash: input.sourceHash,\n\t\ttokenizerId: input.tokenizerId,\n\t})}`;\n}\n\nexport function buildContextBudgetMaterializedRepresentationCacheKeyV2(\n\tinput: ContextBudgetCacheKeyBaseV2 & {\n\t\treadonly representationKind: ContextRepresentationKindV2;\n\t\treadonly sourceHash: string;\n\t\treadonly compressorId?: string;\n\t\treadonly targetTokenBucket: number;\n\t},\n): string {\n\treturn `context-representation-materialized:${sha256Canonical({\n\t\tbudgetBucket: input.budgetBucket,\n\t\tcompressorId: input.compressorId ?? NO_COMPRESSOR_ID,\n\t\tcompressorPolicyHash: input.compressorPolicyHash ?? DEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2,\n\t\tmodelId: input.modelId,\n\t\tnamespace: input.namespace,\n\t\tpolicyVersion: input.policyVersion,\n\t\tqualityPolicyHash: input.qualityPolicyHash ?? DEFAULT_MATERIALIZED_QUALITY_POLICY_HASH_V2,\n\t\tqueryIntentCluster: input.queryIntentCluster ?? input.queryIntentHash,\n\t\tqueryIntentHash: input.queryIntentHash,\n\t\tredactionPolicyHash: input.redactionPolicyHash,\n\t\trepresentationKind: input.representationKind,\n\t\tsafetyProfileHash: input.safetyProfileHash,\n\t\tsourceHash: input.sourceHash,\n\t\ttargetTokenBucket: input.targetTokenBucket,\n\t\ttokenizerId: input.tokenizerId,\n\t})}`;\n}\n\nexport function computeContextBudgetRepresentationFingerprintV2(\n\tcandidate: ContextBudgetRepresentationFingerprintInputV2,\n): string {\n\treturn sha256Canonical({\n\t\tcompressorId: candidate.compressorId ?? NO_COMPRESSOR_ID,\n\t\testimatedTokens: candidate.estimatedTokens,\n\t\tfidelity: candidate.fidelity,\n\t\tkind: candidate.kind,\n\t\tsourceRef: fingerprintSourceRef(candidate.sourceRef),\n\t\tsummaryHash: candidate.summaryHash ?? null,\n\t\ttextHash: sha256Hex(candidate.text),\n\t});\n}\n\nexport function buildContextBudgetRepresentationCandidateKeyV2(\n\tkeyBase: ContextBudgetCacheKeyBaseV2,\n\tcandidate: ContextBudgetRepresentationFingerprintInputV2,\n\tsourceHash: string,\n): string {\n\treturn buildContextBudgetExactRepresentationCacheKeyV2({\n\t\t...keyBase,\n\t\tcompressorId: candidate.compressorId ?? NO_COMPRESSOR_ID,\n\t\trepresentationFingerprint: computeContextBudgetRepresentationFingerprintV2(candidate),\n\t\trepresentationKind: candidate.kind,\n\t\tsourceHash,\n\t});\n}\n\nexport function buildContextBudgetMaterializedRepresentationCandidateKeyV2(\n\tkeyBase: ContextBudgetCacheKeyBaseV2,\n\tcandidate: ContextBudgetRepresentationFingerprintInputV2,\n\tsourceHash: string,\n): string {\n\treturn buildContextBudgetMaterializedRepresentationCacheKeyV2({\n\t\t...keyBase,\n\t\tcompressorId: candidate.compressorId ?? NO_COMPRESSOR_ID,\n\t\trepresentationKind: candidate.kind,\n\t\tsourceHash,\n\t\ttargetTokenBucket: computeContextBudgetTargetTokenBucketV2(candidate.estimatedTokens),\n\t});\n}\n\nexport function computeContextBudgetTargetTokenBucketV2(tokens: number): number {\n\tif (!Number.isFinite(tokens) || tokens <= 0) {\n\t\treturn MATERIALIZED_TARGET_TOKEN_BUCKET_SIZE;\n\t}\n\treturn MATERIALIZED_TARGET_TOKEN_BUCKET_SIZE * Math.ceil(tokens / MATERIALIZED_TARGET_TOKEN_BUCKET_SIZE);\n}\n\nexport function computeContextBudgetOutputTextHashV2(text: string): string {\n\treturn sha256Hex(text);\n}\n\nexport function fingerprintSourceRef(sourceRef: ContextRepresentationCandidateV2[\"sourceRef\"]): unknown {\n\tif (!sourceRef) return null;\n\treturn {\n\t\tcontentHash: sourceRef.contentHash,\n\t\trange: sourceRef.range\n\t\t\t? {\n\t\t\t\t\tendLine: sourceRef.range.endLine,\n\t\t\t\t\tstartLine: sourceRef.range.startLine,\n\t\t\t\t}\n\t\t\t: null,\n\t\tretrievable: sourceRef.retrievable,\n\t\tsymbol: sourceRef.symbol ?? null,\n\t\turi: sourceRef.uri,\n\t};\n}\n"]}
|
|
@@ -40,15 +40,16 @@ export function computeContextBudgetQueryIntentHashV2(query) {
|
|
|
40
40
|
export function buildContextBudgetRepresentationCacheKeyV2(input) {
|
|
41
41
|
return buildContextBudgetExactRepresentationCacheKeyV2(input);
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Exact representation key. Content-addressed: identical content + rendering
|
|
45
|
+
* policy yields one key across queries, budgets, sessions, forks, and worktrees.
|
|
46
|
+
*/
|
|
43
47
|
export function buildContextBudgetExactRepresentationCacheKeyV2(input) {
|
|
44
48
|
return `context-representation-exact:${sha256Canonical({
|
|
45
|
-
budgetBucket: input.budgetBucket,
|
|
46
49
|
compressorId: input.compressorId ?? NO_COMPRESSOR_ID,
|
|
47
|
-
invalidationSnapshotHash: input.invalidationSnapshotHash ?? "none",
|
|
48
50
|
modelId: input.modelId,
|
|
49
51
|
namespace: input.namespace,
|
|
50
52
|
policyVersion: input.policyVersion,
|
|
51
|
-
queryIntentHash: input.queryIntentHash,
|
|
52
53
|
redactionPolicyHash: input.redactionPolicyHash,
|
|
53
54
|
representationFingerprint: input.representationFingerprint ?? "none",
|
|
54
55
|
representationKind: input.representationKind,
|
|
@@ -62,7 +63,6 @@ export function buildContextBudgetMaterializedRepresentationCacheKeyV2(input) {
|
|
|
62
63
|
budgetBucket: input.budgetBucket,
|
|
63
64
|
compressorId: input.compressorId ?? NO_COMPRESSOR_ID,
|
|
64
65
|
compressorPolicyHash: input.compressorPolicyHash ?? DEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2,
|
|
65
|
-
invalidationSnapshotHash: input.invalidationSnapshotHash ?? "none",
|
|
66
66
|
modelId: input.modelId,
|
|
67
67
|
namespace: input.namespace,
|
|
68
68
|
policyVersion: input.policyVersion,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-budget-v2-cache-keys.js","sourceRoot":"","sources":["../../src/core/context-budget-v2-cache-keys.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContextRepresentationCandidateV2, ContextRepresentationKindV2 } from \"./context-budget-headroom.ts\";\nimport { sha256Canonical, sha256Hex } from \"./context-budget-v2-cache-hash.ts\";\nimport {\n\ttype ContextCacheInvalidationSnapshot,\n\tserializeContextCacheSnapshot,\n} from \"./context-budget-v2-cache-invalidation.ts\";\n\nconst DEFAULT_CACHE_NAMESPACE = \"context-budget-v2\";\nconst DEFAULT_TOKENIZER_ID = \"heuristic-v1\";\nconst DEFAULT_REDACTION_POLICY_HASH = \"none\";\nconst DEFAULT_SAFETY_PROFILE_HASH = \"default\";\nconst NO_COMPRESSOR_ID = \"none\";\nexport const DEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2 = \"context-budget-v2-default-compressor\";\nexport const DEFAULT_MATERIALIZED_QUALITY_POLICY_HASH_V2 = \"context-budget-v2-default-quality\";\nconst MATERIALIZED_TARGET_TOKEN_BUCKET_SIZE = 100;\n\ntype ContextBudgetRepresentationFingerprintInputV2 = Pick<\n\tContextRepresentationCandidateV2,\n\t\"compressorId\" | \"estimatedTokens\" | \"fidelity\" | \"kind\" | \"sourceRef\" | \"summaryHash\" | \"text\"\n>;\n\nexport interface ContextBudgetCacheKeyBaseV2 {\n\treadonly namespace: string;\n\treadonly modelId: string;\n\treadonly tokenizerId: string;\n\treadonly policyVersion: string;\n\treadonly queryIntentHash: string;\n\treadonly queryIntentCluster?: string;\n\treadonly budgetBucket: string;\n\treadonly redactionPolicyHash: string;\n\treadonly safetyProfileHash: string;\n\treadonly compressorPolicyHash?: string;\n\treadonly qualityPolicyHash?: string;\n\treadonly invalidationSnapshotHash?: string;\n}\n\nexport function createContextBudgetCacheKeyBaseV2(input: {\n\treadonly namespace?: string;\n\treadonly modelId: string;\n\treadonly tokenizerId?: string;\n\treadonly policyVersion: string;\n\treadonly query?: string;\n\treadonly queryIntentHash?: string;\n\treadonly queryIntentCluster?: string;\n\treadonly budgetBucket?: string;\n\treadonly redactionPolicyHash?: string;\n\treadonly safetyProfileHash?: string;\n\treadonly compressorPolicyHash?: string;\n\treadonly qualityPolicyHash?: string;\n\treadonly cacheInvalidationSnapshot?: ContextCacheInvalidationSnapshot;\n}): ContextBudgetCacheKeyBaseV2 {\n\tconst queryIntentHash = input.queryIntentHash ?? computeContextBudgetQueryIntentHashV2(input.query);\n\treturn {\n\t\tnamespace: input.namespace ?? DEFAULT_CACHE_NAMESPACE,\n\t\tmodelId: input.modelId,\n\t\ttokenizerId: input.tokenizerId ?? DEFAULT_TOKENIZER_ID,\n\t\tpolicyVersion: input.policyVersion,\n\t\tqueryIntentHash,\n\t\tqueryIntentCluster: input.queryIntentCluster ?? queryIntentHash,\n\t\tbudgetBucket: input.budgetBucket ?? \"unknown\",\n\t\tredactionPolicyHash: input.redactionPolicyHash ?? DEFAULT_REDACTION_POLICY_HASH,\n\t\tsafetyProfileHash: input.safetyProfileHash ?? DEFAULT_SAFETY_PROFILE_HASH,\n\t\tcompressorPolicyHash: input.compressorPolicyHash ?? DEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2,\n\t\tqualityPolicyHash: input.qualityPolicyHash ?? DEFAULT_MATERIALIZED_QUALITY_POLICY_HASH_V2,\n\t\tinvalidationSnapshotHash:\n\t\t\tinput.cacheInvalidationSnapshot === undefined\n\t\t\t\t? \"none\"\n\t\t\t\t: sha256Hex(serializeContextCacheSnapshot(input.cacheInvalidationSnapshot)),\n\t};\n}\n\nexport function computeContextBudgetQueryIntentHashV2(query: string | undefined): string {\n\tconst normalized = (query ?? \"\")\n\t\t.toLowerCase()\n\t\t.split(/[\\s,.;:!?()[\\]{}\"'`]+/u)\n\t\t.map((term) => term.trim())\n\t\t.filter((term) => term.length > 0)\n\t\t.sort()\n\t\t.join(\" \");\n\treturn sha256Hex(normalized.length > 0 ? normalized : \"none\");\n}\n\nexport function buildContextBudgetRepresentationCacheKeyV2(\n\tinput: ContextBudgetCacheKeyBaseV2 & {\n\t\treadonly representationKind: ContextRepresentationKindV2;\n\t\treadonly sourceHash: string;\n\t\treadonly representationFingerprint?: string;\n\t\treadonly compressorId?: string;\n\t},\n): string {\n\treturn buildContextBudgetExactRepresentationCacheKeyV2(input);\n}\n\nexport function buildContextBudgetExactRepresentationCacheKeyV2(\n\tinput: ContextBudgetCacheKeyBaseV2 & {\n\t\treadonly representationKind: ContextRepresentationKindV2;\n\t\treadonly sourceHash: string;\n\t\treadonly representationFingerprint?: string;\n\t\treadonly compressorId?: string;\n\t},\n): string {\n\treturn `context-representation-exact:${sha256Canonical({\n\t\tbudgetBucket: input.budgetBucket,\n\t\tcompressorId: input.compressorId ?? NO_COMPRESSOR_ID,\n\t\tinvalidationSnapshotHash: input.invalidationSnapshotHash ?? \"none\",\n\t\tmodelId: input.modelId,\n\t\tnamespace: input.namespace,\n\t\tpolicyVersion: input.policyVersion,\n\t\tqueryIntentHash: input.queryIntentHash,\n\t\tredactionPolicyHash: input.redactionPolicyHash,\n\t\trepresentationFingerprint: input.representationFingerprint ?? \"none\",\n\t\trepresentationKind: input.representationKind,\n\t\tsafetyProfileHash: input.safetyProfileHash,\n\t\tsourceHash: input.sourceHash,\n\t\ttokenizerId: input.tokenizerId,\n\t})}`;\n}\n\nexport function buildContextBudgetMaterializedRepresentationCacheKeyV2(\n\tinput: ContextBudgetCacheKeyBaseV2 & {\n\t\treadonly representationKind: ContextRepresentationKindV2;\n\t\treadonly sourceHash: string;\n\t\treadonly compressorId?: string;\n\t\treadonly targetTokenBucket: number;\n\t},\n): string {\n\treturn `context-representation-materialized:${sha256Canonical({\n\t\tbudgetBucket: input.budgetBucket,\n\t\tcompressorId: input.compressorId ?? NO_COMPRESSOR_ID,\n\t\tcompressorPolicyHash: input.compressorPolicyHash ?? DEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2,\n\t\tinvalidationSnapshotHash: input.invalidationSnapshotHash ?? \"none\",\n\t\tmodelId: input.modelId,\n\t\tnamespace: input.namespace,\n\t\tpolicyVersion: input.policyVersion,\n\t\tqualityPolicyHash: input.qualityPolicyHash ?? DEFAULT_MATERIALIZED_QUALITY_POLICY_HASH_V2,\n\t\tqueryIntentCluster: input.queryIntentCluster ?? input.queryIntentHash,\n\t\tqueryIntentHash: input.queryIntentHash,\n\t\tredactionPolicyHash: input.redactionPolicyHash,\n\t\trepresentationKind: input.representationKind,\n\t\tsafetyProfileHash: input.safetyProfileHash,\n\t\tsourceHash: input.sourceHash,\n\t\ttargetTokenBucket: input.targetTokenBucket,\n\t\ttokenizerId: input.tokenizerId,\n\t})}`;\n}\n\nexport function computeContextBudgetRepresentationFingerprintV2(\n\tcandidate: ContextBudgetRepresentationFingerprintInputV2,\n): string {\n\treturn sha256Canonical({\n\t\tcompressorId: candidate.compressorId ?? NO_COMPRESSOR_ID,\n\t\testimatedTokens: candidate.estimatedTokens,\n\t\tfidelity: candidate.fidelity,\n\t\tkind: candidate.kind,\n\t\tsourceRef: fingerprintSourceRef(candidate.sourceRef),\n\t\tsummaryHash: candidate.summaryHash ?? null,\n\t\ttextHash: sha256Hex(candidate.text),\n\t});\n}\n\nexport function buildContextBudgetRepresentationCandidateKeyV2(\n\tkeyBase: ContextBudgetCacheKeyBaseV2,\n\tcandidate: ContextBudgetRepresentationFingerprintInputV2,\n\tsourceHash: string,\n): string {\n\treturn buildContextBudgetExactRepresentationCacheKeyV2({\n\t\t...keyBase,\n\t\tcompressorId: candidate.compressorId ?? NO_COMPRESSOR_ID,\n\t\trepresentationFingerprint: computeContextBudgetRepresentationFingerprintV2(candidate),\n\t\trepresentationKind: candidate.kind,\n\t\tsourceHash,\n\t});\n}\n\nexport function buildContextBudgetMaterializedRepresentationCandidateKeyV2(\n\tkeyBase: ContextBudgetCacheKeyBaseV2,\n\tcandidate: ContextBudgetRepresentationFingerprintInputV2,\n\tsourceHash: string,\n): string {\n\treturn buildContextBudgetMaterializedRepresentationCacheKeyV2({\n\t\t...keyBase,\n\t\tcompressorId: candidate.compressorId ?? NO_COMPRESSOR_ID,\n\t\trepresentationKind: candidate.kind,\n\t\tsourceHash,\n\t\ttargetTokenBucket: computeContextBudgetTargetTokenBucketV2(candidate.estimatedTokens),\n\t});\n}\n\nexport function computeContextBudgetTargetTokenBucketV2(tokens: number): number {\n\tif (!Number.isFinite(tokens) || tokens <= 0) {\n\t\treturn MATERIALIZED_TARGET_TOKEN_BUCKET_SIZE;\n\t}\n\treturn MATERIALIZED_TARGET_TOKEN_BUCKET_SIZE * Math.ceil(tokens / MATERIALIZED_TARGET_TOKEN_BUCKET_SIZE);\n}\n\nexport function computeContextBudgetOutputTextHashV2(text: string): string {\n\treturn sha256Hex(text);\n}\n\nexport function fingerprintSourceRef(sourceRef: ContextRepresentationCandidateV2[\"sourceRef\"]): unknown {\n\tif (!sourceRef) return null;\n\treturn {\n\t\tcontentHash: sourceRef.contentHash,\n\t\trange: sourceRef.range\n\t\t\t? {\n\t\t\t\t\tendLine: sourceRef.range.endLine,\n\t\t\t\t\tstartLine: sourceRef.range.startLine,\n\t\t\t\t}\n\t\t\t: null,\n\t\tretrievable: sourceRef.retrievable,\n\t\tsymbol: sourceRef.symbol ?? null,\n\t\turi: sourceRef.uri,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"context-budget-v2-cache-keys.js","sourceRoot":"","sources":["../../src/core/context-budget-v2-cache-keys.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContextRepresentationCandidateV2, ContextRepresentationKindV2 } from \"./context-budget-headroom.ts\";\nimport { sha256Canonical, sha256Hex } from \"./context-budget-v2-cache-hash.ts\";\nimport {\n\ttype ContextCacheInvalidationSnapshot,\n\tserializeContextCacheSnapshot,\n} from \"./context-budget-v2-cache-invalidation.ts\";\n\nconst DEFAULT_CACHE_NAMESPACE = \"context-budget-v2\";\nconst DEFAULT_TOKENIZER_ID = \"heuristic-v1\";\nconst DEFAULT_REDACTION_POLICY_HASH = \"none\";\nconst DEFAULT_SAFETY_PROFILE_HASH = \"default\";\nconst NO_COMPRESSOR_ID = \"none\";\nexport const DEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2 = \"context-budget-v2-default-compressor\";\nexport const DEFAULT_MATERIALIZED_QUALITY_POLICY_HASH_V2 = \"context-budget-v2-default-quality\";\nconst MATERIALIZED_TARGET_TOKEN_BUCKET_SIZE = 100;\n\ntype ContextBudgetRepresentationFingerprintInputV2 = Pick<\n\tContextRepresentationCandidateV2,\n\t\"compressorId\" | \"estimatedTokens\" | \"fidelity\" | \"kind\" | \"sourceRef\" | \"summaryHash\" | \"text\"\n>;\n\n/**\n * Cache-key inputs shared by the plan cache and the representation cache.\n *\n * Scope contract (deliberate asymmetry — see the two builders below):\n * - **Plan keys are session-scoped.** A plan is a selection over the whole\n * transcript and runtime state, so {@link invalidationSnapshotHash} (fork id,\n * worktree fingerprint, steering/repair/settings counters) is part of the key.\n * - **Representation keys are content-addressed.** A rendered representation is\n * fully identified by its source content plus the rendering policy, so the\n * invalidation snapshot is deliberately *excluded*. Folding a per-session\n * `forkId` into representation keys made every new session miss every entry\n * (structurally unreachable reuse, not a cold cache), while adding no safety:\n * `validateContextBudgetRepresentationCacheEntryV2` independently re-checks\n * source hash, fingerprint, model, tokenizer, policy version, and\n * TTL on every read, and worktree/model/redaction/safety changes already move\n * the key through `sourceHash` / `modelId` / `redactionPolicyHash` /\n * `safetyProfileHash`.\n */\nexport interface ContextBudgetCacheKeyBaseV2 {\n\treadonly namespace: string;\n\treadonly modelId: string;\n\treadonly tokenizerId: string;\n\treadonly policyVersion: string;\n\treadonly queryIntentHash: string;\n\treadonly queryIntentCluster?: string;\n\treadonly budgetBucket: string;\n\treadonly redactionPolicyHash: string;\n\treadonly safetyProfileHash: string;\n\treadonly compressorPolicyHash?: string;\n\treadonly qualityPolicyHash?: string;\n\treadonly invalidationSnapshotHash?: string;\n}\n\nexport function createContextBudgetCacheKeyBaseV2(input: {\n\treadonly namespace?: string;\n\treadonly modelId: string;\n\treadonly tokenizerId?: string;\n\treadonly policyVersion: string;\n\treadonly query?: string;\n\treadonly queryIntentHash?: string;\n\treadonly queryIntentCluster?: string;\n\treadonly budgetBucket?: string;\n\treadonly redactionPolicyHash?: string;\n\treadonly safetyProfileHash?: string;\n\treadonly compressorPolicyHash?: string;\n\treadonly qualityPolicyHash?: string;\n\treadonly cacheInvalidationSnapshot?: ContextCacheInvalidationSnapshot;\n}): ContextBudgetCacheKeyBaseV2 {\n\tconst queryIntentHash = input.queryIntentHash ?? computeContextBudgetQueryIntentHashV2(input.query);\n\treturn {\n\t\tnamespace: input.namespace ?? DEFAULT_CACHE_NAMESPACE,\n\t\tmodelId: input.modelId,\n\t\ttokenizerId: input.tokenizerId ?? DEFAULT_TOKENIZER_ID,\n\t\tpolicyVersion: input.policyVersion,\n\t\tqueryIntentHash,\n\t\tqueryIntentCluster: input.queryIntentCluster ?? queryIntentHash,\n\t\tbudgetBucket: input.budgetBucket ?? \"unknown\",\n\t\tredactionPolicyHash: input.redactionPolicyHash ?? DEFAULT_REDACTION_POLICY_HASH,\n\t\tsafetyProfileHash: input.safetyProfileHash ?? DEFAULT_SAFETY_PROFILE_HASH,\n\t\tcompressorPolicyHash: input.compressorPolicyHash ?? DEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2,\n\t\tqualityPolicyHash: input.qualityPolicyHash ?? DEFAULT_MATERIALIZED_QUALITY_POLICY_HASH_V2,\n\t\tinvalidationSnapshotHash:\n\t\t\tinput.cacheInvalidationSnapshot === undefined\n\t\t\t\t? \"none\"\n\t\t\t\t: sha256Hex(serializeContextCacheSnapshot(input.cacheInvalidationSnapshot)),\n\t};\n}\n\nexport function computeContextBudgetQueryIntentHashV2(query: string | undefined): string {\n\tconst normalized = (query ?? \"\")\n\t\t.toLowerCase()\n\t\t.split(/[\\s,.;:!?()[\\]{}\"'`]+/u)\n\t\t.map((term) => term.trim())\n\t\t.filter((term) => term.length > 0)\n\t\t.sort()\n\t\t.join(\" \");\n\treturn sha256Hex(normalized.length > 0 ? normalized : \"none\");\n}\n\nexport function buildContextBudgetRepresentationCacheKeyV2(\n\tinput: ContextBudgetCacheKeyBaseV2 & {\n\t\treadonly representationKind: ContextRepresentationKindV2;\n\t\treadonly sourceHash: string;\n\t\treadonly representationFingerprint?: string;\n\t\treadonly compressorId?: string;\n\t},\n): string {\n\treturn buildContextBudgetExactRepresentationCacheKeyV2(input);\n}\n\n/**\n * Exact representation key. Content-addressed: identical content + rendering\n * policy yields one key across queries, budgets, sessions, forks, and worktrees.\n */\nexport function buildContextBudgetExactRepresentationCacheKeyV2(\n\tinput: ContextBudgetCacheKeyBaseV2 & {\n\t\treadonly representationKind: ContextRepresentationKindV2;\n\t\treadonly sourceHash: string;\n\t\treadonly representationFingerprint?: string;\n\t\treadonly compressorId?: string;\n\t},\n): string {\n\treturn `context-representation-exact:${sha256Canonical({\n\t\tcompressorId: input.compressorId ?? NO_COMPRESSOR_ID,\n\t\tmodelId: input.modelId,\n\t\tnamespace: input.namespace,\n\t\tpolicyVersion: input.policyVersion,\n\t\tredactionPolicyHash: input.redactionPolicyHash,\n\t\trepresentationFingerprint: input.representationFingerprint ?? \"none\",\n\t\trepresentationKind: input.representationKind,\n\t\tsafetyProfileHash: input.safetyProfileHash,\n\t\tsourceHash: input.sourceHash,\n\t\ttokenizerId: input.tokenizerId,\n\t})}`;\n}\n\nexport function buildContextBudgetMaterializedRepresentationCacheKeyV2(\n\tinput: ContextBudgetCacheKeyBaseV2 & {\n\t\treadonly representationKind: ContextRepresentationKindV2;\n\t\treadonly sourceHash: string;\n\t\treadonly compressorId?: string;\n\t\treadonly targetTokenBucket: number;\n\t},\n): string {\n\treturn `context-representation-materialized:${sha256Canonical({\n\t\tbudgetBucket: input.budgetBucket,\n\t\tcompressorId: input.compressorId ?? NO_COMPRESSOR_ID,\n\t\tcompressorPolicyHash: input.compressorPolicyHash ?? DEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2,\n\t\tmodelId: input.modelId,\n\t\tnamespace: input.namespace,\n\t\tpolicyVersion: input.policyVersion,\n\t\tqualityPolicyHash: input.qualityPolicyHash ?? DEFAULT_MATERIALIZED_QUALITY_POLICY_HASH_V2,\n\t\tqueryIntentCluster: input.queryIntentCluster ?? input.queryIntentHash,\n\t\tqueryIntentHash: input.queryIntentHash,\n\t\tredactionPolicyHash: input.redactionPolicyHash,\n\t\trepresentationKind: input.representationKind,\n\t\tsafetyProfileHash: input.safetyProfileHash,\n\t\tsourceHash: input.sourceHash,\n\t\ttargetTokenBucket: input.targetTokenBucket,\n\t\ttokenizerId: input.tokenizerId,\n\t})}`;\n}\n\nexport function computeContextBudgetRepresentationFingerprintV2(\n\tcandidate: ContextBudgetRepresentationFingerprintInputV2,\n): string {\n\treturn sha256Canonical({\n\t\tcompressorId: candidate.compressorId ?? NO_COMPRESSOR_ID,\n\t\testimatedTokens: candidate.estimatedTokens,\n\t\tfidelity: candidate.fidelity,\n\t\tkind: candidate.kind,\n\t\tsourceRef: fingerprintSourceRef(candidate.sourceRef),\n\t\tsummaryHash: candidate.summaryHash ?? null,\n\t\ttextHash: sha256Hex(candidate.text),\n\t});\n}\n\nexport function buildContextBudgetRepresentationCandidateKeyV2(\n\tkeyBase: ContextBudgetCacheKeyBaseV2,\n\tcandidate: ContextBudgetRepresentationFingerprintInputV2,\n\tsourceHash: string,\n): string {\n\treturn buildContextBudgetExactRepresentationCacheKeyV2({\n\t\t...keyBase,\n\t\tcompressorId: candidate.compressorId ?? NO_COMPRESSOR_ID,\n\t\trepresentationFingerprint: computeContextBudgetRepresentationFingerprintV2(candidate),\n\t\trepresentationKind: candidate.kind,\n\t\tsourceHash,\n\t});\n}\n\nexport function buildContextBudgetMaterializedRepresentationCandidateKeyV2(\n\tkeyBase: ContextBudgetCacheKeyBaseV2,\n\tcandidate: ContextBudgetRepresentationFingerprintInputV2,\n\tsourceHash: string,\n): string {\n\treturn buildContextBudgetMaterializedRepresentationCacheKeyV2({\n\t\t...keyBase,\n\t\tcompressorId: candidate.compressorId ?? NO_COMPRESSOR_ID,\n\t\trepresentationKind: candidate.kind,\n\t\tsourceHash,\n\t\ttargetTokenBucket: computeContextBudgetTargetTokenBucketV2(candidate.estimatedTokens),\n\t});\n}\n\nexport function computeContextBudgetTargetTokenBucketV2(tokens: number): number {\n\tif (!Number.isFinite(tokens) || tokens <= 0) {\n\t\treturn MATERIALIZED_TARGET_TOKEN_BUCKET_SIZE;\n\t}\n\treturn MATERIALIZED_TARGET_TOKEN_BUCKET_SIZE * Math.ceil(tokens / MATERIALIZED_TARGET_TOKEN_BUCKET_SIZE);\n}\n\nexport function computeContextBudgetOutputTextHashV2(text: string): string {\n\treturn sha256Hex(text);\n}\n\nexport function fingerprintSourceRef(sourceRef: ContextRepresentationCandidateV2[\"sourceRef\"]): unknown {\n\tif (!sourceRef) return null;\n\treturn {\n\t\tcontentHash: sourceRef.contentHash,\n\t\trange: sourceRef.range\n\t\t\t? {\n\t\t\t\t\tendLine: sourceRef.range.endLine,\n\t\t\t\t\tstartLine: sourceRef.range.startLine,\n\t\t\t\t}\n\t\t\t: null,\n\t\tretrievable: sourceRef.retrievable,\n\t\tsymbol: sourceRef.symbol ?? null,\n\t\turi: sourceRef.uri,\n\t};\n}\n"]}
|
|
@@ -2,6 +2,7 @@ import type { ContextBudgetCacheKeyBaseV2 } from "./context-budget-v2-cache-keys
|
|
|
2
2
|
import { type MutableTokenCacheTelemetryV2 } from "./context-budget-v2-cache-telemetry.ts";
|
|
3
3
|
import type { PlannedItemV2 } from "./context-budget-v2-scoring.ts";
|
|
4
4
|
import type { ContextBudgetCacheProviderV2, PromptContextBudgetPlanV2 } from "./context-budget-v2-types.ts";
|
|
5
|
+
export { CONTEXT_BUDGET_DISK_CACHE_SCHEMA_VERSION, createDiskContextBudgetCacheProviderV2, DEFAULT_DISK_CACHE_FLUSH_DEBOUNCE_MS, DEFAULT_DISK_CACHE_MAX_BYTES, DEFAULT_DISK_CACHE_MAX_ENTRIES, type DiskContextBudgetCacheOptionsV2, DiskContextBudgetCacheProviderV2, } from "./context-budget-v2-cache-disk.ts";
|
|
5
6
|
export { buildContextBudgetExactRepresentationCacheKeyV2, buildContextBudgetMaterializedRepresentationCacheKeyV2, buildContextBudgetMaterializedRepresentationCandidateKeyV2, buildContextBudgetRepresentationCacheKeyV2, type ContextBudgetCacheKeyBaseV2, computeContextBudgetOutputTextHashV2, computeContextBudgetQueryIntentHashV2, computeContextBudgetRepresentationFingerprintV2, computeContextBudgetTargetTokenBucketV2, createContextBudgetCacheKeyBaseV2, DEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2, DEFAULT_MATERIALIZED_QUALITY_POLICY_HASH_V2, } from "./context-budget-v2-cache-keys.ts";
|
|
6
7
|
export { createMemoryContextBudgetCacheProviderV2 } from "./context-budget-v2-cache-provider.ts";
|
|
7
8
|
export { finalizeContextBudgetCacheTelemetryV2, type MutableTokenCacheTelemetryV2, withCacheTelemetry, } from "./context-budget-v2-cache-telemetry.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-budget-v2-cache.d.ts","sourceRoot":"","sources":["../../src/core/context-budget-v2-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,mCAAmC,CAAC;AACrF,OAAO,EAEN,KAAK,4BAA4B,EAEjC,MAAM,wCAAwC,CAAC;AAKhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,KAAK,EAAE,4BAA4B,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAE5G,OAAO,EACN,+CAA+C,EAC/C,sDAAsD,EACtD,0DAA0D,EAC1D,0CAA0C,EAC1C,KAAK,2BAA2B,EAChC,oCAAoC,EACpC,qCAAqC,EACrC,+CAA+C,EAC/C,uCAAuC,EACvC,iCAAiC,EACjC,8CAA8C,EAC9C,2CAA2C,GAC3C,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,wCAAwC,EAAE,MAAM,uCAAuC,CAAC;AACjG,OAAO,EACN,qCAAqC,EACrC,KAAK,4BAA4B,EACjC,kBAAkB,GAClB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,gCAAgC,EAAE,MAAM,wCAAwC,CAAC;AAC1F,OAAO,EACN,0BAA0B,EAC1B,gCAAgC,EAChC,0BAA0B,GAC1B,MAAM,6CAA6C,CAAC;AAIrD,MAAM,WAAW,6BAA6B;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,4BAA4B,CAAC;IACjD,QAAQ,CAAC,OAAO,EAAE,2BAA2B,CAAC;IAC9C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,4BAA4B,CAAC;CACjD;AAED,wBAAgB,mCAAmC,CAAC,KAAK,EAAE;IAC1D,QAAQ,CAAC,QAAQ,CAAC,EAAE,4BAA4B,CAAC;IACjD,QAAQ,CAAC,OAAO,EAAE,2BAA2B,CAAC;IAC9C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,6BAA6B,CAQhC;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC3C,QAAQ,CAAC,KAAK,EAAE,6BAA6B,CAAC;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAC3C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CACjC,GAAG,yBAAyB,GAAG,SAAS,CAkBxC;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACvC,QAAQ,CAAC,KAAK,EAAE,6BAA6B,CAAC;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,yBAAyB,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;CAC3C,GAAG,IAAI,CAWP","sourcesContent":["import type { ContextBudgetCacheKeyBaseV2 } from \"./context-budget-v2-cache-keys.ts\";\nimport {\n\tcreateMutableContextBudgetCacheTelemetryV2,\n\ttype MutableTokenCacheTelemetryV2,\n\twithCacheTelemetry,\n} from \"./context-budget-v2-cache-telemetry.ts\";\nimport {\n\tsourceHashesByContextBudgetItemIdV2,\n\tvalidateContextBudgetPlanCacheEntryV2,\n} from \"./context-budget-v2-cache-validation.ts\";\nimport type { PlannedItemV2 } from \"./context-budget-v2-scoring.ts\";\nimport type { ContextBudgetCacheProviderV2, PromptContextBudgetPlanV2 } from \"./context-budget-v2-types.ts\";\n\nexport {\n\tbuildContextBudgetExactRepresentationCacheKeyV2,\n\tbuildContextBudgetMaterializedRepresentationCacheKeyV2,\n\tbuildContextBudgetMaterializedRepresentationCandidateKeyV2,\n\tbuildContextBudgetRepresentationCacheKeyV2,\n\ttype ContextBudgetCacheKeyBaseV2,\n\tcomputeContextBudgetOutputTextHashV2,\n\tcomputeContextBudgetQueryIntentHashV2,\n\tcomputeContextBudgetRepresentationFingerprintV2,\n\tcomputeContextBudgetTargetTokenBucketV2,\n\tcreateContextBudgetCacheKeyBaseV2,\n\tDEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2,\n\tDEFAULT_MATERIALIZED_QUALITY_POLICY_HASH_V2,\n} from \"./context-budget-v2-cache-keys.ts\";\nexport { createMemoryContextBudgetCacheProviderV2 } from \"./context-budget-v2-cache-provider.ts\";\nexport {\n\tfinalizeContextBudgetCacheTelemetryV2,\n\ttype MutableTokenCacheTelemetryV2,\n\twithCacheTelemetry,\n} from \"./context-budget-v2-cache-telemetry.ts\";\nexport { buildContextBudgetPlanCacheKeyV2 } from \"./context-budget-v2-plan-cache-keys.ts\";\nexport {\n\tapplyRepresentationCacheV2,\n\tisMaterializableRepresentationV2,\n\twriteRepresentationCacheV2,\n} from \"./context-budget-v2-representation-cache.ts\";\n\nconst DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000;\n\nexport interface ContextBudgetSelectionCacheV2 {\n\treadonly provider?: ContextBudgetCacheProviderV2;\n\treadonly keyBase: ContextBudgetCacheKeyBaseV2;\n\treadonly nowEpochMs: number;\n\treadonly ttlMs: number;\n\treadonly telemetry: MutableTokenCacheTelemetryV2;\n}\n\nexport function createContextBudgetSelectionCacheV2(input: {\n\treadonly provider?: ContextBudgetCacheProviderV2;\n\treadonly keyBase: ContextBudgetCacheKeyBaseV2;\n\treadonly planCacheKey: string;\n\treadonly nowEpochMs?: number;\n\treadonly ttlMs?: number;\n}): ContextBudgetSelectionCacheV2 {\n\treturn {\n\t\tprovider: input.provider,\n\t\tkeyBase: input.keyBase,\n\t\tnowEpochMs: input.nowEpochMs ?? Date.now(),\n\t\tttlMs: input.ttlMs ?? DEFAULT_CACHE_TTL_MS,\n\t\ttelemetry: createMutableContextBudgetCacheTelemetryV2(input.planCacheKey),\n\t};\n}\n\nexport function readValidPlanCacheV2(input: {\n\treadonly cache: ContextBudgetSelectionCacheV2;\n\treadonly key: string;\n\treadonly planned: readonly PlannedItemV2[];\n\treadonly availableTokens: number;\n}): PromptContextBudgetPlanV2 | undefined {\n\tconst read = input.cache.provider?.readPlan(input.key);\n\tif (!read) return undefined;\n\tconst rejection = validateContextBudgetPlanCacheEntryV2({\n\t\tavailableTokens: input.availableTokens,\n\t\tcache: input.cache,\n\t\tentry: read.entry,\n\t\tplanned: input.planned,\n\t});\n\tif (rejection) {\n\t\tinput.cache.telemetry.planCache.rejectedReason = rejection;\n\t\tif (rejection === \"stale\") input.cache.provider?.deletePlan?.(input.key);\n\t\treturn undefined;\n\t}\n\tinput.cache.telemetry.planCache.hit = true;\n\tinput.cache.telemetry.planCache.layer = read.layer;\n\tinput.cache.telemetry.tokens.savedByCache = read.entry.plan.rawTokens;\n\treturn withCacheTelemetry(read.entry.plan, input.cache.telemetry);\n}\n\nexport function writePlanCacheV2(input: {\n\treadonly cache: ContextBudgetSelectionCacheV2;\n\treadonly key: string;\n\treadonly plan: PromptContextBudgetPlanV2;\n\treadonly planned: readonly PlannedItemV2[];\n}): void {\n\tif (!input.cache.provider || input.plan.emergency) return;\n\tif (input.plan.selectedRepresentations.some((representation) => representation.cache?.hit === true)) return;\n\tinput.cache.provider.writePlan({\n\t\tkey: input.key,\n\t\tentry: {\n\t\t\tcreatedAtEpochMs: input.cache.nowEpochMs,\n\t\t\tplan: input.plan,\n\t\t\tsourceHashes: sourceHashesByContextBudgetItemIdV2(input.planned),\n\t\t},\n\t});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"context-budget-v2-cache.d.ts","sourceRoot":"","sources":["../../src/core/context-budget-v2-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,mCAAmC,CAAC;AACrF,OAAO,EAEN,KAAK,4BAA4B,EAEjC,MAAM,wCAAwC,CAAC;AAKhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,KAAK,EAAE,4BAA4B,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAE5G,OAAO,EACN,wCAAwC,EACxC,sCAAsC,EACtC,oCAAoC,EACpC,4BAA4B,EAC5B,8BAA8B,EAC9B,KAAK,+BAA+B,EACpC,gCAAgC,GAChC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACN,+CAA+C,EAC/C,sDAAsD,EACtD,0DAA0D,EAC1D,0CAA0C,EAC1C,KAAK,2BAA2B,EAChC,oCAAoC,EACpC,qCAAqC,EACrC,+CAA+C,EAC/C,uCAAuC,EACvC,iCAAiC,EACjC,8CAA8C,EAC9C,2CAA2C,GAC3C,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,wCAAwC,EAAE,MAAM,uCAAuC,CAAC;AACjG,OAAO,EACN,qCAAqC,EACrC,KAAK,4BAA4B,EACjC,kBAAkB,GAClB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,gCAAgC,EAAE,MAAM,wCAAwC,CAAC;AAC1F,OAAO,EACN,0BAA0B,EAC1B,gCAAgC,EAChC,0BAA0B,GAC1B,MAAM,6CAA6C,CAAC;AAIrD,MAAM,WAAW,6BAA6B;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,4BAA4B,CAAC;IACjD,QAAQ,CAAC,OAAO,EAAE,2BAA2B,CAAC;IAC9C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,4BAA4B,CAAC;CACjD;AAED,wBAAgB,mCAAmC,CAAC,KAAK,EAAE;IAC1D,QAAQ,CAAC,QAAQ,CAAC,EAAE,4BAA4B,CAAC;IACjD,QAAQ,CAAC,OAAO,EAAE,2BAA2B,CAAC;IAC9C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,6BAA6B,CAQhC;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC3C,QAAQ,CAAC,KAAK,EAAE,6BAA6B,CAAC;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAC3C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CACjC,GAAG,yBAAyB,GAAG,SAAS,CAkBxC;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACvC,QAAQ,CAAC,KAAK,EAAE,6BAA6B,CAAC;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,yBAAyB,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;CAC3C,GAAG,IAAI,CAWP","sourcesContent":["import type { ContextBudgetCacheKeyBaseV2 } from \"./context-budget-v2-cache-keys.ts\";\nimport {\n\tcreateMutableContextBudgetCacheTelemetryV2,\n\ttype MutableTokenCacheTelemetryV2,\n\twithCacheTelemetry,\n} from \"./context-budget-v2-cache-telemetry.ts\";\nimport {\n\tsourceHashesByContextBudgetItemIdV2,\n\tvalidateContextBudgetPlanCacheEntryV2,\n} from \"./context-budget-v2-cache-validation.ts\";\nimport type { PlannedItemV2 } from \"./context-budget-v2-scoring.ts\";\nimport type { ContextBudgetCacheProviderV2, PromptContextBudgetPlanV2 } from \"./context-budget-v2-types.ts\";\n\nexport {\n\tCONTEXT_BUDGET_DISK_CACHE_SCHEMA_VERSION,\n\tcreateDiskContextBudgetCacheProviderV2,\n\tDEFAULT_DISK_CACHE_FLUSH_DEBOUNCE_MS,\n\tDEFAULT_DISK_CACHE_MAX_BYTES,\n\tDEFAULT_DISK_CACHE_MAX_ENTRIES,\n\ttype DiskContextBudgetCacheOptionsV2,\n\tDiskContextBudgetCacheProviderV2,\n} from \"./context-budget-v2-cache-disk.ts\";\nexport {\n\tbuildContextBudgetExactRepresentationCacheKeyV2,\n\tbuildContextBudgetMaterializedRepresentationCacheKeyV2,\n\tbuildContextBudgetMaterializedRepresentationCandidateKeyV2,\n\tbuildContextBudgetRepresentationCacheKeyV2,\n\ttype ContextBudgetCacheKeyBaseV2,\n\tcomputeContextBudgetOutputTextHashV2,\n\tcomputeContextBudgetQueryIntentHashV2,\n\tcomputeContextBudgetRepresentationFingerprintV2,\n\tcomputeContextBudgetTargetTokenBucketV2,\n\tcreateContextBudgetCacheKeyBaseV2,\n\tDEFAULT_MATERIALIZED_COMPRESSOR_POLICY_HASH_V2,\n\tDEFAULT_MATERIALIZED_QUALITY_POLICY_HASH_V2,\n} from \"./context-budget-v2-cache-keys.ts\";\nexport { createMemoryContextBudgetCacheProviderV2 } from \"./context-budget-v2-cache-provider.ts\";\nexport {\n\tfinalizeContextBudgetCacheTelemetryV2,\n\ttype MutableTokenCacheTelemetryV2,\n\twithCacheTelemetry,\n} from \"./context-budget-v2-cache-telemetry.ts\";\nexport { buildContextBudgetPlanCacheKeyV2 } from \"./context-budget-v2-plan-cache-keys.ts\";\nexport {\n\tapplyRepresentationCacheV2,\n\tisMaterializableRepresentationV2,\n\twriteRepresentationCacheV2,\n} from \"./context-budget-v2-representation-cache.ts\";\n\nconst DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000;\n\nexport interface ContextBudgetSelectionCacheV2 {\n\treadonly provider?: ContextBudgetCacheProviderV2;\n\treadonly keyBase: ContextBudgetCacheKeyBaseV2;\n\treadonly nowEpochMs: number;\n\treadonly ttlMs: number;\n\treadonly telemetry: MutableTokenCacheTelemetryV2;\n}\n\nexport function createContextBudgetSelectionCacheV2(input: {\n\treadonly provider?: ContextBudgetCacheProviderV2;\n\treadonly keyBase: ContextBudgetCacheKeyBaseV2;\n\treadonly planCacheKey: string;\n\treadonly nowEpochMs?: number;\n\treadonly ttlMs?: number;\n}): ContextBudgetSelectionCacheV2 {\n\treturn {\n\t\tprovider: input.provider,\n\t\tkeyBase: input.keyBase,\n\t\tnowEpochMs: input.nowEpochMs ?? Date.now(),\n\t\tttlMs: input.ttlMs ?? DEFAULT_CACHE_TTL_MS,\n\t\ttelemetry: createMutableContextBudgetCacheTelemetryV2(input.planCacheKey),\n\t};\n}\n\nexport function readValidPlanCacheV2(input: {\n\treadonly cache: ContextBudgetSelectionCacheV2;\n\treadonly key: string;\n\treadonly planned: readonly PlannedItemV2[];\n\treadonly availableTokens: number;\n}): PromptContextBudgetPlanV2 | undefined {\n\tconst read = input.cache.provider?.readPlan(input.key);\n\tif (!read) return undefined;\n\tconst rejection = validateContextBudgetPlanCacheEntryV2({\n\t\tavailableTokens: input.availableTokens,\n\t\tcache: input.cache,\n\t\tentry: read.entry,\n\t\tplanned: input.planned,\n\t});\n\tif (rejection) {\n\t\tinput.cache.telemetry.planCache.rejectedReason = rejection;\n\t\tif (rejection === \"stale\") input.cache.provider?.deletePlan?.(input.key);\n\t\treturn undefined;\n\t}\n\tinput.cache.telemetry.planCache.hit = true;\n\tinput.cache.telemetry.planCache.layer = read.layer;\n\tinput.cache.telemetry.tokens.savedByCache = read.entry.plan.rawTokens;\n\treturn withCacheTelemetry(read.entry.plan, input.cache.telemetry);\n}\n\nexport function writePlanCacheV2(input: {\n\treadonly cache: ContextBudgetSelectionCacheV2;\n\treadonly key: string;\n\treadonly plan: PromptContextBudgetPlanV2;\n\treadonly planned: readonly PlannedItemV2[];\n}): void {\n\tif (!input.cache.provider || input.plan.emergency) return;\n\tif (input.plan.selectedRepresentations.some((representation) => representation.cache?.hit === true)) return;\n\tinput.cache.provider.writePlan({\n\t\tkey: input.key,\n\t\tentry: {\n\t\t\tcreatedAtEpochMs: input.cache.nowEpochMs,\n\t\t\tplan: input.plan,\n\t\t\tsourceHashes: sourceHashesByContextBudgetItemIdV2(input.planned),\n\t\t},\n\t});\n}\n"]}
|