open-multi-agent-kit 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -1
- package/README.md +2 -2
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +1 -0
- package/dist/cli/help.js.map +1 -1
- package/dist/coordination/awareness.d.ts +32 -0
- package/dist/coordination/awareness.d.ts.map +1 -0
- package/dist/coordination/awareness.js +55 -0
- package/dist/coordination/awareness.js.map +1 -0
- package/dist/coordination/broker.d.ts +79 -0
- package/dist/coordination/broker.d.ts.map +1 -0
- package/dist/coordination/broker.js +195 -0
- package/dist/coordination/broker.js.map +1 -0
- package/dist/coordination/index.d.ts +16 -0
- package/dist/coordination/index.d.ts.map +1 -0
- package/dist/coordination/index.js +16 -0
- package/dist/coordination/index.js.map +1 -0
- package/dist/coordination/integration.d.ts +59 -0
- package/dist/coordination/integration.d.ts.map +1 -0
- package/dist/coordination/integration.js +126 -0
- package/dist/coordination/integration.js.map +1 -0
- package/dist/coordination/operation.d.ts +106 -0
- package/dist/coordination/operation.d.ts.map +1 -0
- package/dist/coordination/operation.js +179 -0
- package/dist/coordination/operation.js.map +1 -0
- package/dist/coordination/resource.d.ts +33 -0
- package/dist/coordination/resource.d.ts.map +1 -0
- package/dist/coordination/resource.js +89 -0
- package/dist/coordination/resource.js.map +1 -0
- package/dist/coordination/session.d.ts +74 -0
- package/dist/coordination/session.d.ts.map +1 -0
- package/dist/coordination/session.js +143 -0
- package/dist/coordination/session.js.map +1 -0
- package/dist/coordination/types.d.ts +68 -0
- package/dist/coordination/types.d.ts.map +1 -0
- package/dist/coordination/types.js +26 -0
- package/dist/coordination/types.js.map +1 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +28 -7
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/control-state.d.ts +41 -0
- package/dist/core/compaction/control-state.d.ts.map +1 -0
- package/dist/core/compaction/control-state.js +85 -0
- package/dist/core/compaction/control-state.js.map +1 -0
- package/dist/core/compaction/fallback.d.ts +60 -0
- package/dist/core/compaction/fallback.d.ts.map +1 -0
- package/dist/core/compaction/fallback.js +117 -0
- package/dist/core/compaction/fallback.js.map +1 -0
- package/dist/core/compaction/index.d.ts +2 -0
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/index.js +2 -0
- package/dist/core/compaction/index.js.map +1 -1
- package/dist/core/context-budget-headroom-candidates.d.ts +16 -1
- package/dist/core/context-budget-headroom-candidates.d.ts.map +1 -1
- package/dist/core/context-budget-headroom-candidates.js +31 -13
- package/dist/core/context-budget-headroom-candidates.js.map +1 -1
- package/dist/core/context-budget-headroom-types.d.ts +7 -1
- package/dist/core/context-budget-headroom-types.d.ts.map +1 -1
- package/dist/core/context-budget-headroom-types.js +0 -1
- package/dist/core/context-budget-headroom-types.js.map +1 -1
- package/dist/core/context-budget-headroom.d.ts +10 -0
- package/dist/core/context-budget-headroom.d.ts.map +1 -1
- package/dist/core/context-budget-headroom.js +11 -2
- package/dist/core/context-budget-headroom.js.map +1 -1
- package/dist/core/context-budget-v2-global-pass.d.ts +21 -0
- package/dist/core/context-budget-v2-global-pass.d.ts.map +1 -0
- package/dist/core/context-budget-v2-global-pass.js +203 -0
- package/dist/core/context-budget-v2-global-pass.js.map +1 -0
- package/dist/core/context-budget-v2-planned-items.d.ts +12 -0
- package/dist/core/context-budget-v2-planned-items.d.ts.map +1 -1
- package/dist/core/context-budget-v2-planned-items.js +21 -2
- package/dist/core/context-budget-v2-planned-items.js.map +1 -1
- package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
- package/dist/core/context-budget-v2-planner.js +18 -19
- package/dist/core/context-budget-v2-planner.js.map +1 -1
- package/dist/core/context-budget-v2-scoring.d.ts +7 -1
- package/dist/core/context-budget-v2-scoring.d.ts.map +1 -1
- package/dist/core/context-budget-v2-scoring.js.map +1 -1
- package/dist/core/context-budget-v2-selection.d.ts +3 -0
- package/dist/core/context-budget-v2-selection.d.ts.map +1 -1
- package/dist/core/context-budget-v2-selection.js +6 -2
- package/dist/core/context-budget-v2-selection.js.map +1 -1
- package/dist/core/context-budget-v2-types.d.ts +6 -1
- package/dist/core/context-budget-v2-types.d.ts.map +1 -1
- package/dist/core/context-budget-v2-types.js +6 -1
- package/dist/core/context-budget-v2-types.js.map +1 -1
- package/dist/core/provider-default-models.d.ts +1 -0
- package/dist/core/provider-default-models.d.ts.map +1 -1
- package/dist/core/provider-default-models.js +1 -0
- package/dist/core/provider-default-models.js.map +1 -1
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/provider-display-names.js +1 -0
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/reasoning-router-resolver.d.ts +7 -0
- package/dist/core/reasoning-router-resolver.d.ts.map +1 -1
- package/dist/core/reasoning-router-resolver.js +21 -3
- package/dist/core/reasoning-router-resolver.js.map +1 -1
- package/dist/core/reasoning-router-v4.d.ts +8 -5
- package/dist/core/reasoning-router-v4.d.ts.map +1 -1
- package/dist/core/reasoning-router-v4.js +8 -5
- package/dist/core/reasoning-router-v4.js.map +1 -1
- package/dist/core/session-compaction-service.d.ts +15 -0
- package/dist/core/session-compaction-service.d.ts.map +1 -1
- package/dist/core/session-compaction-service.js +17 -4
- package/dist/core/session-compaction-service.js.map +1 -1
- package/dist/core/todo-runtime-state.d.ts +12 -0
- package/dist/core/todo-runtime-state.d.ts.map +1 -1
- package/dist/core/todo-runtime-state.js +23 -0
- package/dist/core/todo-runtime-state.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/metacognition/calibration-selective.d.ts +78 -0
- package/dist/metacognition/calibration-selective.d.ts.map +1 -0
- package/dist/metacognition/calibration-selective.js +161 -0
- package/dist/metacognition/calibration-selective.js.map +1 -0
- package/dist/metacognition/calibration.d.ts +62 -0
- package/dist/metacognition/calibration.d.ts.map +1 -0
- package/dist/metacognition/calibration.js +122 -0
- package/dist/metacognition/calibration.js.map +1 -0
- package/dist/metacognition/checkpoint.d.ts +60 -0
- package/dist/metacognition/checkpoint.d.ts.map +1 -0
- package/dist/metacognition/checkpoint.js +57 -0
- package/dist/metacognition/checkpoint.js.map +1 -0
- package/dist/metacognition/context7.d.ts +48 -0
- package/dist/metacognition/context7.d.ts.map +1 -0
- package/dist/metacognition/context7.js +154 -0
- package/dist/metacognition/context7.js.map +1 -0
- package/dist/metacognition/decision.d.ts +44 -0
- package/dist/metacognition/decision.d.ts.map +1 -0
- package/dist/metacognition/decision.js +111 -0
- package/dist/metacognition/decision.js.map +1 -0
- package/dist/metacognition/evaluation.d.ts +73 -0
- package/dist/metacognition/evaluation.d.ts.map +1 -0
- package/dist/metacognition/evaluation.js +97 -0
- package/dist/metacognition/evaluation.js.map +1 -0
- package/dist/metacognition/index.d.ts +31 -0
- package/dist/metacognition/index.d.ts.map +1 -0
- package/dist/metacognition/index.js +31 -0
- package/dist/metacognition/index.js.map +1 -0
- package/dist/metacognition/knowledge-action.d.ts +43 -0
- package/dist/metacognition/knowledge-action.d.ts.map +1 -0
- package/dist/metacognition/knowledge-action.js +60 -0
- package/dist/metacognition/knowledge-action.js.map +1 -0
- package/dist/metacognition/knowledge.d.ts +84 -0
- package/dist/metacognition/knowledge.d.ts.map +1 -0
- package/dist/metacognition/knowledge.js +165 -0
- package/dist/metacognition/knowledge.js.map +1 -0
- package/dist/metacognition/obligations.d.ts +82 -0
- package/dist/metacognition/obligations.d.ts.map +1 -0
- package/dist/metacognition/obligations.js +139 -0
- package/dist/metacognition/obligations.js.map +1 -0
- package/dist/metacognition/observation-validity.d.ts +83 -0
- package/dist/metacognition/observation-validity.d.ts.map +1 -0
- package/dist/metacognition/observation-validity.js +118 -0
- package/dist/metacognition/observation-validity.js.map +1 -0
- package/dist/metacognition/observe.d.ts +45 -0
- package/dist/metacognition/observe.d.ts.map +1 -0
- package/dist/metacognition/observe.js +59 -0
- package/dist/metacognition/observe.js.map +1 -0
- package/dist/metacognition/policy.d.ts +53 -0
- package/dist/metacognition/policy.d.ts.map +1 -0
- package/dist/metacognition/policy.js +155 -0
- package/dist/metacognition/policy.js.map +1 -0
- package/dist/metacognition/predictions.d.ts +78 -0
- package/dist/metacognition/predictions.d.ts.map +1 -0
- package/dist/metacognition/predictions.js +181 -0
- package/dist/metacognition/predictions.js.map +1 -0
- package/dist/metacognition/retrieval.d.ts +53 -0
- package/dist/metacognition/retrieval.d.ts.map +1 -0
- package/dist/metacognition/retrieval.js +170 -0
- package/dist/metacognition/retrieval.js.map +1 -0
- package/dist/metacognition/risk.d.ts +48 -0
- package/dist/metacognition/risk.d.ts.map +1 -0
- package/dist/metacognition/risk.js +165 -0
- package/dist/metacognition/risk.js.map +1 -0
- package/dist/metacognition/route-economics.d.ts +95 -0
- package/dist/metacognition/route-economics.d.ts.map +1 -0
- package/dist/metacognition/route-economics.js +110 -0
- package/dist/metacognition/route-economics.js.map +1 -0
- package/dist/metacognition/runtime-bridge.d.ts +54 -0
- package/dist/metacognition/runtime-bridge.d.ts.map +1 -0
- package/dist/metacognition/runtime-bridge.js +140 -0
- package/dist/metacognition/runtime-bridge.js.map +1 -0
- package/dist/metacognition/skills.d.ts +42 -0
- package/dist/metacognition/skills.d.ts.map +1 -0
- package/dist/metacognition/skills.js +220 -0
- package/dist/metacognition/skills.js.map +1 -0
- package/dist/metacognition/state.d.ts +110 -0
- package/dist/metacognition/state.d.ts.map +1 -0
- package/dist/metacognition/state.js +52 -0
- package/dist/metacognition/state.js.map +1 -0
- package/dist/metacognition/validation.d.ts +19 -0
- package/dist/metacognition/validation.d.ts.map +1 -0
- package/dist/metacognition/validation.js +58 -0
- package/dist/metacognition/validation.js.map +1 -0
- package/dist/metacognition/verification.d.ts +93 -0
- package/dist/metacognition/verification.d.ts.map +1 -0
- package/dist/metacognition/verification.js +132 -0
- package/dist/metacognition/verification.js.map +1 -0
- package/dist/metacognition/verifier.d.ts +49 -0
- package/dist/metacognition/verifier.d.ts.map +1 -0
- package/dist/metacognition/verifier.js +88 -0
- package/dist/metacognition/verifier.js.map +1 -0
- package/dist/observation/identity.d.ts +14 -0
- package/dist/observation/identity.d.ts.map +1 -0
- package/dist/observation/identity.js +29 -0
- package/dist/observation/identity.js.map +1 -0
- package/dist/observation/index.d.ts +13 -0
- package/dist/observation/index.d.ts.map +1 -0
- package/dist/observation/index.js +13 -0
- package/dist/observation/index.js.map +1 -0
- package/dist/observation/observe-mode.d.ts +46 -0
- package/dist/observation/observe-mode.d.ts.map +1 -0
- package/dist/observation/observe-mode.js +83 -0
- package/dist/observation/observe-mode.js.map +1 -0
- package/dist/observation/store.d.ts +53 -0
- package/dist/observation/store.d.ts.map +1 -0
- package/dist/observation/store.js +126 -0
- package/dist/observation/store.js.map +1 -0
- package/dist/observation/types.d.ts +72 -0
- package/dist/observation/types.d.ts.map +1 -0
- package/dist/observation/types.js +9 -0
- package/dist/observation/types.js.map +1 -0
- package/dist/observation/view.d.ts +39 -0
- package/dist/observation/view.d.ts.map +1 -0
- package/dist/observation/view.js +173 -0
- package/dist/observation/view.js.map +1 -0
- package/docs/metacognition.md +51 -0
- package/docs/model-catalog-refresh.md +59 -0
- package/docs/providers.md +53 -0
- package/docs/runtime-algorithms.md +107 -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/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +18 -18
- package/package.json +6 -6
|
@@ -16,19 +16,38 @@ function minAdmissibleTokens(candidates, item, policy, fullTokens) {
|
|
|
16
16
|
}
|
|
17
17
|
return Math.max(1, Number.isFinite(min) ? min : fullTokens);
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Identity of the adapter that actually prices this run's text.
|
|
21
|
+
*
|
|
22
|
+
* Every representation price now depends on the planner's counter (audit F01),
|
|
23
|
+
* but the materialized representation key is bucketed rather than exact, so the
|
|
24
|
+
* static `heuristic-v1` default let two counters share one key space: a run
|
|
25
|
+
* could admit text at a price its own counter never produced, and the entry's
|
|
26
|
+
* `tokenizer_mismatch` check compared that constant against itself. Probe a
|
|
27
|
+
* non-empty string, because `countText("")` short-circuits to the fallback
|
|
28
|
+
* estimator in the registry and would report the wrong adapter.
|
|
29
|
+
*/
|
|
30
|
+
export function resolveEffectiveTokenizerIdV2(tokenCounter, modelId) {
|
|
31
|
+
return (tokenCounter ?? createFallbackTokenCounter()).countText(" ", modelId).adapterId;
|
|
32
|
+
}
|
|
19
33
|
export function createPlannedItems(items, tokenCounter, modelId, qualityPolicy) {
|
|
20
34
|
const counter = tokenCounter ?? createFallbackTokenCounter();
|
|
35
|
+
// One counter prices the full text and every derived representation, so
|
|
36
|
+
// the selector compares like with like (audit F01: a ratio-priced summary
|
|
37
|
+
// was admitted into a budget its materialized text could not fit).
|
|
38
|
+
const countTokens = (text) => counter.countText(text, modelId).tokens;
|
|
21
39
|
return items.map((item) => {
|
|
22
|
-
const overrideTokenEstimate = item.tokenEstimate ??
|
|
40
|
+
const overrideTokenEstimate = item.tokenEstimate ?? countTokens(item.text);
|
|
23
41
|
const itemWithTokens = item.tokenEstimate === undefined ? { ...item, tokenEstimate: overrideTokenEstimate } : item;
|
|
24
42
|
const fullTokens = fullTextTokens(itemWithTokens);
|
|
25
43
|
const isHard = item.priority === "hard" || item.required === true;
|
|
26
44
|
const baseScore = isHard ? Number.POSITIVE_INFINITY : scoreContextBudgetItemV2(itemWithTokens, fullTokens);
|
|
27
|
-
const candidates = itemWithTokens.representations ?? deriveRepresentationCandidates(itemWithTokens, qualityPolicy);
|
|
45
|
+
const candidates = itemWithTokens.representations ?? deriveRepresentationCandidates(itemWithTokens, qualityPolicy, countTokens);
|
|
28
46
|
return {
|
|
29
47
|
item: itemWithTokens,
|
|
30
48
|
fullTokens,
|
|
31
49
|
admissibleTokens: minAdmissibleTokens(candidates, itemWithTokens, qualityPolicy, fullTokens),
|
|
50
|
+
candidates,
|
|
32
51
|
contentHash: contentHashOf(item.text),
|
|
33
52
|
baseScore,
|
|
34
53
|
redundancyPenalty: 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-budget-v2-planned-items.js","sourceRoot":"","sources":["../../src/core/context-budget-v2-planned-items.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,8BAA8B,EAC9B,cAAc,EAEd,wBAAwB,GACxB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,0BAA0B,EAA4B,MAAM,mCAAmC,CAAC;AACzG,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAsB,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAE9F,2EAA2E;AAC3E,0EAA0E;AAC1E,+DAA+D;AAC/D,SAAS,mBAAmB,CAC3B,UAAuD,EACvD,IAAyB,EACzB,MAA2C,EAC3C,UAAkB,EACT;IACT,IAAI,GAAG,GAAG,MAAM,CAAC,iBAAiB,CAAC;IACnC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACpC,IACC,SAAS,CAAC,IAAI,KAAK,MAAM;YACzB,wBAAwB,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC;YACjD,SAAS,CAAC,eAAe,GAAG,GAAG,EAC9B,CAAC;YACF,GAAG,GAAG,SAAS,CAAC,eAAe,CAAC;QACjC,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;AAAA,CAC5D;AAED,MAAM,UAAU,kBAAkB,CACjC,KAAqC,EACrC,YAA6C,EAC7C,OAAe,EACf,aAAoE,EAClD;IAClB,MAAM,OAAO,GAAG,YAAY,IAAI,0BAA0B,EAAE,CAAC;IAC7D,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC1B,MAAM,qBAAqB,GAAG,IAAI,CAAC,aAAa,IAAI,
|
|
1
|
+
{"version":3,"file":"context-budget-v2-planned-items.js","sourceRoot":"","sources":["../../src/core/context-budget-v2-planned-items.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype ContextBudgetItemV2,\n\ttype ContextRepresentationCandidateV2,\n\tderiveRepresentationCandidates,\n\tfullTextTokens,\n\ttype HeadroomQualityPolicyV2,\n\tisRepresentationEligible,\n} from \"./context-budget-headroom.ts\";\nimport { createFallbackTokenCounter, type TokenCounterAdapter } from \"./context-budget-token-counter.ts\";\nimport { contentHashOf } from \"./context-budget-v2-plan-hash.ts\";\nimport { type PlannedItemV2, scoreContextBudgetItemV2 } from \"./context-budget-v2-scoring.ts\";\n\n// Cheapest representation the chooser could actually pick: only candidates\n// passing the selection policy gate count, so a pointer the chooser would\n// reject cannot make an item look cheaper to admit than it is.\nfunction minAdmissibleTokens(\n\tcandidates: readonly ContextRepresentationCandidateV2[],\n\titem: ContextBudgetItemV2,\n\tpolicy: HeadroomQualityPolicyV2 | undefined,\n\tfullTokens: number,\n): number {\n\tlet min = Number.POSITIVE_INFINITY;\n\tfor (const candidate of candidates) {\n\t\tif (\n\t\t\tcandidate.kind !== \"omit\" &&\n\t\t\tisRepresentationEligible(candidate, item, policy) &&\n\t\t\tcandidate.estimatedTokens < min\n\t\t) {\n\t\t\tmin = candidate.estimatedTokens;\n\t\t}\n\t}\n\treturn Math.max(1, Number.isFinite(min) ? min : fullTokens);\n}\n\n/**\n * Identity of the adapter that actually prices this run's text.\n *\n * Every representation price now depends on the planner's counter (audit F01),\n * but the materialized representation key is bucketed rather than exact, so the\n * static `heuristic-v1` default let two counters share one key space: a run\n * could admit text at a price its own counter never produced, and the entry's\n * `tokenizer_mismatch` check compared that constant against itself. Probe a\n * non-empty string, because `countText(\"\")` short-circuits to the fallback\n * estimator in the registry and would report the wrong adapter.\n */\nexport function resolveEffectiveTokenizerIdV2(tokenCounter: TokenCounterAdapter | undefined, modelId: string): string {\n\treturn (tokenCounter ?? createFallbackTokenCounter()).countText(\" \", modelId).adapterId;\n}\n\nexport function createPlannedItems(\n\titems: readonly ContextBudgetItemV2[],\n\ttokenCounter: TokenCounterAdapter | undefined,\n\tmodelId: string,\n\tqualityPolicy?: Parameters<typeof deriveRepresentationCandidates>[1],\n): PlannedItemV2[] {\n\tconst counter = tokenCounter ?? createFallbackTokenCounter();\n\t// One counter prices the full text and every derived representation, so\n\t// the selector compares like with like (audit F01: a ratio-priced summary\n\t// was admitted into a budget its materialized text could not fit).\n\tconst countTokens = (text: string): number => counter.countText(text, modelId).tokens;\n\treturn items.map((item) => {\n\t\tconst overrideTokenEstimate = item.tokenEstimate ?? countTokens(item.text);\n\t\tconst itemWithTokens =\n\t\t\titem.tokenEstimate === undefined ? { ...item, tokenEstimate: overrideTokenEstimate } : item;\n\t\tconst fullTokens = fullTextTokens(itemWithTokens);\n\t\tconst isHard = item.priority === \"hard\" || item.required === true;\n\t\tconst baseScore = isHard ? Number.POSITIVE_INFINITY : scoreContextBudgetItemV2(itemWithTokens, fullTokens);\n\t\tconst candidates =\n\t\t\titemWithTokens.representations ?? deriveRepresentationCandidates(itemWithTokens, qualityPolicy, countTokens);\n\t\treturn {\n\t\t\titem: itemWithTokens,\n\t\t\tfullTokens,\n\t\t\tadmissibleTokens: minAdmissibleTokens(candidates, itemWithTokens, qualityPolicy, fullTokens),\n\t\t\tcandidates,\n\t\t\tcontentHash: contentHashOf(item.text),\n\t\t\tbaseScore,\n\t\t\tredundancyPenalty: 0,\n\t\t\teffectiveScore: baseScore,\n\t\t\tisHard,\n\t\t};\n\t});\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-budget-v2-planner.d.ts","sourceRoot":"","sources":["../../src/core/context-budget-v2-planner.ts"],"names":[],"mappings":"AA8BA,OAAO,EAIN,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAI9B,MAAM,8BAA8B,CAAC;AAEtC,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,0BAA0B,GAAG,yBAAyB,CAmOtG","sourcesContent":["import {\n\ttype ContextBudgetItemV2,\n\ttype ContextBudgetTierV2,\n\ttype ContextRepresentationCandidateV2,\n\ttype ContextSourceRefV2,\n\tDEFAULT_HEADROOM_QUALITY_POLICY,\n} from \"./context-budget-headroom.ts\";\nimport {\n\tbuildContextBudgetPlanCacheKeyV2,\n\tcreateContextBudgetCacheKeyBaseV2,\n\tcreateContextBudgetSelectionCacheV2,\n\tfinalizeContextBudgetCacheTelemetryV2,\n\treadValidPlanCacheV2,\n\twritePlanCacheV2,\n} from \"./context-budget-v2-cache.ts\";\nimport { validateBudgetItems } from \"./context-budget-v2-input-validation.ts\";\nimport { buildObservability } from \"./context-budget-v2-observability.ts\";\nimport { computePlanHash } from \"./context-budget-v2-plan-hash.ts\";\nimport { createPlannedItems } from \"./context-budget-v2-planned-items.ts\";\nimport { compareOptionalForSelection } from \"./context-budget-v2-scoring.ts\";\nimport {\n\tapplyPlannerRedundancyPenalties,\n\tbuildTierAllocations,\n\tcreateTierUsage,\n\temitCoverageDiagnostics,\n\temitOmissionDiagnostics,\n\tselectHardItem,\n\tselectOptionalItem,\n} from \"./context-budget-v2-selection.ts\";\nimport { allocateTiers, computeTierDemand } from \"./context-budget-v2-tiers.ts\";\nimport {\n\tALL_TIERS_V2,\n\tCONTEXT_BUDGET_POLICY_VERSION_V2,\n\tDEFAULT_TIER_POLICY_V2,\n\ttype PromptContextBudgetInputV2,\n\ttype PromptContextBudgetPlanV2,\n\ttype QualityDiagnosticV2,\n\ttype SelectedRepresentationV2,\n\ttype TierBudgetPolicyV2,\n} from \"./context-budget-v2-types.ts\";\n\nexport function planPromptContextBudgetV2(input: PromptContextBudgetInputV2): PromptContextBudgetPlanV2 {\n\tconst modelId = input.modelId ?? \"unknown\";\n\tconst qualityPolicy = input.qualityPolicy ?? DEFAULT_HEADROOM_QUALITY_POLICY;\n\tconst policyVersion = input.policyVersion ?? CONTEXT_BUDGET_POLICY_VERSION_V2;\n\tconst diagnostics: QualityDiagnosticV2[] = [];\n\n\tconst maxTokens = normalizeBudgetTokens(\"maxTokens\", input.maxTokens, diagnostics);\n\tconst responseReserve = normalizeBudgetTokens(\n\t\t\"responseReserveTokens\",\n\t\tinput.responseReserveTokens ?? 0,\n\t\tdiagnostics,\n\t);\n\tconst safetyMargin = normalizeBudgetTokens(\n\t\t\"safetyMarginTokens\",\n\t\tinput.safetyMarginTokens ?? Math.ceil(maxTokens * 0.05),\n\t\tdiagnostics,\n\t);\n\tconst available = Math.max(0, maxTokens - responseReserve - safetyMargin);\n\n\tconst tierPolicy: Readonly<Record<ContextBudgetTierV2, TierBudgetPolicyV2>> = {\n\t\t...DEFAULT_TIER_POLICY_V2,\n\t\t...(input.tierPolicy ?? {}),\n\t};\n\tconst basePlanned = createPlannedItems(\n\t\tvalidateBudgetItems(input.items, diagnostics),\n\t\tinput.tokenCounter,\n\t\tmodelId,\n\t\tqualityPolicy,\n\t);\n\t// Sanitized items can share a key with valid input, but their diagnostics cannot.\n\tconst canUsePlanCache = diagnostics.length === 0;\n\tapplyPlannerRedundancyPenalties(basePlanned);\n\tconst rawTokens = basePlanned.reduce((sum, planned) => sum + planned.fullTokens, 0);\n\n\tconst demand = computeTierDemand(basePlanned);\n\tconst allocation = allocateTiers(available, tierPolicy, demand);\n\tconst cacheKeyBase = createContextBudgetCacheKeyBaseV2({\n\t\tbudgetBucket: input.cacheBudgetBucket ?? String(available),\n\t\tcacheInvalidationSnapshot: input.cacheInvalidationSnapshot ?? input.cacheProvider?.getInvalidationSnapshot?.(),\n\t\tmodelId,\n\t\tnamespace: input.cacheNamespace,\n\t\tpolicyVersion,\n\t\tselectionPolicyVersion: input.selectionPolicyVersion,\n\t\tquery: input.query,\n\t\tqueryIntentHash: input.queryIntentHash,\n\t\tredactionPolicyHash: input.redactionPolicyHash,\n\t\tsafetyProfileHash: input.safetyProfileHash,\n\t\ttokenizerId: input.tokenizerId,\n\t});\n\tconst planCacheKey = buildContextBudgetPlanCacheKeyV2({\n\t\tavailableTokens: available,\n\t\tkeyBase: cacheKeyBase,\n\t\tmaxTokens,\n\t\tplanned: basePlanned,\n\t\tpromptHash: input.promptHash,\n\t\tqualityPolicy,\n\t\tresponseReserveTokens: responseReserve,\n\t\tsafetyMarginTokens: safetyMargin,\n\t\ttierPolicy,\n\t});\n\tconst cache = createContextBudgetSelectionCacheV2({\n\t\tkeyBase: cacheKeyBase,\n\t\tnowEpochMs: input.cacheNowEpochMs,\n\t\tplanCacheKey,\n\t\tprovider: input.cacheProvider,\n\t\tttlMs: input.cacheTtlMs,\n\t});\n\tconst cachedPlan = canUsePlanCache\n\t\t? readValidPlanCacheV2({\n\t\t\t\tavailableTokens: available,\n\t\t\t\tcache,\n\t\t\t\tkey: planCacheKey,\n\t\t\t\tplanned: basePlanned,\n\t\t\t})\n\t\t: undefined;\n\tif (cachedPlan) {\n\t\treturn cachedPlan;\n\t}\n\tconst selection = new Map<string, SelectedRepresentationV2>();\n\tconst tierUsed = createTierUsage();\n\tconst omitted: ContextBudgetItemV2[] = [];\n\tconst retrievalFallbacks: ContextSourceRefV2[] = [];\n\tlet usedTokens = 0;\n\n\tfor (const planned of basePlanned) {\n\t\tif (!planned.isHard) continue;\n\t\tusedTokens += selectHardItem(planned, selection, tierUsed);\n\t}\n\tif (usedTokens > available) {\n\t\tdiagnostics.push({\n\t\t\treason: \"hard_pin_over_capacity\",\n\t\t\tdetail: `hard-pinned context uses ${usedTokens} tokens against ${available} available tokens`,\n\t\t});\n\t}\n\n\tconst optionalPlanned = basePlanned.filter((planned) => !planned.isHard).sort(compareOptionalForSelection);\n\n\t// Floor-reservation pass: each tier spends its guaranteed claim (the\n\t// `allocated` field — hard demand, else demand capped at the floor) on its\n\t// own optional items before anything competes globally. A tier's floor is\n\t// therefore a real reservation, not a lower bound on its ceiling. Items\n\t// that cannot fit inside the remaining floor stay unselected for the\n\t// global pass; when the summed floors exceed the budget the reservation is\n\t// best-effort in tier order and the plan reports it explicitly.\n\t// One cache-resolution per item, shared by both passes so an item that is\n\t// deferred out of the floor and reconsidered globally does not double\n\t// count provider reads or redo materialization work.\n\tconst resolvedCandidates = new Map<string, readonly ContextRepresentationCandidateV2[]>();\n\tlet totalFloor = 0;\n\tfor (const tier of ALL_TIERS_V2) {\n\t\ttotalFloor += allocation.get(tier)?.floor ?? 0;\n\t}\n\tif (totalFloor > available) {\n\t\tdiagnostics.push({\n\t\t\treason: \"tier_floor_over_budget\",\n\t\t\tdetail: `tier floor guarantees total ${totalFloor} tokens against ${available} available; floors degrade to tier-order best effort`,\n\t\t});\n\t}\n\tfor (const tier of ALL_TIERS_V2) {\n\t\tconst floor = allocation.get(tier)?.floor ?? 0;\n\t\tif (floor <= 0 || tierUsed[tier] >= floor) continue;\n\t\tfor (const planned of optionalPlanned) {\n\t\t\tif (planned.item.tier !== tier || selection.has(planned.item.id)) continue;\n\t\t\tusedTokens = selectOptionalItem(planned, {\n\t\t\t\tallocation,\n\t\t\t\tavailable,\n\t\t\t\tcache,\n\t\t\t\tdiagnostics,\n\t\t\t\tomitted,\n\t\t\t\tqualityPolicy,\n\t\t\t\tretrievalFallbacks,\n\t\t\t\tselection,\n\t\t\t\ttierUsed,\n\t\t\t\tusedTokens,\n\t\t\t\tfloorReservation: { tier, floorTokens: floor },\n\t\t\t\tresolvedCandidates,\n\t\t\t});\n\t\t\tif (tierUsed[tier] >= floor || usedTokens >= available) break;\n\t\t}\n\t}\n\n\tfor (const planned of optionalPlanned) {\n\t\tif (selection.has(planned.item.id)) continue;\n\t\tusedTokens = selectOptionalItem(planned, {\n\t\t\tallocation,\n\t\t\tavailable,\n\t\t\tcache,\n\t\t\tdiagnostics,\n\t\t\tomitted,\n\t\t\tqualityPolicy,\n\t\t\tresolvedCandidates,\n\t\t\tretrievalFallbacks,\n\t\t\tselection,\n\t\t\ttierUsed,\n\t\t\tusedTokens,\n\t\t});\n\t}\n\n\tconst omittedHighPriority = omitted.some((item) => item.priority === \"high\" || item.required === true);\n\temitOmissionDiagnostics(omitted, diagnostics, retrievalFallbacks);\n\temitCoverageDiagnostics(input.query, selection, diagnostics);\n\n\tconst tierAllocations = buildTierAllocations(allocation, demand, tierUsed);\n\tconst omittedTokens = omitted.reduce(\n\t\t(sum, item) => sum + (basePlanned.find((planned) => planned.item.id === item.id)?.fullTokens ?? 0),\n\t\t0,\n\t);\n\tconst omittedItemIds = omitted.map((item) => item.id);\n\tconst planHash = computePlanHash({\n\t\tpolicyVersion,\n\t\tpromptHash: input.promptHash,\n\t\tplanned: basePlanned,\n\t\tselection,\n\t\tallocations: tierAllocations,\n\t\tomittedItemIds,\n\t});\n\tconst observability = buildObservability({\n\t\tavailable,\n\t\tdiagnostics,\n\t\tomittedItemIds,\n\t\tomittedTokens,\n\t\tplanHash,\n\t\trawTokens,\n\t\tretrievalFallbacks,\n\t\tselection,\n\t\tusedTokens,\n\t\tcacheTelemetry: finalizeContextBudgetCacheTelemetryV2(cache.telemetry, {\n\t\t\tomittedTokens,\n\t\t\trawTokens,\n\t\t\tusedTokens,\n\t\t}),\n\t});\n\n\tconst plan: PromptContextBudgetPlanV2 = {\n\t\tpolicyVersion,\n\t\tpromptHash: input.promptHash,\n\t\tplanHash,\n\t\tmaxTokens,\n\t\tresponseReserveTokens: responseReserve,\n\t\tsafetyMarginTokens: safetyMargin,\n\t\tavailableTokens: available,\n\t\tusedTokens,\n\t\tomittedTokens,\n\t\trawTokens,\n\t\ttokenSavingsRatio: rawTokens > 0 ? Math.max(0, 1 - usedTokens / rawTokens) : 0,\n\t\temergency: usedTokens > available || diagnostics.some((diagnostic) => diagnostic.reason === \"invalid_budget\"),\n\t\tomittedHighPriority,\n\t\ttierAllocations,\n\t\tselectedRepresentations: [...selection.values()].sort((a, b) => a.itemId.localeCompare(b.itemId)),\n\t\tincludedItemIds: basePlanned\n\t\t\t.map((planned) => planned.item.id)\n\t\t\t.filter((id) => selection.has(id))\n\t\t\t.sort(),\n\t\tomittedItemIds,\n\t\tdiagnostics,\n\t\tretrievalFallbacks,\n\t\tobservability,\n\t};\n\tif (canUsePlanCache) {\n\t\twritePlanCacheV2({\n\t\t\tcache,\n\t\t\tkey: planCacheKey,\n\t\t\tplan,\n\t\t\tplanned: basePlanned,\n\t\t});\n\t}\n\treturn plan;\n}\n\nfunction normalizeBudgetTokens(field: string, value: number, diagnostics: QualityDiagnosticV2[]): number {\n\tif (!Number.isFinite(value) || value < 0) {\n\t\tdiagnostics.push({\n\t\t\treason: \"invalid_budget\",\n\t\t\tdetail: `${field} must be a non-negative finite number, got ${value}`,\n\t\t});\n\t\treturn 0;\n\t}\n\treturn Math.floor(value);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"context-budget-v2-planner.d.ts","sourceRoot":"","sources":["../../src/core/context-budget-v2-planner.ts"],"names":[],"mappings":"AA+BA,OAAO,EAIN,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAI9B,MAAM,8BAA8B,CAAC;AAEtC,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,0BAA0B,GAAG,yBAAyB,CAkOtG","sourcesContent":["import {\n\ttype ContextBudgetItemV2,\n\ttype ContextBudgetTierV2,\n\ttype ContextRepresentationCandidateV2,\n\ttype ContextSourceRefV2,\n\tDEFAULT_HEADROOM_QUALITY_POLICY,\n} from \"./context-budget-headroom.ts\";\nimport {\n\tbuildContextBudgetPlanCacheKeyV2,\n\tcreateContextBudgetCacheKeyBaseV2,\n\tcreateContextBudgetSelectionCacheV2,\n\tfinalizeContextBudgetCacheTelemetryV2,\n\treadValidPlanCacheV2,\n\twritePlanCacheV2,\n} from \"./context-budget-v2-cache.ts\";\nimport { runGlobalSelectionPass } from \"./context-budget-v2-global-pass.ts\";\nimport { validateBudgetItems } from \"./context-budget-v2-input-validation.ts\";\nimport { buildObservability } from \"./context-budget-v2-observability.ts\";\nimport { computePlanHash } from \"./context-budget-v2-plan-hash.ts\";\nimport { createPlannedItems, resolveEffectiveTokenizerIdV2 } from \"./context-budget-v2-planned-items.ts\";\nimport { compareOptionalForSelection } from \"./context-budget-v2-scoring.ts\";\nimport {\n\tapplyPlannerRedundancyPenalties,\n\tbuildTierAllocations,\n\tcreateTierUsage,\n\temitCoverageDiagnostics,\n\temitOmissionDiagnostics,\n\tselectHardItem,\n\tselectOptionalItem,\n} from \"./context-budget-v2-selection.ts\";\nimport { allocateTiers, computeTierDemand } from \"./context-budget-v2-tiers.ts\";\nimport {\n\tALL_TIERS_V2,\n\tCONTEXT_BUDGET_POLICY_VERSION_V2,\n\tDEFAULT_TIER_POLICY_V2,\n\ttype PromptContextBudgetInputV2,\n\ttype PromptContextBudgetPlanV2,\n\ttype QualityDiagnosticV2,\n\ttype SelectedRepresentationV2,\n\ttype TierBudgetPolicyV2,\n} from \"./context-budget-v2-types.ts\";\n\nexport function planPromptContextBudgetV2(input: PromptContextBudgetInputV2): PromptContextBudgetPlanV2 {\n\tconst modelId = input.modelId ?? \"unknown\";\n\tconst qualityPolicy = input.qualityPolicy ?? DEFAULT_HEADROOM_QUALITY_POLICY;\n\tconst policyVersion = input.policyVersion ?? CONTEXT_BUDGET_POLICY_VERSION_V2;\n\tconst diagnostics: QualityDiagnosticV2[] = [];\n\n\tconst maxTokens = normalizeBudgetTokens(\"maxTokens\", input.maxTokens, diagnostics);\n\tconst responseReserve = normalizeBudgetTokens(\n\t\t\"responseReserveTokens\",\n\t\tinput.responseReserveTokens ?? 0,\n\t\tdiagnostics,\n\t);\n\tconst safetyMargin = normalizeBudgetTokens(\n\t\t\"safetyMarginTokens\",\n\t\tinput.safetyMarginTokens ?? Math.ceil(maxTokens * 0.05),\n\t\tdiagnostics,\n\t);\n\tconst available = Math.max(0, maxTokens - responseReserve - safetyMargin);\n\n\tconst tierPolicy: Readonly<Record<ContextBudgetTierV2, TierBudgetPolicyV2>> = {\n\t\t...DEFAULT_TIER_POLICY_V2,\n\t\t...(input.tierPolicy ?? {}),\n\t};\n\tconst basePlanned = createPlannedItems(\n\t\tvalidateBudgetItems(input.items, diagnostics),\n\t\tinput.tokenCounter,\n\t\tmodelId,\n\t\tqualityPolicy,\n\t);\n\t// Sanitized items can share a key with valid input, but their diagnostics cannot.\n\tconst canUsePlanCache = diagnostics.length === 0;\n\tapplyPlannerRedundancyPenalties(basePlanned);\n\tconst rawTokens = basePlanned.reduce((sum, planned) => sum + planned.fullTokens, 0);\n\n\tconst demand = computeTierDemand(basePlanned);\n\tconst allocation = allocateTiers(available, tierPolicy, demand);\n\tconst cacheKeyBase = createContextBudgetCacheKeyBaseV2({\n\t\tbudgetBucket: input.cacheBudgetBucket ?? String(available),\n\t\tcacheInvalidationSnapshot: input.cacheInvalidationSnapshot ?? input.cacheProvider?.getInvalidationSnapshot?.(),\n\t\tmodelId,\n\t\tnamespace: input.cacheNamespace,\n\t\tpolicyVersion,\n\t\tselectionPolicyVersion: input.selectionPolicyVersion,\n\t\tquery: input.query,\n\t\tqueryIntentHash: input.queryIntentHash,\n\t\tredactionPolicyHash: input.redactionPolicyHash,\n\t\tsafetyProfileHash: input.safetyProfileHash,\n\t\ttokenizerId: input.tokenizerId ?? resolveEffectiveTokenizerIdV2(input.tokenCounter, modelId),\n\t});\n\tconst planCacheKey = buildContextBudgetPlanCacheKeyV2({\n\t\tavailableTokens: available,\n\t\tkeyBase: cacheKeyBase,\n\t\tmaxTokens,\n\t\tplanned: basePlanned,\n\t\tpromptHash: input.promptHash,\n\t\tqualityPolicy,\n\t\tresponseReserveTokens: responseReserve,\n\t\tsafetyMarginTokens: safetyMargin,\n\t\ttierPolicy,\n\t});\n\tconst cache = createContextBudgetSelectionCacheV2({\n\t\tkeyBase: cacheKeyBase,\n\t\tnowEpochMs: input.cacheNowEpochMs,\n\t\tplanCacheKey,\n\t\tprovider: input.cacheProvider,\n\t\tttlMs: input.cacheTtlMs,\n\t});\n\tconst cachedPlan = canUsePlanCache\n\t\t? readValidPlanCacheV2({\n\t\t\t\tavailableTokens: available,\n\t\t\t\tcache,\n\t\t\t\tkey: planCacheKey,\n\t\t\t\tplanned: basePlanned,\n\t\t\t})\n\t\t: undefined;\n\tif (cachedPlan) {\n\t\treturn cachedPlan;\n\t}\n\tconst selection = new Map<string, SelectedRepresentationV2>();\n\tconst tierUsed = createTierUsage();\n\tconst omitted: ContextBudgetItemV2[] = [];\n\tconst retrievalFallbacks: ContextSourceRefV2[] = [];\n\tlet usedTokens = 0;\n\n\tfor (const planned of basePlanned) {\n\t\tif (!planned.isHard) continue;\n\t\tusedTokens += selectHardItem(planned, selection, tierUsed);\n\t}\n\tif (usedTokens > available) {\n\t\tdiagnostics.push({\n\t\t\treason: \"hard_pin_over_capacity\",\n\t\t\tdetail: `hard-pinned context uses ${usedTokens} tokens against ${available} available tokens`,\n\t\t});\n\t}\n\n\tconst optionalPlanned = basePlanned.filter((planned) => !planned.isHard).sort(compareOptionalForSelection);\n\n\t// Floor-reservation pass: each tier spends its guaranteed claim (the\n\t// `allocated` field — hard demand, else demand capped at the floor) on its\n\t// own optional items before anything competes globally. A tier's floor is\n\t// therefore a real reservation, not a lower bound on its ceiling. Items\n\t// that cannot fit inside the remaining floor stay unselected for the\n\t// global pass; when the summed floors exceed the budget the reservation is\n\t// best-effort in tier order and the plan reports it explicitly.\n\t// One cache-resolution per item, shared by both passes so an item that is\n\t// deferred out of the floor and reconsidered globally does not double\n\t// count provider reads or redo materialization work.\n\tconst resolvedCandidates = new Map<string, readonly ContextRepresentationCandidateV2[]>();\n\tlet totalFloor = 0;\n\tfor (const tier of ALL_TIERS_V2) {\n\t\ttotalFloor += allocation.get(tier)?.floor ?? 0;\n\t}\n\tif (totalFloor > available) {\n\t\tdiagnostics.push({\n\t\t\treason: \"tier_floor_over_budget\",\n\t\t\tdetail: `tier floor guarantees total ${totalFloor} tokens against ${available} available; floors degrade to tier-order best effort`,\n\t\t});\n\t}\n\tfor (const tier of ALL_TIERS_V2) {\n\t\tconst floor = allocation.get(tier)?.floor ?? 0;\n\t\tif (floor <= 0 || tierUsed[tier] >= floor) continue;\n\t\tfor (const planned of optionalPlanned) {\n\t\t\tif (planned.item.tier !== tier || selection.has(planned.item.id)) continue;\n\t\t\tusedTokens = selectOptionalItem(planned, {\n\t\t\t\tallocation,\n\t\t\t\tavailable,\n\t\t\t\tcache,\n\t\t\t\tdiagnostics,\n\t\t\t\tomitted,\n\t\t\t\tqualityPolicy,\n\t\t\t\tretrievalFallbacks,\n\t\t\t\tselection,\n\t\t\t\ttierUsed,\n\t\t\t\tusedTokens,\n\t\t\t\tfloorReservation: { tier, floorTokens: floor },\n\t\t\t\tresolvedCandidates,\n\t\t\t});\n\t\t\tif (tierUsed[tier] >= floor || usedTokens >= available) break;\n\t\t}\n\t}\n\n\t// Global pass under tier ceilings, then promotion of floor-admitted items\n\t// with whatever the global pass left unused (audit F03).\n\tusedTokens = runGlobalSelectionPass(optionalPlanned, {\n\t\tallocation,\n\t\tavailable,\n\t\tcache,\n\t\tdiagnostics,\n\t\tomitted,\n\t\tqualityPolicy,\n\t\tresolvedCandidates,\n\t\tretrievalFallbacks,\n\t\tselection,\n\t\ttierUsed,\n\t\tusedTokens,\n\t});\n\n\tconst omittedHighPriority = omitted.some((item) => item.priority === \"high\" || item.required === true);\n\temitOmissionDiagnostics(omitted, diagnostics, retrievalFallbacks);\n\temitCoverageDiagnostics(input.query, selection, diagnostics);\n\n\tconst tierAllocations = buildTierAllocations(allocation, demand, tierUsed);\n\tconst omittedTokens = omitted.reduce(\n\t\t(sum, item) => sum + (basePlanned.find((planned) => planned.item.id === item.id)?.fullTokens ?? 0),\n\t\t0,\n\t);\n\tconst omittedItemIds = omitted.map((item) => item.id);\n\tconst planHash = computePlanHash({\n\t\tpolicyVersion,\n\t\tpromptHash: input.promptHash,\n\t\tplanned: basePlanned,\n\t\tselection,\n\t\tallocations: tierAllocations,\n\t\tomittedItemIds,\n\t});\n\tconst observability = buildObservability({\n\t\tavailable,\n\t\tdiagnostics,\n\t\tomittedItemIds,\n\t\tomittedTokens,\n\t\tplanHash,\n\t\trawTokens,\n\t\tretrievalFallbacks,\n\t\tselection,\n\t\tusedTokens,\n\t\tcacheTelemetry: finalizeContextBudgetCacheTelemetryV2(cache.telemetry, {\n\t\t\tomittedTokens,\n\t\t\trawTokens,\n\t\t\tusedTokens,\n\t\t}),\n\t});\n\n\tconst plan: PromptContextBudgetPlanV2 = {\n\t\tpolicyVersion,\n\t\tpromptHash: input.promptHash,\n\t\tplanHash,\n\t\tmaxTokens,\n\t\tresponseReserveTokens: responseReserve,\n\t\tsafetyMarginTokens: safetyMargin,\n\t\tavailableTokens: available,\n\t\tusedTokens,\n\t\tomittedTokens,\n\t\trawTokens,\n\t\ttokenSavingsRatio: rawTokens > 0 ? Math.max(0, 1 - usedTokens / rawTokens) : 0,\n\t\temergency: usedTokens > available || diagnostics.some((diagnostic) => diagnostic.reason === \"invalid_budget\"),\n\t\tomittedHighPriority,\n\t\ttierAllocations,\n\t\tselectedRepresentations: [...selection.values()].sort((a, b) => a.itemId.localeCompare(b.itemId)),\n\t\tincludedItemIds: basePlanned\n\t\t\t.map((planned) => planned.item.id)\n\t\t\t.filter((id) => selection.has(id))\n\t\t\t.sort(),\n\t\tomittedItemIds,\n\t\tdiagnostics,\n\t\tretrievalFallbacks,\n\t\tobservability,\n\t};\n\tif (canUsePlanCache) {\n\t\twritePlanCacheV2({\n\t\t\tcache,\n\t\t\tkey: planCacheKey,\n\t\t\tplan,\n\t\t\tplanned: basePlanned,\n\t\t});\n\t}\n\treturn plan;\n}\n\nfunction normalizeBudgetTokens(field: string, value: number, diagnostics: QualityDiagnosticV2[]): number {\n\tif (!Number.isFinite(value) || value < 0) {\n\t\tdiagnostics.push({\n\t\t\treason: \"invalid_budget\",\n\t\t\tdetail: `${field} must be a non-negative finite number, got ${value}`,\n\t\t});\n\t\treturn 0;\n\t}\n\treturn Math.floor(value);\n}\n"]}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { DEFAULT_HEADROOM_QUALITY_POLICY, } from "./context-budget-headroom.js";
|
|
2
2
|
import { buildContextBudgetPlanCacheKeyV2, createContextBudgetCacheKeyBaseV2, createContextBudgetSelectionCacheV2, finalizeContextBudgetCacheTelemetryV2, readValidPlanCacheV2, writePlanCacheV2, } from "./context-budget-v2-cache.js";
|
|
3
|
+
import { runGlobalSelectionPass } from "./context-budget-v2-global-pass.js";
|
|
3
4
|
import { validateBudgetItems } from "./context-budget-v2-input-validation.js";
|
|
4
5
|
import { buildObservability } from "./context-budget-v2-observability.js";
|
|
5
6
|
import { computePlanHash } from "./context-budget-v2-plan-hash.js";
|
|
6
|
-
import { createPlannedItems } from "./context-budget-v2-planned-items.js";
|
|
7
|
+
import { createPlannedItems, resolveEffectiveTokenizerIdV2 } from "./context-budget-v2-planned-items.js";
|
|
7
8
|
import { compareOptionalForSelection } from "./context-budget-v2-scoring.js";
|
|
8
9
|
import { applyPlannerRedundancyPenalties, buildTierAllocations, createTierUsage, emitCoverageDiagnostics, emitOmissionDiagnostics, selectHardItem, selectOptionalItem, } from "./context-budget-v2-selection.js";
|
|
9
10
|
import { allocateTiers, computeTierDemand } from "./context-budget-v2-tiers.js";
|
|
@@ -39,7 +40,7 @@ export function planPromptContextBudgetV2(input) {
|
|
|
39
40
|
queryIntentHash: input.queryIntentHash,
|
|
40
41
|
redactionPolicyHash: input.redactionPolicyHash,
|
|
41
42
|
safetyProfileHash: input.safetyProfileHash,
|
|
42
|
-
tokenizerId: input.tokenizerId,
|
|
43
|
+
tokenizerId: input.tokenizerId ?? resolveEffectiveTokenizerIdV2(input.tokenCounter, modelId),
|
|
43
44
|
});
|
|
44
45
|
const planCacheKey = buildContextBudgetPlanCacheKeyV2({
|
|
45
46
|
availableTokens: available,
|
|
@@ -133,23 +134,21 @@ export function planPromptContextBudgetV2(input) {
|
|
|
133
134
|
break;
|
|
134
135
|
}
|
|
135
136
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
});
|
|
152
|
-
}
|
|
137
|
+
// Global pass under tier ceilings, then promotion of floor-admitted items
|
|
138
|
+
// with whatever the global pass left unused (audit F03).
|
|
139
|
+
usedTokens = runGlobalSelectionPass(optionalPlanned, {
|
|
140
|
+
allocation,
|
|
141
|
+
available,
|
|
142
|
+
cache,
|
|
143
|
+
diagnostics,
|
|
144
|
+
omitted,
|
|
145
|
+
qualityPolicy,
|
|
146
|
+
resolvedCandidates,
|
|
147
|
+
retrievalFallbacks,
|
|
148
|
+
selection,
|
|
149
|
+
tierUsed,
|
|
150
|
+
usedTokens,
|
|
151
|
+
});
|
|
153
152
|
const omittedHighPriority = omitted.some((item) => item.priority === "high" || item.required === true);
|
|
154
153
|
emitOmissionDiagnostics(omitted, diagnostics, retrievalFallbacks);
|
|
155
154
|
emitCoverageDiagnostics(input.query, selection, diagnostics);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-budget-v2-planner.js","sourceRoot":"","sources":["../../src/core/context-budget-v2-planner.ts"],"names":[],"mappings":"AAAA,OAAO,EAKN,+BAA+B,GAC/B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACN,gCAAgC,EAChC,iCAAiC,EACjC,mCAAmC,EACnC,qCAAqC,EACrC,oBAAoB,EACpB,gBAAgB,GAChB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAC9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,EACN,+BAA+B,EAC/B,oBAAoB,EACpB,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,cAAc,EACd,kBAAkB,GAClB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,EACN,YAAY,EACZ,gCAAgC,EAChC,sBAAsB,GAMtB,MAAM,8BAA8B,CAAC;AAEtC,MAAM,UAAU,yBAAyB,CAAC,KAAiC,EAA6B;IACvG,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,SAAS,CAAC;IAC3C,MAAM,aAAa,GAAG,KAAK,CAAC,aAAa,IAAI,+BAA+B,CAAC;IAC7E,MAAM,aAAa,GAAG,KAAK,CAAC,aAAa,IAAI,gCAAgC,CAAC;IAC9E,MAAM,WAAW,GAA0B,EAAE,CAAC;IAE9C,MAAM,SAAS,GAAG,qBAAqB,CAAC,WAAW,EAAE,KAAK,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IACnF,MAAM,eAAe,GAAG,qBAAqB,CAC5C,uBAAuB,EACvB,KAAK,CAAC,qBAAqB,IAAI,CAAC,EAChC,WAAW,CACX,CAAC;IACF,MAAM,YAAY,GAAG,qBAAqB,CACzC,oBAAoB,EACpB,KAAK,CAAC,kBAAkB,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,EACvD,WAAW,CACX,CAAC;IACF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,eAAe,GAAG,YAAY,CAAC,CAAC;IAE1E,MAAM,UAAU,GAA8D;QAC7E,GAAG,sBAAsB;QACzB,GAAG,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC;KAC3B,CAAC;IACF,MAAM,WAAW,GAAG,kBAAkB,CACrC,mBAAmB,CAAC,KAAK,CAAC,KAAK,EAAE,WAAW,CAAC,EAC7C,KAAK,CAAC,YAAY,EAClB,OAAO,EACP,aAAa,CACb,CAAC;IACF,kFAAkF;IAClF,MAAM,eAAe,GAAG,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC;IACjD,+BAA+B,CAAC,WAAW,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAEpF,MAAM,MAAM,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,aAAa,CAAC,SAAS,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;IAChE,MAAM,YAAY,GAAG,iCAAiC,CAAC;QACtD,YAAY,EAAE,KAAK,CAAC,iBAAiB,IAAI,MAAM,CAAC,SAAS,CAAC;QAC1D,yBAAyB,EAAE,KAAK,CAAC,yBAAyB,IAAI,KAAK,CAAC,aAAa,EAAE,uBAAuB,EAAE,EAAE;QAC9G,OAAO;QACP,SAAS,EAAE,KAAK,CAAC,cAAc;QAC/B,aAAa;QACb,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;QACpD,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,eAAe,EAAE,KAAK,CAAC,eAAe;QACtC,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;QAC9C,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;QAC1C,WAAW,EAAE,KAAK,CAAC,WAAW;KAC9B,CAAC,CAAC;IACH,MAAM,YAAY,GAAG,gCAAgC,CAAC;QACrD,eAAe,EAAE,SAAS;QAC1B,OAAO,EAAE,YAAY;QACrB,SAAS;QACT,OAAO,EAAE,WAAW;QACpB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,aAAa;QACb,qBAAqB,EAAE,eAAe;QACtC,kBAAkB,EAAE,YAAY;QAChC,UAAU;KACV,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,mCAAmC,CAAC;QACjD,OAAO,EAAE,YAAY;QACrB,UAAU,EAAE,KAAK,CAAC,eAAe;QACjC,YAAY;QACZ,QAAQ,EAAE,KAAK,CAAC,aAAa;QAC7B,KAAK,EAAE,KAAK,CAAC,UAAU;KACvB,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,eAAe;QACjC,CAAC,CAAC,oBAAoB,CAAC;YACrB,eAAe,EAAE,SAAS;YAC1B,KAAK;YACL,GAAG,EAAE,YAAY;YACjB,OAAO,EAAE,WAAW;SACpB,CAAC;QACH,CAAC,CAAC,SAAS,CAAC;IACb,IAAI,UAAU,EAAE,CAAC;QAChB,OAAO,UAAU,CAAC;IACnB,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoC,CAAC;IAC9D,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,MAAM,OAAO,GAA0B,EAAE,CAAC;IAC1C,MAAM,kBAAkB,GAAyB,EAAE,CAAC;IACpD,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,KAAK,MAAM,OAAO,IAAI,WAAW,EAAE,CAAC;QACnC,IAAI,CAAC,OAAO,CAAC,MAAM;YAAE,SAAS;QAC9B,UAAU,IAAI,cAAc,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,UAAU,GAAG,SAAS,EAAE,CAAC;QAC5B,WAAW,CAAC,IAAI,CAAC;YAChB,MAAM,EAAE,wBAAwB;YAChC,MAAM,EAAE,4BAA4B,UAAU,mBAAmB,SAAS,mBAAmB;SAC7F,CAAC,CAAC;IACJ,CAAC;IAED,MAAM,eAAe,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IAE3G,qEAAqE;IACrE,6EAA2E;IAC3E,0EAA0E;IAC1E,wEAAwE;IACxE,qEAAqE;IACrE,2EAA2E;IAC3E,gEAAgE;IAChE,0EAA0E;IAC1E,sEAAsE;IACtE,qDAAqD;IACrD,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAuD,CAAC;IAC1F,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QACjC,UAAU,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,UAAU,GAAG,SAAS,EAAE,CAAC;QAC5B,WAAW,CAAC,IAAI,CAAC;YAChB,MAAM,EAAE,wBAAwB;YAChC,MAAM,EAAE,+BAA+B,UAAU,mBAAmB,SAAS,sDAAsD;SACnI,CAAC,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;QAC/C,IAAI,KAAK,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK;YAAE,SAAS;QACpD,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;YACvC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBAAE,SAAS;YAC3E,UAAU,GAAG,kBAAkB,CAAC,OAAO,EAAE;gBACxC,UAAU;gBACV,SAAS;gBACT,KAAK;gBACL,WAAW;gBACX,OAAO;gBACP,aAAa;gBACb,kBAAkB;gBAClB,SAAS;gBACT,QAAQ;gBACR,UAAU;gBACV,gBAAgB,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE;gBAC9C,kBAAkB;aAClB,CAAC,CAAC;YACH,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,UAAU,IAAI,SAAS;gBAAE,MAAM;QAC/D,CAAC;IACF,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;QACvC,IAAI,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,SAAS;QAC7C,UAAU,GAAG,kBAAkB,CAAC,OAAO,EAAE;YACxC,UAAU;YACV,SAAS;YACT,KAAK;YACL,WAAW;YACX,OAAO;YACP,aAAa;YACb,kBAAkB;YAClB,kBAAkB;YAClB,SAAS;YACT,QAAQ;YACR,UAAU;SACV,CAAC,CAAC;IACJ,CAAC;IAED,MAAM,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,MAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC;IACvG,uBAAuB,CAAC,OAAO,EAAE,WAAW,EAAE,kBAAkB,CAAC,CAAC;IAClE,uBAAuB,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IAE7D,MAAM,eAAe,GAAG,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC3E,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CACnC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,EAAE,UAAU,IAAI,CAAC,CAAC,EAClG,CAAC,CACD,CAAC;IACF,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,eAAe,CAAC;QAChC,aAAa;QACb,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,OAAO,EAAE,WAAW;QACpB,SAAS;QACT,WAAW,EAAE,eAAe;QAC5B,cAAc;KACd,CAAC,CAAC;IACH,MAAM,aAAa,GAAG,kBAAkB,CAAC;QACxC,SAAS;QACT,WAAW;QACX,cAAc;QACd,aAAa;QACb,QAAQ;QACR,SAAS;QACT,kBAAkB;QAClB,SAAS;QACT,UAAU;QACV,cAAc,EAAE,qCAAqC,CAAC,KAAK,CAAC,SAAS,EAAE;YACtE,aAAa;YACb,SAAS;YACT,UAAU;SACV,CAAC;KACF,CAAC,CAAC;IAEH,MAAM,IAAI,GAA8B;QACvC,aAAa;QACb,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,QAAQ;QACR,SAAS;QACT,qBAAqB,EAAE,eAAe;QACtC,kBAAkB,EAAE,YAAY;QAChC,eAAe,EAAE,SAAS;QAC1B,UAAU;QACV,aAAa;QACb,SAAS;QACT,iBAAiB,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9E,SAAS,EAAE,UAAU,GAAG,SAAS,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,KAAK,gBAAgB,CAAC;QAC7G,mBAAmB;QACnB,eAAe;QACf,uBAAuB,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACjG,eAAe,EAAE,WAAW;aAC1B,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;aACjC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;aACjC,IAAI,EAAE;QACR,cAAc;QACd,WAAW;QACX,kBAAkB;QAClB,aAAa;KACb,CAAC;IACF,IAAI,eAAe,EAAE,CAAC;QACrB,gBAAgB,CAAC;YAChB,KAAK;YACL,GAAG,EAAE,YAAY;YACjB,IAAI;YACJ,OAAO,EAAE,WAAW;SACpB,CAAC,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACZ;AAED,SAAS,qBAAqB,CAAC,KAAa,EAAE,KAAa,EAAE,WAAkC,EAAU;IACxG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC1C,WAAW,CAAC,IAAI,CAAC;YAChB,MAAM,EAAE,gBAAgB;YACxB,MAAM,EAAE,GAAG,KAAK,8CAA8C,KAAK,EAAE;SACrE,CAAC,CAAC;QACH,OAAO,CAAC,CAAC;IACV,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAAA,CACzB","sourcesContent":["import {\n\ttype ContextBudgetItemV2,\n\ttype ContextBudgetTierV2,\n\ttype ContextRepresentationCandidateV2,\n\ttype ContextSourceRefV2,\n\tDEFAULT_HEADROOM_QUALITY_POLICY,\n} from \"./context-budget-headroom.ts\";\nimport {\n\tbuildContextBudgetPlanCacheKeyV2,\n\tcreateContextBudgetCacheKeyBaseV2,\n\tcreateContextBudgetSelectionCacheV2,\n\tfinalizeContextBudgetCacheTelemetryV2,\n\treadValidPlanCacheV2,\n\twritePlanCacheV2,\n} from \"./context-budget-v2-cache.ts\";\nimport { validateBudgetItems } from \"./context-budget-v2-input-validation.ts\";\nimport { buildObservability } from \"./context-budget-v2-observability.ts\";\nimport { computePlanHash } from \"./context-budget-v2-plan-hash.ts\";\nimport { createPlannedItems } from \"./context-budget-v2-planned-items.ts\";\nimport { compareOptionalForSelection } from \"./context-budget-v2-scoring.ts\";\nimport {\n\tapplyPlannerRedundancyPenalties,\n\tbuildTierAllocations,\n\tcreateTierUsage,\n\temitCoverageDiagnostics,\n\temitOmissionDiagnostics,\n\tselectHardItem,\n\tselectOptionalItem,\n} from \"./context-budget-v2-selection.ts\";\nimport { allocateTiers, computeTierDemand } from \"./context-budget-v2-tiers.ts\";\nimport {\n\tALL_TIERS_V2,\n\tCONTEXT_BUDGET_POLICY_VERSION_V2,\n\tDEFAULT_TIER_POLICY_V2,\n\ttype PromptContextBudgetInputV2,\n\ttype PromptContextBudgetPlanV2,\n\ttype QualityDiagnosticV2,\n\ttype SelectedRepresentationV2,\n\ttype TierBudgetPolicyV2,\n} from \"./context-budget-v2-types.ts\";\n\nexport function planPromptContextBudgetV2(input: PromptContextBudgetInputV2): PromptContextBudgetPlanV2 {\n\tconst modelId = input.modelId ?? \"unknown\";\n\tconst qualityPolicy = input.qualityPolicy ?? DEFAULT_HEADROOM_QUALITY_POLICY;\n\tconst policyVersion = input.policyVersion ?? CONTEXT_BUDGET_POLICY_VERSION_V2;\n\tconst diagnostics: QualityDiagnosticV2[] = [];\n\n\tconst maxTokens = normalizeBudgetTokens(\"maxTokens\", input.maxTokens, diagnostics);\n\tconst responseReserve = normalizeBudgetTokens(\n\t\t\"responseReserveTokens\",\n\t\tinput.responseReserveTokens ?? 0,\n\t\tdiagnostics,\n\t);\n\tconst safetyMargin = normalizeBudgetTokens(\n\t\t\"safetyMarginTokens\",\n\t\tinput.safetyMarginTokens ?? Math.ceil(maxTokens * 0.05),\n\t\tdiagnostics,\n\t);\n\tconst available = Math.max(0, maxTokens - responseReserve - safetyMargin);\n\n\tconst tierPolicy: Readonly<Record<ContextBudgetTierV2, TierBudgetPolicyV2>> = {\n\t\t...DEFAULT_TIER_POLICY_V2,\n\t\t...(input.tierPolicy ?? {}),\n\t};\n\tconst basePlanned = createPlannedItems(\n\t\tvalidateBudgetItems(input.items, diagnostics),\n\t\tinput.tokenCounter,\n\t\tmodelId,\n\t\tqualityPolicy,\n\t);\n\t// Sanitized items can share a key with valid input, but their diagnostics cannot.\n\tconst canUsePlanCache = diagnostics.length === 0;\n\tapplyPlannerRedundancyPenalties(basePlanned);\n\tconst rawTokens = basePlanned.reduce((sum, planned) => sum + planned.fullTokens, 0);\n\n\tconst demand = computeTierDemand(basePlanned);\n\tconst allocation = allocateTiers(available, tierPolicy, demand);\n\tconst cacheKeyBase = createContextBudgetCacheKeyBaseV2({\n\t\tbudgetBucket: input.cacheBudgetBucket ?? String(available),\n\t\tcacheInvalidationSnapshot: input.cacheInvalidationSnapshot ?? input.cacheProvider?.getInvalidationSnapshot?.(),\n\t\tmodelId,\n\t\tnamespace: input.cacheNamespace,\n\t\tpolicyVersion,\n\t\tselectionPolicyVersion: input.selectionPolicyVersion,\n\t\tquery: input.query,\n\t\tqueryIntentHash: input.queryIntentHash,\n\t\tredactionPolicyHash: input.redactionPolicyHash,\n\t\tsafetyProfileHash: input.safetyProfileHash,\n\t\ttokenizerId: input.tokenizerId,\n\t});\n\tconst planCacheKey = buildContextBudgetPlanCacheKeyV2({\n\t\tavailableTokens: available,\n\t\tkeyBase: cacheKeyBase,\n\t\tmaxTokens,\n\t\tplanned: basePlanned,\n\t\tpromptHash: input.promptHash,\n\t\tqualityPolicy,\n\t\tresponseReserveTokens: responseReserve,\n\t\tsafetyMarginTokens: safetyMargin,\n\t\ttierPolicy,\n\t});\n\tconst cache = createContextBudgetSelectionCacheV2({\n\t\tkeyBase: cacheKeyBase,\n\t\tnowEpochMs: input.cacheNowEpochMs,\n\t\tplanCacheKey,\n\t\tprovider: input.cacheProvider,\n\t\tttlMs: input.cacheTtlMs,\n\t});\n\tconst cachedPlan = canUsePlanCache\n\t\t? readValidPlanCacheV2({\n\t\t\t\tavailableTokens: available,\n\t\t\t\tcache,\n\t\t\t\tkey: planCacheKey,\n\t\t\t\tplanned: basePlanned,\n\t\t\t})\n\t\t: undefined;\n\tif (cachedPlan) {\n\t\treturn cachedPlan;\n\t}\n\tconst selection = new Map<string, SelectedRepresentationV2>();\n\tconst tierUsed = createTierUsage();\n\tconst omitted: ContextBudgetItemV2[] = [];\n\tconst retrievalFallbacks: ContextSourceRefV2[] = [];\n\tlet usedTokens = 0;\n\n\tfor (const planned of basePlanned) {\n\t\tif (!planned.isHard) continue;\n\t\tusedTokens += selectHardItem(planned, selection, tierUsed);\n\t}\n\tif (usedTokens > available) {\n\t\tdiagnostics.push({\n\t\t\treason: \"hard_pin_over_capacity\",\n\t\t\tdetail: `hard-pinned context uses ${usedTokens} tokens against ${available} available tokens`,\n\t\t});\n\t}\n\n\tconst optionalPlanned = basePlanned.filter((planned) => !planned.isHard).sort(compareOptionalForSelection);\n\n\t// Floor-reservation pass: each tier spends its guaranteed claim (the\n\t// `allocated` field — hard demand, else demand capped at the floor) on its\n\t// own optional items before anything competes globally. A tier's floor is\n\t// therefore a real reservation, not a lower bound on its ceiling. Items\n\t// that cannot fit inside the remaining floor stay unselected for the\n\t// global pass; when the summed floors exceed the budget the reservation is\n\t// best-effort in tier order and the plan reports it explicitly.\n\t// One cache-resolution per item, shared by both passes so an item that is\n\t// deferred out of the floor and reconsidered globally does not double\n\t// count provider reads or redo materialization work.\n\tconst resolvedCandidates = new Map<string, readonly ContextRepresentationCandidateV2[]>();\n\tlet totalFloor = 0;\n\tfor (const tier of ALL_TIERS_V2) {\n\t\ttotalFloor += allocation.get(tier)?.floor ?? 0;\n\t}\n\tif (totalFloor > available) {\n\t\tdiagnostics.push({\n\t\t\treason: \"tier_floor_over_budget\",\n\t\t\tdetail: `tier floor guarantees total ${totalFloor} tokens against ${available} available; floors degrade to tier-order best effort`,\n\t\t});\n\t}\n\tfor (const tier of ALL_TIERS_V2) {\n\t\tconst floor = allocation.get(tier)?.floor ?? 0;\n\t\tif (floor <= 0 || tierUsed[tier] >= floor) continue;\n\t\tfor (const planned of optionalPlanned) {\n\t\t\tif (planned.item.tier !== tier || selection.has(planned.item.id)) continue;\n\t\t\tusedTokens = selectOptionalItem(planned, {\n\t\t\t\tallocation,\n\t\t\t\tavailable,\n\t\t\t\tcache,\n\t\t\t\tdiagnostics,\n\t\t\t\tomitted,\n\t\t\t\tqualityPolicy,\n\t\t\t\tretrievalFallbacks,\n\t\t\t\tselection,\n\t\t\t\ttierUsed,\n\t\t\t\tusedTokens,\n\t\t\t\tfloorReservation: { tier, floorTokens: floor },\n\t\t\t\tresolvedCandidates,\n\t\t\t});\n\t\t\tif (tierUsed[tier] >= floor || usedTokens >= available) break;\n\t\t}\n\t}\n\n\tfor (const planned of optionalPlanned) {\n\t\tif (selection.has(planned.item.id)) continue;\n\t\tusedTokens = selectOptionalItem(planned, {\n\t\t\tallocation,\n\t\t\tavailable,\n\t\t\tcache,\n\t\t\tdiagnostics,\n\t\t\tomitted,\n\t\t\tqualityPolicy,\n\t\t\tresolvedCandidates,\n\t\t\tretrievalFallbacks,\n\t\t\tselection,\n\t\t\ttierUsed,\n\t\t\tusedTokens,\n\t\t});\n\t}\n\n\tconst omittedHighPriority = omitted.some((item) => item.priority === \"high\" || item.required === true);\n\temitOmissionDiagnostics(omitted, diagnostics, retrievalFallbacks);\n\temitCoverageDiagnostics(input.query, selection, diagnostics);\n\n\tconst tierAllocations = buildTierAllocations(allocation, demand, tierUsed);\n\tconst omittedTokens = omitted.reduce(\n\t\t(sum, item) => sum + (basePlanned.find((planned) => planned.item.id === item.id)?.fullTokens ?? 0),\n\t\t0,\n\t);\n\tconst omittedItemIds = omitted.map((item) => item.id);\n\tconst planHash = computePlanHash({\n\t\tpolicyVersion,\n\t\tpromptHash: input.promptHash,\n\t\tplanned: basePlanned,\n\t\tselection,\n\t\tallocations: tierAllocations,\n\t\tomittedItemIds,\n\t});\n\tconst observability = buildObservability({\n\t\tavailable,\n\t\tdiagnostics,\n\t\tomittedItemIds,\n\t\tomittedTokens,\n\t\tplanHash,\n\t\trawTokens,\n\t\tretrievalFallbacks,\n\t\tselection,\n\t\tusedTokens,\n\t\tcacheTelemetry: finalizeContextBudgetCacheTelemetryV2(cache.telemetry, {\n\t\t\tomittedTokens,\n\t\t\trawTokens,\n\t\t\tusedTokens,\n\t\t}),\n\t});\n\n\tconst plan: PromptContextBudgetPlanV2 = {\n\t\tpolicyVersion,\n\t\tpromptHash: input.promptHash,\n\t\tplanHash,\n\t\tmaxTokens,\n\t\tresponseReserveTokens: responseReserve,\n\t\tsafetyMarginTokens: safetyMargin,\n\t\tavailableTokens: available,\n\t\tusedTokens,\n\t\tomittedTokens,\n\t\trawTokens,\n\t\ttokenSavingsRatio: rawTokens > 0 ? Math.max(0, 1 - usedTokens / rawTokens) : 0,\n\t\temergency: usedTokens > available || diagnostics.some((diagnostic) => diagnostic.reason === \"invalid_budget\"),\n\t\tomittedHighPriority,\n\t\ttierAllocations,\n\t\tselectedRepresentations: [...selection.values()].sort((a, b) => a.itemId.localeCompare(b.itemId)),\n\t\tincludedItemIds: basePlanned\n\t\t\t.map((planned) => planned.item.id)\n\t\t\t.filter((id) => selection.has(id))\n\t\t\t.sort(),\n\t\tomittedItemIds,\n\t\tdiagnostics,\n\t\tretrievalFallbacks,\n\t\tobservability,\n\t};\n\tif (canUsePlanCache) {\n\t\twritePlanCacheV2({\n\t\t\tcache,\n\t\t\tkey: planCacheKey,\n\t\t\tplan,\n\t\t\tplanned: basePlanned,\n\t\t});\n\t}\n\treturn plan;\n}\n\nfunction normalizeBudgetTokens(field: string, value: number, diagnostics: QualityDiagnosticV2[]): number {\n\tif (!Number.isFinite(value) || value < 0) {\n\t\tdiagnostics.push({\n\t\t\treason: \"invalid_budget\",\n\t\t\tdetail: `${field} must be a non-negative finite number, got ${value}`,\n\t\t});\n\t\treturn 0;\n\t}\n\treturn Math.floor(value);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"context-budget-v2-planner.js","sourceRoot":"","sources":["../../src/core/context-budget-v2-planner.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype ContextBudgetItemV2,\n\ttype ContextBudgetTierV2,\n\ttype ContextRepresentationCandidateV2,\n\ttype ContextSourceRefV2,\n\tDEFAULT_HEADROOM_QUALITY_POLICY,\n} from \"./context-budget-headroom.ts\";\nimport {\n\tbuildContextBudgetPlanCacheKeyV2,\n\tcreateContextBudgetCacheKeyBaseV2,\n\tcreateContextBudgetSelectionCacheV2,\n\tfinalizeContextBudgetCacheTelemetryV2,\n\treadValidPlanCacheV2,\n\twritePlanCacheV2,\n} from \"./context-budget-v2-cache.ts\";\nimport { runGlobalSelectionPass } from \"./context-budget-v2-global-pass.ts\";\nimport { validateBudgetItems } from \"./context-budget-v2-input-validation.ts\";\nimport { buildObservability } from \"./context-budget-v2-observability.ts\";\nimport { computePlanHash } from \"./context-budget-v2-plan-hash.ts\";\nimport { createPlannedItems, resolveEffectiveTokenizerIdV2 } from \"./context-budget-v2-planned-items.ts\";\nimport { compareOptionalForSelection } from \"./context-budget-v2-scoring.ts\";\nimport {\n\tapplyPlannerRedundancyPenalties,\n\tbuildTierAllocations,\n\tcreateTierUsage,\n\temitCoverageDiagnostics,\n\temitOmissionDiagnostics,\n\tselectHardItem,\n\tselectOptionalItem,\n} from \"./context-budget-v2-selection.ts\";\nimport { allocateTiers, computeTierDemand } from \"./context-budget-v2-tiers.ts\";\nimport {\n\tALL_TIERS_V2,\n\tCONTEXT_BUDGET_POLICY_VERSION_V2,\n\tDEFAULT_TIER_POLICY_V2,\n\ttype PromptContextBudgetInputV2,\n\ttype PromptContextBudgetPlanV2,\n\ttype QualityDiagnosticV2,\n\ttype SelectedRepresentationV2,\n\ttype TierBudgetPolicyV2,\n} from \"./context-budget-v2-types.ts\";\n\nexport function planPromptContextBudgetV2(input: PromptContextBudgetInputV2): PromptContextBudgetPlanV2 {\n\tconst modelId = input.modelId ?? \"unknown\";\n\tconst qualityPolicy = input.qualityPolicy ?? DEFAULT_HEADROOM_QUALITY_POLICY;\n\tconst policyVersion = input.policyVersion ?? CONTEXT_BUDGET_POLICY_VERSION_V2;\n\tconst diagnostics: QualityDiagnosticV2[] = [];\n\n\tconst maxTokens = normalizeBudgetTokens(\"maxTokens\", input.maxTokens, diagnostics);\n\tconst responseReserve = normalizeBudgetTokens(\n\t\t\"responseReserveTokens\",\n\t\tinput.responseReserveTokens ?? 0,\n\t\tdiagnostics,\n\t);\n\tconst safetyMargin = normalizeBudgetTokens(\n\t\t\"safetyMarginTokens\",\n\t\tinput.safetyMarginTokens ?? Math.ceil(maxTokens * 0.05),\n\t\tdiagnostics,\n\t);\n\tconst available = Math.max(0, maxTokens - responseReserve - safetyMargin);\n\n\tconst tierPolicy: Readonly<Record<ContextBudgetTierV2, TierBudgetPolicyV2>> = {\n\t\t...DEFAULT_TIER_POLICY_V2,\n\t\t...(input.tierPolicy ?? {}),\n\t};\n\tconst basePlanned = createPlannedItems(\n\t\tvalidateBudgetItems(input.items, diagnostics),\n\t\tinput.tokenCounter,\n\t\tmodelId,\n\t\tqualityPolicy,\n\t);\n\t// Sanitized items can share a key with valid input, but their diagnostics cannot.\n\tconst canUsePlanCache = diagnostics.length === 0;\n\tapplyPlannerRedundancyPenalties(basePlanned);\n\tconst rawTokens = basePlanned.reduce((sum, planned) => sum + planned.fullTokens, 0);\n\n\tconst demand = computeTierDemand(basePlanned);\n\tconst allocation = allocateTiers(available, tierPolicy, demand);\n\tconst cacheKeyBase = createContextBudgetCacheKeyBaseV2({\n\t\tbudgetBucket: input.cacheBudgetBucket ?? String(available),\n\t\tcacheInvalidationSnapshot: input.cacheInvalidationSnapshot ?? input.cacheProvider?.getInvalidationSnapshot?.(),\n\t\tmodelId,\n\t\tnamespace: input.cacheNamespace,\n\t\tpolicyVersion,\n\t\tselectionPolicyVersion: input.selectionPolicyVersion,\n\t\tquery: input.query,\n\t\tqueryIntentHash: input.queryIntentHash,\n\t\tredactionPolicyHash: input.redactionPolicyHash,\n\t\tsafetyProfileHash: input.safetyProfileHash,\n\t\ttokenizerId: input.tokenizerId ?? resolveEffectiveTokenizerIdV2(input.tokenCounter, modelId),\n\t});\n\tconst planCacheKey = buildContextBudgetPlanCacheKeyV2({\n\t\tavailableTokens: available,\n\t\tkeyBase: cacheKeyBase,\n\t\tmaxTokens,\n\t\tplanned: basePlanned,\n\t\tpromptHash: input.promptHash,\n\t\tqualityPolicy,\n\t\tresponseReserveTokens: responseReserve,\n\t\tsafetyMarginTokens: safetyMargin,\n\t\ttierPolicy,\n\t});\n\tconst cache = createContextBudgetSelectionCacheV2({\n\t\tkeyBase: cacheKeyBase,\n\t\tnowEpochMs: input.cacheNowEpochMs,\n\t\tplanCacheKey,\n\t\tprovider: input.cacheProvider,\n\t\tttlMs: input.cacheTtlMs,\n\t});\n\tconst cachedPlan = canUsePlanCache\n\t\t? readValidPlanCacheV2({\n\t\t\t\tavailableTokens: available,\n\t\t\t\tcache,\n\t\t\t\tkey: planCacheKey,\n\t\t\t\tplanned: basePlanned,\n\t\t\t})\n\t\t: undefined;\n\tif (cachedPlan) {\n\t\treturn cachedPlan;\n\t}\n\tconst selection = new Map<string, SelectedRepresentationV2>();\n\tconst tierUsed = createTierUsage();\n\tconst omitted: ContextBudgetItemV2[] = [];\n\tconst retrievalFallbacks: ContextSourceRefV2[] = [];\n\tlet usedTokens = 0;\n\n\tfor (const planned of basePlanned) {\n\t\tif (!planned.isHard) continue;\n\t\tusedTokens += selectHardItem(planned, selection, tierUsed);\n\t}\n\tif (usedTokens > available) {\n\t\tdiagnostics.push({\n\t\t\treason: \"hard_pin_over_capacity\",\n\t\t\tdetail: `hard-pinned context uses ${usedTokens} tokens against ${available} available tokens`,\n\t\t});\n\t}\n\n\tconst optionalPlanned = basePlanned.filter((planned) => !planned.isHard).sort(compareOptionalForSelection);\n\n\t// Floor-reservation pass: each tier spends its guaranteed claim (the\n\t// `allocated` field — hard demand, else demand capped at the floor) on its\n\t// own optional items before anything competes globally. A tier's floor is\n\t// therefore a real reservation, not a lower bound on its ceiling. Items\n\t// that cannot fit inside the remaining floor stay unselected for the\n\t// global pass; when the summed floors exceed the budget the reservation is\n\t// best-effort in tier order and the plan reports it explicitly.\n\t// One cache-resolution per item, shared by both passes so an item that is\n\t// deferred out of the floor and reconsidered globally does not double\n\t// count provider reads or redo materialization work.\n\tconst resolvedCandidates = new Map<string, readonly ContextRepresentationCandidateV2[]>();\n\tlet totalFloor = 0;\n\tfor (const tier of ALL_TIERS_V2) {\n\t\ttotalFloor += allocation.get(tier)?.floor ?? 0;\n\t}\n\tif (totalFloor > available) {\n\t\tdiagnostics.push({\n\t\t\treason: \"tier_floor_over_budget\",\n\t\t\tdetail: `tier floor guarantees total ${totalFloor} tokens against ${available} available; floors degrade to tier-order best effort`,\n\t\t});\n\t}\n\tfor (const tier of ALL_TIERS_V2) {\n\t\tconst floor = allocation.get(tier)?.floor ?? 0;\n\t\tif (floor <= 0 || tierUsed[tier] >= floor) continue;\n\t\tfor (const planned of optionalPlanned) {\n\t\t\tif (planned.item.tier !== tier || selection.has(planned.item.id)) continue;\n\t\t\tusedTokens = selectOptionalItem(planned, {\n\t\t\t\tallocation,\n\t\t\t\tavailable,\n\t\t\t\tcache,\n\t\t\t\tdiagnostics,\n\t\t\t\tomitted,\n\t\t\t\tqualityPolicy,\n\t\t\t\tretrievalFallbacks,\n\t\t\t\tselection,\n\t\t\t\ttierUsed,\n\t\t\t\tusedTokens,\n\t\t\t\tfloorReservation: { tier, floorTokens: floor },\n\t\t\t\tresolvedCandidates,\n\t\t\t});\n\t\t\tif (tierUsed[tier] >= floor || usedTokens >= available) break;\n\t\t}\n\t}\n\n\t// Global pass under tier ceilings, then promotion of floor-admitted items\n\t// with whatever the global pass left unused (audit F03).\n\tusedTokens = runGlobalSelectionPass(optionalPlanned, {\n\t\tallocation,\n\t\tavailable,\n\t\tcache,\n\t\tdiagnostics,\n\t\tomitted,\n\t\tqualityPolicy,\n\t\tresolvedCandidates,\n\t\tretrievalFallbacks,\n\t\tselection,\n\t\ttierUsed,\n\t\tusedTokens,\n\t});\n\n\tconst omittedHighPriority = omitted.some((item) => item.priority === \"high\" || item.required === true);\n\temitOmissionDiagnostics(omitted, diagnostics, retrievalFallbacks);\n\temitCoverageDiagnostics(input.query, selection, diagnostics);\n\n\tconst tierAllocations = buildTierAllocations(allocation, demand, tierUsed);\n\tconst omittedTokens = omitted.reduce(\n\t\t(sum, item) => sum + (basePlanned.find((planned) => planned.item.id === item.id)?.fullTokens ?? 0),\n\t\t0,\n\t);\n\tconst omittedItemIds = omitted.map((item) => item.id);\n\tconst planHash = computePlanHash({\n\t\tpolicyVersion,\n\t\tpromptHash: input.promptHash,\n\t\tplanned: basePlanned,\n\t\tselection,\n\t\tallocations: tierAllocations,\n\t\tomittedItemIds,\n\t});\n\tconst observability = buildObservability({\n\t\tavailable,\n\t\tdiagnostics,\n\t\tomittedItemIds,\n\t\tomittedTokens,\n\t\tplanHash,\n\t\trawTokens,\n\t\tretrievalFallbacks,\n\t\tselection,\n\t\tusedTokens,\n\t\tcacheTelemetry: finalizeContextBudgetCacheTelemetryV2(cache.telemetry, {\n\t\t\tomittedTokens,\n\t\t\trawTokens,\n\t\t\tusedTokens,\n\t\t}),\n\t});\n\n\tconst plan: PromptContextBudgetPlanV2 = {\n\t\tpolicyVersion,\n\t\tpromptHash: input.promptHash,\n\t\tplanHash,\n\t\tmaxTokens,\n\t\tresponseReserveTokens: responseReserve,\n\t\tsafetyMarginTokens: safetyMargin,\n\t\tavailableTokens: available,\n\t\tusedTokens,\n\t\tomittedTokens,\n\t\trawTokens,\n\t\ttokenSavingsRatio: rawTokens > 0 ? Math.max(0, 1 - usedTokens / rawTokens) : 0,\n\t\temergency: usedTokens > available || diagnostics.some((diagnostic) => diagnostic.reason === \"invalid_budget\"),\n\t\tomittedHighPriority,\n\t\ttierAllocations,\n\t\tselectedRepresentations: [...selection.values()].sort((a, b) => a.itemId.localeCompare(b.itemId)),\n\t\tincludedItemIds: basePlanned\n\t\t\t.map((planned) => planned.item.id)\n\t\t\t.filter((id) => selection.has(id))\n\t\t\t.sort(),\n\t\tomittedItemIds,\n\t\tdiagnostics,\n\t\tretrievalFallbacks,\n\t\tobservability,\n\t};\n\tif (canUsePlanCache) {\n\t\twritePlanCacheV2({\n\t\t\tcache,\n\t\t\tkey: planCacheKey,\n\t\t\tplan,\n\t\t\tplanned: basePlanned,\n\t\t});\n\t}\n\treturn plan;\n}\n\nfunction normalizeBudgetTokens(field: string, value: number, diagnostics: QualityDiagnosticV2[]): number {\n\tif (!Number.isFinite(value) || value < 0) {\n\t\tdiagnostics.push({\n\t\t\treason: \"invalid_budget\",\n\t\t\tdetail: `${field} must be a non-negative finite number, got ${value}`,\n\t\t});\n\t\treturn 0;\n\t}\n\treturn Math.floor(value);\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ContextBudgetItemV2 } from "./context-budget-headroom.ts";
|
|
1
|
+
import type { ContextBudgetItemV2, ContextRepresentationCandidateV2 } from "./context-budget-headroom.ts";
|
|
2
2
|
export interface PlannedItemV2 {
|
|
3
3
|
readonly item: ContextBudgetItemV2;
|
|
4
4
|
readonly fullTokens: number;
|
|
@@ -8,6 +8,12 @@ export interface PlannedItemV2 {
|
|
|
8
8
|
* cheaper pointer/summary/headroom representation.
|
|
9
9
|
*/
|
|
10
10
|
readonly admissibleTokens: number;
|
|
11
|
+
/**
|
|
12
|
+
* Representations priced with the planner's token counter. Selection must
|
|
13
|
+
* choose from these rather than re-deriving with a different estimator, or
|
|
14
|
+
* the cost an item was ranked on and the cost it pays can diverge.
|
|
15
|
+
*/
|
|
16
|
+
readonly candidates?: readonly ContextRepresentationCandidateV2[];
|
|
11
17
|
readonly contentHash: string;
|
|
12
18
|
readonly baseScore: number;
|
|
13
19
|
redundancyPenalty: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-budget-v2-scoring.d.ts","sourceRoot":"","sources":["../../src/core/context-budget-v2-scoring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"context-budget-v2-scoring.d.ts","sourceRoot":"","sources":["../../src/core/context-budget-v2-scoring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,mBAAmB,EAGnB,gCAAgC,EAChC,MAAM,8BAA8B,CAAC;AAEtC,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,gCAAgC,EAAE,CAAC;IAClE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CACzB;AAsBD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAUnG;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA8B7F;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,GAAG,MAAM,CAiBtF","sourcesContent":["import type {\n\tContextBudgetItemV2,\n\tContextBudgetPriorityV2,\n\tContextBudgetTierV2,\n\tContextRepresentationCandidateV2,\n} from \"./context-budget-headroom.ts\";\n\nexport interface PlannedItemV2 {\n\treadonly item: ContextBudgetItemV2;\n\treadonly fullTokens: number;\n\t/**\n\t * Cheapest non-omit representation cost, i.e. the true marginal cost of\n\t * admitting this item at all. Equals `fullTokens` when the item has no\n\t * cheaper pointer/summary/headroom representation.\n\t */\n\treadonly admissibleTokens: number;\n\t/**\n\t * Representations priced with the planner's token counter. Selection must\n\t * choose from these rather than re-deriving with a different estimator, or\n\t * the cost an item was ranked on and the cost it pays can diverge.\n\t */\n\treadonly candidates?: readonly ContextRepresentationCandidateV2[];\n\treadonly contentHash: string;\n\treadonly baseScore: number;\n\tredundancyPenalty: number;\n\teffectiveScore: number;\n\treadonly isHard: boolean;\n}\n\nconst PRIORITY_WEIGHT_V2: Record<ContextBudgetPriorityV2, number> = {\n\thard: 1_000_000,\n\thigh: 120,\n\tmedium: 60,\n\tlow: 15,\n};\n\n/** E-folding time in turns: at this age the factor is exp(-1), not one half. */\nconst RECENCY_TIME_CONSTANT_BY_TIER: Readonly<Record<ContextBudgetTierV2, number>> = {\n\tsystem: 999,\n\t\"active-goal\": 12,\n\t\"current-files\": 8,\n\ttools: 4,\n\tskills: 6,\n\tmcp: 6,\n\thistory: 3,\n\tevidence: 8,\n\tscratch: 2,\n};\n\nexport function scoreContextBudgetItemV2(item: ContextBudgetItemV2, estimatedTokens: number): number {\n\tif (item.priority === \"hard\") {\n\t\treturn Number.POSITIVE_INFINITY;\n\t}\n\tconst priority = PRIORITY_WEIGHT_V2[item.priority];\n\tconst relevance = clamp01(item.relevance) * 25;\n\tconst recency = deriveRecency(item) * 15;\n\tconst evidence = clamp01(item.evidenceValue) * 25;\n\tconst cost = Math.sqrt(Math.max(0, estimatedTokens)) * 0.55;\n\treturn priority + relevance + recency + evidence - cost;\n}\n\nexport function applyRedundancyPenalties(items: readonly PlannedItemV2[]): Map<string, number> {\n\tconst penalties = new Map<string, number>();\n\tconst groups = new Map<string, PlannedItemV2[]>();\n\tfor (const planned of items) {\n\t\tif (!planned.item.redundancyKey) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst group = groups.get(planned.item.redundancyKey);\n\t\tif (group) {\n\t\t\tgroup.push(planned);\n\t\t} else {\n\t\t\tgroups.set(planned.item.redundancyKey, [planned]);\n\t\t}\n\t}\n\tfor (const group of groups.values()) {\n\t\tif (group.length <= 1) {\n\t\t\tcontinue;\n\t\t}\n\t\tgroup.sort((a, b) => {\n\t\t\tif (b.baseScore !== a.baseScore) {\n\t\t\t\treturn b.baseScore - a.baseScore;\n\t\t\t}\n\t\t\treturn a.item.id.localeCompare(b.item.id);\n\t\t});\n\t\tfor (let index = 1; index < group.length; index++) {\n\t\t\tconst duplicate = group[index];\n\t\t\tpenalties.set(duplicate.item.id, redundancyPenalty(duplicate.fullTokens) * index);\n\t\t}\n\t}\n\treturn penalties;\n}\n\n/**\n * Order optional items for the budgeted 0/1 knapsack the planner greedily fills.\n *\n * Value density (effective score per token) is the primary key. Ordering by\n * priority class first would let a single expensive `high` item evict an\n * arbitrary number of far denser `medium` items, which makes the greedy\n * unbounded-bad against the optimal packing. Priority still shapes the outcome\n * through `PRIORITY_WEIGHT_V2` in the score numerator, and non-negotiable\n * context uses `hard`/`required`, which the planner pins before this ordering\n * is consulted. Remaining keys break ties into a deterministic total order.\n */\nexport function compareOptionalForSelection(a: PlannedItemV2, b: PlannedItemV2): number {\n\tconst aDensity = density(a);\n\tconst bDensity = density(b);\n\tif (bDensity !== aDensity) {\n\t\treturn bDensity - aDensity;\n\t}\n\tconst aScore = Number.isNaN(a.effectiveScore) ? Number.NEGATIVE_INFINITY : a.effectiveScore;\n\tconst bScore = Number.isNaN(b.effectiveScore) ? Number.NEGATIVE_INFINITY : b.effectiveScore;\n\tif (bScore !== aScore) return bScore - aScore;\n\tconst priorityDelta = priorityRank(b.item.priority) - priorityRank(a.item.priority);\n\tif (priorityDelta !== 0) {\n\t\treturn priorityDelta;\n\t}\n\tconst aTokens = Number.isNaN(a.fullTokens) ? Number.POSITIVE_INFINITY : a.fullTokens;\n\tconst bTokens = Number.isNaN(b.fullTokens) ? Number.POSITIVE_INFINITY : b.fullTokens;\n\tif (aTokens !== bTokens) return aTokens - bTokens;\n\treturn a.item.id.localeCompare(b.item.id);\n}\n\nfunction priorityRank(priority: ContextBudgetPriorityV2): number {\n\tswitch (priority) {\n\t\tcase \"hard\":\n\t\t\treturn 4;\n\t\tcase \"high\":\n\t\t\treturn 3;\n\t\tcase \"medium\":\n\t\t\treturn 2;\n\t\tcase \"low\":\n\t\t\treturn 1;\n\t}\n}\n\nfunction clamp01(value: number | undefined): number {\n\tif (value === undefined || !Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\treturn Math.max(0, Math.min(1, value));\n}\n\nfunction deriveRecency(item: ContextBudgetItemV2): number {\n\tif (item.recency !== undefined) {\n\t\treturn clamp01(item.recency);\n\t}\n\tconst age = item.ageTurns ?? 0;\n\tconst timeConstant = RECENCY_TIME_CONSTANT_BY_TIER[item.tier] ?? 6;\n\treturn clamp01(Math.exp(-age / timeConstant));\n}\n\nfunction redundancyPenalty(tokens: number): number {\n\treturn Math.max(10, Math.sqrt(Math.max(0, tokens)) * 0.8);\n}\n\n/**\n * Value per token of the CHEAPEST admissible representation. Dividing by\n * `fullTokens` would systematically penalize retrievable or summarizable items,\n * which are exactly the items the planner admits cheaply when the budget is\n * tight — the regime where this ordering decides anything at all.\n */\nfunction density(planned: PlannedItemV2): number {\n\tif (!Number.isFinite(planned.effectiveScore) || planned.effectiveScore <= 0) {\n\t\treturn planned.effectiveScore > 0 ? planned.effectiveScore : 0;\n\t}\n\tconst value = planned.effectiveScore / Math.max(planned.admissibleTokens, 1);\n\treturn Number.isNaN(value) ? 0 : value;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-budget-v2-scoring.js","sourceRoot":"","sources":["../../src/core/context-budget-v2-scoring.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContextBudgetItemV2, ContextBudgetPriorityV2, ContextBudgetTierV2 } from \"./context-budget-headroom.ts\";\n\nexport interface PlannedItemV2 {\n\treadonly item: ContextBudgetItemV2;\n\treadonly fullTokens: number;\n\t/**\n\t * Cheapest non-omit representation cost, i.e. the true marginal cost of\n\t * admitting this item at all. Equals `fullTokens` when the item has no\n\t * cheaper pointer/summary/headroom representation.\n\t */\n\treadonly admissibleTokens: number;\n\treadonly contentHash: string;\n\treadonly baseScore: number;\n\tredundancyPenalty: number;\n\teffectiveScore: number;\n\treadonly isHard: boolean;\n}\n\nconst PRIORITY_WEIGHT_V2: Record<ContextBudgetPriorityV2, number> = {\n\thard: 1_000_000,\n\thigh: 120,\n\tmedium: 60,\n\tlow: 15,\n};\n\n/** E-folding time in turns: at this age the factor is exp(-1), not one half. */\nconst RECENCY_TIME_CONSTANT_BY_TIER: Readonly<Record<ContextBudgetTierV2, number>> = {\n\tsystem: 999,\n\t\"active-goal\": 12,\n\t\"current-files\": 8,\n\ttools: 4,\n\tskills: 6,\n\tmcp: 6,\n\thistory: 3,\n\tevidence: 8,\n\tscratch: 2,\n};\n\nexport function scoreContextBudgetItemV2(item: ContextBudgetItemV2, estimatedTokens: number): number {\n\tif (item.priority === \"hard\") {\n\t\treturn Number.POSITIVE_INFINITY;\n\t}\n\tconst priority = PRIORITY_WEIGHT_V2[item.priority];\n\tconst relevance = clamp01(item.relevance) * 25;\n\tconst recency = deriveRecency(item) * 15;\n\tconst evidence = clamp01(item.evidenceValue) * 25;\n\tconst cost = Math.sqrt(Math.max(0, estimatedTokens)) * 0.55;\n\treturn priority + relevance + recency + evidence - cost;\n}\n\nexport function applyRedundancyPenalties(items: readonly PlannedItemV2[]): Map<string, number> {\n\tconst penalties = new Map<string, number>();\n\tconst groups = new Map<string, PlannedItemV2[]>();\n\tfor (const planned of items) {\n\t\tif (!planned.item.redundancyKey) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst group = groups.get(planned.item.redundancyKey);\n\t\tif (group) {\n\t\t\tgroup.push(planned);\n\t\t} else {\n\t\t\tgroups.set(planned.item.redundancyKey, [planned]);\n\t\t}\n\t}\n\tfor (const group of groups.values()) {\n\t\tif (group.length <= 1) {\n\t\t\tcontinue;\n\t\t}\n\t\tgroup.sort((a, b) => {\n\t\t\tif (b.baseScore !== a.baseScore) {\n\t\t\t\treturn b.baseScore - a.baseScore;\n\t\t\t}\n\t\t\treturn a.item.id.localeCompare(b.item.id);\n\t\t});\n\t\tfor (let index = 1; index < group.length; index++) {\n\t\t\tconst duplicate = group[index];\n\t\t\tpenalties.set(duplicate.item.id, redundancyPenalty(duplicate.fullTokens) * index);\n\t\t}\n\t}\n\treturn penalties;\n}\n\n/**\n * Order optional items for the budgeted 0/1 knapsack the planner greedily fills.\n *\n * Value density (effective score per token) is the primary key. Ordering by\n * priority class first would let a single expensive `high` item evict an\n * arbitrary number of far denser `medium` items, which makes the greedy\n * unbounded-bad against the optimal packing. Priority still shapes the outcome\n * through `PRIORITY_WEIGHT_V2` in the score numerator, and non-negotiable\n * context uses `hard`/`required`, which the planner pins before this ordering\n * is consulted. Remaining keys break ties into a deterministic total order.\n */\nexport function compareOptionalForSelection(a: PlannedItemV2, b: PlannedItemV2): number {\n\tconst aDensity = density(a);\n\tconst bDensity = density(b);\n\tif (bDensity !== aDensity) {\n\t\treturn bDensity - aDensity;\n\t}\n\tconst aScore = Number.isNaN(a.effectiveScore) ? Number.NEGATIVE_INFINITY : a.effectiveScore;\n\tconst bScore = Number.isNaN(b.effectiveScore) ? Number.NEGATIVE_INFINITY : b.effectiveScore;\n\tif (bScore !== aScore) return bScore - aScore;\n\tconst priorityDelta = priorityRank(b.item.priority) - priorityRank(a.item.priority);\n\tif (priorityDelta !== 0) {\n\t\treturn priorityDelta;\n\t}\n\tconst aTokens = Number.isNaN(a.fullTokens) ? Number.POSITIVE_INFINITY : a.fullTokens;\n\tconst bTokens = Number.isNaN(b.fullTokens) ? Number.POSITIVE_INFINITY : b.fullTokens;\n\tif (aTokens !== bTokens) return aTokens - bTokens;\n\treturn a.item.id.localeCompare(b.item.id);\n}\n\nfunction priorityRank(priority: ContextBudgetPriorityV2): number {\n\tswitch (priority) {\n\t\tcase \"hard\":\n\t\t\treturn 4;\n\t\tcase \"high\":\n\t\t\treturn 3;\n\t\tcase \"medium\":\n\t\t\treturn 2;\n\t\tcase \"low\":\n\t\t\treturn 1;\n\t}\n}\n\nfunction clamp01(value: number | undefined): number {\n\tif (value === undefined || !Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\treturn Math.max(0, Math.min(1, value));\n}\n\nfunction deriveRecency(item: ContextBudgetItemV2): number {\n\tif (item.recency !== undefined) {\n\t\treturn clamp01(item.recency);\n\t}\n\tconst age = item.ageTurns ?? 0;\n\tconst timeConstant = RECENCY_TIME_CONSTANT_BY_TIER[item.tier] ?? 6;\n\treturn clamp01(Math.exp(-age / timeConstant));\n}\n\nfunction redundancyPenalty(tokens: number): number {\n\treturn Math.max(10, Math.sqrt(Math.max(0, tokens)) * 0.8);\n}\n\n/**\n * Value per token of the CHEAPEST admissible representation. Dividing by\n * `fullTokens` would systematically penalize retrievable or summarizable items,\n * which are exactly the items the planner admits cheaply when the budget is\n * tight — the regime where this ordering decides anything at all.\n */\nfunction density(planned: PlannedItemV2): number {\n\tif (!Number.isFinite(planned.effectiveScore) || planned.effectiveScore <= 0) {\n\t\treturn planned.effectiveScore > 0 ? planned.effectiveScore : 0;\n\t}\n\tconst value = planned.effectiveScore / Math.max(planned.admissibleTokens, 1);\n\treturn Number.isNaN(value) ? 0 : value;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"context-budget-v2-scoring.js","sourceRoot":"","sources":["../../src/core/context-budget-v2-scoring.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tContextBudgetItemV2,\n\tContextBudgetPriorityV2,\n\tContextBudgetTierV2,\n\tContextRepresentationCandidateV2,\n} from \"./context-budget-headroom.ts\";\n\nexport interface PlannedItemV2 {\n\treadonly item: ContextBudgetItemV2;\n\treadonly fullTokens: number;\n\t/**\n\t * Cheapest non-omit representation cost, i.e. the true marginal cost of\n\t * admitting this item at all. Equals `fullTokens` when the item has no\n\t * cheaper pointer/summary/headroom representation.\n\t */\n\treadonly admissibleTokens: number;\n\t/**\n\t * Representations priced with the planner's token counter. Selection must\n\t * choose from these rather than re-deriving with a different estimator, or\n\t * the cost an item was ranked on and the cost it pays can diverge.\n\t */\n\treadonly candidates?: readonly ContextRepresentationCandidateV2[];\n\treadonly contentHash: string;\n\treadonly baseScore: number;\n\tredundancyPenalty: number;\n\teffectiveScore: number;\n\treadonly isHard: boolean;\n}\n\nconst PRIORITY_WEIGHT_V2: Record<ContextBudgetPriorityV2, number> = {\n\thard: 1_000_000,\n\thigh: 120,\n\tmedium: 60,\n\tlow: 15,\n};\n\n/** E-folding time in turns: at this age the factor is exp(-1), not one half. */\nconst RECENCY_TIME_CONSTANT_BY_TIER: Readonly<Record<ContextBudgetTierV2, number>> = {\n\tsystem: 999,\n\t\"active-goal\": 12,\n\t\"current-files\": 8,\n\ttools: 4,\n\tskills: 6,\n\tmcp: 6,\n\thistory: 3,\n\tevidence: 8,\n\tscratch: 2,\n};\n\nexport function scoreContextBudgetItemV2(item: ContextBudgetItemV2, estimatedTokens: number): number {\n\tif (item.priority === \"hard\") {\n\t\treturn Number.POSITIVE_INFINITY;\n\t}\n\tconst priority = PRIORITY_WEIGHT_V2[item.priority];\n\tconst relevance = clamp01(item.relevance) * 25;\n\tconst recency = deriveRecency(item) * 15;\n\tconst evidence = clamp01(item.evidenceValue) * 25;\n\tconst cost = Math.sqrt(Math.max(0, estimatedTokens)) * 0.55;\n\treturn priority + relevance + recency + evidence - cost;\n}\n\nexport function applyRedundancyPenalties(items: readonly PlannedItemV2[]): Map<string, number> {\n\tconst penalties = new Map<string, number>();\n\tconst groups = new Map<string, PlannedItemV2[]>();\n\tfor (const planned of items) {\n\t\tif (!planned.item.redundancyKey) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst group = groups.get(planned.item.redundancyKey);\n\t\tif (group) {\n\t\t\tgroup.push(planned);\n\t\t} else {\n\t\t\tgroups.set(planned.item.redundancyKey, [planned]);\n\t\t}\n\t}\n\tfor (const group of groups.values()) {\n\t\tif (group.length <= 1) {\n\t\t\tcontinue;\n\t\t}\n\t\tgroup.sort((a, b) => {\n\t\t\tif (b.baseScore !== a.baseScore) {\n\t\t\t\treturn b.baseScore - a.baseScore;\n\t\t\t}\n\t\t\treturn a.item.id.localeCompare(b.item.id);\n\t\t});\n\t\tfor (let index = 1; index < group.length; index++) {\n\t\t\tconst duplicate = group[index];\n\t\t\tpenalties.set(duplicate.item.id, redundancyPenalty(duplicate.fullTokens) * index);\n\t\t}\n\t}\n\treturn penalties;\n}\n\n/**\n * Order optional items for the budgeted 0/1 knapsack the planner greedily fills.\n *\n * Value density (effective score per token) is the primary key. Ordering by\n * priority class first would let a single expensive `high` item evict an\n * arbitrary number of far denser `medium` items, which makes the greedy\n * unbounded-bad against the optimal packing. Priority still shapes the outcome\n * through `PRIORITY_WEIGHT_V2` in the score numerator, and non-negotiable\n * context uses `hard`/`required`, which the planner pins before this ordering\n * is consulted. Remaining keys break ties into a deterministic total order.\n */\nexport function compareOptionalForSelection(a: PlannedItemV2, b: PlannedItemV2): number {\n\tconst aDensity = density(a);\n\tconst bDensity = density(b);\n\tif (bDensity !== aDensity) {\n\t\treturn bDensity - aDensity;\n\t}\n\tconst aScore = Number.isNaN(a.effectiveScore) ? Number.NEGATIVE_INFINITY : a.effectiveScore;\n\tconst bScore = Number.isNaN(b.effectiveScore) ? Number.NEGATIVE_INFINITY : b.effectiveScore;\n\tif (bScore !== aScore) return bScore - aScore;\n\tconst priorityDelta = priorityRank(b.item.priority) - priorityRank(a.item.priority);\n\tif (priorityDelta !== 0) {\n\t\treturn priorityDelta;\n\t}\n\tconst aTokens = Number.isNaN(a.fullTokens) ? Number.POSITIVE_INFINITY : a.fullTokens;\n\tconst bTokens = Number.isNaN(b.fullTokens) ? Number.POSITIVE_INFINITY : b.fullTokens;\n\tif (aTokens !== bTokens) return aTokens - bTokens;\n\treturn a.item.id.localeCompare(b.item.id);\n}\n\nfunction priorityRank(priority: ContextBudgetPriorityV2): number {\n\tswitch (priority) {\n\t\tcase \"hard\":\n\t\t\treturn 4;\n\t\tcase \"high\":\n\t\t\treturn 3;\n\t\tcase \"medium\":\n\t\t\treturn 2;\n\t\tcase \"low\":\n\t\t\treturn 1;\n\t}\n}\n\nfunction clamp01(value: number | undefined): number {\n\tif (value === undefined || !Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\treturn Math.max(0, Math.min(1, value));\n}\n\nfunction deriveRecency(item: ContextBudgetItemV2): number {\n\tif (item.recency !== undefined) {\n\t\treturn clamp01(item.recency);\n\t}\n\tconst age = item.ageTurns ?? 0;\n\tconst timeConstant = RECENCY_TIME_CONSTANT_BY_TIER[item.tier] ?? 6;\n\treturn clamp01(Math.exp(-age / timeConstant));\n}\n\nfunction redundancyPenalty(tokens: number): number {\n\treturn Math.max(10, Math.sqrt(Math.max(0, tokens)) * 0.8);\n}\n\n/**\n * Value per token of the CHEAPEST admissible representation. Dividing by\n * `fullTokens` would systematically penalize retrievable or summarizable items,\n * which are exactly the items the planner admits cheaply when the budget is\n * tight — the regime where this ordering decides anything at all.\n */\nfunction density(planned: PlannedItemV2): number {\n\tif (!Number.isFinite(planned.effectiveScore) || planned.effectiveScore <= 0) {\n\t\treturn planned.effectiveScore > 0 ? planned.effectiveScore : 0;\n\t}\n\tconst value = planned.effectiveScore / Math.max(planned.admissibleTokens, 1);\n\treturn Number.isNaN(value) ? 0 : value;\n}\n"]}
|
|
@@ -3,8 +3,10 @@ import { type ContextBudgetSelectionCacheV2 } from "./context-budget-v2-cache.ts
|
|
|
3
3
|
import { type PlannedItemV2 } from "./context-budget-v2-scoring.ts";
|
|
4
4
|
import { type QualityDiagnosticV2, type SelectedRepresentationV2, type TierBudgetAllocationV2 } from "./context-budget-v2-types.ts";
|
|
5
5
|
export interface OptionalSelectionState {
|
|
6
|
+
/** Per-tier caps; `floor` is the tier's reservation, which the exchange pass must not raid. */
|
|
6
7
|
readonly allocation: ReadonlyMap<ContextBudgetTierV2, {
|
|
7
8
|
readonly ceiling: number;
|
|
9
|
+
readonly floor?: number;
|
|
8
10
|
}>;
|
|
9
11
|
readonly available: number;
|
|
10
12
|
readonly cache?: ContextBudgetSelectionCacheV2;
|
|
@@ -47,4 +49,5 @@ export declare function buildTierAllocations(allocation: ReadonlyMap<ContextBudg
|
|
|
47
49
|
readonly hard: number;
|
|
48
50
|
}>, tierUsed: Record<ContextBudgetTierV2, number>): TierBudgetAllocationV2[];
|
|
49
51
|
export declare function createTierUsage(): Record<ContextBudgetTierV2, number>;
|
|
52
|
+
export declare function toSelected(itemId: string, candidate: ContextRepresentationCandidateV2): SelectedRepresentationV2;
|
|
50
53
|
//# sourceMappingURL=context-budget-v2-selection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-budget-v2-selection.d.ts","sourceRoot":"","sources":["../../src/core/context-budget-v2-selection.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype ContextBudgetItemV2,\n\ttype ContextBudgetTierV2,\n\ttype ContextRepresentationCandidateV2,\n\ttype ContextSourceRefV2,\n\tchooseHeadroomRepresentation,\n\tderiveRepresentationCandidates,\n} from \"./context-budget-headroom.ts\";\nimport {\n\tapplyRepresentationCacheV2,\n\ttype ContextBudgetSelectionCacheV2,\n\twriteRepresentationCacheV2,\n} from \"./context-budget-v2-cache.ts\";\nimport { recordContextBudgetRepresentationCacheHitV2 } from \"./context-budget-v2-cache-telemetry.ts\";\nimport { computeCoverageGap } from \"./context-budget-v2-coverage.ts\";\nimport { applyRedundancyPenalties, type PlannedItemV2 } from \"./context-budget-v2-scoring.ts\";\nimport {\n\tALL_TIERS_V2,\n\ttype QualityDiagnosticV2,\n\ttype SelectedRepresentationV2,\n\ttype TierBudgetAllocationV2,\n} from \"./context-budget-v2-types.ts\";\n\nexport interface OptionalSelectionState {\n\treadonly allocation: ReadonlyMap<ContextBudgetTierV2, { readonly ceiling: number }>;\n\treadonly available: number;\n\treadonly cache?: ContextBudgetSelectionCacheV2;\n\treadonly diagnostics: QualityDiagnosticV2[];\n\treadonly omitted: ContextBudgetItemV2[];\n\treadonly qualityPolicy: Parameters<typeof chooseHeadroomRepresentation>[2];\n\treadonly retrievalFallbacks: ContextSourceRefV2[];\n\treadonly selection: Map<string, SelectedRepresentationV2>;\n\treadonly tierUsed: Record<ContextBudgetTierV2, number>;\n\treadonly usedTokens: number;\n\t/**\n\t * Floor-reservation pass state. When set and the item belongs to this\n\t * tier, the call admits it only while the tier's floor has headroom; an\n\t * item that cannot fit inside the remaining floor is left unselected\n\t * (never omitted) for the later global pass to reconsider under the\n\t * tier's ceiling.\n\t */\n\treadonly floorReservation?: { readonly tier: ContextBudgetTierV2; readonly floorTokens: number };\n\t/**\n\t * Cache-resolved candidates per item, shared across the floor and global\n\t * passes so one item does not double-count provider reads (negative hits,\n\t * stale rejects, misses) or repeat materialization work when it is\n\t * reconsidered.\n\t */\n\treadonly resolvedCandidates?: Map<string, readonly ContextRepresentationCandidateV2[]>;\n}\n\nexport function applyPlannerRedundancyPenalties(plannedItems: PlannedItemV2[]): void {\n\tconst penalties = applyRedundancyPenalties(plannedItems.filter((planned) => !planned.isHard));\n\tfor (const planned of plannedItems) {\n\t\tconst penalty = penalties.get(planned.item.id);\n\t\tif (penalty === undefined) continue;\n\t\tplanned.redundancyPenalty = penalty;\n\t\tplanned.effectiveScore = planned.baseScore - penalty;\n\t}\n}\n\nexport function selectHardItem(\n\tplanned: PlannedItemV2,\n\tselection: Map<string, SelectedRepresentationV2>,\n\ttierUsed: Record<ContextBudgetTierV2, number>,\n): number {\n\tconst candidate: ContextRepresentationCandidateV2 = {\n\t\tkind: \"full\",\n\t\ttext: planned.item.text,\n\t\testimatedTokens: planned.fullTokens,\n\t\tfidelity: planned.item.tokenEstimate !== undefined ? \"exact\" : \"bounded\",\n\t\tsourceRef: planned.item.sourceRef,\n\t};\n\tselection.set(planned.item.id, toSelected(planned.item.id, candidate));\n\ttierUsed[planned.item.tier] += planned.fullTokens;\n\treturn planned.fullTokens;\n}\n\nexport function selectOptionalItem(planned: PlannedItemV2, state: OptionalSelectionState): number {\n\tconst floorPass =\n\t\tstate.floorReservation !== undefined && planned.item.tier === state.floorReservation.tier\n\t\t\t? state.floorReservation\n\t\t\t: undefined;\n\tif (floorPass !== undefined && state.tierUsed[planned.item.tier] >= floorPass.floorTokens) {\n\t\t// This tier's guaranteed claim is already spent; leave the item for the\n\t\t// global pass rather than consuming another tier's budget.\n\t\treturn state.usedTokens;\n\t}\n\tif (state.usedTokens >= state.available) {\n\t\tif (floorPass === undefined) omitItem(planned, state);\n\t\treturn state.usedTokens;\n\t}\n\t// During the floor pass the binding cap is the tier's remaining floor;\n\t// afterwards the tier's ceiling (or the global remainder) applies.\n\tconst tierCeiling =\n\t\tfloorPass !== undefined\n\t\t\t? floorPass.floorTokens\n\t\t\t: (state.allocation.get(planned.item.tier)?.ceiling ?? state.available);\n\tconst remaining = Math.max(0, state.available - state.usedTokens);\n\tconst candidates = planned.item.representations ?? deriveRepresentationCandidates(planned.item, state.qualityPolicy);\n\tconst materializedEnabled = planned.item.representations === undefined;\n\tlet cachedCandidates = state.resolvedCandidates?.get(planned.item.id);\n\tif (cachedCandidates === undefined) {\n\t\tcachedCandidates = state.cache\n\t\t\t? applyRepresentationCacheV2({ planned, candidates, cache: state.cache, materializedEnabled })\n\t\t\t: candidates;\n\t\tstate.resolvedCandidates?.set(planned.item.id, cachedCandidates);\n\t}\n\tconst chosen = chooseHeadroomRepresentation(\n\t\t{ ...planned.item, representations: cachedCandidates },\n\t\t{\n\t\t\ttierUsedTokens: state.tierUsed[planned.item.tier],\n\t\t\ttierCeilingTokens: tierCeiling,\n\t\t\tremainingGlobalTokens: remaining,\n\t\t},\n\t\tstate.qualityPolicy,\n\t);\n\tif (chosen.kind === \"omit\") {\n\t\tif (floorPass !== undefined) {\n\t\t\t// No admissible representation fits inside the remaining floor; the\n\t\t\t// global pass may still admit it against the tier's ceiling.\n\t\t\treturn state.usedTokens;\n\t\t}\n\t\tconst tierRemaining = Math.max(0, tierCeiling - state.tierUsed[planned.item.tier]);\n\t\tconst globalFit = cachedCandidates.filter(\n\t\t\t(candidate) => candidate.kind !== \"omit\" && candidate.estimatedTokens <= remaining,\n\t\t);\n\t\tif (globalFit.length > 0 && globalFit.every((candidate) => candidate.estimatedTokens > tierRemaining)) {\n\t\t\tstate.diagnostics.push({\n\t\t\t\treason: \"tier_ceiling_exceeded\",\n\t\t\t\titemId: planned.item.id,\n\t\t\t\tdetail: `${planned.item.tier} item \"${planned.item.id}\" needs ${Math.min(\n\t\t\t\t\t...globalFit.map((candidate) => candidate.estimatedTokens),\n\t\t\t\t)} tokens with ${tierRemaining} tier tokens remaining`,\n\t\t\t});\n\t\t}\n\t\tomitItem(planned, state);\n\t\treturn state.usedTokens;\n\t}\n\tif (state.tierUsed[planned.item.tier] + chosen.estimatedTokens > tierCeiling) {\n\t\tif (floorPass !== undefined) {\n\t\t\treturn state.usedTokens;\n\t\t}\n\t\tstate.diagnostics.push({\n\t\t\treason: \"tier_ceiling_exceeded\",\n\t\t\titemId: planned.item.id,\n\t\t\tdetail: `${planned.item.tier} item \"${planned.item.id}\" needs ${chosen.estimatedTokens} tokens with ${Math.max(0, tierCeiling - state.tierUsed[planned.item.tier])} tier tokens remaining`,\n\t\t});\n\t\tomitItem(planned, state);\n\t\treturn state.usedTokens;\n\t}\n\tif (state.usedTokens + chosen.estimatedTokens > state.available) {\n\t\tif (floorPass === undefined) omitItem(planned, state);\n\t\treturn state.usedTokens;\n\t}\n\tif (state.cache) {\n\t\tif (chosen.cache?.hit === true) {\n\t\t\trecordContextBudgetRepresentationCacheHitV2(\n\t\t\t\tstate.cache.telemetry,\n\t\t\t\tchosen.kind,\n\t\t\t\tchosen.cache.keyKind,\n\t\t\t\tplanned.fullTokens,\n\t\t\t);\n\t\t}\n\t\twriteRepresentationCacheV2({ planned, selected: chosen, cache: state.cache, materializedEnabled });\n\t}\n\tstate.selection.set(planned.item.id, toSelected(planned.item.id, chosen));\n\tstate.tierUsed[planned.item.tier] += chosen.estimatedTokens;\n\treturn state.usedTokens + chosen.estimatedTokens;\n}\n\nexport function emitOmissionDiagnostics(\n\tomitted: readonly ContextBudgetItemV2[],\n\tdiagnostics: QualityDiagnosticV2[],\n\tretrievalFallbacks: ContextSourceRefV2[],\n): void {\n\tfor (const item of omitted) {\n\t\tif (item.priority === \"high\" || item.required === true) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"omitted_high_priority\",\n\t\t\t\titemId: item.id,\n\t\t\t\tdetail: `${item.tier} item \"${item.id}\" could not fit within the prompt budget`,\n\t\t\t});\n\t\t}\n\t\tif (item.sourceRef?.retrievable) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"restore_on_demand_hint\",\n\t\t\t\titemId: item.id,\n\t\t\t\tdetail: `retrievable \"${item.id}\" kept as fallback via ${item.sourceRef.uri}`,\n\t\t\t});\n\t\t\tretrievalFallbacks.push(item.sourceRef);\n\t\t}\n\t}\n}\n\nexport function emitCoverageDiagnostics(\n\tquery: string | undefined,\n\tselection: ReadonlyMap<string, SelectedRepresentationV2>,\n\tdiagnostics: QualityDiagnosticV2[],\n): void {\n\tconst coverage = computeCoverageGap(\n\t\tquery,\n\t\t[...selection.values()].map((representation) => representation.text),\n\t);\n\tif (!coverage.gap) return;\n\tdiagnostics.push({\n\t\treason: \"coverage_gap\",\n\t\tdetail: `query terms not covered by selected context: ${coverage.missing.join(\", \")}`,\n\t});\n}\n\nexport function buildTierAllocations(\n\tallocation: ReadonlyMap<\n\t\tContextBudgetTierV2,\n\t\t{ readonly floor: number; readonly ceiling: number; readonly allocated: number }\n\t>,\n\tdemand: ReadonlyMap<ContextBudgetTierV2, { readonly hard: number }>,\n\ttierUsed: Record<ContextBudgetTierV2, number>,\n): TierBudgetAllocationV2[] {\n\treturn ALL_TIERS_V2.map((tier) => {\n\t\tconst raw = allocation.get(tier) ?? { floor: 0, ceiling: 0, allocated: 0 };\n\t\treturn {\n\t\t\ttier,\n\t\t\tfloorTokens: raw.floor,\n\t\t\tceilingTokens: raw.ceiling,\n\t\t\tallocatedTokens: raw.allocated,\n\t\t\tusedTokens: tierUsed[tier],\n\t\t\thardTokens: demand.get(tier)?.hard ?? 0,\n\t\t};\n\t});\n}\n\nexport function createTierUsage(): Record<ContextBudgetTierV2, number> {\n\treturn Object.fromEntries(ALL_TIERS_V2.map((tier) => [tier, 0])) as Record<ContextBudgetTierV2, number>;\n}\n\nfunction toSelected(itemId: string, candidate: ContextRepresentationCandidateV2): SelectedRepresentationV2 {\n\treturn {\n\t\titemId,\n\t\tkind: candidate.kind,\n\t\ttext: candidate.text,\n\t\testimatedTokens: candidate.estimatedTokens,\n\t\tfidelity: candidate.fidelity,\n\t\tsourceRef: candidate.sourceRef,\n\t\tsummaryHash: candidate.summaryHash,\n\t\tcompressorId: candidate.compressorId,\n\t\tcache: candidate.cache,\n\t};\n}\n\nfunction omitItem(\n\tplanned: PlannedItemV2,\n\tstate: Pick<OptionalSelectionState, \"diagnostics\" | \"omitted\" | \"retrievalFallbacks\">,\n): void {\n\tstate.omitted.push(planned.item);\n\tif (planned.item.sourceRef?.retrievable) {\n\t\tstate.diagnostics.push({\n\t\t\treason: \"retrieval_miss_risk\",\n\t\t\titemId: planned.item.id,\n\t\t\tdetail: `retrievable ${planned.item.tier} item \"${planned.item.id}\" omitted; keep pointer for restore-on-demand`,\n\t\t});\n\t\tstate.retrievalFallbacks.push(planned.item.sourceRef);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"context-budget-v2-selection.d.ts","sourceRoot":"","sources":["../../src/core/context-budget-v2-selection.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype ContextBudgetItemV2,\n\ttype ContextBudgetTierV2,\n\ttype ContextRepresentationCandidateV2,\n\ttype ContextSourceRefV2,\n\tchooseHeadroomRepresentation,\n\tderiveRepresentationCandidates,\n} from \"./context-budget-headroom.ts\";\nimport {\n\tapplyRepresentationCacheV2,\n\ttype ContextBudgetSelectionCacheV2,\n\twriteRepresentationCacheV2,\n} from \"./context-budget-v2-cache.ts\";\nimport { recordContextBudgetRepresentationCacheHitV2 } from \"./context-budget-v2-cache-telemetry.ts\";\nimport { computeCoverageGap } from \"./context-budget-v2-coverage.ts\";\nimport { applyRedundancyPenalties, type PlannedItemV2 } from \"./context-budget-v2-scoring.ts\";\nimport {\n\tALL_TIERS_V2,\n\ttype QualityDiagnosticV2,\n\ttype SelectedRepresentationV2,\n\ttype TierBudgetAllocationV2,\n} from \"./context-budget-v2-types.ts\";\n\nexport interface OptionalSelectionState {\n\t/** Per-tier caps; `floor` is the tier's reservation, which the exchange pass must not raid. */\n\treadonly allocation: ReadonlyMap<ContextBudgetTierV2, { readonly ceiling: number; readonly floor?: number }>;\n\treadonly available: number;\n\treadonly cache?: ContextBudgetSelectionCacheV2;\n\treadonly diagnostics: QualityDiagnosticV2[];\n\treadonly omitted: ContextBudgetItemV2[];\n\treadonly qualityPolicy: Parameters<typeof chooseHeadroomRepresentation>[2];\n\treadonly retrievalFallbacks: ContextSourceRefV2[];\n\treadonly selection: Map<string, SelectedRepresentationV2>;\n\treadonly tierUsed: Record<ContextBudgetTierV2, number>;\n\treadonly usedTokens: number;\n\t/**\n\t * Floor-reservation pass state. When set and the item belongs to this\n\t * tier, the call admits it only while the tier's floor has headroom; an\n\t * item that cannot fit inside the remaining floor is left unselected\n\t * (never omitted) for the later global pass to reconsider under the\n\t * tier's ceiling.\n\t */\n\treadonly floorReservation?: { readonly tier: ContextBudgetTierV2; readonly floorTokens: number };\n\t/**\n\t * Cache-resolved candidates per item, shared across the floor and global\n\t * passes so one item does not double-count provider reads (negative hits,\n\t * stale rejects, misses) or repeat materialization work when it is\n\t * reconsidered.\n\t */\n\treadonly resolvedCandidates?: Map<string, readonly ContextRepresentationCandidateV2[]>;\n}\n\nexport function applyPlannerRedundancyPenalties(plannedItems: PlannedItemV2[]): void {\n\tconst penalties = applyRedundancyPenalties(plannedItems.filter((planned) => !planned.isHard));\n\tfor (const planned of plannedItems) {\n\t\tconst penalty = penalties.get(planned.item.id);\n\t\tif (penalty === undefined) continue;\n\t\tplanned.redundancyPenalty = penalty;\n\t\tplanned.effectiveScore = planned.baseScore - penalty;\n\t}\n}\n\nexport function selectHardItem(\n\tplanned: PlannedItemV2,\n\tselection: Map<string, SelectedRepresentationV2>,\n\ttierUsed: Record<ContextBudgetTierV2, number>,\n): number {\n\tconst candidate: ContextRepresentationCandidateV2 = {\n\t\tkind: \"full\",\n\t\ttext: planned.item.text,\n\t\testimatedTokens: planned.fullTokens,\n\t\tfidelity: planned.item.tokenEstimate !== undefined ? \"exact\" : \"bounded\",\n\t\tsourceRef: planned.item.sourceRef,\n\t};\n\tselection.set(planned.item.id, toSelected(planned.item.id, candidate));\n\ttierUsed[planned.item.tier] += planned.fullTokens;\n\treturn planned.fullTokens;\n}\n\nexport function selectOptionalItem(planned: PlannedItemV2, state: OptionalSelectionState): number {\n\tconst floorPass =\n\t\tstate.floorReservation !== undefined && planned.item.tier === state.floorReservation.tier\n\t\t\t? state.floorReservation\n\t\t\t: undefined;\n\tif (floorPass !== undefined && state.tierUsed[planned.item.tier] >= floorPass.floorTokens) {\n\t\t// This tier's guaranteed claim is already spent; leave the item for the\n\t\t// global pass rather than consuming another tier's budget.\n\t\treturn state.usedTokens;\n\t}\n\tif (state.usedTokens >= state.available) {\n\t\tif (floorPass === undefined) omitItem(planned, state);\n\t\treturn state.usedTokens;\n\t}\n\t// During the floor pass the binding cap is the tier's remaining floor;\n\t// afterwards the tier's ceiling (or the global remainder) applies.\n\tconst tierCeiling =\n\t\tfloorPass !== undefined\n\t\t\t? floorPass.floorTokens\n\t\t\t: (state.allocation.get(planned.item.tier)?.ceiling ?? state.available);\n\tconst remaining = Math.max(0, state.available - state.usedTokens);\n\t// Prefer the planner-priced candidates: re-deriving here with the default\n\t// heuristic would price the chosen text differently from the ranking cost.\n\tconst candidates =\n\t\tplanned.candidates ??\n\t\tplanned.item.representations ??\n\t\tderiveRepresentationCandidates(planned.item, state.qualityPolicy);\n\tconst materializedEnabled = planned.item.representations === undefined;\n\tlet cachedCandidates = state.resolvedCandidates?.get(planned.item.id);\n\tif (cachedCandidates === undefined) {\n\t\tcachedCandidates = state.cache\n\t\t\t? applyRepresentationCacheV2({ planned, candidates, cache: state.cache, materializedEnabled })\n\t\t\t: candidates;\n\t\tstate.resolvedCandidates?.set(planned.item.id, cachedCandidates);\n\t}\n\tconst chosen = chooseHeadroomRepresentation(\n\t\t{ ...planned.item, representations: cachedCandidates },\n\t\t{\n\t\t\ttierUsedTokens: state.tierUsed[planned.item.tier],\n\t\t\ttierCeilingTokens: tierCeiling,\n\t\t\tremainingGlobalTokens: remaining,\n\t\t},\n\t\tstate.qualityPolicy,\n\t);\n\tif (chosen.kind === \"omit\") {\n\t\tif (floorPass !== undefined) {\n\t\t\t// No admissible representation fits inside the remaining floor; the\n\t\t\t// global pass may still admit it against the tier's ceiling.\n\t\t\treturn state.usedTokens;\n\t\t}\n\t\tconst tierRemaining = Math.max(0, tierCeiling - state.tierUsed[planned.item.tier]);\n\t\tconst globalFit = cachedCandidates.filter(\n\t\t\t(candidate) => candidate.kind !== \"omit\" && candidate.estimatedTokens <= remaining,\n\t\t);\n\t\tif (globalFit.length > 0 && globalFit.every((candidate) => candidate.estimatedTokens > tierRemaining)) {\n\t\t\tstate.diagnostics.push({\n\t\t\t\treason: \"tier_ceiling_exceeded\",\n\t\t\t\titemId: planned.item.id,\n\t\t\t\tdetail: `${planned.item.tier} item \"${planned.item.id}\" needs ${Math.min(\n\t\t\t\t\t...globalFit.map((candidate) => candidate.estimatedTokens),\n\t\t\t\t)} tokens with ${tierRemaining} tier tokens remaining`,\n\t\t\t});\n\t\t}\n\t\tomitItem(planned, state);\n\t\treturn state.usedTokens;\n\t}\n\tif (state.tierUsed[planned.item.tier] + chosen.estimatedTokens > tierCeiling) {\n\t\tif (floorPass !== undefined) {\n\t\t\treturn state.usedTokens;\n\t\t}\n\t\tstate.diagnostics.push({\n\t\t\treason: \"tier_ceiling_exceeded\",\n\t\t\titemId: planned.item.id,\n\t\t\tdetail: `${planned.item.tier} item \"${planned.item.id}\" needs ${chosen.estimatedTokens} tokens with ${Math.max(0, tierCeiling - state.tierUsed[planned.item.tier])} tier tokens remaining`,\n\t\t});\n\t\tomitItem(planned, state);\n\t\treturn state.usedTokens;\n\t}\n\tif (state.usedTokens + chosen.estimatedTokens > state.available) {\n\t\tif (floorPass === undefined) omitItem(planned, state);\n\t\treturn state.usedTokens;\n\t}\n\tif (state.cache) {\n\t\tif (chosen.cache?.hit === true) {\n\t\t\trecordContextBudgetRepresentationCacheHitV2(\n\t\t\t\tstate.cache.telemetry,\n\t\t\t\tchosen.kind,\n\t\t\t\tchosen.cache.keyKind,\n\t\t\t\tplanned.fullTokens,\n\t\t\t);\n\t\t}\n\t\twriteRepresentationCacheV2({ planned, selected: chosen, cache: state.cache, materializedEnabled });\n\t}\n\tstate.selection.set(planned.item.id, toSelected(planned.item.id, chosen));\n\tstate.tierUsed[planned.item.tier] += chosen.estimatedTokens;\n\treturn state.usedTokens + chosen.estimatedTokens;\n}\n\nexport function emitOmissionDiagnostics(\n\tomitted: readonly ContextBudgetItemV2[],\n\tdiagnostics: QualityDiagnosticV2[],\n\tretrievalFallbacks: ContextSourceRefV2[],\n): void {\n\tfor (const item of omitted) {\n\t\tif (item.priority === \"high\" || item.required === true) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"omitted_high_priority\",\n\t\t\t\titemId: item.id,\n\t\t\t\tdetail: `${item.tier} item \"${item.id}\" could not fit within the prompt budget`,\n\t\t\t});\n\t\t}\n\t\tif (item.sourceRef?.retrievable) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"restore_on_demand_hint\",\n\t\t\t\titemId: item.id,\n\t\t\t\tdetail: `retrievable \"${item.id}\" kept as fallback via ${item.sourceRef.uri}`,\n\t\t\t});\n\t\t\tretrievalFallbacks.push(item.sourceRef);\n\t\t}\n\t}\n}\n\nexport function emitCoverageDiagnostics(\n\tquery: string | undefined,\n\tselection: ReadonlyMap<string, SelectedRepresentationV2>,\n\tdiagnostics: QualityDiagnosticV2[],\n): void {\n\tconst coverage = computeCoverageGap(\n\t\tquery,\n\t\t[...selection.values()].map((representation) => representation.text),\n\t);\n\tif (!coverage.gap) return;\n\tdiagnostics.push({\n\t\treason: \"coverage_gap\",\n\t\tdetail: `query terms not covered by selected context: ${coverage.missing.join(\", \")}`,\n\t});\n}\n\nexport function buildTierAllocations(\n\tallocation: ReadonlyMap<\n\t\tContextBudgetTierV2,\n\t\t{ readonly floor: number; readonly ceiling: number; readonly allocated: number }\n\t>,\n\tdemand: ReadonlyMap<ContextBudgetTierV2, { readonly hard: number }>,\n\ttierUsed: Record<ContextBudgetTierV2, number>,\n): TierBudgetAllocationV2[] {\n\treturn ALL_TIERS_V2.map((tier) => {\n\t\tconst raw = allocation.get(tier) ?? { floor: 0, ceiling: 0, allocated: 0 };\n\t\treturn {\n\t\t\ttier,\n\t\t\tfloorTokens: raw.floor,\n\t\t\tceilingTokens: raw.ceiling,\n\t\t\tallocatedTokens: raw.allocated,\n\t\t\tusedTokens: tierUsed[tier],\n\t\t\thardTokens: demand.get(tier)?.hard ?? 0,\n\t\t};\n\t});\n}\n\nexport function createTierUsage(): Record<ContextBudgetTierV2, number> {\n\treturn Object.fromEntries(ALL_TIERS_V2.map((tier) => [tier, 0])) as Record<ContextBudgetTierV2, number>;\n}\n\nexport function toSelected(itemId: string, candidate: ContextRepresentationCandidateV2): SelectedRepresentationV2 {\n\treturn {\n\t\titemId,\n\t\tkind: candidate.kind,\n\t\ttext: candidate.text,\n\t\testimatedTokens: candidate.estimatedTokens,\n\t\tfidelity: candidate.fidelity,\n\t\tsourceRef: candidate.sourceRef,\n\t\tsummaryHash: candidate.summaryHash,\n\t\tcompressorId: candidate.compressorId,\n\t\tcache: candidate.cache,\n\t};\n}\n\nfunction omitItem(\n\tplanned: PlannedItemV2,\n\tstate: Pick<OptionalSelectionState, \"diagnostics\" | \"omitted\" | \"retrievalFallbacks\">,\n): void {\n\tstate.omitted.push(planned.item);\n\tif (planned.item.sourceRef?.retrievable) {\n\t\tstate.diagnostics.push({\n\t\t\treason: \"retrieval_miss_risk\",\n\t\t\titemId: planned.item.id,\n\t\t\tdetail: `retrievable ${planned.item.tier} item \"${planned.item.id}\" omitted; keep pointer for restore-on-demand`,\n\t\t});\n\t\tstate.retrievalFallbacks.push(planned.item.sourceRef);\n\t}\n}\n"]}
|
|
@@ -46,7 +46,11 @@ export function selectOptionalItem(planned, state) {
|
|
|
46
46
|
? floorPass.floorTokens
|
|
47
47
|
: (state.allocation.get(planned.item.tier)?.ceiling ?? state.available);
|
|
48
48
|
const remaining = Math.max(0, state.available - state.usedTokens);
|
|
49
|
-
|
|
49
|
+
// Prefer the planner-priced candidates: re-deriving here with the default
|
|
50
|
+
// heuristic would price the chosen text differently from the ranking cost.
|
|
51
|
+
const candidates = planned.candidates ??
|
|
52
|
+
planned.item.representations ??
|
|
53
|
+
deriveRepresentationCandidates(planned.item, state.qualityPolicy);
|
|
50
54
|
const materializedEnabled = planned.item.representations === undefined;
|
|
51
55
|
let cachedCandidates = state.resolvedCandidates?.get(planned.item.id);
|
|
52
56
|
if (cachedCandidates === undefined) {
|
|
@@ -149,7 +153,7 @@ export function buildTierAllocations(allocation, demand, tierUsed) {
|
|
|
149
153
|
export function createTierUsage() {
|
|
150
154
|
return Object.fromEntries(ALL_TIERS_V2.map((tier) => [tier, 0]));
|
|
151
155
|
}
|
|
152
|
-
function toSelected(itemId, candidate) {
|
|
156
|
+
export function toSelected(itemId, candidate) {
|
|
153
157
|
return {
|
|
154
158
|
itemId,
|
|
155
159
|
kind: candidate.kind,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-budget-v2-selection.js","sourceRoot":"","sources":["../../src/core/context-budget-v2-selection.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype ContextBudgetItemV2,\n\ttype ContextBudgetTierV2,\n\ttype ContextRepresentationCandidateV2,\n\ttype ContextSourceRefV2,\n\tchooseHeadroomRepresentation,\n\tderiveRepresentationCandidates,\n} from \"./context-budget-headroom.ts\";\nimport {\n\tapplyRepresentationCacheV2,\n\ttype ContextBudgetSelectionCacheV2,\n\twriteRepresentationCacheV2,\n} from \"./context-budget-v2-cache.ts\";\nimport { recordContextBudgetRepresentationCacheHitV2 } from \"./context-budget-v2-cache-telemetry.ts\";\nimport { computeCoverageGap } from \"./context-budget-v2-coverage.ts\";\nimport { applyRedundancyPenalties, type PlannedItemV2 } from \"./context-budget-v2-scoring.ts\";\nimport {\n\tALL_TIERS_V2,\n\ttype QualityDiagnosticV2,\n\ttype SelectedRepresentationV2,\n\ttype TierBudgetAllocationV2,\n} from \"./context-budget-v2-types.ts\";\n\nexport interface OptionalSelectionState {\n\treadonly allocation: ReadonlyMap<ContextBudgetTierV2, { readonly ceiling: number }>;\n\treadonly available: number;\n\treadonly cache?: ContextBudgetSelectionCacheV2;\n\treadonly diagnostics: QualityDiagnosticV2[];\n\treadonly omitted: ContextBudgetItemV2[];\n\treadonly qualityPolicy: Parameters<typeof chooseHeadroomRepresentation>[2];\n\treadonly retrievalFallbacks: ContextSourceRefV2[];\n\treadonly selection: Map<string, SelectedRepresentationV2>;\n\treadonly tierUsed: Record<ContextBudgetTierV2, number>;\n\treadonly usedTokens: number;\n\t/**\n\t * Floor-reservation pass state. When set and the item belongs to this\n\t * tier, the call admits it only while the tier's floor has headroom; an\n\t * item that cannot fit inside the remaining floor is left unselected\n\t * (never omitted) for the later global pass to reconsider under the\n\t * tier's ceiling.\n\t */\n\treadonly floorReservation?: { readonly tier: ContextBudgetTierV2; readonly floorTokens: number };\n\t/**\n\t * Cache-resolved candidates per item, shared across the floor and global\n\t * passes so one item does not double-count provider reads (negative hits,\n\t * stale rejects, misses) or repeat materialization work when it is\n\t * reconsidered.\n\t */\n\treadonly resolvedCandidates?: Map<string, readonly ContextRepresentationCandidateV2[]>;\n}\n\nexport function applyPlannerRedundancyPenalties(plannedItems: PlannedItemV2[]): void {\n\tconst penalties = applyRedundancyPenalties(plannedItems.filter((planned) => !planned.isHard));\n\tfor (const planned of plannedItems) {\n\t\tconst penalty = penalties.get(planned.item.id);\n\t\tif (penalty === undefined) continue;\n\t\tplanned.redundancyPenalty = penalty;\n\t\tplanned.effectiveScore = planned.baseScore - penalty;\n\t}\n}\n\nexport function selectHardItem(\n\tplanned: PlannedItemV2,\n\tselection: Map<string, SelectedRepresentationV2>,\n\ttierUsed: Record<ContextBudgetTierV2, number>,\n): number {\n\tconst candidate: ContextRepresentationCandidateV2 = {\n\t\tkind: \"full\",\n\t\ttext: planned.item.text,\n\t\testimatedTokens: planned.fullTokens,\n\t\tfidelity: planned.item.tokenEstimate !== undefined ? \"exact\" : \"bounded\",\n\t\tsourceRef: planned.item.sourceRef,\n\t};\n\tselection.set(planned.item.id, toSelected(planned.item.id, candidate));\n\ttierUsed[planned.item.tier] += planned.fullTokens;\n\treturn planned.fullTokens;\n}\n\nexport function selectOptionalItem(planned: PlannedItemV2, state: OptionalSelectionState): number {\n\tconst floorPass =\n\t\tstate.floorReservation !== undefined && planned.item.tier === state.floorReservation.tier\n\t\t\t? state.floorReservation\n\t\t\t: undefined;\n\tif (floorPass !== undefined && state.tierUsed[planned.item.tier] >= floorPass.floorTokens) {\n\t\t// This tier's guaranteed claim is already spent; leave the item for the\n\t\t// global pass rather than consuming another tier's budget.\n\t\treturn state.usedTokens;\n\t}\n\tif (state.usedTokens >= state.available) {\n\t\tif (floorPass === undefined) omitItem(planned, state);\n\t\treturn state.usedTokens;\n\t}\n\t// During the floor pass the binding cap is the tier's remaining floor;\n\t// afterwards the tier's ceiling (or the global remainder) applies.\n\tconst tierCeiling =\n\t\tfloorPass !== undefined\n\t\t\t? floorPass.floorTokens\n\t\t\t: (state.allocation.get(planned.item.tier)?.ceiling ?? state.available);\n\tconst remaining = Math.max(0, state.available - state.usedTokens);\n\tconst candidates = planned.item.representations ?? deriveRepresentationCandidates(planned.item, state.qualityPolicy);\n\tconst materializedEnabled = planned.item.representations === undefined;\n\tlet cachedCandidates = state.resolvedCandidates?.get(planned.item.id);\n\tif (cachedCandidates === undefined) {\n\t\tcachedCandidates = state.cache\n\t\t\t? applyRepresentationCacheV2({ planned, candidates, cache: state.cache, materializedEnabled })\n\t\t\t: candidates;\n\t\tstate.resolvedCandidates?.set(planned.item.id, cachedCandidates);\n\t}\n\tconst chosen = chooseHeadroomRepresentation(\n\t\t{ ...planned.item, representations: cachedCandidates },\n\t\t{\n\t\t\ttierUsedTokens: state.tierUsed[planned.item.tier],\n\t\t\ttierCeilingTokens: tierCeiling,\n\t\t\tremainingGlobalTokens: remaining,\n\t\t},\n\t\tstate.qualityPolicy,\n\t);\n\tif (chosen.kind === \"omit\") {\n\t\tif (floorPass !== undefined) {\n\t\t\t// No admissible representation fits inside the remaining floor; the\n\t\t\t// global pass may still admit it against the tier's ceiling.\n\t\t\treturn state.usedTokens;\n\t\t}\n\t\tconst tierRemaining = Math.max(0, tierCeiling - state.tierUsed[planned.item.tier]);\n\t\tconst globalFit = cachedCandidates.filter(\n\t\t\t(candidate) => candidate.kind !== \"omit\" && candidate.estimatedTokens <= remaining,\n\t\t);\n\t\tif (globalFit.length > 0 && globalFit.every((candidate) => candidate.estimatedTokens > tierRemaining)) {\n\t\t\tstate.diagnostics.push({\n\t\t\t\treason: \"tier_ceiling_exceeded\",\n\t\t\t\titemId: planned.item.id,\n\t\t\t\tdetail: `${planned.item.tier} item \"${planned.item.id}\" needs ${Math.min(\n\t\t\t\t\t...globalFit.map((candidate) => candidate.estimatedTokens),\n\t\t\t\t)} tokens with ${tierRemaining} tier tokens remaining`,\n\t\t\t});\n\t\t}\n\t\tomitItem(planned, state);\n\t\treturn state.usedTokens;\n\t}\n\tif (state.tierUsed[planned.item.tier] + chosen.estimatedTokens > tierCeiling) {\n\t\tif (floorPass !== undefined) {\n\t\t\treturn state.usedTokens;\n\t\t}\n\t\tstate.diagnostics.push({\n\t\t\treason: \"tier_ceiling_exceeded\",\n\t\t\titemId: planned.item.id,\n\t\t\tdetail: `${planned.item.tier} item \"${planned.item.id}\" needs ${chosen.estimatedTokens} tokens with ${Math.max(0, tierCeiling - state.tierUsed[planned.item.tier])} tier tokens remaining`,\n\t\t});\n\t\tomitItem(planned, state);\n\t\treturn state.usedTokens;\n\t}\n\tif (state.usedTokens + chosen.estimatedTokens > state.available) {\n\t\tif (floorPass === undefined) omitItem(planned, state);\n\t\treturn state.usedTokens;\n\t}\n\tif (state.cache) {\n\t\tif (chosen.cache?.hit === true) {\n\t\t\trecordContextBudgetRepresentationCacheHitV2(\n\t\t\t\tstate.cache.telemetry,\n\t\t\t\tchosen.kind,\n\t\t\t\tchosen.cache.keyKind,\n\t\t\t\tplanned.fullTokens,\n\t\t\t);\n\t\t}\n\t\twriteRepresentationCacheV2({ planned, selected: chosen, cache: state.cache, materializedEnabled });\n\t}\n\tstate.selection.set(planned.item.id, toSelected(planned.item.id, chosen));\n\tstate.tierUsed[planned.item.tier] += chosen.estimatedTokens;\n\treturn state.usedTokens + chosen.estimatedTokens;\n}\n\nexport function emitOmissionDiagnostics(\n\tomitted: readonly ContextBudgetItemV2[],\n\tdiagnostics: QualityDiagnosticV2[],\n\tretrievalFallbacks: ContextSourceRefV2[],\n): void {\n\tfor (const item of omitted) {\n\t\tif (item.priority === \"high\" || item.required === true) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"omitted_high_priority\",\n\t\t\t\titemId: item.id,\n\t\t\t\tdetail: `${item.tier} item \"${item.id}\" could not fit within the prompt budget`,\n\t\t\t});\n\t\t}\n\t\tif (item.sourceRef?.retrievable) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"restore_on_demand_hint\",\n\t\t\t\titemId: item.id,\n\t\t\t\tdetail: `retrievable \"${item.id}\" kept as fallback via ${item.sourceRef.uri}`,\n\t\t\t});\n\t\t\tretrievalFallbacks.push(item.sourceRef);\n\t\t}\n\t}\n}\n\nexport function emitCoverageDiagnostics(\n\tquery: string | undefined,\n\tselection: ReadonlyMap<string, SelectedRepresentationV2>,\n\tdiagnostics: QualityDiagnosticV2[],\n): void {\n\tconst coverage = computeCoverageGap(\n\t\tquery,\n\t\t[...selection.values()].map((representation) => representation.text),\n\t);\n\tif (!coverage.gap) return;\n\tdiagnostics.push({\n\t\treason: \"coverage_gap\",\n\t\tdetail: `query terms not covered by selected context: ${coverage.missing.join(\", \")}`,\n\t});\n}\n\nexport function buildTierAllocations(\n\tallocation: ReadonlyMap<\n\t\tContextBudgetTierV2,\n\t\t{ readonly floor: number; readonly ceiling: number; readonly allocated: number }\n\t>,\n\tdemand: ReadonlyMap<ContextBudgetTierV2, { readonly hard: number }>,\n\ttierUsed: Record<ContextBudgetTierV2, number>,\n): TierBudgetAllocationV2[] {\n\treturn ALL_TIERS_V2.map((tier) => {\n\t\tconst raw = allocation.get(tier) ?? { floor: 0, ceiling: 0, allocated: 0 };\n\t\treturn {\n\t\t\ttier,\n\t\t\tfloorTokens: raw.floor,\n\t\t\tceilingTokens: raw.ceiling,\n\t\t\tallocatedTokens: raw.allocated,\n\t\t\tusedTokens: tierUsed[tier],\n\t\t\thardTokens: demand.get(tier)?.hard ?? 0,\n\t\t};\n\t});\n}\n\nexport function createTierUsage(): Record<ContextBudgetTierV2, number> {\n\treturn Object.fromEntries(ALL_TIERS_V2.map((tier) => [tier, 0])) as Record<ContextBudgetTierV2, number>;\n}\n\nfunction toSelected(itemId: string, candidate: ContextRepresentationCandidateV2): SelectedRepresentationV2 {\n\treturn {\n\t\titemId,\n\t\tkind: candidate.kind,\n\t\ttext: candidate.text,\n\t\testimatedTokens: candidate.estimatedTokens,\n\t\tfidelity: candidate.fidelity,\n\t\tsourceRef: candidate.sourceRef,\n\t\tsummaryHash: candidate.summaryHash,\n\t\tcompressorId: candidate.compressorId,\n\t\tcache: candidate.cache,\n\t};\n}\n\nfunction omitItem(\n\tplanned: PlannedItemV2,\n\tstate: Pick<OptionalSelectionState, \"diagnostics\" | \"omitted\" | \"retrievalFallbacks\">,\n): void {\n\tstate.omitted.push(planned.item);\n\tif (planned.item.sourceRef?.retrievable) {\n\t\tstate.diagnostics.push({\n\t\t\treason: \"retrieval_miss_risk\",\n\t\t\titemId: planned.item.id,\n\t\t\tdetail: `retrievable ${planned.item.tier} item \"${planned.item.id}\" omitted; keep pointer for restore-on-demand`,\n\t\t});\n\t\tstate.retrievalFallbacks.push(planned.item.sourceRef);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"context-budget-v2-selection.js","sourceRoot":"","sources":["../../src/core/context-budget-v2-selection.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype ContextBudgetItemV2,\n\ttype ContextBudgetTierV2,\n\ttype ContextRepresentationCandidateV2,\n\ttype ContextSourceRefV2,\n\tchooseHeadroomRepresentation,\n\tderiveRepresentationCandidates,\n} from \"./context-budget-headroom.ts\";\nimport {\n\tapplyRepresentationCacheV2,\n\ttype ContextBudgetSelectionCacheV2,\n\twriteRepresentationCacheV2,\n} from \"./context-budget-v2-cache.ts\";\nimport { recordContextBudgetRepresentationCacheHitV2 } from \"./context-budget-v2-cache-telemetry.ts\";\nimport { computeCoverageGap } from \"./context-budget-v2-coverage.ts\";\nimport { applyRedundancyPenalties, type PlannedItemV2 } from \"./context-budget-v2-scoring.ts\";\nimport {\n\tALL_TIERS_V2,\n\ttype QualityDiagnosticV2,\n\ttype SelectedRepresentationV2,\n\ttype TierBudgetAllocationV2,\n} from \"./context-budget-v2-types.ts\";\n\nexport interface OptionalSelectionState {\n\t/** Per-tier caps; `floor` is the tier's reservation, which the exchange pass must not raid. */\n\treadonly allocation: ReadonlyMap<ContextBudgetTierV2, { readonly ceiling: number; readonly floor?: number }>;\n\treadonly available: number;\n\treadonly cache?: ContextBudgetSelectionCacheV2;\n\treadonly diagnostics: QualityDiagnosticV2[];\n\treadonly omitted: ContextBudgetItemV2[];\n\treadonly qualityPolicy: Parameters<typeof chooseHeadroomRepresentation>[2];\n\treadonly retrievalFallbacks: ContextSourceRefV2[];\n\treadonly selection: Map<string, SelectedRepresentationV2>;\n\treadonly tierUsed: Record<ContextBudgetTierV2, number>;\n\treadonly usedTokens: number;\n\t/**\n\t * Floor-reservation pass state. When set and the item belongs to this\n\t * tier, the call admits it only while the tier's floor has headroom; an\n\t * item that cannot fit inside the remaining floor is left unselected\n\t * (never omitted) for the later global pass to reconsider under the\n\t * tier's ceiling.\n\t */\n\treadonly floorReservation?: { readonly tier: ContextBudgetTierV2; readonly floorTokens: number };\n\t/**\n\t * Cache-resolved candidates per item, shared across the floor and global\n\t * passes so one item does not double-count provider reads (negative hits,\n\t * stale rejects, misses) or repeat materialization work when it is\n\t * reconsidered.\n\t */\n\treadonly resolvedCandidates?: Map<string, readonly ContextRepresentationCandidateV2[]>;\n}\n\nexport function applyPlannerRedundancyPenalties(plannedItems: PlannedItemV2[]): void {\n\tconst penalties = applyRedundancyPenalties(plannedItems.filter((planned) => !planned.isHard));\n\tfor (const planned of plannedItems) {\n\t\tconst penalty = penalties.get(planned.item.id);\n\t\tif (penalty === undefined) continue;\n\t\tplanned.redundancyPenalty = penalty;\n\t\tplanned.effectiveScore = planned.baseScore - penalty;\n\t}\n}\n\nexport function selectHardItem(\n\tplanned: PlannedItemV2,\n\tselection: Map<string, SelectedRepresentationV2>,\n\ttierUsed: Record<ContextBudgetTierV2, number>,\n): number {\n\tconst candidate: ContextRepresentationCandidateV2 = {\n\t\tkind: \"full\",\n\t\ttext: planned.item.text,\n\t\testimatedTokens: planned.fullTokens,\n\t\tfidelity: planned.item.tokenEstimate !== undefined ? \"exact\" : \"bounded\",\n\t\tsourceRef: planned.item.sourceRef,\n\t};\n\tselection.set(planned.item.id, toSelected(planned.item.id, candidate));\n\ttierUsed[planned.item.tier] += planned.fullTokens;\n\treturn planned.fullTokens;\n}\n\nexport function selectOptionalItem(planned: PlannedItemV2, state: OptionalSelectionState): number {\n\tconst floorPass =\n\t\tstate.floorReservation !== undefined && planned.item.tier === state.floorReservation.tier\n\t\t\t? state.floorReservation\n\t\t\t: undefined;\n\tif (floorPass !== undefined && state.tierUsed[planned.item.tier] >= floorPass.floorTokens) {\n\t\t// This tier's guaranteed claim is already spent; leave the item for the\n\t\t// global pass rather than consuming another tier's budget.\n\t\treturn state.usedTokens;\n\t}\n\tif (state.usedTokens >= state.available) {\n\t\tif (floorPass === undefined) omitItem(planned, state);\n\t\treturn state.usedTokens;\n\t}\n\t// During the floor pass the binding cap is the tier's remaining floor;\n\t// afterwards the tier's ceiling (or the global remainder) applies.\n\tconst tierCeiling =\n\t\tfloorPass !== undefined\n\t\t\t? floorPass.floorTokens\n\t\t\t: (state.allocation.get(planned.item.tier)?.ceiling ?? state.available);\n\tconst remaining = Math.max(0, state.available - state.usedTokens);\n\t// Prefer the planner-priced candidates: re-deriving here with the default\n\t// heuristic would price the chosen text differently from the ranking cost.\n\tconst candidates =\n\t\tplanned.candidates ??\n\t\tplanned.item.representations ??\n\t\tderiveRepresentationCandidates(planned.item, state.qualityPolicy);\n\tconst materializedEnabled = planned.item.representations === undefined;\n\tlet cachedCandidates = state.resolvedCandidates?.get(planned.item.id);\n\tif (cachedCandidates === undefined) {\n\t\tcachedCandidates = state.cache\n\t\t\t? applyRepresentationCacheV2({ planned, candidates, cache: state.cache, materializedEnabled })\n\t\t\t: candidates;\n\t\tstate.resolvedCandidates?.set(planned.item.id, cachedCandidates);\n\t}\n\tconst chosen = chooseHeadroomRepresentation(\n\t\t{ ...planned.item, representations: cachedCandidates },\n\t\t{\n\t\t\ttierUsedTokens: state.tierUsed[planned.item.tier],\n\t\t\ttierCeilingTokens: tierCeiling,\n\t\t\tremainingGlobalTokens: remaining,\n\t\t},\n\t\tstate.qualityPolicy,\n\t);\n\tif (chosen.kind === \"omit\") {\n\t\tif (floorPass !== undefined) {\n\t\t\t// No admissible representation fits inside the remaining floor; the\n\t\t\t// global pass may still admit it against the tier's ceiling.\n\t\t\treturn state.usedTokens;\n\t\t}\n\t\tconst tierRemaining = Math.max(0, tierCeiling - state.tierUsed[planned.item.tier]);\n\t\tconst globalFit = cachedCandidates.filter(\n\t\t\t(candidate) => candidate.kind !== \"omit\" && candidate.estimatedTokens <= remaining,\n\t\t);\n\t\tif (globalFit.length > 0 && globalFit.every((candidate) => candidate.estimatedTokens > tierRemaining)) {\n\t\t\tstate.diagnostics.push({\n\t\t\t\treason: \"tier_ceiling_exceeded\",\n\t\t\t\titemId: planned.item.id,\n\t\t\t\tdetail: `${planned.item.tier} item \"${planned.item.id}\" needs ${Math.min(\n\t\t\t\t\t...globalFit.map((candidate) => candidate.estimatedTokens),\n\t\t\t\t)} tokens with ${tierRemaining} tier tokens remaining`,\n\t\t\t});\n\t\t}\n\t\tomitItem(planned, state);\n\t\treturn state.usedTokens;\n\t}\n\tif (state.tierUsed[planned.item.tier] + chosen.estimatedTokens > tierCeiling) {\n\t\tif (floorPass !== undefined) {\n\t\t\treturn state.usedTokens;\n\t\t}\n\t\tstate.diagnostics.push({\n\t\t\treason: \"tier_ceiling_exceeded\",\n\t\t\titemId: planned.item.id,\n\t\t\tdetail: `${planned.item.tier} item \"${planned.item.id}\" needs ${chosen.estimatedTokens} tokens with ${Math.max(0, tierCeiling - state.tierUsed[planned.item.tier])} tier tokens remaining`,\n\t\t});\n\t\tomitItem(planned, state);\n\t\treturn state.usedTokens;\n\t}\n\tif (state.usedTokens + chosen.estimatedTokens > state.available) {\n\t\tif (floorPass === undefined) omitItem(planned, state);\n\t\treturn state.usedTokens;\n\t}\n\tif (state.cache) {\n\t\tif (chosen.cache?.hit === true) {\n\t\t\trecordContextBudgetRepresentationCacheHitV2(\n\t\t\t\tstate.cache.telemetry,\n\t\t\t\tchosen.kind,\n\t\t\t\tchosen.cache.keyKind,\n\t\t\t\tplanned.fullTokens,\n\t\t\t);\n\t\t}\n\t\twriteRepresentationCacheV2({ planned, selected: chosen, cache: state.cache, materializedEnabled });\n\t}\n\tstate.selection.set(planned.item.id, toSelected(planned.item.id, chosen));\n\tstate.tierUsed[planned.item.tier] += chosen.estimatedTokens;\n\treturn state.usedTokens + chosen.estimatedTokens;\n}\n\nexport function emitOmissionDiagnostics(\n\tomitted: readonly ContextBudgetItemV2[],\n\tdiagnostics: QualityDiagnosticV2[],\n\tretrievalFallbacks: ContextSourceRefV2[],\n): void {\n\tfor (const item of omitted) {\n\t\tif (item.priority === \"high\" || item.required === true) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"omitted_high_priority\",\n\t\t\t\titemId: item.id,\n\t\t\t\tdetail: `${item.tier} item \"${item.id}\" could not fit within the prompt budget`,\n\t\t\t});\n\t\t}\n\t\tif (item.sourceRef?.retrievable) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"restore_on_demand_hint\",\n\t\t\t\titemId: item.id,\n\t\t\t\tdetail: `retrievable \"${item.id}\" kept as fallback via ${item.sourceRef.uri}`,\n\t\t\t});\n\t\t\tretrievalFallbacks.push(item.sourceRef);\n\t\t}\n\t}\n}\n\nexport function emitCoverageDiagnostics(\n\tquery: string | undefined,\n\tselection: ReadonlyMap<string, SelectedRepresentationV2>,\n\tdiagnostics: QualityDiagnosticV2[],\n): void {\n\tconst coverage = computeCoverageGap(\n\t\tquery,\n\t\t[...selection.values()].map((representation) => representation.text),\n\t);\n\tif (!coverage.gap) return;\n\tdiagnostics.push({\n\t\treason: \"coverage_gap\",\n\t\tdetail: `query terms not covered by selected context: ${coverage.missing.join(\", \")}`,\n\t});\n}\n\nexport function buildTierAllocations(\n\tallocation: ReadonlyMap<\n\t\tContextBudgetTierV2,\n\t\t{ readonly floor: number; readonly ceiling: number; readonly allocated: number }\n\t>,\n\tdemand: ReadonlyMap<ContextBudgetTierV2, { readonly hard: number }>,\n\ttierUsed: Record<ContextBudgetTierV2, number>,\n): TierBudgetAllocationV2[] {\n\treturn ALL_TIERS_V2.map((tier) => {\n\t\tconst raw = allocation.get(tier) ?? { floor: 0, ceiling: 0, allocated: 0 };\n\t\treturn {\n\t\t\ttier,\n\t\t\tfloorTokens: raw.floor,\n\t\t\tceilingTokens: raw.ceiling,\n\t\t\tallocatedTokens: raw.allocated,\n\t\t\tusedTokens: tierUsed[tier],\n\t\t\thardTokens: demand.get(tier)?.hard ?? 0,\n\t\t};\n\t});\n}\n\nexport function createTierUsage(): Record<ContextBudgetTierV2, number> {\n\treturn Object.fromEntries(ALL_TIERS_V2.map((tier) => [tier, 0])) as Record<ContextBudgetTierV2, number>;\n}\n\nexport function toSelected(itemId: string, candidate: ContextRepresentationCandidateV2): SelectedRepresentationV2 {\n\treturn {\n\t\titemId,\n\t\tkind: candidate.kind,\n\t\ttext: candidate.text,\n\t\testimatedTokens: candidate.estimatedTokens,\n\t\tfidelity: candidate.fidelity,\n\t\tsourceRef: candidate.sourceRef,\n\t\tsummaryHash: candidate.summaryHash,\n\t\tcompressorId: candidate.compressorId,\n\t\tcache: candidate.cache,\n\t};\n}\n\nfunction omitItem(\n\tplanned: PlannedItemV2,\n\tstate: Pick<OptionalSelectionState, \"diagnostics\" | \"omitted\" | \"retrievalFallbacks\">,\n): void {\n\tstate.omitted.push(planned.item);\n\tif (planned.item.sourceRef?.retrievable) {\n\t\tstate.diagnostics.push({\n\t\t\treason: \"retrieval_miss_risk\",\n\t\t\titemId: planned.item.id,\n\t\t\tdetail: `retrievable ${planned.item.tier} item \"${planned.item.id}\" omitted; keep pointer for restore-on-demand`,\n\t\t});\n\t\tstate.retrievalFallbacks.push(planned.item.sourceRef);\n\t}\n}\n"]}
|
|
@@ -15,8 +15,13 @@ export declare const CONTEXT_BUDGET_POLICY_VERSION_V2 = "context-budget-v2";
|
|
|
15
15
|
*
|
|
16
16
|
* `sel-2`: density-ordered selection over the cheapest admissible representation
|
|
17
17
|
* (previously priority-class-ordered over full-text tokens).
|
|
18
|
+
* `sel-3`: derived representations are priced by counting their materialized
|
|
19
|
+
* text with the planner's counter; the summary ratio is no longer a cost, so
|
|
20
|
+
* plans cached under `sel-2` carry under-priced summaries and must not be served.
|
|
21
|
+
* The same token covers the exchange and promotion passes added alongside it,
|
|
22
|
+
* which change the selected set for identical inputs.
|
|
18
23
|
*/
|
|
19
|
-
export declare const CONTEXT_BUDGET_SELECTION_POLICY_V2 = "sel-
|
|
24
|
+
export declare const CONTEXT_BUDGET_SELECTION_POLICY_V2 = "sel-3";
|
|
20
25
|
/** Fixed compatibility telemetry for the removed legacy token optimizer. */
|
|
21
26
|
export interface TokenOptimizerRuntimeStatus {
|
|
22
27
|
readonly optimizerId: "legacy-token-optimizer";
|