open-multi-agent-kit 0.99.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 +30 -1
- package/README.md +3 -3
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/cli.js +1 -0
- package/dist/bun/cli.js.map +1 -1
- package/dist/bun/register-bundled-coding-agent.d.ts +10 -0
- package/dist/bun/register-bundled-coding-agent.d.ts.map +1 -0
- package/dist/bun/register-bundled-coding-agent.js +12 -0
- package/dist/bun/register-bundled-coding-agent.js.map +1 -0
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +2 -1
- package/dist/cli/help.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +14 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/neo-cli.d.ts +9 -0
- package/dist/commands/neo-cli.d.ts.map +1 -0
- package/dist/commands/neo-cli.js +61 -0
- package/dist/commands/neo-cli.js.map +1 -0
- 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 +29 -2
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +135 -37
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bundled-skills.d.ts +4 -0
- package/dist/core/bundled-skills.d.ts.map +1 -0
- package/dist/core/bundled-skills.js +32 -0
- package/dist/core/bundled-skills.js.map +1 -0
- package/dist/core/cli-diagnostics.d.ts +6 -0
- package/dist/core/cli-diagnostics.d.ts.map +1 -0
- package/dist/core/cli-diagnostics.js +20 -0
- package/dist/core/cli-diagnostics.js.map +1 -0
- 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 +22 -0
- package/dist/core/context-budget-headroom.d.ts.map +1 -1
- package/dist/core/context-budget-headroom.js +46 -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-input-validation.d.ts +4 -0
- package/dist/core/context-budget-v2-input-validation.d.ts.map +1 -0
- package/dist/core/context-budget-v2-input-validation.js +79 -0
- package/dist/core/context-budget-v2-input-validation.js.map +1 -0
- package/dist/core/context-budget-v2-observability.d.ts +15 -0
- package/dist/core/context-budget-v2-observability.d.ts.map +1 -0
- package/dist/core/context-budget-v2-observability.js +35 -0
- package/dist/core/context-budget-v2-observability.js.map +1 -0
- package/dist/core/context-budget-v2-planned-items.d.ts +17 -0
- package/dist/core/context-budget-v2-planned-items.d.ts.map +1 -0
- package/dist/core/context-budget-v2-planned-items.js +59 -0
- package/dist/core/context-budget-v2-planned-items.js.map +1 -0
- package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
- package/dist/core/context-budget-v2-planner.js +69 -51
- 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 +22 -3
- package/dist/core/context-budget-v2-selection.d.ts.map +1 -1
- package/dist/core/context-budget-v2-selection.js +41 -59
- package/dist/core/context-budget-v2-selection.js.map +1 -1
- package/dist/core/context-budget-v2-tiers.d.ts.map +1 -1
- package/dist/core/context-budget-v2-tiers.js +9 -42
- package/dist/core/context-budget-v2-tiers.js.map +1 -1
- package/dist/core/context-budget-v2-types.d.ts +14 -2
- 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/extensions/bundled-virtual-modules.d.ts +15 -0
- package/dist/core/extensions/bundled-virtual-modules.d.ts.map +1 -0
- package/dist/core/extensions/bundled-virtual-modules.js +63 -0
- package/dist/core/extensions/bundled-virtual-modules.js.map +1 -0
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +2 -42
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +6 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +10 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/loadout-runtime.d.ts +2 -8
- package/dist/core/loadout-runtime.d.ts.map +1 -1
- package/dist/core/loadout-runtime.js.map +1 -1
- package/dist/core/mcp/client.d.ts +27 -6
- package/dist/core/mcp/client.d.ts.map +1 -1
- package/dist/core/mcp/client.js +80 -20
- package/dist/core/mcp/client.js.map +1 -1
- package/dist/core/mcp/manager.d.ts +10 -1
- package/dist/core/mcp/manager.d.ts.map +1 -1
- package/dist/core/mcp/manager.js +68 -9
- package/dist/core/mcp/manager.js.map +1 -1
- package/dist/core/mcp/protocol.d.ts +9 -3
- package/dist/core/mcp/protocol.d.ts.map +1 -1
- package/dist/core/mcp/protocol.js +61 -15
- package/dist/core/mcp/protocol.js.map +1 -1
- package/dist/core/mcp/stdio-transport.d.ts +12 -1
- package/dist/core/mcp/stdio-transport.d.ts.map +1 -1
- package/dist/core/mcp/stdio-transport.js +30 -2
- package/dist/core/mcp/stdio-transport.js.map +1 -1
- package/dist/core/mcp-descriptor-injection.d.ts +26 -0
- package/dist/core/mcp-descriptor-injection.d.ts.map +1 -0
- package/dist/core/mcp-descriptor-injection.js +25 -0
- package/dist/core/mcp-descriptor-injection.js.map +1 -0
- package/dist/core/mcp-public-presets.d.ts +1 -3
- package/dist/core/mcp-public-presets.d.ts.map +1 -1
- package/dist/core/mcp-public-presets.js +3 -15
- package/dist/core/mcp-public-presets.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +24 -3
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/neo/catalog.d.ts +20 -0
- package/dist/core/neo/catalog.d.ts.map +1 -0
- package/dist/core/neo/catalog.js +50 -0
- package/dist/core/neo/catalog.js.map +1 -0
- package/dist/core/neo/setup.d.ts +3 -0
- package/dist/core/neo/setup.d.ts.map +1 -0
- package/dist/core/neo/setup.js +47 -0
- package/dist/core/neo/setup.js.map +1 -0
- package/dist/core/provider-default-models.d.ts +2 -0
- package/dist/core/provider-default-models.d.ts.map +1 -1
- package/dist/core/provider-default-models.js +2 -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 +2 -0
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/provider-error-classification.d.ts +57 -0
- package/dist/core/provider-error-classification.d.ts.map +1 -0
- package/dist/core/provider-error-classification.js +103 -0
- package/dist/core/provider-error-classification.js.map +1 -0
- package/dist/core/provider-resilience.d.ts +10 -0
- package/dist/core/provider-resilience.d.ts.map +1 -1
- package/dist/core/provider-resilience.js +36 -3
- package/dist/core/provider-resilience.js.map +1 -1
- package/dist/core/provider-usage-commandcode.d.ts +9 -0
- package/dist/core/provider-usage-commandcode.d.ts.map +1 -0
- package/dist/core/provider-usage-commandcode.js +198 -0
- package/dist/core/provider-usage-commandcode.js.map +1 -0
- package/dist/core/provider-usage-devin.d.ts +5 -3
- package/dist/core/provider-usage-devin.d.ts.map +1 -1
- package/dist/core/provider-usage-devin.js +15 -5
- package/dist/core/provider-usage-devin.js.map +1 -1
- package/dist/core/provider-usage-types.d.ts +1 -1
- package/dist/core/provider-usage-types.d.ts.map +1 -1
- package/dist/core/provider-usage-types.js.map +1 -1
- package/dist/core/provider-usage.d.ts.map +1 -1
- package/dist/core/provider-usage.js +6 -0
- package/dist/core/provider-usage.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/resource-admission.d.ts +36 -0
- package/dist/core/resource-admission.d.ts.map +1 -1
- package/dist/core/resource-admission.js +59 -0
- package/dist/core/resource-admission.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +2 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/run-usage-ledger.d.ts +47 -0
- package/dist/core/run-usage-ledger.d.ts.map +1 -0
- package/dist/core/run-usage-ledger.js +162 -0
- package/dist/core/run-usage-ledger.js.map +1 -0
- package/dist/core/run-usage-operation.d.ts +8 -0
- package/dist/core/run-usage-operation.d.ts.map +1 -0
- package/dist/core/run-usage-operation.js +12 -0
- package/dist/core/run-usage-operation.js.map +1 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +5 -6
- package/dist/core/sdk.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/session-failure-cause.d.ts.map +1 -1
- package/dist/core/session-failure-cause.js +14 -5
- package/dist/core/session-failure-cause.js.map +1 -1
- package/dist/core/session-prompt-lifecycle.d.ts +6 -0
- package/dist/core/session-prompt-lifecycle.d.ts.map +1 -1
- package/dist/core/session-prompt-lifecycle.js +47 -2
- package/dist/core/session-prompt-lifecycle.js.map +1 -1
- package/dist/core/session-termination.d.ts.map +1 -1
- package/dist/core/session-termination.js +4 -2
- package/dist/core/session-termination.js.map +1 -1
- package/dist/core/subagent-lane-authority.d.ts +28 -0
- package/dist/core/subagent-lane-authority.d.ts.map +1 -0
- package/dist/core/subagent-lane-authority.js +119 -0
- package/dist/core/subagent-lane-authority.js.map +1 -0
- package/dist/core/subagent-lane-contract.d.ts +114 -0
- package/dist/core/subagent-lane-contract.d.ts.map +1 -0
- package/dist/core/subagent-lane-contract.js +18 -0
- package/dist/core/subagent-lane-contract.js.map +1 -0
- package/dist/core/subagent-lane-launcher.d.ts +3 -6
- package/dist/core/subagent-lane-launcher.d.ts.map +1 -1
- package/dist/core/subagent-lane-launcher.js +53 -12
- package/dist/core/subagent-lane-launcher.js.map +1 -1
- package/dist/core/subagent-orchestration.d.ts +4 -17
- package/dist/core/subagent-orchestration.d.ts.map +1 -1
- package/dist/core/subagent-orchestration.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/core/verified-run/broker.d.ts.map +1 -1
- package/dist/core/verified-run/broker.js +4 -1
- package/dist/core/verified-run/broker.js.map +1 -1
- package/dist/core/workload-permit-pool.d.ts +1 -1
- package/dist/core/workload-permit-pool.d.ts.map +1 -1
- package/dist/core/workload-permit-pool.js +3 -0
- package/dist/core/workload-permit-pool.js.map +1 -1
- package/dist/guardrails/strict-evidence-approval-adapter.d.ts +34 -0
- package/dist/guardrails/strict-evidence-approval-adapter.d.ts.map +1 -0
- package/dist/guardrails/strict-evidence-approval-adapter.js +70 -0
- package/dist/guardrails/strict-evidence-approval-adapter.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +11 -18
- package/dist/main.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/modes/acp/acp-agent.d.ts +24 -0
- package/dist/modes/acp/acp-agent.d.ts.map +1 -0
- package/dist/modes/acp/acp-agent.js +133 -0
- package/dist/modes/acp/acp-agent.js.map +1 -0
- package/dist/modes/acp/acp-mode.d.ts +4 -0
- package/dist/modes/acp/acp-mode.d.ts.map +1 -0
- package/dist/modes/acp/acp-mode.js +34 -0
- package/dist/modes/acp/acp-mode.js.map +1 -0
- package/dist/modes/acp/acp-session.d.ts +4 -0
- package/dist/modes/acp/acp-session.d.ts.map +1 -0
- package/dist/modes/acp/acp-session.js +76 -0
- package/dist/modes/acp/acp-session.js.map +1 -0
- package/dist/modes/acp/acp-transport.d.ts +5 -0
- package/dist/modes/acp/acp-transport.d.ts.map +1 -0
- package/dist/modes/acp/acp-transport.js +90 -0
- package/dist/modes/acp/acp-transport.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +1 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- 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/audit-revalidation-2026-09-17.md +77 -0
- package/docs/devin-harness.md +33 -4
- package/docs/ecraf-normalization.md +83 -0
- package/docs/metacognition.md +51 -0
- package/docs/model-catalog-refresh.md +110 -1
- package/docs/models.md +1 -1
- package/docs/neo.md +134 -0
- package/docs/providers.md +125 -6
- package/docs/run-usage-ledger.md +56 -0
- package/docs/runtime-algorithms.md +151 -3
- package/docs/skills.md +1 -1
- package/docs/usage.md +2 -1
- 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/subagent/adaptive-agent-runtime.ts +14 -1
- package/examples/extensions/subagent/graph-result.ts +48 -0
- package/examples/extensions/subagent/index.ts +246 -111
- package/examples/extensions/subagent/managed-process-tree.ts +42 -0
- package/examples/extensions/subagent/managed-process.test.ts +24 -0
- package/examples/extensions/subagent/managed-process.ts +93 -112
- package/examples/extensions/subagent/subagent-runtime-types.ts +17 -1
- package/examples/extensions/subagent/subagent-stream.ts +161 -0
- package/examples/extensions/terminal-browser/README.md +54 -0
- package/examples/extensions/terminal-browser/bridge-protocol.ts +29 -0
- package/examples/extensions/terminal-browser/bridge.ts +219 -0
- package/examples/extensions/terminal-browser/browser-surface.ts +288 -0
- package/examples/extensions/terminal-browser/index.ts +215 -0
- package/examples/extensions/terminal-browser/placeholders.ts +49 -0
- 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 +8 -7
- package/resources/neo/skills/omk-browser/SKILL.md +32 -0
- package/resources/neo/skills/omk-code-review/SKILL.md +24 -0
- package/resources/neo/skills/omk-computeruse/SKILL.md +34 -0
- package/resources/neo/skills/omk-mcp-setup/SKILL.md +48 -0
- package/resources/neo/skills/omk-research/SKILL.md +24 -0
- package/resources/neo/skills/omk-site/SKILL.md +28 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { chooseHeadroomRepresentation, deriveRepresentationCandidates, isRepresentationEligible, scoreRepresentationPreferenceV2, } from "./context-budget-headroom.js";
|
|
2
|
+
import { writeRepresentationCacheV2 } from "./context-budget-v2-cache.js";
|
|
3
|
+
import { selectOptionalItem, toSelected } from "./context-budget-v2-selection.js";
|
|
4
|
+
/**
|
|
5
|
+
* Everything that happens once every tier has spent its floor:
|
|
6
|
+
*
|
|
7
|
+
* 1. the global pass admits still-unselected optional items in rank order
|
|
8
|
+
* under their tier ceilings;
|
|
9
|
+
* 2. the exchange pass lets a still-omitted item pay for its admission by
|
|
10
|
+
* stepping selected items down to their cheapest admissible form (F04);
|
|
11
|
+
* 3. the promotion pass spends whatever is left on costlier representations
|
|
12
|
+
* the policy prefers (F03).
|
|
13
|
+
*
|
|
14
|
+
* Breadth is settled before quality: an exchange that admits another item
|
|
15
|
+
* cannot be undone by a promotion, because promotion only spends the budget
|
|
16
|
+
* the exchange left. Returns the final token usage.
|
|
17
|
+
*/
|
|
18
|
+
export function runGlobalSelectionPass(optionalPlanned, state) {
|
|
19
|
+
let usedTokens = state.usedTokens;
|
|
20
|
+
for (const planned of optionalPlanned) {
|
|
21
|
+
if (state.selection.has(planned.item.id))
|
|
22
|
+
continue;
|
|
23
|
+
usedTokens = selectOptionalItem(planned, { ...state, usedTokens });
|
|
24
|
+
}
|
|
25
|
+
usedTokens = exchangeForOmittedItems(optionalPlanned, { ...state, usedTokens });
|
|
26
|
+
return promoteSelectedRepresentations(optionalPlanned, { ...state, usedTokens });
|
|
27
|
+
}
|
|
28
|
+
/** Representations the planner priced for this item, in the order selection saw them. */
|
|
29
|
+
function candidatesFor(planned, state) {
|
|
30
|
+
return (state.resolvedCandidates?.get(planned.item.id) ??
|
|
31
|
+
planned.candidates ??
|
|
32
|
+
planned.item.representations ??
|
|
33
|
+
deriveRepresentationCandidates(planned.item, state.qualityPolicy));
|
|
34
|
+
}
|
|
35
|
+
/** Cheapest representation the policy would allow at all, ignoring budget. */
|
|
36
|
+
function cheapestAdmissible(planned, state) {
|
|
37
|
+
let best;
|
|
38
|
+
for (const candidate of candidatesFor(planned, state)) {
|
|
39
|
+
if (candidate.kind === "omit")
|
|
40
|
+
continue;
|
|
41
|
+
if (!isRepresentationEligible(candidate, planned.item, state.qualityPolicy))
|
|
42
|
+
continue;
|
|
43
|
+
if (best === undefined || candidate.estimatedTokens < best.estimatedTokens)
|
|
44
|
+
best = candidate;
|
|
45
|
+
}
|
|
46
|
+
return best;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Plan the cheapest set of step-downs that makes room for `cost` tokens in
|
|
50
|
+
* `target`'s tier, or `undefined` when no admissible set exists.
|
|
51
|
+
*
|
|
52
|
+
* Donors are ordered by the preference the policy loses per token freed, so
|
|
53
|
+
* the item whose fidelity matters least to the policy yields first. A donor is
|
|
54
|
+
* skipped when stepping it down would drop its tier below the floor it is
|
|
55
|
+
* currently honouring: the floor is a reservation, not a budget to raid. An
|
|
56
|
+
* empty swap list is legitimate — an earlier exchange may already have freed
|
|
57
|
+
* enough for this item.
|
|
58
|
+
*/
|
|
59
|
+
function planExchange(target, cost, optionalPlanned, state, usedTokens) {
|
|
60
|
+
const ceilingOf = (tier) => state.allocation.get(tier)?.ceiling ?? state.available;
|
|
61
|
+
const floorOf = (tier) => state.allocation.get(tier)?.floor ?? 0;
|
|
62
|
+
const projected = new Map();
|
|
63
|
+
const tierNow = (tier) => projected.get(tier) ?? state.tierUsed[tier];
|
|
64
|
+
const donors = [];
|
|
65
|
+
for (const donor of optionalPlanned) {
|
|
66
|
+
if (donor.item.id === target.item.id)
|
|
67
|
+
continue;
|
|
68
|
+
const current = state.selection.get(donor.item.id);
|
|
69
|
+
if (current === undefined || current.kind === "omit")
|
|
70
|
+
continue;
|
|
71
|
+
const cheap = cheapestAdmissible(donor, state);
|
|
72
|
+
if (cheap === undefined || cheap.estimatedTokens >= current.estimatedTokens)
|
|
73
|
+
continue;
|
|
74
|
+
const freed = current.estimatedTokens - cheap.estimatedTokens;
|
|
75
|
+
const from = toCandidate(current);
|
|
76
|
+
const loss = scoreRepresentationPreferenceV2(from, donor.item, state.qualityPolicy, false) -
|
|
77
|
+
scoreRepresentationPreferenceV2(cheap, donor.item, state.qualityPolicy, false);
|
|
78
|
+
donors.push({ donor, current, cheap, freed, lossPerToken: loss / freed });
|
|
79
|
+
}
|
|
80
|
+
donors.sort((a, b) => a.lossPerToken - b.lossPerToken || a.donor.item.id.localeCompare(b.donor.item.id));
|
|
81
|
+
const swaps = [];
|
|
82
|
+
let freed = 0;
|
|
83
|
+
const fits = () => cost <= state.available - (usedTokens - freed) && tierNow(target.item.tier) + cost <= ceilingOf(target.item.tier);
|
|
84
|
+
for (const entry of donors) {
|
|
85
|
+
if (fits())
|
|
86
|
+
break;
|
|
87
|
+
const after = tierNow(entry.donor.item.tier) - entry.freed;
|
|
88
|
+
if (tierNow(entry.donor.item.tier) >= floorOf(entry.donor.item.tier) && after < floorOf(entry.donor.item.tier)) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
projected.set(entry.donor.item.tier, after);
|
|
92
|
+
swaps.push({ donor: entry.donor, from: entry.current, to: entry.cheap });
|
|
93
|
+
freed += entry.freed;
|
|
94
|
+
}
|
|
95
|
+
return fits() ? { swaps, freed } : undefined;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Admit still-omitted items by exchanging fidelity for coverage (audit F04).
|
|
99
|
+
*
|
|
100
|
+
* Ranking prices an item by its cheapest admissible representation but the
|
|
101
|
+
* selector may admit it at full text, so one item ranked on a 10-token pointer
|
|
102
|
+
* can spend 100 and displace two 45-token items the policy would rather keep.
|
|
103
|
+
* After the global pass, each omitted item in rank order may buy its cheapest
|
|
104
|
+
* admissible form by stepping selected items down to theirs. The whole exchange
|
|
105
|
+
* is applied or none of it is; tier floors and ceilings hold throughout. This
|
|
106
|
+
* is a bounded repair, not joint `(item, representation)` optimization.
|
|
107
|
+
*/
|
|
108
|
+
function exchangeForOmittedItems(optionalPlanned, state) {
|
|
109
|
+
let usedTokens = state.usedTokens;
|
|
110
|
+
for (const target of optionalPlanned) {
|
|
111
|
+
if (state.selection.has(target.item.id))
|
|
112
|
+
continue;
|
|
113
|
+
const admit = cheapestAdmissible(target, state);
|
|
114
|
+
if (admit === undefined)
|
|
115
|
+
continue;
|
|
116
|
+
const exchange = planExchange(target, admit.estimatedTokens, optionalPlanned, state, usedTokens);
|
|
117
|
+
if (exchange === undefined)
|
|
118
|
+
continue;
|
|
119
|
+
for (const swap of exchange.swaps) {
|
|
120
|
+
state.tierUsed[swap.donor.item.tier] += swap.to.estimatedTokens - swap.from.estimatedTokens;
|
|
121
|
+
state.selection.set(swap.donor.item.id, toSelected(swap.donor.item.id, swap.to));
|
|
122
|
+
writeSelected(swap.donor, swap.to, state);
|
|
123
|
+
}
|
|
124
|
+
state.tierUsed[target.item.tier] += admit.estimatedTokens;
|
|
125
|
+
state.selection.set(target.item.id, toSelected(target.item.id, admit));
|
|
126
|
+
writeSelected(target, admit, state);
|
|
127
|
+
// The global pass already recorded this item as omitted; an admitted item
|
|
128
|
+
// must leave that list, or the plan reports it as both included and
|
|
129
|
+
// omitted and bills its full text in omittedTokens.
|
|
130
|
+
const omittedIndex = state.omitted.findIndex((entry) => entry.id === target.item.id);
|
|
131
|
+
if (omittedIndex >= 0)
|
|
132
|
+
state.omitted.splice(omittedIndex, 1);
|
|
133
|
+
usedTokens = usedTokens - exchange.freed + admit.estimatedTokens;
|
|
134
|
+
}
|
|
135
|
+
return usedTokens;
|
|
136
|
+
}
|
|
137
|
+
function writeSelected(planned, selected, state) {
|
|
138
|
+
if (!state.cache)
|
|
139
|
+
return;
|
|
140
|
+
writeRepresentationCacheV2({
|
|
141
|
+
planned,
|
|
142
|
+
selected,
|
|
143
|
+
cache: state.cache,
|
|
144
|
+
materializedEnabled: planned.item.representations === undefined,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Re-offer each selected optional item its costlier representations against
|
|
149
|
+
* the leftover budget (audit F03). The floor pass admits an item at whatever
|
|
150
|
+
* fits the tier's remaining floor and the global pass then skips it by id,
|
|
151
|
+
* so a pointer chosen under a small floor stayed a pointer while most of the
|
|
152
|
+
* budget went unused. Runs once, in selection-rank order, after the global
|
|
153
|
+
* pass; a swap happens only when the selection policy itself prefers the
|
|
154
|
+
* costlier representation under the real remainder and it fits both the
|
|
155
|
+
* tier ceiling and the global budget. It never demotes, never touches hard
|
|
156
|
+
* items, and never spends beyond either cap. Returns the updated token usage.
|
|
157
|
+
*/
|
|
158
|
+
function promoteSelectedRepresentations(optionalPlanned, state) {
|
|
159
|
+
let usedTokens = state.usedTokens;
|
|
160
|
+
for (const planned of optionalPlanned) {
|
|
161
|
+
const current = state.selection.get(planned.item.id);
|
|
162
|
+
if (current === undefined || current.kind === "omit")
|
|
163
|
+
continue;
|
|
164
|
+
const remaining = state.available - usedTokens;
|
|
165
|
+
if (remaining <= 0)
|
|
166
|
+
break;
|
|
167
|
+
const ceiling = state.allocation.get(planned.item.tier)?.ceiling ?? state.available;
|
|
168
|
+
const tierUsedWithout = state.tierUsed[planned.item.tier] - current.estimatedTokens;
|
|
169
|
+
const upgrades = candidatesFor(planned, state).filter((candidate) => candidate.kind !== "omit" &&
|
|
170
|
+
candidate.estimatedTokens > current.estimatedTokens &&
|
|
171
|
+
candidate.estimatedTokens <= remaining + current.estimatedTokens &&
|
|
172
|
+
tierUsedWithout + candidate.estimatedTokens <= ceiling);
|
|
173
|
+
if (upgrades.length === 0)
|
|
174
|
+
continue;
|
|
175
|
+
// Let the policy rank the current choice against every affordable upgrade
|
|
176
|
+
// under the real leftover; only a strictly costlier winner is a promotion.
|
|
177
|
+
const chosen = chooseHeadroomRepresentation({ ...planned.item, representations: [...upgrades, toCandidate(current)] }, {
|
|
178
|
+
tierUsedTokens: tierUsedWithout,
|
|
179
|
+
tierCeilingTokens: ceiling,
|
|
180
|
+
remainingGlobalTokens: remaining + current.estimatedTokens,
|
|
181
|
+
}, state.qualityPolicy);
|
|
182
|
+
if (chosen.kind === "omit" || chosen.estimatedTokens <= current.estimatedTokens)
|
|
183
|
+
continue;
|
|
184
|
+
writeSelected(planned, chosen, state);
|
|
185
|
+
state.tierUsed[planned.item.tier] = tierUsedWithout + chosen.estimatedTokens;
|
|
186
|
+
usedTokens += chosen.estimatedTokens - current.estimatedTokens;
|
|
187
|
+
state.selection.set(planned.item.id, toSelected(planned.item.id, chosen));
|
|
188
|
+
}
|
|
189
|
+
return usedTokens;
|
|
190
|
+
}
|
|
191
|
+
function toCandidate(selected) {
|
|
192
|
+
return {
|
|
193
|
+
kind: selected.kind,
|
|
194
|
+
text: selected.text,
|
|
195
|
+
estimatedTokens: selected.estimatedTokens,
|
|
196
|
+
fidelity: selected.fidelity,
|
|
197
|
+
sourceRef: selected.sourceRef,
|
|
198
|
+
summaryHash: selected.summaryHash,
|
|
199
|
+
compressorId: selected.compressorId,
|
|
200
|
+
cache: selected.cache,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=context-budget-v2-global-pass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-budget-v2-global-pass.js","sourceRoot":"","sources":["../../src/core/context-budget-v2-global-pass.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype ContextRepresentationCandidateV2,\n\tchooseHeadroomRepresentation,\n\tderiveRepresentationCandidates,\n\tisRepresentationEligible,\n\tscoreRepresentationPreferenceV2,\n} from \"./context-budget-headroom.ts\";\nimport { writeRepresentationCacheV2 } from \"./context-budget-v2-cache.ts\";\nimport type { PlannedItemV2 } from \"./context-budget-v2-scoring.ts\";\nimport { type OptionalSelectionState, selectOptionalItem, toSelected } from \"./context-budget-v2-selection.ts\";\nimport type { SelectedRepresentationV2 } from \"./context-budget-v2-types.ts\";\n\n/** Selection state after the floor-reservation passes; `usedTokens` is the running total so far. */\nexport type GlobalPassState = Omit<OptionalSelectionState, \"floorReservation\">;\n\nexport type PromotionState = Pick<\n\tGlobalPassState,\n\t| \"allocation\"\n\t| \"available\"\n\t| \"cache\"\n\t| \"qualityPolicy\"\n\t| \"resolvedCandidates\"\n\t| \"selection\"\n\t| \"tierUsed\"\n\t| \"usedTokens\"\n>;\n\n/**\n * Everything that happens once every tier has spent its floor:\n *\n * 1. the global pass admits still-unselected optional items in rank order\n * under their tier ceilings;\n * 2. the exchange pass lets a still-omitted item pay for its admission by\n * stepping selected items down to their cheapest admissible form (F04);\n * 3. the promotion pass spends whatever is left on costlier representations\n * the policy prefers (F03).\n *\n * Breadth is settled before quality: an exchange that admits another item\n * cannot be undone by a promotion, because promotion only spends the budget\n * the exchange left. Returns the final token usage.\n */\nexport function runGlobalSelectionPass(optionalPlanned: readonly PlannedItemV2[], state: GlobalPassState): number {\n\tlet usedTokens = state.usedTokens;\n\tfor (const planned of optionalPlanned) {\n\t\tif (state.selection.has(planned.item.id)) continue;\n\t\tusedTokens = selectOptionalItem(planned, { ...state, usedTokens });\n\t}\n\tusedTokens = exchangeForOmittedItems(optionalPlanned, { ...state, usedTokens });\n\treturn promoteSelectedRepresentations(optionalPlanned, { ...state, usedTokens });\n}\n\n/** Representations the planner priced for this item, in the order selection saw them. */\nfunction candidatesFor(planned: PlannedItemV2, state: PromotionState): readonly ContextRepresentationCandidateV2[] {\n\treturn (\n\t\tstate.resolvedCandidates?.get(planned.item.id) ??\n\t\tplanned.candidates ??\n\t\tplanned.item.representations ??\n\t\tderiveRepresentationCandidates(planned.item, state.qualityPolicy)\n\t);\n}\n\n/** Cheapest representation the policy would allow at all, ignoring budget. */\nfunction cheapestAdmissible(\n\tplanned: PlannedItemV2,\n\tstate: PromotionState,\n): ContextRepresentationCandidateV2 | undefined {\n\tlet best: ContextRepresentationCandidateV2 | undefined;\n\tfor (const candidate of candidatesFor(planned, state)) {\n\t\tif (candidate.kind === \"omit\") continue;\n\t\tif (!isRepresentationEligible(candidate, planned.item, state.qualityPolicy)) continue;\n\t\tif (best === undefined || candidate.estimatedTokens < best.estimatedTokens) best = candidate;\n\t}\n\treturn best;\n}\n\ninterface PlannedExchange {\n\treadonly swaps: ReadonlyArray<{\n\t\treadonly donor: PlannedItemV2;\n\t\treadonly from: SelectedRepresentationV2;\n\t\treadonly to: ContextRepresentationCandidateV2;\n\t}>;\n\treadonly freed: number;\n}\n\n/**\n * Plan the cheapest set of step-downs that makes room for `cost` tokens in\n * `target`'s tier, or `undefined` when no admissible set exists.\n *\n * Donors are ordered by the preference the policy loses per token freed, so\n * the item whose fidelity matters least to the policy yields first. A donor is\n * skipped when stepping it down would drop its tier below the floor it is\n * currently honouring: the floor is a reservation, not a budget to raid. An\n * empty swap list is legitimate — an earlier exchange may already have freed\n * enough for this item.\n */\nfunction planExchange(\n\ttarget: PlannedItemV2,\n\tcost: number,\n\toptionalPlanned: readonly PlannedItemV2[],\n\tstate: PromotionState,\n\tusedTokens: number,\n): PlannedExchange | undefined {\n\tconst ceilingOf = (tier: PlannedItemV2[\"item\"][\"tier\"]): number =>\n\t\tstate.allocation.get(tier)?.ceiling ?? state.available;\n\tconst floorOf = (tier: PlannedItemV2[\"item\"][\"tier\"]): number => state.allocation.get(tier)?.floor ?? 0;\n\tconst projected = new Map<string, number>();\n\tconst tierNow = (tier: PlannedItemV2[\"item\"][\"tier\"]): number => projected.get(tier) ?? state.tierUsed[tier];\n\n\tconst donors = [];\n\tfor (const donor of optionalPlanned) {\n\t\tif (donor.item.id === target.item.id) continue;\n\t\tconst current = state.selection.get(donor.item.id);\n\t\tif (current === undefined || current.kind === \"omit\") continue;\n\t\tconst cheap = cheapestAdmissible(donor, state);\n\t\tif (cheap === undefined || cheap.estimatedTokens >= current.estimatedTokens) continue;\n\t\tconst freed = current.estimatedTokens - cheap.estimatedTokens;\n\t\tconst from = toCandidate(current);\n\t\tconst loss =\n\t\t\tscoreRepresentationPreferenceV2(from, donor.item, state.qualityPolicy, false) -\n\t\t\tscoreRepresentationPreferenceV2(cheap, donor.item, state.qualityPolicy, false);\n\t\tdonors.push({ donor, current, cheap, freed, lossPerToken: loss / freed });\n\t}\n\tdonors.sort((a, b) => a.lossPerToken - b.lossPerToken || a.donor.item.id.localeCompare(b.donor.item.id));\n\n\tconst swaps: Array<PlannedExchange[\"swaps\"][number]> = [];\n\tlet freed = 0;\n\tconst fits = (): boolean =>\n\t\tcost <= state.available - (usedTokens - freed) && tierNow(target.item.tier) + cost <= ceilingOf(target.item.tier);\n\tfor (const entry of donors) {\n\t\tif (fits()) break;\n\t\tconst after = tierNow(entry.donor.item.tier) - entry.freed;\n\t\tif (tierNow(entry.donor.item.tier) >= floorOf(entry.donor.item.tier) && after < floorOf(entry.donor.item.tier)) {\n\t\t\tcontinue;\n\t\t}\n\t\tprojected.set(entry.donor.item.tier, after);\n\t\tswaps.push({ donor: entry.donor, from: entry.current, to: entry.cheap });\n\t\tfreed += entry.freed;\n\t}\n\treturn fits() ? { swaps, freed } : undefined;\n}\n\n/**\n * Admit still-omitted items by exchanging fidelity for coverage (audit F04).\n *\n * Ranking prices an item by its cheapest admissible representation but the\n * selector may admit it at full text, so one item ranked on a 10-token pointer\n * can spend 100 and displace two 45-token items the policy would rather keep.\n * After the global pass, each omitted item in rank order may buy its cheapest\n * admissible form by stepping selected items down to theirs. The whole exchange\n * is applied or none of it is; tier floors and ceilings hold throughout. This\n * is a bounded repair, not joint `(item, representation)` optimization.\n */\nfunction exchangeForOmittedItems(optionalPlanned: readonly PlannedItemV2[], state: GlobalPassState): number {\n\tlet usedTokens = state.usedTokens;\n\tfor (const target of optionalPlanned) {\n\t\tif (state.selection.has(target.item.id)) continue;\n\t\tconst admit = cheapestAdmissible(target, state);\n\t\tif (admit === undefined) continue;\n\t\tconst exchange = planExchange(target, admit.estimatedTokens, optionalPlanned, state, usedTokens);\n\t\tif (exchange === undefined) continue;\n\t\tfor (const swap of exchange.swaps) {\n\t\t\tstate.tierUsed[swap.donor.item.tier] += swap.to.estimatedTokens - swap.from.estimatedTokens;\n\t\t\tstate.selection.set(swap.donor.item.id, toSelected(swap.donor.item.id, swap.to));\n\t\t\twriteSelected(swap.donor, swap.to, state);\n\t\t}\n\t\tstate.tierUsed[target.item.tier] += admit.estimatedTokens;\n\t\tstate.selection.set(target.item.id, toSelected(target.item.id, admit));\n\t\twriteSelected(target, admit, state);\n\t\t// The global pass already recorded this item as omitted; an admitted item\n\t\t// must leave that list, or the plan reports it as both included and\n\t\t// omitted and bills its full text in omittedTokens.\n\t\tconst omittedIndex = state.omitted.findIndex((entry) => entry.id === target.item.id);\n\t\tif (omittedIndex >= 0) state.omitted.splice(omittedIndex, 1);\n\t\tusedTokens = usedTokens - exchange.freed + admit.estimatedTokens;\n\t}\n\treturn usedTokens;\n}\n\nfunction writeSelected(\n\tplanned: PlannedItemV2,\n\tselected: ContextRepresentationCandidateV2,\n\tstate: PromotionState,\n): void {\n\tif (!state.cache) return;\n\twriteRepresentationCacheV2({\n\t\tplanned,\n\t\tselected,\n\t\tcache: state.cache,\n\t\tmaterializedEnabled: planned.item.representations === undefined,\n\t});\n}\n\n/**\n * Re-offer each selected optional item its costlier representations against\n * the leftover budget (audit F03). The floor pass admits an item at whatever\n * fits the tier's remaining floor and the global pass then skips it by id,\n * so a pointer chosen under a small floor stayed a pointer while most of the\n * budget went unused. Runs once, in selection-rank order, after the global\n * pass; a swap happens only when the selection policy itself prefers the\n * costlier representation under the real remainder and it fits both the\n * tier ceiling and the global budget. It never demotes, never touches hard\n * items, and never spends beyond either cap. Returns the updated token usage.\n */\nfunction promoteSelectedRepresentations(optionalPlanned: readonly PlannedItemV2[], state: PromotionState): number {\n\tlet usedTokens = state.usedTokens;\n\tfor (const planned of optionalPlanned) {\n\t\tconst current = state.selection.get(planned.item.id);\n\t\tif (current === undefined || current.kind === \"omit\") continue;\n\t\tconst remaining = state.available - usedTokens;\n\t\tif (remaining <= 0) break;\n\t\tconst ceiling = state.allocation.get(planned.item.tier)?.ceiling ?? state.available;\n\t\tconst tierUsedWithout = state.tierUsed[planned.item.tier] - current.estimatedTokens;\n\t\tconst upgrades = candidatesFor(planned, state).filter(\n\t\t\t(candidate) =>\n\t\t\t\tcandidate.kind !== \"omit\" &&\n\t\t\t\tcandidate.estimatedTokens > current.estimatedTokens &&\n\t\t\t\tcandidate.estimatedTokens <= remaining + current.estimatedTokens &&\n\t\t\t\ttierUsedWithout + candidate.estimatedTokens <= ceiling,\n\t\t);\n\t\tif (upgrades.length === 0) continue;\n\t\t// Let the policy rank the current choice against every affordable upgrade\n\t\t// under the real leftover; only a strictly costlier winner is a promotion.\n\t\tconst chosen = chooseHeadroomRepresentation(\n\t\t\t{ ...planned.item, representations: [...upgrades, toCandidate(current)] },\n\t\t\t{\n\t\t\t\ttierUsedTokens: tierUsedWithout,\n\t\t\t\ttierCeilingTokens: ceiling,\n\t\t\t\tremainingGlobalTokens: remaining + current.estimatedTokens,\n\t\t\t},\n\t\t\tstate.qualityPolicy,\n\t\t);\n\t\tif (chosen.kind === \"omit\" || chosen.estimatedTokens <= current.estimatedTokens) continue;\n\t\twriteSelected(planned, chosen, state);\n\t\tstate.tierUsed[planned.item.tier] = tierUsedWithout + chosen.estimatedTokens;\n\t\tusedTokens += chosen.estimatedTokens - current.estimatedTokens;\n\t\tstate.selection.set(planned.item.id, toSelected(planned.item.id, chosen));\n\t}\n\treturn usedTokens;\n}\n\nfunction toCandidate(selected: SelectedRepresentationV2): ContextRepresentationCandidateV2 {\n\treturn {\n\t\tkind: selected.kind,\n\t\ttext: selected.text,\n\t\testimatedTokens: selected.estimatedTokens,\n\t\tfidelity: selected.fidelity,\n\t\tsourceRef: selected.sourceRef,\n\t\tsummaryHash: selected.summaryHash,\n\t\tcompressorId: selected.compressorId,\n\t\tcache: selected.cache,\n\t};\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ContextBudgetItemV2 } from "./context-budget-headroom.ts";
|
|
2
|
+
import { type QualityDiagnosticV2 } from "./context-budget-v2-types.ts";
|
|
3
|
+
export declare function validateBudgetItems(items: readonly ContextBudgetItemV2[], diagnostics: QualityDiagnosticV2[]): ContextBudgetItemV2[];
|
|
4
|
+
//# sourceMappingURL=context-budget-v2-input-validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-budget-v2-input-validation.d.ts","sourceRoot":"","sources":["../../src/core/context-budget-v2-input-validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAgB,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAatF,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,SAAS,mBAAmB,EAAE,EACrC,WAAW,EAAE,mBAAmB,EAAE,GAChC,mBAAmB,EAAE,CAoEvB","sourcesContent":["import type { ContextBudgetItemV2 } from \"./context-budget-headroom.ts\";\nimport { ALL_TIERS_V2, type QualityDiagnosticV2 } from \"./context-budget-v2-types.ts\";\n\n/**\n * Input boundary for the planner (audit §13): selection is keyed by `item.id`,\n * so a duplicate id would silently overwrite an earlier selection while its\n * tokens still counted twice in demand; a NaN or negative numeric field\n * poisons every budget sum it touches; an unregistered tier lands in no\n * allocation and corrupts `tierUsed` with NaN. Identity violations drop the\n * item with a diagnostic; invalid numeric fields are dropped and recomputed\n * rather than silently corrected.\n */\nconst KNOWN_TIERS_V2 = new Set<string>(ALL_TIERS_V2);\n\nexport function validateBudgetItems(\n\titems: readonly ContextBudgetItemV2[],\n\tdiagnostics: QualityDiagnosticV2[],\n): ContextBudgetItemV2[] {\n\tconst seen = new Set<string>();\n\tconst out: ContextBudgetItemV2[] = [];\n\tfor (const [position, item] of items.entries()) {\n\t\tif (typeof item.id !== \"string\" || item.id.length === 0) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"invalid_input\",\n\t\t\t\tdetail: `items[${position}] has a missing or non-string id and was dropped`,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (seen.has(item.id)) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"invalid_input\",\n\t\t\t\titemId: item.id,\n\t\t\t\tdetail: `duplicate item id \"${item.id}\" dropped — a later entry would overwrite the earlier selection`,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(item.id);\n\t\tif (!KNOWN_TIERS_V2.has(item.tier)) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"invalid_input\",\n\t\t\t\titemId: item.id,\n\t\t\t\tdetail: `item \"${item.id}\" has unregistered tier \"${String(item.tier)}\" and was dropped`,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tlet sanitized = item;\n\t\tif (item.tokenEstimate !== undefined && (!Number.isFinite(item.tokenEstimate) || item.tokenEstimate < 0)) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"invalid_input\",\n\t\t\t\titemId: item.id,\n\t\t\t\tdetail: `item \"${item.id}\" tokenEstimate ${item.tokenEstimate} is not a finite non-negative number; recomputed from text`,\n\t\t\t});\n\t\t\tsanitized = { ...sanitized, tokenEstimate: undefined };\n\t\t}\n\t\tif (item.representations !== undefined) {\n\t\t\tconst reps = item.representations.filter((rep) => {\n\t\t\t\tif (!Number.isFinite(rep.estimatedTokens) || rep.estimatedTokens < 0) {\n\t\t\t\t\tdiagnostics.push({\n\t\t\t\t\t\treason: \"invalid_input\",\n\t\t\t\t\t\titemId: item.id,\n\t\t\t\t\t\tdetail: `item \"${item.id}\" ${rep.kind} representation cost ${rep.estimatedTokens} is not a finite non-negative number; dropped`,\n\t\t\t\t\t});\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t});\n\t\t\tif (reps.length !== item.representations.length) {\n\t\t\t\tsanitized = { ...sanitized, representations: reps };\n\t\t\t}\n\t\t}\n\t\tif (\n\t\t\titem.priority !== \"hard\" &&\n\t\t\titem.priority !== \"high\" &&\n\t\t\titem.priority !== \"medium\" &&\n\t\t\titem.priority !== \"low\"\n\t\t) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"invalid_input\",\n\t\t\t\titemId: item.id,\n\t\t\t\tdetail: `item \"${item.id}\" has unknown priority \"${String(item.priority)}\"; scored without a priority weight`,\n\t\t\t});\n\t\t}\n\t\tout.push(sanitized);\n\t}\n\treturn out;\n}\n"]}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ALL_TIERS_V2 } from "./context-budget-v2-types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Input boundary for the planner (audit §13): selection is keyed by `item.id`,
|
|
4
|
+
* so a duplicate id would silently overwrite an earlier selection while its
|
|
5
|
+
* tokens still counted twice in demand; a NaN or negative numeric field
|
|
6
|
+
* poisons every budget sum it touches; an unregistered tier lands in no
|
|
7
|
+
* allocation and corrupts `tierUsed` with NaN. Identity violations drop the
|
|
8
|
+
* item with a diagnostic; invalid numeric fields are dropped and recomputed
|
|
9
|
+
* rather than silently corrected.
|
|
10
|
+
*/
|
|
11
|
+
const KNOWN_TIERS_V2 = new Set(ALL_TIERS_V2);
|
|
12
|
+
export function validateBudgetItems(items, diagnostics) {
|
|
13
|
+
const seen = new Set();
|
|
14
|
+
const out = [];
|
|
15
|
+
for (const [position, item] of items.entries()) {
|
|
16
|
+
if (typeof item.id !== "string" || item.id.length === 0) {
|
|
17
|
+
diagnostics.push({
|
|
18
|
+
reason: "invalid_input",
|
|
19
|
+
detail: `items[${position}] has a missing or non-string id and was dropped`,
|
|
20
|
+
});
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (seen.has(item.id)) {
|
|
24
|
+
diagnostics.push({
|
|
25
|
+
reason: "invalid_input",
|
|
26
|
+
itemId: item.id,
|
|
27
|
+
detail: `duplicate item id "${item.id}" dropped — a later entry would overwrite the earlier selection`,
|
|
28
|
+
});
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
seen.add(item.id);
|
|
32
|
+
if (!KNOWN_TIERS_V2.has(item.tier)) {
|
|
33
|
+
diagnostics.push({
|
|
34
|
+
reason: "invalid_input",
|
|
35
|
+
itemId: item.id,
|
|
36
|
+
detail: `item "${item.id}" has unregistered tier "${String(item.tier)}" and was dropped`,
|
|
37
|
+
});
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
let sanitized = item;
|
|
41
|
+
if (item.tokenEstimate !== undefined && (!Number.isFinite(item.tokenEstimate) || item.tokenEstimate < 0)) {
|
|
42
|
+
diagnostics.push({
|
|
43
|
+
reason: "invalid_input",
|
|
44
|
+
itemId: item.id,
|
|
45
|
+
detail: `item "${item.id}" tokenEstimate ${item.tokenEstimate} is not a finite non-negative number; recomputed from text`,
|
|
46
|
+
});
|
|
47
|
+
sanitized = { ...sanitized, tokenEstimate: undefined };
|
|
48
|
+
}
|
|
49
|
+
if (item.representations !== undefined) {
|
|
50
|
+
const reps = item.representations.filter((rep) => {
|
|
51
|
+
if (!Number.isFinite(rep.estimatedTokens) || rep.estimatedTokens < 0) {
|
|
52
|
+
diagnostics.push({
|
|
53
|
+
reason: "invalid_input",
|
|
54
|
+
itemId: item.id,
|
|
55
|
+
detail: `item "${item.id}" ${rep.kind} representation cost ${rep.estimatedTokens} is not a finite non-negative number; dropped`,
|
|
56
|
+
});
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
});
|
|
61
|
+
if (reps.length !== item.representations.length) {
|
|
62
|
+
sanitized = { ...sanitized, representations: reps };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (item.priority !== "hard" &&
|
|
66
|
+
item.priority !== "high" &&
|
|
67
|
+
item.priority !== "medium" &&
|
|
68
|
+
item.priority !== "low") {
|
|
69
|
+
diagnostics.push({
|
|
70
|
+
reason: "invalid_input",
|
|
71
|
+
itemId: item.id,
|
|
72
|
+
detail: `item "${item.id}" has unknown priority "${String(item.priority)}"; scored without a priority weight`,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
out.push(sanitized);
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=context-budget-v2-input-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-budget-v2-input-validation.js","sourceRoot":"","sources":["../../src/core/context-budget-v2-input-validation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ContextBudgetItemV2 } from \"./context-budget-headroom.ts\";\nimport { ALL_TIERS_V2, type QualityDiagnosticV2 } from \"./context-budget-v2-types.ts\";\n\n/**\n * Input boundary for the planner (audit §13): selection is keyed by `item.id`,\n * so a duplicate id would silently overwrite an earlier selection while its\n * tokens still counted twice in demand; a NaN or negative numeric field\n * poisons every budget sum it touches; an unregistered tier lands in no\n * allocation and corrupts `tierUsed` with NaN. Identity violations drop the\n * item with a diagnostic; invalid numeric fields are dropped and recomputed\n * rather than silently corrected.\n */\nconst KNOWN_TIERS_V2 = new Set<string>(ALL_TIERS_V2);\n\nexport function validateBudgetItems(\n\titems: readonly ContextBudgetItemV2[],\n\tdiagnostics: QualityDiagnosticV2[],\n): ContextBudgetItemV2[] {\n\tconst seen = new Set<string>();\n\tconst out: ContextBudgetItemV2[] = [];\n\tfor (const [position, item] of items.entries()) {\n\t\tif (typeof item.id !== \"string\" || item.id.length === 0) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"invalid_input\",\n\t\t\t\tdetail: `items[${position}] has a missing or non-string id and was dropped`,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (seen.has(item.id)) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"invalid_input\",\n\t\t\t\titemId: item.id,\n\t\t\t\tdetail: `duplicate item id \"${item.id}\" dropped — a later entry would overwrite the earlier selection`,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(item.id);\n\t\tif (!KNOWN_TIERS_V2.has(item.tier)) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"invalid_input\",\n\t\t\t\titemId: item.id,\n\t\t\t\tdetail: `item \"${item.id}\" has unregistered tier \"${String(item.tier)}\" and was dropped`,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tlet sanitized = item;\n\t\tif (item.tokenEstimate !== undefined && (!Number.isFinite(item.tokenEstimate) || item.tokenEstimate < 0)) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"invalid_input\",\n\t\t\t\titemId: item.id,\n\t\t\t\tdetail: `item \"${item.id}\" tokenEstimate ${item.tokenEstimate} is not a finite non-negative number; recomputed from text`,\n\t\t\t});\n\t\t\tsanitized = { ...sanitized, tokenEstimate: undefined };\n\t\t}\n\t\tif (item.representations !== undefined) {\n\t\t\tconst reps = item.representations.filter((rep) => {\n\t\t\t\tif (!Number.isFinite(rep.estimatedTokens) || rep.estimatedTokens < 0) {\n\t\t\t\t\tdiagnostics.push({\n\t\t\t\t\t\treason: \"invalid_input\",\n\t\t\t\t\t\titemId: item.id,\n\t\t\t\t\t\tdetail: `item \"${item.id}\" ${rep.kind} representation cost ${rep.estimatedTokens} is not a finite non-negative number; dropped`,\n\t\t\t\t\t});\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t});\n\t\t\tif (reps.length !== item.representations.length) {\n\t\t\t\tsanitized = { ...sanitized, representations: reps };\n\t\t\t}\n\t\t}\n\t\tif (\n\t\t\titem.priority !== \"hard\" &&\n\t\t\titem.priority !== \"high\" &&\n\t\t\titem.priority !== \"medium\" &&\n\t\t\titem.priority !== \"low\"\n\t\t) {\n\t\t\tdiagnostics.push({\n\t\t\t\treason: \"invalid_input\",\n\t\t\t\titemId: item.id,\n\t\t\t\tdetail: `item \"${item.id}\" has unknown priority \"${String(item.priority)}\"; scored without a priority weight`,\n\t\t\t});\n\t\t}\n\t\tout.push(sanitized);\n\t}\n\treturn out;\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ContextSourceRefV2 } from "./context-budget-headroom.ts";
|
|
2
|
+
import type { PromptContextBudgetObservabilityV2, QualityDiagnosticV2, SelectedRepresentationV2 } from "./context-budget-v2-types.ts";
|
|
3
|
+
export declare function buildObservability(input: {
|
|
4
|
+
readonly available: number;
|
|
5
|
+
readonly diagnostics: readonly QualityDiagnosticV2[];
|
|
6
|
+
readonly omittedItemIds: readonly string[];
|
|
7
|
+
readonly omittedTokens: number;
|
|
8
|
+
readonly planHash: string;
|
|
9
|
+
readonly rawTokens: number;
|
|
10
|
+
readonly retrievalFallbacks: readonly ContextSourceRefV2[];
|
|
11
|
+
readonly selection: ReadonlyMap<string, SelectedRepresentationV2>;
|
|
12
|
+
readonly usedTokens: number;
|
|
13
|
+
readonly cacheTelemetry: PromptContextBudgetObservabilityV2["cache"];
|
|
14
|
+
}): PromptContextBudgetObservabilityV2;
|
|
15
|
+
//# sourceMappingURL=context-budget-v2-observability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-budget-v2-observability.d.ts","sourceRoot":"","sources":["../../src/core/context-budget-v2-observability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,KAAK,EACX,kCAAkC,EAClC,mBAAmB,EACnB,wBAAwB,EAExB,MAAM,8BAA8B,CAAC;AAUtC,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACzC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACrD,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,kBAAkB,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC3D,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;IAClE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,kCAAkC,CAAC,OAAO,CAAC,CAAC;CACrE,GAAG,kCAAkC,CAuBrC","sourcesContent":["import type { ContextSourceRefV2 } from \"./context-budget-headroom.ts\";\nimport type {\n\tPromptContextBudgetObservabilityV2,\n\tQualityDiagnosticV2,\n\tSelectedRepresentationV2,\n\tTokenOptimizerRuntimeStatus,\n} from \"./context-budget-v2-types.ts\";\n\nconst TOKEN_OPTIMIZER_RUNTIME_STATUS: TokenOptimizerRuntimeStatus = {\n\toptimizerId: \"legacy-token-optimizer\",\n\tstatus: \"quarantined_compatibility\",\n\tactive: false,\n\tactiveContextBudgetOptimizer: \"context-budget-v2\",\n\tcompatibilityOnly: true,\n};\n\nexport function buildObservability(input: {\n\treadonly available: number;\n\treadonly diagnostics: readonly QualityDiagnosticV2[];\n\treadonly omittedItemIds: readonly string[];\n\treadonly omittedTokens: number;\n\treadonly planHash: string;\n\treadonly rawTokens: number;\n\treadonly retrievalFallbacks: readonly ContextSourceRefV2[];\n\treadonly selection: ReadonlyMap<string, SelectedRepresentationV2>;\n\treadonly usedTokens: number;\n\treadonly cacheTelemetry: PromptContextBudgetObservabilityV2[\"cache\"];\n}): PromptContextBudgetObservabilityV2 {\n\tconst selected = [...input.selection.values()];\n\treturn {\n\t\tcounts: {\n\t\t\tselected: selected.length,\n\t\t\tomitted: input.omittedItemIds.length,\n\t\t\tpointer: selected.filter((representation) => representation.kind === \"pointer\").length,\n\t\t\tcompressed: selected.filter((representation) => representation.kind === \"headroom-compressed\").length,\n\t\t\tfull: selected.filter((representation) => representation.kind === \"full\").length,\n\t\t\tretrievalFallback: countUniqueRetrievalFallbacks(input.retrievalFallbacks),\n\t\t},\n\t\tdiagnosticReasons: [...new Set(input.diagnostics.map((diagnostic) => diagnostic.reason))].sort(),\n\t\ttokens: {\n\t\t\tavailable: input.available,\n\t\t\tused: input.usedTokens,\n\t\t\traw: input.rawTokens,\n\t\t\tomitted: input.omittedTokens,\n\t\t\ttokenSavings: Math.max(0, input.rawTokens - input.usedTokens),\n\t\t},\n\t\tplanHash: input.planHash,\n\t\tcache: input.cacheTelemetry,\n\t\ttokenOptimizer: TOKEN_OPTIMIZER_RUNTIME_STATUS,\n\t};\n}\n\nfunction countUniqueRetrievalFallbacks(retrievalFallbacks: readonly ContextSourceRefV2[]): number {\n\treturn new Set(\n\t\tretrievalFallbacks.map((ref) =>\n\t\t\t[ref.uri, ref.contentHash, ref.symbol ?? \"\", ref.range?.startLine ?? \"\", ref.range?.endLine ?? \"\"].join(\"\\0\"),\n\t\t),\n\t).size;\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const TOKEN_OPTIMIZER_RUNTIME_STATUS = {
|
|
2
|
+
optimizerId: "legacy-token-optimizer",
|
|
3
|
+
status: "quarantined_compatibility",
|
|
4
|
+
active: false,
|
|
5
|
+
activeContextBudgetOptimizer: "context-budget-v2",
|
|
6
|
+
compatibilityOnly: true,
|
|
7
|
+
};
|
|
8
|
+
export function buildObservability(input) {
|
|
9
|
+
const selected = [...input.selection.values()];
|
|
10
|
+
return {
|
|
11
|
+
counts: {
|
|
12
|
+
selected: selected.length,
|
|
13
|
+
omitted: input.omittedItemIds.length,
|
|
14
|
+
pointer: selected.filter((representation) => representation.kind === "pointer").length,
|
|
15
|
+
compressed: selected.filter((representation) => representation.kind === "headroom-compressed").length,
|
|
16
|
+
full: selected.filter((representation) => representation.kind === "full").length,
|
|
17
|
+
retrievalFallback: countUniqueRetrievalFallbacks(input.retrievalFallbacks),
|
|
18
|
+
},
|
|
19
|
+
diagnosticReasons: [...new Set(input.diagnostics.map((diagnostic) => diagnostic.reason))].sort(),
|
|
20
|
+
tokens: {
|
|
21
|
+
available: input.available,
|
|
22
|
+
used: input.usedTokens,
|
|
23
|
+
raw: input.rawTokens,
|
|
24
|
+
omitted: input.omittedTokens,
|
|
25
|
+
tokenSavings: Math.max(0, input.rawTokens - input.usedTokens),
|
|
26
|
+
},
|
|
27
|
+
planHash: input.planHash,
|
|
28
|
+
cache: input.cacheTelemetry,
|
|
29
|
+
tokenOptimizer: TOKEN_OPTIMIZER_RUNTIME_STATUS,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function countUniqueRetrievalFallbacks(retrievalFallbacks) {
|
|
33
|
+
return new Set(retrievalFallbacks.map((ref) => [ref.uri, ref.contentHash, ref.symbol ?? "", ref.range?.startLine ?? "", ref.range?.endLine ?? ""].join("\0"))).size;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=context-budget-v2-observability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-budget-v2-observability.js","sourceRoot":"","sources":["../../src/core/context-budget-v2-observability.ts"],"names":[],"mappings":"AAQA,MAAM,8BAA8B,GAAgC;IACnE,WAAW,EAAE,wBAAwB;IACrC,MAAM,EAAE,2BAA2B;IACnC,MAAM,EAAE,KAAK;IACb,4BAA4B,EAAE,mBAAmB;IACjD,iBAAiB,EAAE,IAAI;CACvB,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAAC,KAWlC,EAAsC;IACtC,MAAM,QAAQ,GAAG,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/C,OAAO;QACN,MAAM,EAAE;YACP,QAAQ,EAAE,QAAQ,CAAC,MAAM;YACzB,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM;YACpC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,MAAM;YACtF,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,KAAK,qBAAqB,CAAC,CAAC,MAAM;YACrG,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,MAAM;YAChF,iBAAiB,EAAE,6BAA6B,CAAC,KAAK,CAAC,kBAAkB,CAAC;SAC1E;QACD,iBAAiB,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;QAChG,MAAM,EAAE;YACP,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,IAAI,EAAE,KAAK,CAAC,UAAU;YACtB,GAAG,EAAE,KAAK,CAAC,SAAS;YACpB,OAAO,EAAE,KAAK,CAAC,aAAa;YAC5B,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,UAAU,CAAC;SAC7D;QACD,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,KAAK,EAAE,KAAK,CAAC,cAAc;QAC3B,cAAc,EAAE,8BAA8B;KAC9C,CAAC;AAAA,CACF;AAED,SAAS,6BAA6B,CAAC,kBAAiD,EAAU;IACjG,OAAO,IAAI,GAAG,CACb,kBAAkB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAC9B,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,GAAG,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,EAAE,GAAG,CAAC,KAAK,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAC7G,CACD,CAAC,IAAI,CAAC;AAAA,CACP","sourcesContent":["import type { ContextSourceRefV2 } from \"./context-budget-headroom.ts\";\nimport type {\n\tPromptContextBudgetObservabilityV2,\n\tQualityDiagnosticV2,\n\tSelectedRepresentationV2,\n\tTokenOptimizerRuntimeStatus,\n} from \"./context-budget-v2-types.ts\";\n\nconst TOKEN_OPTIMIZER_RUNTIME_STATUS: TokenOptimizerRuntimeStatus = {\n\toptimizerId: \"legacy-token-optimizer\",\n\tstatus: \"quarantined_compatibility\",\n\tactive: false,\n\tactiveContextBudgetOptimizer: \"context-budget-v2\",\n\tcompatibilityOnly: true,\n};\n\nexport function buildObservability(input: {\n\treadonly available: number;\n\treadonly diagnostics: readonly QualityDiagnosticV2[];\n\treadonly omittedItemIds: readonly string[];\n\treadonly omittedTokens: number;\n\treadonly planHash: string;\n\treadonly rawTokens: number;\n\treadonly retrievalFallbacks: readonly ContextSourceRefV2[];\n\treadonly selection: ReadonlyMap<string, SelectedRepresentationV2>;\n\treadonly usedTokens: number;\n\treadonly cacheTelemetry: PromptContextBudgetObservabilityV2[\"cache\"];\n}): PromptContextBudgetObservabilityV2 {\n\tconst selected = [...input.selection.values()];\n\treturn {\n\t\tcounts: {\n\t\t\tselected: selected.length,\n\t\t\tomitted: input.omittedItemIds.length,\n\t\t\tpointer: selected.filter((representation) => representation.kind === \"pointer\").length,\n\t\t\tcompressed: selected.filter((representation) => representation.kind === \"headroom-compressed\").length,\n\t\t\tfull: selected.filter((representation) => representation.kind === \"full\").length,\n\t\t\tretrievalFallback: countUniqueRetrievalFallbacks(input.retrievalFallbacks),\n\t\t},\n\t\tdiagnosticReasons: [...new Set(input.diagnostics.map((diagnostic) => diagnostic.reason))].sort(),\n\t\ttokens: {\n\t\t\tavailable: input.available,\n\t\t\tused: input.usedTokens,\n\t\t\traw: input.rawTokens,\n\t\t\tomitted: input.omittedTokens,\n\t\t\ttokenSavings: Math.max(0, input.rawTokens - input.usedTokens),\n\t\t},\n\t\tplanHash: input.planHash,\n\t\tcache: input.cacheTelemetry,\n\t\ttokenOptimizer: TOKEN_OPTIMIZER_RUNTIME_STATUS,\n\t};\n}\n\nfunction countUniqueRetrievalFallbacks(retrievalFallbacks: readonly ContextSourceRefV2[]): number {\n\treturn new Set(\n\t\tretrievalFallbacks.map((ref) =>\n\t\t\t[ref.uri, ref.contentHash, ref.symbol ?? \"\", ref.range?.startLine ?? \"\", ref.range?.endLine ?? \"\"].join(\"\\0\"),\n\t\t),\n\t).size;\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ContextBudgetItemV2, deriveRepresentationCandidates } from "./context-budget-headroom.ts";
|
|
2
|
+
import { type TokenCounterAdapter } from "./context-budget-token-counter.ts";
|
|
3
|
+
import { type PlannedItemV2 } from "./context-budget-v2-scoring.ts";
|
|
4
|
+
/**
|
|
5
|
+
* Identity of the adapter that actually prices this run's text.
|
|
6
|
+
*
|
|
7
|
+
* Every representation price now depends on the planner's counter (audit F01),
|
|
8
|
+
* but the materialized representation key is bucketed rather than exact, so the
|
|
9
|
+
* static `heuristic-v1` default let two counters share one key space: a run
|
|
10
|
+
* could admit text at a price its own counter never produced, and the entry's
|
|
11
|
+
* `tokenizer_mismatch` check compared that constant against itself. Probe a
|
|
12
|
+
* non-empty string, because `countText("")` short-circuits to the fallback
|
|
13
|
+
* estimator in the registry and would report the wrong adapter.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveEffectiveTokenizerIdV2(tokenCounter: TokenCounterAdapter | undefined, modelId: string): string;
|
|
16
|
+
export declare function createPlannedItems(items: readonly ContextBudgetItemV2[], tokenCounter: TokenCounterAdapter | undefined, modelId: string, qualityPolicy?: Parameters<typeof deriveRepresentationCandidates>[1]): PlannedItemV2[];
|
|
17
|
+
//# sourceMappingURL=context-budget-v2-planned-items.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-budget-v2-planned-items.d.ts","sourceRoot":"","sources":["../../src/core/context-budget-v2-planned-items.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,mBAAmB,EAExB,8BAA8B,EAI9B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAA8B,KAAK,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAEzG,OAAO,EAAE,KAAK,aAAa,EAA4B,MAAM,gCAAgC,CAAC;AAwB9F;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,mBAAmB,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpH;AAED,wBAAgB,kBAAkB,CACjC,KAAK,EAAE,SAAS,mBAAmB,EAAE,EACrC,YAAY,EAAE,mBAAmB,GAAG,SAAS,EAC7C,OAAO,EAAE,MAAM,EACf,aAAa,CAAC,EAAE,UAAU,CAAC,OAAO,8BAA8B,CAAC,CAAC,CAAC,CAAC,GAClE,aAAa,EAAE,CA2BjB","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"]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { deriveRepresentationCandidates, fullTextTokens, isRepresentationEligible, } from "./context-budget-headroom.js";
|
|
2
|
+
import { createFallbackTokenCounter } from "./context-budget-token-counter.js";
|
|
3
|
+
import { contentHashOf } from "./context-budget-v2-plan-hash.js";
|
|
4
|
+
import { scoreContextBudgetItemV2 } from "./context-budget-v2-scoring.js";
|
|
5
|
+
// Cheapest representation the chooser could actually pick: only candidates
|
|
6
|
+
// passing the selection policy gate count, so a pointer the chooser would
|
|
7
|
+
// reject cannot make an item look cheaper to admit than it is.
|
|
8
|
+
function minAdmissibleTokens(candidates, item, policy, fullTokens) {
|
|
9
|
+
let min = Number.POSITIVE_INFINITY;
|
|
10
|
+
for (const candidate of candidates) {
|
|
11
|
+
if (candidate.kind !== "omit" &&
|
|
12
|
+
isRepresentationEligible(candidate, item, policy) &&
|
|
13
|
+
candidate.estimatedTokens < min) {
|
|
14
|
+
min = candidate.estimatedTokens;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return Math.max(1, Number.isFinite(min) ? min : fullTokens);
|
|
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
|
+
}
|
|
33
|
+
export function createPlannedItems(items, tokenCounter, modelId, qualityPolicy) {
|
|
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;
|
|
39
|
+
return items.map((item) => {
|
|
40
|
+
const overrideTokenEstimate = item.tokenEstimate ?? countTokens(item.text);
|
|
41
|
+
const itemWithTokens = item.tokenEstimate === undefined ? { ...item, tokenEstimate: overrideTokenEstimate } : item;
|
|
42
|
+
const fullTokens = fullTextTokens(itemWithTokens);
|
|
43
|
+
const isHard = item.priority === "hard" || item.required === true;
|
|
44
|
+
const baseScore = isHard ? Number.POSITIVE_INFINITY : scoreContextBudgetItemV2(itemWithTokens, fullTokens);
|
|
45
|
+
const candidates = itemWithTokens.representations ?? deriveRepresentationCandidates(itemWithTokens, qualityPolicy, countTokens);
|
|
46
|
+
return {
|
|
47
|
+
item: itemWithTokens,
|
|
48
|
+
fullTokens,
|
|
49
|
+
admissibleTokens: minAdmissibleTokens(candidates, itemWithTokens, qualityPolicy, fullTokens),
|
|
50
|
+
candidates,
|
|
51
|
+
contentHash: contentHashOf(item.text),
|
|
52
|
+
baseScore,
|
|
53
|
+
redundancyPenalty: 0,
|
|
54
|
+
effectiveScore: baseScore,
|
|
55
|
+
isHard,
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=context-budget-v2-planned-items.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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":"AA2BA,OAAO,EAGN,KAAK,0BAA0B,EAE/B,KAAK,yBAAyB,EAK9B,MAAM,8BAA8B,CAAC;AAUtC,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,0BAA0B,GAAG,yBAAyB,CA8KtG","sourcesContent":["import {\n\ttype ContextBudgetItemV2,\n\ttype ContextBudgetTierV2,\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 { computePlanHash } from \"./context-budget-v2-plan-hash.ts\";\nimport { compareOptionalForSelection } from \"./context-budget-v2-scoring.ts\";\nimport {\n\tapplyPlannerRedundancyPenalties,\n\tbuildTierAllocations,\n\tcreatePlannedItems,\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\tCONTEXT_BUDGET_POLICY_VERSION_V2,\n\tDEFAULT_TIER_POLICY_V2,\n\ttype PromptContextBudgetInputV2,\n\ttype PromptContextBudgetObservabilityV2,\n\ttype PromptContextBudgetPlanV2,\n\ttype QualityDiagnosticV2,\n\ttype SelectedRepresentationV2,\n\ttype TierBudgetPolicyV2,\n\ttype TokenOptimizerRuntimeStatus,\n} from \"./context-budget-v2-types.ts\";\n\nconst TOKEN_OPTIMIZER_RUNTIME_STATUS: TokenOptimizerRuntimeStatus = {\n\toptimizerId: \"legacy-token-optimizer\",\n\tstatus: \"quarantined_compatibility\",\n\tactive: false,\n\tactiveContextBudgetOptimizer: \"context-budget-v2\",\n\tcompatibilityOnly: true,\n};\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\tconst canUsePlanCache = !diagnostics.some((diagnostic) => diagnostic.reason === \"invalid_budget\");\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(input.items, input.tokenCounter, modelId, qualityPolicy);\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\tfor (const planned of optionalPlanned) {\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\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\nfunction buildObservability(input: {\n\treadonly available: number;\n\treadonly diagnostics: readonly QualityDiagnosticV2[];\n\treadonly omittedItemIds: readonly string[];\n\treadonly omittedTokens: number;\n\treadonly planHash: string;\n\treadonly rawTokens: number;\n\treadonly retrievalFallbacks: readonly ContextSourceRefV2[];\n\treadonly selection: ReadonlyMap<string, SelectedRepresentationV2>;\n\treadonly usedTokens: number;\n\treadonly cacheTelemetry: PromptContextBudgetObservabilityV2[\"cache\"];\n}): PromptContextBudgetObservabilityV2 {\n\tconst selected = [...input.selection.values()];\n\treturn {\n\t\tcounts: {\n\t\t\tselected: selected.length,\n\t\t\tomitted: input.omittedItemIds.length,\n\t\t\tpointer: selected.filter((representation) => representation.kind === \"pointer\").length,\n\t\t\tcompressed: selected.filter((representation) => representation.kind === \"headroom-compressed\").length,\n\t\t\tfull: selected.filter((representation) => representation.kind === \"full\").length,\n\t\t\tretrievalFallback: countUniqueRetrievalFallbacks(input.retrievalFallbacks),\n\t\t},\n\t\tdiagnosticReasons: [...new Set(input.diagnostics.map((diagnostic) => diagnostic.reason))].sort(),\n\t\ttokens: {\n\t\t\tavailable: input.available,\n\t\t\tused: input.usedTokens,\n\t\t\traw: input.rawTokens,\n\t\t\tomitted: input.omittedTokens,\n\t\t\ttokenSavings: Math.max(0, input.rawTokens - input.usedTokens),\n\t\t},\n\t\tplanHash: input.planHash,\n\t\tcache: input.cacheTelemetry,\n\t\ttokenOptimizer: TOKEN_OPTIMIZER_RUNTIME_STATUS,\n\t};\n}\n\nfunction countUniqueRetrievalFallbacks(retrievalFallbacks: readonly ContextSourceRefV2[]): number {\n\treturn new Set(\n\t\tretrievalFallbacks.map((ref) =>\n\t\t\t[ref.uri, ref.contentHash, ref.symbol ?? \"\", ref.range?.startLine ?? \"\", ref.range?.endLine ?? \"\"].join(\"\\0\"),\n\t\t),\n\t).size;\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"]}
|