@iowarp/clio-coder 0.3.3 → 0.3.6
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 +74 -0
- package/CONTRIBUTING.md +7 -7
- package/README.md +3 -3
- package/dist/{acp-P2AQILE2.js → acp-2BEHC4DL.js} +9 -8
- package/dist/{agents-72W3BI7I.js → agents-LNNFTM53.js} +29 -24
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-5TWEIYDN.js → auth-KXXFI2VS.js} +14 -10
- package/dist/{chunk-GGXXDWE4.js → chunk-22NAGB7X.js} +2 -2
- package/dist/{chunk-YCWGATWI.js → chunk-24I7BN55.js} +2 -2
- package/dist/{chunk-EKMEHE4H.js → chunk-33YXPOE3.js} +2 -3
- package/dist/chunk-3BPUFZDL.js +37 -0
- package/dist/chunk-43AOLP7E.js +375 -0
- package/dist/{chunk-ZDOOVTXZ.js → chunk-4OC57DA6.js} +27 -4
- package/dist/{chunk-6SGHMWE3.js → chunk-5JGRAMKL.js} +5 -5
- package/dist/{chunk-V6RTAOC2.js → chunk-6US73PDB.js} +572 -51
- package/dist/{chunk-5UFT4SUX.js → chunk-6XXKFVSN.js} +3 -3
- package/dist/{chunk-A3CYT5EX.js → chunk-AD2SYQYC.js} +55 -2
- package/dist/chunk-AOCYTWAV.js +449 -0
- package/dist/chunk-CFGTUFWB.js +67 -0
- package/dist/chunk-CJUB2JJ2.js +1478 -0
- package/dist/{chunk-FNTMWMX5.js → chunk-CKXWIANG.js} +14 -12
- package/dist/{chunk-PIWWS5BL.js → chunk-CYQKWTG3.js} +63 -78
- package/dist/{chunk-LZSJBIVT.js → chunk-DJVECN66.js} +271 -762
- package/dist/{chunk-CBCAPZAA.js → chunk-E25LMLRW.js} +2 -2
- package/dist/{chunk-ZWMF7253.js → chunk-E2ER4LJF.js} +304 -9
- package/dist/{chunk-STBPMHSX.js → chunk-EKY57CSP.js} +51 -84
- package/dist/{chunk-DUYJ5IO6.js → chunk-EYPA3EGJ.js} +12 -4
- package/dist/{chunk-M6SHUN7Q.js → chunk-FO5ZOVUY.js} +2 -2
- package/dist/chunk-FYYLNIL5.js +313 -0
- package/dist/{chunk-OQ33BKR3.js → chunk-G7MUEIGA.js} +3 -60
- package/dist/chunk-GEYXPTRF.js +613 -0
- package/dist/chunk-GOXNB3AO.js +261 -0
- package/dist/{chunk-G4BMMOKF.js → chunk-HVDIIIQW.js} +2 -2
- package/dist/chunk-HWUFFB6L.js +83 -0
- package/dist/{chunk-4XUGQOHA.js → chunk-K7T3E2SR.js} +15 -8
- package/dist/chunk-K7VKOLQQ.js +15 -0
- package/dist/{chunk-UFIIWP2H.js → chunk-KHSFENX2.js} +8 -8
- package/dist/{chunk-BMEMKKIT.js → chunk-KOHPCX4K.js} +2 -2
- package/dist/chunk-LCGCVYZ4.js +57 -0
- package/dist/chunk-LL4KHSZI.js +22 -0
- package/dist/{chunk-PAJK6MAQ.js → chunk-LYF7OHWH.js} +42 -15
- package/dist/{chunk-POHLU5DW.js → chunk-M6L6IDJG.js} +3 -3
- package/dist/{chunk-5UUP6MWO.js → chunk-MV3K5QF2.js} +5 -436
- package/dist/{chunk-X4RCMKVQ.js → chunk-NDINPTJ4.js} +2 -2
- package/dist/{chunk-TZK7PACC.js → chunk-NILBFAPG.js} +14 -8
- package/dist/chunk-ODFEOB4F.js +1082 -0
- package/dist/{chunk-AGYYIBLL.js → chunk-OH3TOQTB.js} +6 -2
- package/dist/chunk-OZNBF4L3.js +23 -0
- package/dist/{chunk-DSELYM6W.js → chunk-PBTHKCPN.js} +30 -10
- package/dist/{verify-375KUB3Y.js → chunk-PCZJO5TI.js} +127 -42
- package/dist/{chunk-ED4KHGC3.js → chunk-PPAMZ32Z.js} +9 -2
- package/dist/{chunk-SRDMMSEP.js → chunk-QM3F2GKX.js} +1063 -1645
- package/dist/{chunk-X6IAEBZR.js → chunk-QNQHSOLF.js} +7 -7
- package/dist/{chunk-OC7FIQPC.js → chunk-R46L2BIR.js} +10 -7
- package/dist/{chunk-2TLUCQVG.js → chunk-RD5U66HV.js} +3 -3
- package/dist/{chunk-6N5PTWMY.js → chunk-RY3LY4J5.js} +50 -13
- package/dist/{chunk-OKGUZO2U.js → chunk-SPULKLCF.js} +4 -3
- package/dist/{chunk-OOJYHWRB.js → chunk-TSHXZTOQ.js} +6 -5
- package/dist/chunk-TZSKNMZG.js +434 -0
- package/dist/{chunk-7MNJORFF.js → chunk-UL3WSD3F.js} +6 -1
- package/dist/{chunk-VJWL6YS5.js → chunk-UUVG37B4.js} +2 -2
- package/dist/{chunk-COU2UHX6.js → chunk-VEZEGCGW.js} +170 -2
- package/dist/chunk-W6GROXXM.js +69 -0
- package/dist/{chunk-OAO4GE4M.js → chunk-WHGPSPT5.js} +2 -2
- package/dist/chunk-WHJYKASB.js +677 -0
- package/dist/{chunk-ORBHGJC5.js → chunk-WR67VIZY.js} +3 -3
- package/dist/{chunk-YHZX5GEU.js → chunk-XAKHZX5N.js} +2 -2
- package/dist/{chunk-TZTZS7QK.js → chunk-XE2VEJHX.js} +5 -3
- package/dist/{chunk-LM5TQCJZ.js → chunk-XF5N4U5A.js} +8 -7
- package/dist/{chunk-LWLEKMDQ.js → chunk-XXQNGV4M.js} +1073 -552
- package/dist/{chunk-KZWTDYJF.js → chunk-XYDYPRZI.js} +7 -7
- package/dist/chunk-ZGVHUX3M.js +66 -0
- package/dist/{chunk-LW6DSM3M.js → chunk-ZRGEBJ4T.js} +1192 -1119
- package/dist/{chunk-2DJ2KNFG.js → chunk-ZXF4XRKW.js} +202 -40
- package/dist/chunk-ZZMN5OM4.js +122 -0
- package/dist/cli/index.js +34 -30
- package/dist/{clio-JOU4FXVA.js → clio-M2KGYUFZ.js} +7 -6
- package/dist/{code-nav-7AX6FYE6.js → code-nav-GQNL7XA6.js} +8 -6
- package/dist/codewiki/build-worker.js +4 -4
- package/dist/{components-KELWS457.js → components-5TTYYX6G.js} +3 -3
- package/dist/{config-XCDVKR23.js → config-XUUYQIWO.js} +47 -35
- package/dist/{configure-4GAP54ZW.js → configure-IHJ7YOMV.js} +18 -15
- package/dist/{context-77FM5DV5.js → context-74JLXAWD.js} +18 -10
- package/dist/{context-4UOGGLQ5.js → context-75MIWW3U.js} +41 -29
- package/dist/{context-5VKGUVJJ.js → context-ZQ7SIFJV.js} +85 -9
- package/dist/{context-clear-XXJRLCJJ.js → context-clear-GYKWNUML.js} +41 -29
- package/dist/{context-index-BZ4UYMTC.js → context-index-SSR5ECNE.js} +3 -3
- package/dist/context-working-set-UX5KEP4J.js +1553 -0
- package/dist/{dispatch-runner-QPRDDBDX.js → dispatch-runner-GIJBHNFL.js} +47 -32
- package/dist/{docs-2C2LTVT2.js → docs-6FZSCG5B.js} +3 -3
- package/dist/{doctor-HR46URBJ.js → doctor-SVJ5BZCW.js} +12 -12
- package/dist/{eval-XSSNATB4.js → eval-CG6LLBLD.js} +54 -238
- package/dist/{evidence-6HG2PY2B.js → evidence-ZYFIEN42.js} +57 -28
- package/dist/{evolve-K7YU3NCY.js → evolve-QGEXEMDW.js} +36 -25
- package/dist/{extensions-QVDOHDGJ.js → extensions-ADGNCJJD.js} +3 -3
- package/dist/{fleet-VY3HHKN6.js → fleet-S5R4ZOQY.js} +73 -44
- package/dist/{fleet-preflight-DDN536IT.js → fleet-preflight-BHSNPBMH.js} +3 -3
- package/dist/{init-JYGXI3FK.js → init-5DRU55YR.js} +49 -37
- package/dist/memory-7YKKR6UC.js +467 -0
- package/dist/{models-I5QWSEOM.js → models-ZPOLRU2C.js} +24 -21
- package/dist/{monitor-GE4ID3IA.js → monitor-US5F5YGZ.js} +73 -46
- package/dist/{orchestrator-EM5MC3HM.js → orchestrator-E2AL4T5N.js} +1624 -1007
- package/dist/{paths-UXLN5YYZ.js → paths-E7KYAQWE.js} +3 -3
- package/dist/{reset-L2FQEE3E.js → reset-KZ652EK6.js} +6 -5
- package/dist/{run-ZU3QMZPZ.js → run-SRNBKDWD.js} +76 -54
- package/dist/{share-S5BZQC5I.js → share-CGZE33UP.js} +7 -6
- package/dist/{skills-X5VXCRNQ.js → skills-S2X4DLY5.js} +4 -4
- package/dist/{skills-eval-WKIHWTHR.js → skills-eval-W2GGIC4R.js} +40 -29
- package/dist/{targets-SNCPI2NR.js → targets-54SWINWB.js} +28 -23
- package/dist/{terminal-lease-BNAHVHBS.js → terminal-lease-SAIF2OGY.js} +6 -4
- package/dist/{uninstall-FZCQCDKC.js → uninstall-BVLWXKBT.js} +3 -3
- package/dist/{upgrade-JQHHPQ4K.js → upgrade-JKAR27XC.js} +20 -19
- package/dist/{usage-OR4O5SMZ.js → usage-MSAWCLX4.js} +79 -36
- package/dist/verifiers-NCBTHHN2.js +1220 -0
- package/dist/verify-X5HDROLA.js +25 -0
- package/dist/{wiki-generate-UEXP2ARI.js → wiki-generate-GUSOQ6ZP.js} +50 -37
- package/dist/worker/entry.js +90 -70
- package/dist/{workspace-G4ZWUIPR.js → workspace-ZJ6BFM3Q.js} +4 -4
- package/docs/README.md +8 -7
- package/docs/acp.md +1 -1
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/artifact-placement.md +1 -2
- package/docs/artifact-versions.md +1 -1
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +1 -1
- package/docs/commands-and-modes.md +60 -26
- package/docs/config-knobs-audit.md +1 -2
- package/docs/configuration-and-targets.md +26 -1
- package/docs/context-engine.md +67 -13
- package/docs/context-working-set.md +194 -0
- package/docs/development-pipeline.md +1 -1
- package/docs/documentation-coverage.md +6 -6
- package/docs/documentation-guide.md +7 -6
- package/docs/environment-variables.md +2 -1
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +4 -32
- package/docs/evidence-and-memory.md +139 -7
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +1 -1
- package/docs/extensions-and-sharing.md +2 -2
- package/docs/fleet-dispatch.md +49 -8
- package/docs/glossary.md +21 -1
- package/docs/installation-and-lifecycle.md +2 -2
- package/docs/middleware-and-components.md +19 -2
- package/docs/model-catalog.md +7 -9
- package/docs/observability.md +4 -4
- package/docs/proactive-memory.md +26 -16
- package/docs/prompt-envelope-and-tools.md +7 -5
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +43 -40
- package/docs/safety-model.md +49 -8
- package/docs/scientific-validation.md +21 -3
- package/docs/session-lifecycle.md +3 -3
- package/docs/skills-marketplace.md +1 -1
- package/docs/tool-usage.md +79 -12
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +1 -1
- package/docs/tui-design.md +38 -4
- package/docs/worker-dispatch-mechanics.md +11 -1
- package/package.json +13 -13
- package/skills/meta/clio-test/SKILL.md +20 -17
- package/skills/meta/clio-test/evals.md +3 -3
- package/skills/meta/clio-test/references/harness.md +35 -6
- package/skills/meta/clio-test/references/test-map.md +20 -10
- package/skills/registry.yaml +2 -2
- package/skills/skill-marketplace.json +1 -1
- package/src/cli/agents.ts +2 -3
- package/src/cli/argv.ts +14 -1
- package/src/cli/context-working-set.ts +513 -0
- package/src/cli/context.ts +8 -0
- package/src/cli/evidence.ts +20 -2
- package/src/cli/fleet.ts +15 -0
- package/src/cli/index.ts +5 -1
- package/src/cli/memory.ts +272 -10
- package/src/cli/modes/json-stream.ts +2 -2
- package/src/cli/modes/print.ts +12 -1
- package/src/cli/run.ts +22 -2
- package/src/cli/targets.ts +12 -3
- package/src/cli/usage.ts +55 -7
- package/src/cli/verifiers.ts +325 -0
- package/src/core/bash-exec.ts +39 -14
- package/src/core/bus-events.ts +22 -4
- package/src/core/config.ts +54 -0
- package/src/core/defaults.ts +50 -3
- package/src/core/response-model-id.ts +134 -0
- package/src/core/toml.ts +62 -0
- package/src/core/verification-scripts.ts +6 -0
- package/src/core/workspace-files.ts +0 -1
- package/src/domains/agents/builtins/architect.md +1 -1
- package/src/domains/agents/builtins/verifier.md +3 -0
- package/src/domains/agents/catalog.ts +5 -4
- package/src/domains/agents/recipe.ts +54 -14
- package/src/domains/agents/result-contract.ts +7 -4
- package/src/domains/config/classify.ts +1 -0
- package/src/domains/context/bootstrap.ts +36 -27
- package/src/domains/context/project-metadata.ts +19 -63
- package/src/domains/context/prompt-context.ts +8 -0
- package/src/domains/context/working-set/contract.ts +161 -0
- package/src/domains/context/working-set/defaults.ts +28 -0
- package/src/domains/context/working-set/engine.ts +203 -0
- package/src/domains/context/working-set/fold.ts +62 -0
- package/src/domains/context/working-set/horizon.ts +38 -0
- package/src/domains/context/working-set/marker.ts +103 -0
- package/src/domains/context/working-set/path-index.ts +436 -0
- package/src/domains/context/working-set/payload.ts +152 -0
- package/src/domains/context/working-set/policies/age-horizon.ts +55 -0
- package/src/domains/context/working-set/policies/index.ts +20 -0
- package/src/domains/context/working-set/policies/structural.ts +160 -0
- package/src/domains/context/working-set/project.ts +132 -0
- package/src/domains/context/working-set/protect.ts +109 -0
- package/src/domains/context/working-set/recall.ts +177 -0
- package/src/domains/context/working-set/replay/controls.ts +112 -0
- package/src/domains/context/working-set/replay/load-clio.ts +199 -0
- package/src/domains/context/working-set/replay/metrics.ts +185 -0
- package/src/domains/context/working-set/replay/reference-graph.ts +79 -0
- package/src/domains/context/working-set/replay/report.ts +139 -0
- package/src/domains/context/working-set/replay/runner.ts +325 -0
- package/src/domains/context/working-set/replay/synthetic.ts +422 -0
- package/src/domains/context/working-set/replay/trace.ts +21 -0
- package/src/domains/context/working-set/visible.ts +54 -0
- package/src/domains/dispatch/budget-envelope.ts +396 -0
- package/src/domains/dispatch/contract.ts +2 -0
- package/src/domains/dispatch/extension.ts +81 -27
- package/src/domains/dispatch/orphan-recovery.ts +1 -0
- package/src/domains/dispatch/receipt-integrity.ts +4 -0
- package/src/domains/dispatch/state.ts +1 -0
- package/src/domains/dispatch/types.ts +10 -3
- package/src/domains/dispatch/validation.ts +14 -0
- package/src/domains/dispatch/worker-spawn.ts +14 -3
- package/src/domains/eval/metrics/evidence.ts +0 -116
- package/src/domains/eval/metrics/invariants.ts +1 -1
- package/src/domains/eval/runners/clio-run.ts +1 -10
- package/src/domains/eval/runners/external-command.ts +2 -29
- package/src/domains/eval/schema/suite.ts +0 -7
- package/src/domains/eval/suites/run.ts +1 -7
- package/src/domains/evidence/build.ts +112 -45
- package/src/domains/evidence/eval.ts +24 -7
- package/src/domains/evidence/index.ts +53 -0
- package/src/domains/evidence/ordering.ts +12 -0
- package/src/domains/evidence/run-trust.ts +221 -0
- package/src/domains/evidence/store.ts +46 -6
- package/src/domains/evidence/trust-status.ts +854 -0
- package/src/domains/evidence/types.ts +26 -0
- package/src/domains/memory/index.ts +22 -0
- package/src/domains/memory/operations.ts +58 -1
- package/src/domains/memory/promotion.ts +281 -0
- package/src/domains/memory/prompt-section.ts +25 -5
- package/src/domains/memory/proposal.ts +51 -7
- package/src/domains/memory/task-bank.ts +3 -2
- package/src/domains/memory/task-memory-handoff.ts +181 -24
- package/src/domains/memory/task-memory-policy.ts +3 -1
- package/src/domains/memory/types.ts +37 -0
- package/src/domains/memory/validate.ts +178 -0
- package/src/domains/middleware/memory-intervention.ts +38 -25
- package/src/domains/middleware/runtime.ts +6 -0
- package/src/domains/middleware/skills-reminder.ts +19 -4
- package/src/domains/middleware/stalled-turn.ts +208 -5
- package/src/domains/middleware/types.ts +10 -0
- package/src/domains/observability/contract.ts +6 -1
- package/src/domains/observability/cost.ts +20 -4
- package/src/domains/observability/extension.ts +2 -2
- package/src/domains/providers/index.ts +3 -0
- package/src/domains/providers/model-discovery.ts +9 -0
- package/src/domains/providers/runtime-resolution.ts +38 -1
- package/src/domains/providers/runtimes/common/probe-helpers.ts +97 -16
- package/src/domains/providers/types/context-window-slots.ts +18 -0
- package/src/domains/providers/types/runtime-descriptor.ts +3 -1
- package/src/domains/safety/autonomy.ts +1 -1
- package/src/domains/safety/call-target.ts +211 -14
- package/src/domains/safety/decision-presentation.ts +268 -0
- package/src/domains/safety/default-path-policy.ts +8 -0
- package/src/domains/safety/finish-contract.ts +4 -3
- package/src/domains/safety/policy-engine.ts +48 -6
- package/src/domains/safety/redaction.ts +73 -0
- package/src/domains/session/compaction/compact.ts +23 -1
- package/src/domains/session/compaction/cut-point.ts +2 -0
- package/src/domains/session/compaction/tokens.ts +16 -1
- package/src/domains/session/context-ledger.ts +12 -1
- package/src/domains/session/decision-board.ts +4 -0
- package/src/domains/session/entries.ts +110 -1
- package/src/domains/session/history.ts +68 -19
- package/src/domains/session/manager.ts +9 -2
- package/src/domains/session/migrations/index.ts +22 -3
- package/src/domains/session/usage.ts +24 -7
- package/src/engine/acp/event-mapper.ts +7 -0
- package/src/engine/acp/server.ts +32 -2
- package/src/engine/agent.ts +18 -1
- package/src/engine/apis/lmstudio.ts +25 -4
- package/src/engine/apis/openai-completions.ts +147 -22
- package/src/engine/claude/sdk-runtime.ts +8 -2
- package/src/engine/claude/tool-safety.ts +13 -0
- package/src/engine/loop-guard.ts +27 -3
- package/src/engine/session.ts +9 -3
- package/src/engine/worker-events.ts +4 -3
- package/src/engine/worker-runtime.ts +59 -54
- package/src/entry/orchestrator.ts +34 -5
- package/src/interactive/chat-loop-messages.ts +40 -6
- package/src/interactive/chat-loop.ts +13 -0
- package/src/interactive/chat-panel.ts +17 -1
- package/src/interactive/chat-renderer.ts +49 -24
- package/src/interactive/clio-editor.ts +44 -7
- package/src/interactive/context-meter.ts +10 -0
- package/src/interactive/context-overlay.ts +120 -7
- package/src/interactive/context-recall-command.ts +110 -0
- package/src/interactive/cost-overlay.ts +39 -8
- package/src/interactive/dispatch-board.ts +212 -35
- package/src/interactive/footer/widgets.ts +13 -0
- package/src/interactive/interactive-application.ts +6 -1
- package/src/interactive/interactive-input-runtime.ts +11 -1
- package/src/interactive/interactive-presentation.ts +11 -1
- package/src/interactive/interactive-slash-runtime.ts +37 -1
- package/src/interactive/memory-overlay.ts +89 -4
- package/src/interactive/model-session-replay.ts +21 -0
- package/src/interactive/overlay-ask-user-lifecycle.ts +1 -1
- package/src/interactive/overlay-frame.ts +5 -2
- package/src/interactive/overlay-general-openers.ts +46 -1
- package/src/interactive/overlay-key-routing.ts +41 -1
- package/src/interactive/overlay-lifecycle.ts +11 -4
- package/src/interactive/overlay-permission-lifecycle.ts +23 -8
- package/src/interactive/overlay-session-lifecycle.ts +8 -4
- package/src/interactive/overlay-transitions.ts +11 -0
- package/src/interactive/overlays/ask-user.ts +74 -30
- package/src/interactive/overlays/decisions.ts +3 -1
- package/src/interactive/permission-hint.ts +35 -0
- package/src/interactive/permission-overlay.ts +95 -45
- package/src/interactive/renderers/tool-execution.ts +37 -51
- package/src/interactive/session-last-turn.ts +8 -1
- package/src/interactive/session-transcript.ts +2 -2
- package/src/interactive/session-usage-reseed.ts +36 -10
- package/src/interactive/slash-commands.ts +31 -4
- package/src/interactive/status/summary.ts +5 -0
- package/src/interactive/status/types.ts +5 -0
- package/src/interactive/terminal-lease.ts +1 -0
- package/src/interactive/turn-context.ts +333 -110
- package/src/interactive/turn-middleware.ts +7 -6
- package/src/interactive/turn-runtime.ts +37 -8
- package/src/interactive/turn-state.ts +3 -0
- package/src/interactive/worker-progress.ts +440 -0
- package/src/interactive/worker-stream.ts +51 -110
- package/src/tools/agent-tools.ts +39 -7
- package/src/tools/ask-user.ts +21 -1
- package/src/tools/bash.ts +144 -82
- package/src/tools/builtin-tool-catalog.ts +11 -5
- package/src/tools/context/index.ts +107 -5
- package/src/tools/context/surface.ts +3 -2
- package/src/tools/core-bootstrap.ts +21 -0
- package/src/tools/dispatch-arguments.ts +8 -0
- package/src/tools/dispatch-event-text.ts +19 -0
- package/src/tools/dispatch-runner.ts +9 -7
- package/src/tools/dispatch.ts +24 -1
- package/src/tools/monitor.ts +43 -20
- package/src/tools/registry.ts +72 -10
- package/src/tools/result-disposition.ts +706 -0
- package/src/tools/result-shaping.ts +321 -20
- package/src/tools/safe-exec.ts +2 -0
- package/src/tools/verify/authoring.ts +1120 -0
- package/src/tools/verify/catalog.ts +346 -0
- package/src/tools/verify/index.ts +13 -3
- package/src/tools/verify/scripts.ts +135 -37
- package/src/tools/verify/surface.ts +9 -5
- package/src/tools/worker-evidence.ts +54 -12
- package/src/worker/spec-contract.ts +43 -3
- package/dist/chunk-J7CWMCQD.js +0 -255
- package/dist/chunk-T6YILFSB.js +0 -80
- package/dist/chunk-VAKQQHWR.js +0 -434
- package/dist/chunk-VPAYEGVX.js +0 -184
- package/dist/chunk-XBXAASKX.js +0 -18
- package/dist/memory-WFZMGYHX.js +0 -236
- package/src/domains/eval/metrics/chaos-stream.ts +0 -93
|
@@ -10,15 +10,25 @@ import {
|
|
|
10
10
|
BusChannels,
|
|
11
11
|
type ContextActivityStatus,
|
|
12
12
|
type ContextPrunedPayload,
|
|
13
|
+
type ContextRecalledPayload,
|
|
13
14
|
type ContextWarningPayload,
|
|
14
15
|
} from "../core/bus-events.js";
|
|
15
16
|
import type { ClioSettings } from "../core/config.js";
|
|
16
17
|
import type { SafeEventBus } from "../core/event-bus.js";
|
|
17
18
|
import type { ToolName } from "../core/tool-names.js";
|
|
19
|
+
import { buildEvictionFields, planEviction } from "../domains/context/working-set/engine.js";
|
|
20
|
+
import { foldWorkingSet } from "../domains/context/working-set/fold.js";
|
|
21
|
+
import { resolveWorkingSetPolicy } from "../domains/context/working-set/policies/index.js";
|
|
22
|
+
import { selectVisibleEntries } from "../domains/context/working-set/visible.js";
|
|
18
23
|
import type { ObservabilityContract } from "../domains/observability/contract.js";
|
|
19
24
|
import type { CompiledSessionPrompt, SessionPromptInputs } from "../domains/prompts/compiler.js";
|
|
20
25
|
import type { PromptsContract } from "../domains/prompts/contract.js";
|
|
21
|
-
import
|
|
26
|
+
import {
|
|
27
|
+
type ContextWindowDetails,
|
|
28
|
+
type ContextWindowSource,
|
|
29
|
+
type ProvidersContract,
|
|
30
|
+
resolveRuntimeTarget,
|
|
31
|
+
} from "../domains/providers/index.js";
|
|
22
32
|
import type { LocalModelQuirks } from "../domains/providers/types/local-model-quirks.js";
|
|
23
33
|
import {
|
|
24
34
|
AutoCompactionTrigger,
|
|
@@ -27,6 +37,7 @@ import {
|
|
|
27
37
|
} from "../domains/session/compaction/auto.js";
|
|
28
38
|
import type { CompactResult } from "../domains/session/compaction/compact.js";
|
|
29
39
|
import { maskStaleObservations } from "../domains/session/compaction/mask-observations.js";
|
|
40
|
+
import { estimateTokens } from "../domains/session/compaction/tokens.js";
|
|
30
41
|
import {
|
|
31
42
|
appendContextSnapshot,
|
|
32
43
|
type CaptureContextSnapshotInput,
|
|
@@ -57,7 +68,7 @@ import {
|
|
|
57
68
|
sumRunUsage,
|
|
58
69
|
toolNamesFromAgentState,
|
|
59
70
|
} from "./chat-loop-messages.js";
|
|
60
|
-
import {
|
|
71
|
+
import { buildModelReplayAgentMessagesFromTurns } from "./model-session-replay.js";
|
|
61
72
|
import { renderCompactionSummaryLine } from "./renderers/compaction-summary.js";
|
|
62
73
|
import type { TurnMiddleware } from "./turn-middleware.js";
|
|
63
74
|
import type { AgentRuntime, ChatTurnState } from "./turn-state.js";
|
|
@@ -73,6 +84,8 @@ export interface TurnContextDeps {
|
|
|
73
84
|
bus?: SafeEventBus | undefined;
|
|
74
85
|
readSessionEntries?: (() => ReadonlyArray<SessionEntry>) | undefined;
|
|
75
86
|
autoCompact?: ((instructions?: string, trigger?: CompactionTrigger) => Promise<CompactResult | null>) | undefined;
|
|
87
|
+
/** Test seam for the eviction planner; production uses `planEviction` from the working-set engine. */
|
|
88
|
+
planEviction?: typeof planEviction;
|
|
76
89
|
getMemorySection?: (() => string) | undefined;
|
|
77
90
|
middleware: TurnMiddleware;
|
|
78
91
|
emitNotice: (text: string) => void;
|
|
@@ -159,6 +172,11 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
159
172
|
let sessionPromptKey: string | null = null;
|
|
160
173
|
const sessionWorkingContextPaths = new Set<string>();
|
|
161
174
|
let pendingPromptLogEntry: SessionPromptCompileRecord | null = null;
|
|
175
|
+
// A post-tool guard can run after every tool result in one model turn. Once
|
|
176
|
+
// both automatic stages report that they have nothing to do, remember that
|
|
177
|
+
// stable user-turn id so the remaining results do not repeat the same plan
|
|
178
|
+
// and summary probes. A new submitted user turn gets a new id naturally.
|
|
179
|
+
let emptyAutoCompactTurnId: string | null = null;
|
|
162
180
|
|
|
163
181
|
// Cache-disturbance honesty (T3.3). Dispatch traffic and history
|
|
164
182
|
// compaction invalidate a single-slot local backend's prefix cache.
|
|
@@ -167,20 +185,41 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
167
185
|
// its first assistant entry, and shows one dim notice.
|
|
168
186
|
const pendingColdReasons = new Set<string>();
|
|
169
187
|
let runExpectedColdReasons: string[] = [];
|
|
170
|
-
let
|
|
188
|
+
let nextAssistantColdReasons: string[] = [];
|
|
189
|
+
// A working-set eviction changes the prefix itself, so it cools every
|
|
190
|
+
// tier's cache, not only a single-slot local one. Dispatch and compaction
|
|
191
|
+
// disturbances keep the local-native gate below.
|
|
192
|
+
const TIER_INDEPENDENT_COLD_REASONS: ReadonlySet<string> = new Set(["working_set_evict"]);
|
|
193
|
+
const stampsOnTier = (reason: string, runtimeId: string | undefined): boolean =>
|
|
194
|
+
TIER_INDEPENDENT_COLD_REASONS.has(reason) ||
|
|
195
|
+
(runtimeId !== undefined && deps.providers.getRuntime(runtimeId)?.tier === "local-native");
|
|
196
|
+
const noteColdReason = (reason: string): void => {
|
|
197
|
+
if (!state.streaming) {
|
|
198
|
+
pendingColdReasons.add(reason);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (!stampsOnTier(reason, state.runtime?.runtimeId)) return;
|
|
202
|
+
if (!runExpectedColdReasons.includes(reason)) runExpectedColdReasons.push(reason);
|
|
203
|
+
if (nextAssistantColdReasons.includes(reason)) return;
|
|
204
|
+
nextAssistantColdReasons.push(reason);
|
|
205
|
+
deps.emitNotice(`[context engine] backend prefix cache likely cold this turn: ${reason}`);
|
|
206
|
+
};
|
|
171
207
|
const unsubscribeColdReasonSources = [
|
|
172
208
|
...[BusChannels.DispatchStarted, BusChannels.DispatchCompleted, BusChannels.DispatchFailed].map(
|
|
173
209
|
(channel) =>
|
|
174
210
|
deps.bus?.on(channel, () => {
|
|
175
|
-
|
|
211
|
+
noteColdReason("dispatch");
|
|
176
212
|
}) ?? null,
|
|
177
213
|
),
|
|
178
214
|
...[BusChannels.CompactionBegin, BusChannels.CompactionEnd].map(
|
|
179
215
|
(channel) =>
|
|
180
216
|
deps.bus?.on(channel, () => {
|
|
181
|
-
|
|
217
|
+
noteColdReason("compaction");
|
|
182
218
|
}) ?? null,
|
|
183
219
|
),
|
|
220
|
+
deps.bus?.on(BusChannels.ContextRecalled, (payload: ContextRecalledPayload) => {
|
|
221
|
+
middleware.fireCompactionHook("working_set_recall", payload.trigger);
|
|
222
|
+
}) ?? null,
|
|
184
223
|
];
|
|
185
224
|
|
|
186
225
|
/**
|
|
@@ -275,6 +314,75 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
275
314
|
return ceilChars(snapshot.pendingUserInput.length);
|
|
276
315
|
};
|
|
277
316
|
|
|
317
|
+
/**
|
|
318
|
+
* The window the next turn will resolve to, read the way ensureRuntime
|
|
319
|
+
* reads it but without building an agent. Before the first turn of a
|
|
320
|
+
* process, /resume included, state.runtime is null, and the ledger and the
|
|
321
|
+
* footer meter said `context window unknown · 0 tokens` until a turn ran
|
|
322
|
+
* (issue #189). Null when no target is configured or it does not resolve,
|
|
323
|
+
* and the overlay's "unknown" is then true.
|
|
324
|
+
*/
|
|
325
|
+
const resolveWindowWithoutRuntime = (): ContextWindowDetails | null => {
|
|
326
|
+
const settings = deps.getSettings();
|
|
327
|
+
const targetId = settings.orchestrator?.target?.trim();
|
|
328
|
+
const wireModelId = settings.orchestrator?.model?.trim();
|
|
329
|
+
if (!targetId || !wireModelId) return null;
|
|
330
|
+
const resolved = resolveRuntimeTarget(deps.providers, {
|
|
331
|
+
targetId,
|
|
332
|
+
wireModelId,
|
|
333
|
+
requestedThinkingLevel: settings.orchestrator?.thinkingLevel ?? "off",
|
|
334
|
+
use: "orchestrator",
|
|
335
|
+
requireTools: false,
|
|
336
|
+
requireOutputBudget: true,
|
|
337
|
+
});
|
|
338
|
+
return resolved.ok ? resolved.target.contextWindowDetails : null;
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
const CONTEXT_WINDOW_SOURCES: ReadonlySet<string> = new Set<ContextWindowSource>([
|
|
342
|
+
"catalog",
|
|
343
|
+
"probe",
|
|
344
|
+
"loaded",
|
|
345
|
+
"target-override",
|
|
346
|
+
"model-hint",
|
|
347
|
+
"descriptor-default",
|
|
348
|
+
"unknown",
|
|
349
|
+
]);
|
|
350
|
+
|
|
351
|
+
/** The snapshot stores its source as a plain string; only a known label is worth repeating. */
|
|
352
|
+
const snapshotWindowSource = (snapshot: ContextSnapshot): ContextWindowSource | null =>
|
|
353
|
+
CONTEXT_WINDOW_SOURCES.has(snapshot.contextWindowSource)
|
|
354
|
+
? (snapshot.contextWindowSource as ContextWindowSource)
|
|
355
|
+
: null;
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Window facts while no runtime exists: the live resolution first, then the
|
|
359
|
+
* resumed snapshot's recorded window, which is what the previous process
|
|
360
|
+
* measured the same messages against.
|
|
361
|
+
*/
|
|
362
|
+
const windowWithoutRuntime = (): {
|
|
363
|
+
contextWindow: number;
|
|
364
|
+
contextWindowSource: ContextWindowSource | null;
|
|
365
|
+
contextWindowSlots: ContextWindowDetails["contextWindowSlots"];
|
|
366
|
+
} => {
|
|
367
|
+
const details = resolveWindowWithoutRuntime();
|
|
368
|
+
if (details) {
|
|
369
|
+
return {
|
|
370
|
+
contextWindow: details.effectiveContextWindow,
|
|
371
|
+
contextWindowSource: details.contextWindowSource,
|
|
372
|
+
contextWindowSlots: details.contextWindowSlots,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
const snapshot = currentContextSnapshot;
|
|
376
|
+
if (snapshot && snapshot.effectiveContextWindow > 0) {
|
|
377
|
+
return {
|
|
378
|
+
contextWindow: snapshot.effectiveContextWindow,
|
|
379
|
+
contextWindowSource: snapshotWindowSource(snapshot),
|
|
380
|
+
contextWindowSlots: null,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
return { contextWindow: 0, contextWindowSource: null, contextWindowSlots: null };
|
|
384
|
+
};
|
|
385
|
+
|
|
278
386
|
const liveContextEstimate = (agentRuntime: AgentRuntime, pendingUserText?: string): LiveContextEstimate => {
|
|
279
387
|
const contextWindow = agentRuntime.runtimeResolution.contextWindowDetails.effectiveContextWindow;
|
|
280
388
|
const estimateInput = {
|
|
@@ -292,7 +400,7 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
292
400
|
|
|
293
401
|
const refreshAgentMessagesFromSession = (agentRuntime: AgentRuntime): ReadonlyArray<SessionEntry> => {
|
|
294
402
|
const refreshedEntries = deps.readSessionEntries?.() ?? [];
|
|
295
|
-
agentRuntime.agent.state.messages =
|
|
403
|
+
agentRuntime.agent.state.messages = buildModelReplayAgentMessagesFromTurns(refreshedEntries, {
|
|
296
404
|
...(state.lastTurnId ? { activeLeafTurnId: state.lastTurnId } : {}),
|
|
297
405
|
});
|
|
298
406
|
state.replayedContextMessages = [];
|
|
@@ -339,12 +447,12 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
339
447
|
|
|
340
448
|
/**
|
|
341
449
|
* Two-mechanism context protection. When pressure crosses the single
|
|
342
|
-
* threshold, first
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
450
|
+
* threshold, first apply a non-destructive working-set eviction. If pressure
|
|
451
|
+
* stays above the threshold, delegate to the pi-style LLM compaction path:
|
|
452
|
+
* append a compaction summary entry, then replay from the session view. The
|
|
453
|
+
* destructive observation mask remains only as a one-release escape hatch.
|
|
346
454
|
*
|
|
347
|
-
* `force = true` skips the pressure check and
|
|
455
|
+
* `force = true` skips the pressure check and every pre-stage and runs
|
|
348
456
|
* the LLM summary directly. Used for `/context compact`, CLIO_CODER_FORCE_COMPACT=1,
|
|
349
457
|
* and overflow recovery.
|
|
350
458
|
*/
|
|
@@ -355,11 +463,17 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
355
463
|
triggerOverride?: CompactionTrigger,
|
|
356
464
|
pendingUserText?: string,
|
|
357
465
|
): Promise<boolean> => {
|
|
358
|
-
if (!deps.
|
|
466
|
+
if (!deps.readSessionEntries) return false;
|
|
467
|
+
const activeAutoTurnId = force ? null : state.activeUserTurnId;
|
|
468
|
+
if (activeAutoTurnId && emptyAutoCompactTurnId === activeAutoTurnId) return false;
|
|
359
469
|
const settings = deps.getSettings();
|
|
360
470
|
const cfg = settings.compaction;
|
|
361
471
|
const autoEnabled = cfg?.auto !== false;
|
|
362
472
|
if (!force && !autoEnabled) return false;
|
|
473
|
+
let preSummaryStageActed = false;
|
|
474
|
+
const rememberEmptyAutomaticAttempt = (): void => {
|
|
475
|
+
if (!force && !preSummaryStageActed && activeAutoTurnId) emptyAutoCompactTurnId = activeAutoTurnId;
|
|
476
|
+
};
|
|
363
477
|
|
|
364
478
|
const compactionThreshold = cfg?.threshold ?? DEFAULT_COMPACTION_THRESHOLD;
|
|
365
479
|
const trigger: CompactionTrigger = triggerOverride ?? (force ? "force" : "auto");
|
|
@@ -369,91 +483,198 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
369
483
|
const verdict = shouldCompact(estimate.tokens, compactionThreshold, estimate.contextWindow);
|
|
370
484
|
if (!verdict.shouldCompact) return false;
|
|
371
485
|
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
//
|
|
375
|
-
// CompactionBegin/End subscription explains the next cold turn.
|
|
486
|
+
// One-release compatibility escape hatch. This is the destructive
|
|
487
|
+
// pre-stage that working-set eviction replaces; keep it byte-for-byte
|
|
488
|
+
// reachable only when explicitly requested.
|
|
376
489
|
if (deps.session?.current()) {
|
|
377
490
|
const beforeSnapshotId = currentContextSnapshot?.snapshotId ?? null;
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
lastCompactionEvent = {
|
|
407
|
-
stage: "mask_observations",
|
|
408
|
-
tokensBefore: estimate.tokens,
|
|
409
|
-
tokensAfter: tokensAfterMask,
|
|
410
|
-
trigger,
|
|
411
|
-
};
|
|
412
|
-
deps.bus?.emit(BusChannels.ContextPruned, {
|
|
413
|
-
stage: "mask_observations",
|
|
414
|
-
pressure: verdict.pressure,
|
|
415
|
-
tokensBefore: estimate.tokens,
|
|
416
|
-
tokensAfter: tokensAfterMask,
|
|
417
|
-
maskedObservations: masked.maskedObservations,
|
|
418
|
-
maskedThinkingBlocks: masked.maskedThinkingBlocks,
|
|
419
|
-
maskedThinkingChars: masked.maskedThinkingChars,
|
|
420
|
-
trigger,
|
|
421
|
-
snapshotIdBefore: beforeSnapshotId,
|
|
422
|
-
snapshotIdAfter: postMaskSnapshot.snapshotId,
|
|
423
|
-
at: Date.now(),
|
|
424
|
-
} satisfies ContextPrunedPayload);
|
|
425
|
-
emitCompactionActivity("completed", `${masked.maskedObservations} observations masked`);
|
|
426
|
-
const thinkingNote =
|
|
427
|
-
masked.maskedThinkingBlocks > 0
|
|
428
|
-
? `, ${masked.maskedThinkingBlocks} thinking blocks dropped (~${masked.maskedThinkingChars} chars)`
|
|
429
|
-
: "";
|
|
430
|
-
deps.emitNotice(
|
|
431
|
-
`[context engine] mask_observations: ${masked.maskedObservations} observations masked${thinkingNote}; ~${estimate.tokens} tokens -> ~${tokensAfterMask} tokens`,
|
|
432
|
-
);
|
|
491
|
+
if (process.env.CLIO_CODER_LEGACY_MASK === "1") {
|
|
492
|
+
let masked: ReturnType<typeof maskStaleObservations>;
|
|
493
|
+
try {
|
|
494
|
+
masked = maskStaleObservations(deps.readSessionEntries() ?? [], cfg?.excludeLastTurns ?? 6);
|
|
495
|
+
} catch (error) {
|
|
496
|
+
middleware.fireCompactionHook("mask_observations", trigger, estimate.tokens);
|
|
497
|
+
deps.bus?.emit(BusChannels.CompactionBegin, { trigger, at: Date.now() });
|
|
498
|
+
emitCompactionActivity("started", "compacting context (mask stage)");
|
|
499
|
+
emitCompactionActivity("failed", compactionFailureMessage(error));
|
|
500
|
+
deps.bus?.emit(BusChannels.CompactionEnd, { trigger, at: Date.now() });
|
|
501
|
+
throw error;
|
|
502
|
+
}
|
|
503
|
+
if (masked.changed) {
|
|
504
|
+
preSummaryStageActed = true;
|
|
505
|
+
middleware.fireCompactionHook("mask_observations", trigger, estimate.tokens);
|
|
506
|
+
deps.bus?.emit(BusChannels.CompactionBegin, { trigger, at: Date.now() });
|
|
507
|
+
emitCompactionActivity("started", "compacting context (mask stage)");
|
|
508
|
+
deps.session.replaceEntries(masked.entries);
|
|
509
|
+
refreshAgentMessagesFromSession(agentRuntime);
|
|
510
|
+
deps.bus?.emit(BusChannels.CompactionEnd, { trigger, at: Date.now() });
|
|
511
|
+
|
|
512
|
+
const postMaskSnapshot = captureRuntimeContextSnapshot(
|
|
513
|
+
agentRuntime,
|
|
514
|
+
state.activeUserTurnId || "compaction",
|
|
515
|
+
compactionThreshold,
|
|
516
|
+
);
|
|
517
|
+
currentContextSnapshot = postMaskSnapshot;
|
|
518
|
+
persistContextSnapshot(postMaskSnapshot);
|
|
433
519
|
|
|
434
|
-
|
|
435
|
-
|
|
520
|
+
const tokensAfterMask = snapshotInputTokens(postMaskSnapshot);
|
|
521
|
+
lastCompactionEvent = {
|
|
522
|
+
stage: "mask_observations",
|
|
523
|
+
tokensBefore: estimate.tokens,
|
|
524
|
+
tokensAfter: tokensAfterMask,
|
|
525
|
+
trigger,
|
|
526
|
+
};
|
|
527
|
+
deps.bus?.emit(BusChannels.ContextPruned, {
|
|
528
|
+
stage: "mask_observations",
|
|
529
|
+
pressure: verdict.pressure,
|
|
530
|
+
tokensBefore: estimate.tokens,
|
|
531
|
+
tokensAfter: tokensAfterMask,
|
|
532
|
+
maskedObservations: masked.maskedObservations,
|
|
533
|
+
maskedThinkingBlocks: masked.maskedThinkingBlocks,
|
|
534
|
+
maskedThinkingChars: masked.maskedThinkingChars,
|
|
535
|
+
trigger,
|
|
536
|
+
snapshotIdBefore: beforeSnapshotId,
|
|
537
|
+
snapshotIdAfter: postMaskSnapshot.snapshotId,
|
|
538
|
+
at: Date.now(),
|
|
539
|
+
} satisfies ContextPrunedPayload);
|
|
540
|
+
emitCompactionActivity("completed", `${masked.maskedObservations} observations masked`);
|
|
541
|
+
const thinkingNote =
|
|
542
|
+
masked.maskedThinkingBlocks > 0
|
|
543
|
+
? `, ${masked.maskedThinkingBlocks} thinking blocks dropped (~${masked.maskedThinkingChars} chars)`
|
|
544
|
+
: "";
|
|
545
|
+
deps.emitNotice(
|
|
546
|
+
`[context engine] mask_observations: ${masked.maskedObservations} observations masked${thinkingNote}; ~${estimate.tokens} tokens -> ~${tokensAfterMask} tokens`,
|
|
547
|
+
);
|
|
548
|
+
|
|
549
|
+
const after = liveContextEstimate(agentRuntime, pendingUserText);
|
|
550
|
+
if (!shouldCompact(after.tokens, compactionThreshold, after.contextWindow).shouldCompact) return true;
|
|
551
|
+
}
|
|
552
|
+
} else if (settings.context.workingSet.enabled) {
|
|
553
|
+
let planned: ReturnType<typeof planEviction>;
|
|
554
|
+
try {
|
|
555
|
+
const entries = deps.readSessionEntries() ?? [];
|
|
556
|
+
const view = foldWorkingSet(entries, state.lastTurnId ?? undefined);
|
|
557
|
+
const policy = resolveWorkingSetPolicy(settings.context.workingSet.policy);
|
|
558
|
+
planned = (deps.planEviction ?? planEviction)(policy, {
|
|
559
|
+
entries: selectVisibleEntries(entries, state.lastTurnId ?? undefined),
|
|
560
|
+
view,
|
|
561
|
+
cwd: deps.session.current()?.cwd ?? null,
|
|
562
|
+
settings: settings.context.workingSet,
|
|
563
|
+
pressure: {
|
|
564
|
+
tokens: estimate.tokens,
|
|
565
|
+
contextWindow: estimate.contextWindow,
|
|
566
|
+
threshold: compactionThreshold,
|
|
567
|
+
target: settings.context.workingSet.target,
|
|
568
|
+
},
|
|
569
|
+
estimateTokens,
|
|
570
|
+
});
|
|
571
|
+
} catch (error) {
|
|
572
|
+
middleware.fireCompactionHook("working_set_evict", "pressure", estimate.tokens);
|
|
573
|
+
emitCompactionActivity("started", "compacting context (working-set eviction)");
|
|
574
|
+
emitCompactionActivity("failed", compactionFailureMessage(error));
|
|
575
|
+
throw error;
|
|
576
|
+
}
|
|
577
|
+
if (planned) {
|
|
578
|
+
preSummaryStageActed = true;
|
|
579
|
+
middleware.fireCompactionHook("working_set_evict", "pressure", estimate.tokens);
|
|
580
|
+
emitCompactionActivity("started", "compacting context (working-set eviction)");
|
|
581
|
+
try {
|
|
582
|
+
deps.session.appendEntry({
|
|
583
|
+
...buildEvictionFields(planned, {
|
|
584
|
+
trigger: "pressure",
|
|
585
|
+
pressureBefore: verdict.pressure,
|
|
586
|
+
snapshotIdBefore: beforeSnapshotId,
|
|
587
|
+
}),
|
|
588
|
+
// appendEntry does not infer this anchor; the interactive
|
|
589
|
+
// cursor is the leaf the next message will extend.
|
|
590
|
+
parentTurnId: state.lastTurnId,
|
|
591
|
+
});
|
|
592
|
+
noteColdReason("working_set_evict");
|
|
593
|
+
refreshAgentMessagesFromSession(agentRuntime);
|
|
594
|
+
|
|
595
|
+
const postEvictionSnapshot = captureRuntimeContextSnapshot(
|
|
596
|
+
agentRuntime,
|
|
597
|
+
state.activeUserTurnId || "compaction",
|
|
598
|
+
compactionThreshold,
|
|
599
|
+
);
|
|
600
|
+
currentContextSnapshot = postEvictionSnapshot;
|
|
601
|
+
persistContextSnapshot(postEvictionSnapshot);
|
|
602
|
+
|
|
603
|
+
// Every surface that describes this event (the notice, the toast
|
|
604
|
+
// ContextPruned feeds, the overlay's last-compaction line, the
|
|
605
|
+
// ledger entry) quotes the plan: the same chars/4 pricing over the
|
|
606
|
+
// same visible slice. The live estimate prices the agent message
|
|
607
|
+
// list and differs by the tool schemas and replay text; it stays
|
|
608
|
+
// what the meter and the re-check below read, not what the event
|
|
609
|
+
// reports about itself.
|
|
610
|
+
lastCompactionEvent = {
|
|
611
|
+
stage: "working_set",
|
|
612
|
+
tokensBefore: planned.tokensBefore,
|
|
613
|
+
tokensAfter: planned.tokensAfter,
|
|
614
|
+
trigger,
|
|
615
|
+
};
|
|
616
|
+
deps.bus?.emit(BusChannels.ContextPruned, {
|
|
617
|
+
stage: "working_set",
|
|
618
|
+
pressure: verdict.pressure,
|
|
619
|
+
tokensBefore: planned.tokensBefore,
|
|
620
|
+
tokensAfter: planned.tokensAfter,
|
|
621
|
+
trigger,
|
|
622
|
+
snapshotIdBefore: beforeSnapshotId,
|
|
623
|
+
snapshotIdAfter: postEvictionSnapshot.snapshotId,
|
|
624
|
+
policyId: planned.policyId,
|
|
625
|
+
evictedItems: planned.items.length,
|
|
626
|
+
at: Date.now(),
|
|
627
|
+
} satisfies ContextPrunedPayload);
|
|
628
|
+
const itemsWord = planned.items.length === 1 ? "item" : "items";
|
|
629
|
+
emitCompactionActivity("completed", `${planned.items.length} working-set ${itemsWord} evicted`);
|
|
630
|
+
deps.emitNotice(
|
|
631
|
+
`[context engine] working set: ${planned.items.length} ${itemsWord} evicted by ${planned.policyId}; ~${planned.tokensBefore} -> ~${planned.tokensAfter} tokens, recall by ref with context(scope="recall")`,
|
|
632
|
+
);
|
|
633
|
+
|
|
634
|
+
const after = liveContextEstimate(agentRuntime, pendingUserText);
|
|
635
|
+
if (!shouldCompact(after.tokens, compactionThreshold, after.contextWindow).shouldCompact) return true;
|
|
636
|
+
} catch (error) {
|
|
637
|
+
emitCompactionActivity("failed", compactionFailureMessage(error));
|
|
638
|
+
throw error;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
436
641
|
}
|
|
437
642
|
}
|
|
438
643
|
}
|
|
439
644
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
645
|
+
if (!deps.autoCompact) {
|
|
646
|
+
rememberEmptyAutomaticAttempt();
|
|
647
|
+
return false;
|
|
648
|
+
}
|
|
649
|
+
let summaryLifecycleStarted = false;
|
|
650
|
+
const startSummaryLifecycle = (): void => {
|
|
651
|
+
middleware.fireCompactionHook("llm_summary", trigger);
|
|
652
|
+
deps.bus?.emit(BusChannels.CompactionBegin, { trigger, at: Date.now() });
|
|
653
|
+
emitCompactionActivity("started", "compacting context (summary)");
|
|
654
|
+
summaryLifecycleStarted = true;
|
|
655
|
+
};
|
|
656
|
+
if (force) startSummaryLifecycle();
|
|
443
657
|
let result: CompactResult | null = null;
|
|
444
658
|
const beforeSnapshotId = currentContextSnapshot?.snapshotId ?? null;
|
|
445
659
|
try {
|
|
446
660
|
result = await compactionTrigger.fire(() => (deps.autoCompact ?? (async () => null))(instructions, trigger));
|
|
447
661
|
} catch (error) {
|
|
662
|
+
if (!summaryLifecycleStarted) startSummaryLifecycle();
|
|
448
663
|
emitCompactionActivity("failed", compactionFailureMessage(error));
|
|
449
|
-
throw error;
|
|
450
|
-
} finally {
|
|
451
664
|
deps.bus?.emit(BusChannels.CompactionEnd, { trigger, at: Date.now() });
|
|
665
|
+
throw error;
|
|
452
666
|
}
|
|
453
667
|
if (!result || result.summary.length === 0) {
|
|
454
|
-
|
|
668
|
+
if (summaryLifecycleStarted) {
|
|
669
|
+
deps.bus?.emit(BusChannels.CompactionEnd, { trigger, at: Date.now() });
|
|
670
|
+
emitCompactionActivity("completed", "nothing to compact");
|
|
671
|
+
} else {
|
|
672
|
+
rememberEmptyAutomaticAttempt();
|
|
673
|
+
}
|
|
455
674
|
return false;
|
|
456
675
|
}
|
|
676
|
+
if (!summaryLifecycleStarted) startSummaryLifecycle();
|
|
677
|
+
deps.bus?.emit(BusChannels.CompactionEnd, { trigger, at: Date.now() });
|
|
457
678
|
|
|
458
679
|
// The summarization call spends tokens on the same target the turn would
|
|
459
680
|
// have. The ledger entry carries its usage for a later reseed; this is the
|
|
@@ -699,8 +920,9 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
699
920
|
},
|
|
700
921
|
|
|
701
922
|
contextUsage(): ContextUsageSnapshot {
|
|
702
|
-
|
|
703
|
-
|
|
923
|
+
const effectiveWindow = state.runtime
|
|
924
|
+
? state.runtime.runtimeResolution.contextWindowDetails.effectiveContextWindow
|
|
925
|
+
: windowWithoutRuntime().contextWindow;
|
|
704
926
|
if (!currentContextSnapshot) {
|
|
705
927
|
return contextUsageSnapshot(null, effectiveWindow);
|
|
706
928
|
}
|
|
@@ -720,28 +942,27 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
720
942
|
const settings = deps.getSettings();
|
|
721
943
|
const compactionThreshold = settings.compaction?.threshold ?? null;
|
|
722
944
|
const compactionAuto = settings.compaction?.auto !== false;
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
const
|
|
736
|
-
const
|
|
945
|
+
// Without a runtime (before the first turn of this process, /resume
|
|
946
|
+
// included) the window comes from the live resolution or the resumed
|
|
947
|
+
// snapshot, and the token facts from the snapshot: the resumed
|
|
948
|
+
// messages are the ones it measured.
|
|
949
|
+
const window = state.runtime
|
|
950
|
+
? {
|
|
951
|
+
contextWindow: state.runtime.runtimeResolution.contextWindowDetails.effectiveContextWindow,
|
|
952
|
+
contextWindowSource: state.runtime.runtimeResolution.contextWindowDetails.contextWindowSource,
|
|
953
|
+
contextWindowSlots: state.runtime.runtimeResolution.contextWindowDetails.contextWindowSlots,
|
|
954
|
+
}
|
|
955
|
+
: windowWithoutRuntime();
|
|
956
|
+
const provider = state.runtime?.targetId ?? settings.orchestrator?.target ?? null;
|
|
957
|
+
const model = state.runtime?.wireModelId ?? settings.orchestrator?.model ?? null;
|
|
958
|
+
const liveToolCount = state.runtime?.agent.state.tools.length ?? 0;
|
|
737
959
|
|
|
738
960
|
if (!currentContextSnapshot) {
|
|
739
961
|
return buildContextLedger({
|
|
740
962
|
provider,
|
|
741
963
|
model,
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
toolCount: state.runtime.agent.state.tools.length,
|
|
964
|
+
...window,
|
|
965
|
+
toolCount: liveToolCount,
|
|
745
966
|
compactionThreshold,
|
|
746
967
|
compactionAuto,
|
|
747
968
|
promptCache: lastPromptCache,
|
|
@@ -756,15 +977,14 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
756
977
|
return buildContextLedger({
|
|
757
978
|
provider,
|
|
758
979
|
model,
|
|
759
|
-
|
|
760
|
-
contextWindowSource: windowDetails.contextWindowSource,
|
|
980
|
+
...window,
|
|
761
981
|
compactionThreshold,
|
|
762
982
|
compactionAuto,
|
|
763
983
|
systemPromptTokens: currentContextSnapshot.categories.system,
|
|
764
984
|
toolSchemaTokens: currentContextSnapshot.categories.tools,
|
|
765
985
|
// Persisted snapshots strip the captured schemas; fall back to
|
|
766
986
|
// the live agent state after a session resume.
|
|
767
|
-
toolCount: currentContextSnapshot.activeToolSchemas?.length ??
|
|
987
|
+
toolCount: currentContextSnapshot.activeToolSchemas?.length ?? liveToolCount,
|
|
768
988
|
messageTokens: currentContextSnapshot.categories.messages,
|
|
769
989
|
agentsTokens: currentContextSnapshot.categories.agents,
|
|
770
990
|
skillsTokens: currentContextSnapshot.categories.skills,
|
|
@@ -790,16 +1010,17 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
790
1010
|
consumeExpectedColdReasons(runtimeId: string): void {
|
|
791
1011
|
// Cache-disturbance honesty (T3.3): consume disturbances since
|
|
792
1012
|
// the last settled run. Only single-slot local backends lose their
|
|
793
|
-
// prefix cache to interleaved work, so
|
|
794
|
-
// stamp
|
|
1013
|
+
// prefix cache to interleaved work, so dispatch and compaction
|
|
1014
|
+
// stamp only on local-native targets; a working-set eviction moved
|
|
1015
|
+
// the prefix itself and stamps on every tier (see stampsOnTier).
|
|
795
1016
|
runExpectedColdReasons = [];
|
|
796
|
-
|
|
1017
|
+
nextAssistantColdReasons = [];
|
|
797
1018
|
if (pendingColdReasons.size > 0) {
|
|
798
|
-
const reasons = [...pendingColdReasons];
|
|
1019
|
+
const reasons = [...pendingColdReasons].filter((reason) => stampsOnTier(reason, runtimeId));
|
|
799
1020
|
pendingColdReasons.clear();
|
|
800
|
-
if (
|
|
1021
|
+
if (reasons.length > 0) {
|
|
801
1022
|
runExpectedColdReasons = reasons;
|
|
802
|
-
|
|
1023
|
+
nextAssistantColdReasons = reasons;
|
|
803
1024
|
deps.emitNotice(`[context engine] backend prefix cache likely cold this turn: ${reasons.join(", ")}`);
|
|
804
1025
|
}
|
|
805
1026
|
}
|
|
@@ -818,9 +1039,9 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
818
1039
|
cacheWrite,
|
|
819
1040
|
backendVerdict: backendCacheVerdict(input, cacheRead),
|
|
820
1041
|
};
|
|
821
|
-
if (
|
|
822
|
-
promptCache.expectedColdReasons = [...
|
|
823
|
-
|
|
1042
|
+
if (nextAssistantColdReasons.length > 0) {
|
|
1043
|
+
promptCache.expectedColdReasons = [...nextAssistantColdReasons];
|
|
1044
|
+
nextAssistantColdReasons = [];
|
|
824
1045
|
}
|
|
825
1046
|
return promptCache;
|
|
826
1047
|
},
|
|
@@ -834,6 +1055,7 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
834
1055
|
cacheWriteTokens: cacheSummary.cacheRead > 0 || cacheSummary.cacheWrite > 0 ? cacheSummary.cacheWrite : null,
|
|
835
1056
|
uncachedInputTokens: cacheSummary.input,
|
|
836
1057
|
backendVerdict: runFirstCallVerdict,
|
|
1058
|
+
...(runExpectedColdReasons.length > 0 ? { expectedColdReasons: [...runExpectedColdReasons] } : {}),
|
|
837
1059
|
};
|
|
838
1060
|
}
|
|
839
1061
|
},
|
|
@@ -844,6 +1066,7 @@ export function createTurnContext(deps: TurnContextDeps): TurnContext {
|
|
|
844
1066
|
sessionPromptKey = null;
|
|
845
1067
|
sessionWorkingContextPaths.clear();
|
|
846
1068
|
pendingPromptLogEntry = null;
|
|
1069
|
+
emptyAutoCompactTurnId = null;
|
|
847
1070
|
const session = deps.session?.current();
|
|
848
1071
|
currentContextSnapshot = session ? getLatestContextSnapshot(session) : null;
|
|
849
1072
|
},
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
type MiddlewareToolChoiceControl,
|
|
16
16
|
} from "../domains/middleware/index.js";
|
|
17
17
|
import type { SessionContract } from "../domains/session/contract.js";
|
|
18
|
-
import type { CompactionTrigger } from "../domains/session/entries.js";
|
|
18
|
+
import type { CompactionTrigger, EvictionTrigger, RecallTrigger } from "../domains/session/entries.js";
|
|
19
19
|
import type { AgentMessage } from "../engine/types.js";
|
|
20
20
|
import { extractText, hasStructuredToolCall, toolNamesFromAgentState } from "./chat-loop-messages.js";
|
|
21
21
|
import type { AgentRuntime, ChatTurnState } from "./turn-state.js";
|
|
@@ -42,8 +42,8 @@ export interface TurnMiddleware {
|
|
|
42
42
|
terminalToolResult?: { toolCallId: string; toolName: string },
|
|
43
43
|
): Promise<void>;
|
|
44
44
|
fireCompactionHook(
|
|
45
|
-
stage: "mask_observations" | "llm_summary",
|
|
46
|
-
trigger: CompactionTrigger,
|
|
45
|
+
stage: "mask_observations" | "working_set_evict" | "working_set_recall" | "llm_summary",
|
|
46
|
+
trigger: CompactionTrigger | EvictionTrigger | RecallTrigger,
|
|
47
47
|
tokensBefore?: number,
|
|
48
48
|
): void;
|
|
49
49
|
flushPendingReminders(): string;
|
|
@@ -205,6 +205,7 @@ export function createTurnMiddleware(deps: TurnMiddlewareDeps): TurnMiddleware {
|
|
|
205
205
|
runtimeTier: agentRuntime.runtimeResolution.runtimeTier ?? "",
|
|
206
206
|
activeToolNames: toolNamesFromAgentState(agentRuntime.agent.state.tools).join(","),
|
|
207
207
|
turnToolCalls: state.turnToolCalls,
|
|
208
|
+
turnToolNames: state.turnToolNames.join(","),
|
|
208
209
|
sharedWorkerNote: state.turnSharedWorkerNote,
|
|
209
210
|
};
|
|
210
211
|
if (terminalToolResult !== undefined) {
|
|
@@ -240,9 +241,9 @@ export function createTurnMiddleware(deps: TurnMiddlewareDeps): TurnMiddleware {
|
|
|
240
241
|
},
|
|
241
242
|
|
|
242
243
|
/**
|
|
243
|
-
* Observe-only lifecycle point fired before each compaction
|
|
244
|
-
*
|
|
245
|
-
*
|
|
244
|
+
* Observe-only lifecycle point fired before each compaction or working-set
|
|
245
|
+
* stage. Consumers record telemetry or state around projected context
|
|
246
|
+
* changes; returned effects are discarded by design.
|
|
246
247
|
*/
|
|
247
248
|
fireCompactionHook(stage, trigger, tokensBefore): void {
|
|
248
249
|
if (!deps.middleware) return;
|