@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
|
@@ -3,6 +3,7 @@ import type { RunPersonaOverride, RunPipelineProvenance, RunReceiptAutonomyEnfor
|
|
|
3
3
|
import type { EvalCommandPhase, EvalFailureClass, EvalRunRecord } from "../eval/index.js";
|
|
4
4
|
import type { ProtectedArtifact } from "../safety/protected-artifacts.js";
|
|
5
5
|
import type { RunEscalationCounts } from "./provenance.js";
|
|
6
|
+
import type { CanonicalTrustStatus } from "./trust-status.js";
|
|
6
7
|
|
|
7
8
|
export const EVIDENCE_VERSION = 1;
|
|
8
9
|
|
|
@@ -131,13 +132,38 @@ export interface EvidenceBuildResult {
|
|
|
131
132
|
directory: string;
|
|
132
133
|
overview: EvidenceOverview;
|
|
133
134
|
findings: EvidenceFinding[];
|
|
135
|
+
trustStatus: EvidenceTrustStatusFile;
|
|
134
136
|
}
|
|
135
137
|
|
|
136
138
|
export interface EvidenceInspectable {
|
|
137
139
|
overview: EvidenceOverview;
|
|
138
140
|
findings: EvidenceFinding[];
|
|
141
|
+
trustStatus: EvidenceTrustStatusView;
|
|
139
142
|
}
|
|
140
143
|
|
|
144
|
+
export interface EvidenceRunTrustStatus {
|
|
145
|
+
runId: string;
|
|
146
|
+
status: CanonicalTrustStatus;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Canonical per-run projection persisted by current evidence builders. */
|
|
150
|
+
export interface EvidenceTrustStatusFile {
|
|
151
|
+
version: 1;
|
|
152
|
+
evidenceId: string;
|
|
153
|
+
projection: "canonical";
|
|
154
|
+
runs: EvidenceRunTrustStatus[];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Explicit compatibility result for a bundle built before the projection existed. */
|
|
158
|
+
export interface HistoricalEvidenceTrustStatus {
|
|
159
|
+
version: 1;
|
|
160
|
+
evidenceId: string;
|
|
161
|
+
projection: "historical_format";
|
|
162
|
+
runs: [];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export type EvidenceTrustStatusView = EvidenceTrustStatusFile | HistoricalEvidenceTrustStatus;
|
|
166
|
+
|
|
141
167
|
export interface EvidenceRunSource {
|
|
142
168
|
envelope: RunEnvelope;
|
|
143
169
|
receipt: RunReceipt | null;
|
|
@@ -6,6 +6,20 @@ export {
|
|
|
6
6
|
rejectMemoryRecord,
|
|
7
7
|
selectApprovedMemory,
|
|
8
8
|
} from "./operations.js";
|
|
9
|
+
export {
|
|
10
|
+
applyScopeIdentity,
|
|
11
|
+
MEMORY_PROMOTION_SCOPES,
|
|
12
|
+
type MemoryPromotionScope,
|
|
13
|
+
type MemoryPromotionSource,
|
|
14
|
+
type MemoryPromotionSourceRedaction,
|
|
15
|
+
type MemoryScopeSelection,
|
|
16
|
+
memoryAgentIdentity,
|
|
17
|
+
memoryRecordFromPromotion,
|
|
18
|
+
memoryRuntimeIdentity,
|
|
19
|
+
memoryScopeIdentityKey,
|
|
20
|
+
proposeMemoryPromotion,
|
|
21
|
+
validateMemoryScopeSelection,
|
|
22
|
+
} from "./promotion.js";
|
|
9
23
|
export {
|
|
10
24
|
buildMemoryPromptSection,
|
|
11
25
|
MEMORY_PROMPT_DEFAULT_MAX_ITEMS,
|
|
@@ -46,7 +60,9 @@ export {
|
|
|
46
60
|
type TaskMemorySnapshot,
|
|
47
61
|
} from "./task-bank.js";
|
|
48
62
|
export {
|
|
63
|
+
type LegacyTaskMemoryHandoffSnapshot,
|
|
49
64
|
parseTaskMemoryHandoffSnapshot,
|
|
65
|
+
type ReviewedTaskMemoryHandoffSnapshot,
|
|
50
66
|
readNewestTaskMemoryHandoff,
|
|
51
67
|
renderTaskMemoryHandoffSnapshot,
|
|
52
68
|
renderTaskMemoryHandoffSource,
|
|
@@ -57,9 +73,11 @@ export {
|
|
|
57
73
|
type TaskMemoryHandoffArtifact,
|
|
58
74
|
type TaskMemoryHandoffEntry,
|
|
59
75
|
type TaskMemoryHandoffOffer,
|
|
76
|
+
type TaskMemoryHandoffRedaction,
|
|
60
77
|
type TaskMemoryHandoffSeedOutcome,
|
|
61
78
|
type TaskMemoryHandoffSeedResult,
|
|
62
79
|
type TaskMemoryHandoffSnapshot,
|
|
80
|
+
type TaskMemoryHandoffSourceProvenance,
|
|
63
81
|
taskMemoryHandoffSeedOffer,
|
|
64
82
|
taskMemoryHandoffSnapshot,
|
|
65
83
|
} from "./task-memory-handoff.js";
|
|
@@ -112,12 +130,16 @@ export {
|
|
|
112
130
|
taskMemoryTracePath,
|
|
113
131
|
} from "./task-memory-trace.js";
|
|
114
132
|
export type {
|
|
133
|
+
MemoryAgentIdentity,
|
|
134
|
+
MemoryPromotionRedaction,
|
|
115
135
|
MemoryProposalResult,
|
|
116
136
|
MemoryPruneResult,
|
|
117
137
|
MemoryRecord,
|
|
138
|
+
MemoryRecordProvenance,
|
|
118
139
|
MemoryRecordValidationResult,
|
|
119
140
|
MemoryRepositoryIdentity,
|
|
120
141
|
MemoryRetrievalOptions,
|
|
142
|
+
MemoryRuntimeIdentity,
|
|
121
143
|
MemoryScope,
|
|
122
144
|
MemoryStatus,
|
|
123
145
|
MemoryStoreFile,
|
|
@@ -2,7 +2,13 @@ import { isAbsolute } from "node:path";
|
|
|
2
2
|
import { canonicalizeExistingPath } from "../../core/path-canonical.js";
|
|
3
3
|
import { ceilChars } from "../session/context-accounting.js";
|
|
4
4
|
import { pruneStaleMemoryRecords, sortMemoryRecords, updateMemoryRecord } from "./store.js";
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
MemoryAgentIdentity,
|
|
7
|
+
MemoryRecord,
|
|
8
|
+
MemoryRepositoryIdentity,
|
|
9
|
+
MemoryRetrievalOptions,
|
|
10
|
+
MemoryRuntimeIdentity,
|
|
11
|
+
} from "./types.js";
|
|
6
12
|
|
|
7
13
|
export async function approveMemoryRecord(
|
|
8
14
|
dataDir: string,
|
|
@@ -31,12 +37,16 @@ export function selectApprovedMemory(
|
|
|
31
37
|
if (options.tokenBudget <= 0) return [];
|
|
32
38
|
const allowedScopes = options.scopes === undefined ? null : new Set(options.scopes);
|
|
33
39
|
const activeRepository = canonicalActiveRepository(options.activeRepository);
|
|
40
|
+
const activeRuntime = validActiveNamedIdentity(options.activeRuntime, "runtime");
|
|
41
|
+
const activeAgent = validActiveNamedIdentity(options.activeAgent, "agent");
|
|
34
42
|
const candidates = sortMemoryRecords(records)
|
|
35
43
|
.filter((record) => record.approved)
|
|
36
44
|
.filter((record) => record.evidenceRefs.length > 0)
|
|
37
45
|
.filter((record) => record.regressions === undefined || record.regressions.length === 0)
|
|
38
46
|
.filter((record) => allowedScopes === null || allowedScopes.has(record.scope))
|
|
39
47
|
.filter((record) => repositoryApplies(record, activeRepository))
|
|
48
|
+
.filter((record) => runtimeApplies(record, activeRuntime))
|
|
49
|
+
.filter((record) => agentApplies(record, activeAgent))
|
|
40
50
|
.sort(compareRetrievalPriority);
|
|
41
51
|
const selected: MemoryRecord[] = [];
|
|
42
52
|
let spent = 0;
|
|
@@ -55,6 +65,8 @@ export function estimateMemoryTokens(record: MemoryRecord): number {
|
|
|
55
65
|
record.key,
|
|
56
66
|
record.lesson,
|
|
57
67
|
...(record.repository === undefined ? [] : [record.repository.kind, record.repository.key]),
|
|
68
|
+
...(record.runtime === undefined ? [] : [record.runtime.kind, record.runtime.key]),
|
|
69
|
+
...(record.agent === undefined ? [] : [record.agent.kind, record.agent.key]),
|
|
58
70
|
...record.evidenceRefs,
|
|
59
71
|
...record.appliesWhen,
|
|
60
72
|
...record.avoidWhen,
|
|
@@ -80,6 +92,21 @@ function cloneRecord(record: MemoryRecord): MemoryRecord {
|
|
|
80
92
|
if (record.regressions !== undefined) next.regressions = [...record.regressions];
|
|
81
93
|
if (record.rejectedAt !== undefined) next.rejectedAt = record.rejectedAt;
|
|
82
94
|
if (record.repository !== undefined) next.repository = { ...record.repository };
|
|
95
|
+
if (record.runtime !== undefined) next.runtime = { ...record.runtime };
|
|
96
|
+
if (record.agent !== undefined) next.agent = { ...record.agent };
|
|
97
|
+
if (record.provenance !== undefined) {
|
|
98
|
+
next.provenance = {
|
|
99
|
+
...record.provenance,
|
|
100
|
+
...(record.provenance.redaction === undefined
|
|
101
|
+
? {}
|
|
102
|
+
: {
|
|
103
|
+
redaction: {
|
|
104
|
+
...record.provenance.redaction,
|
|
105
|
+
sourceFields: [...record.provenance.redaction.sourceFields],
|
|
106
|
+
},
|
|
107
|
+
}),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
83
110
|
return next;
|
|
84
111
|
}
|
|
85
112
|
|
|
@@ -115,6 +142,36 @@ function repositoryApplies(record: MemoryRecord, activeRepository: MemoryReposit
|
|
|
115
142
|
return record.repository.kind === activeRepository.kind && record.repository.key === activeRepository.key;
|
|
116
143
|
}
|
|
117
144
|
|
|
145
|
+
function runtimeApplies(record: MemoryRecord, activeRuntime: MemoryRuntimeIdentity | null): boolean {
|
|
146
|
+
if (record.scope !== "runtime") return true;
|
|
147
|
+
if (activeRuntime === null || record.runtime === undefined) return false;
|
|
148
|
+
return record.runtime.kind === activeRuntime.kind && record.runtime.key === activeRuntime.key;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function agentApplies(record: MemoryRecord, activeAgent: MemoryAgentIdentity | null): boolean {
|
|
152
|
+
if (record.scope !== "agent") return true;
|
|
153
|
+
if (activeAgent === null || record.agent === undefined) return false;
|
|
154
|
+
return record.agent.kind === activeAgent.kind && record.agent.key === activeAgent.key;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function validActiveNamedIdentity<T extends "runtime" | "agent">(
|
|
158
|
+
identity: { kind: T; key: string } | null | undefined,
|
|
159
|
+
kind: T,
|
|
160
|
+
): { kind: T; key: string } | null {
|
|
161
|
+
if (
|
|
162
|
+
identity === null ||
|
|
163
|
+
identity === undefined ||
|
|
164
|
+
identity.kind !== kind ||
|
|
165
|
+
identity.key.length === 0 ||
|
|
166
|
+
identity.key.length > 256 ||
|
|
167
|
+
identity.key.trim() !== identity.key ||
|
|
168
|
+
/[\0\r\n\t ]/u.test(identity.key)
|
|
169
|
+
) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
return { kind, key: identity.key };
|
|
173
|
+
}
|
|
174
|
+
|
|
118
175
|
function isUsableAbsoluteRepositoryPath(value: string): boolean {
|
|
119
176
|
return value.length > 0 && !/[\0\r\n]/u.test(value) && isAbsolute(value);
|
|
120
177
|
}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { createRedactionTally, redactSecretsText } from "../evidence/redact.js";
|
|
3
|
+
import { canonicalMemoryRepositoryIdentity } from "./operations.js";
|
|
4
|
+
import { loadMemoryRecords, upsertMemoryRecord } from "./store.js";
|
|
5
|
+
import type { TaskMemoryEntry, TaskMemoryRenderableClass } from "./task-bank.js";
|
|
6
|
+
import type {
|
|
7
|
+
MemoryAgentIdentity,
|
|
8
|
+
MemoryProposalResult,
|
|
9
|
+
MemoryRecord,
|
|
10
|
+
MemoryRepositoryIdentity,
|
|
11
|
+
MemoryRuntimeIdentity,
|
|
12
|
+
} from "./types.js";
|
|
13
|
+
import { validateMemoryRecord } from "./validate.js";
|
|
14
|
+
|
|
15
|
+
export const MEMORY_PROMOTION_SCOPES = ["repo", "global", "runtime", "agent"] as const;
|
|
16
|
+
export type MemoryPromotionScope = (typeof MEMORY_PROMOTION_SCOPES)[number];
|
|
17
|
+
|
|
18
|
+
export type MemoryScopeSelection =
|
|
19
|
+
| { scope: "repo"; repository: MemoryRepositoryIdentity }
|
|
20
|
+
| { scope: "global"; acknowledgeGlobal: true }
|
|
21
|
+
| { scope: "runtime"; runtime: MemoryRuntimeIdentity }
|
|
22
|
+
| { scope: "agent"; agent: MemoryAgentIdentity };
|
|
23
|
+
|
|
24
|
+
export interface MemoryPromotionSourceRedaction {
|
|
25
|
+
replacementCount: number;
|
|
26
|
+
sourceFields: ReadonlyArray<string>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface MemoryPromotionSource {
|
|
30
|
+
kind: "task-bank-entry" | "handoff-snapshot";
|
|
31
|
+
sessionId: string;
|
|
32
|
+
evidenceRefs: ReadonlyArray<string>;
|
|
33
|
+
entry: TaskMemoryEntry;
|
|
34
|
+
runtimeIds?: ReadonlyArray<string>;
|
|
35
|
+
agentIds?: ReadonlyArray<string>;
|
|
36
|
+
redaction?: MemoryPromotionSourceRedaction;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface ScopeSourceIdentities {
|
|
40
|
+
runtimeIds?: ReadonlyArray<string>;
|
|
41
|
+
agentIds?: ReadonlyArray<string>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Validate an operator-selected scope without inferring or widening it.
|
|
46
|
+
* Runtime and agent scopes must name identities carried by the source.
|
|
47
|
+
*/
|
|
48
|
+
export function validateMemoryScopeSelection(
|
|
49
|
+
selection: MemoryScopeSelection,
|
|
50
|
+
source: ScopeSourceIdentities,
|
|
51
|
+
): MemoryScopeSelection {
|
|
52
|
+
switch (selection.scope) {
|
|
53
|
+
case "repo": {
|
|
54
|
+
const repository = canonicalMemoryRepositoryIdentity(selection.repository.key);
|
|
55
|
+
if (
|
|
56
|
+
selection.repository.kind !== "canonical-path" ||
|
|
57
|
+
repository === null ||
|
|
58
|
+
repository.key !== selection.repository.key
|
|
59
|
+
) {
|
|
60
|
+
throw new Error("repo scope requires an existing canonical absolute repository identity");
|
|
61
|
+
}
|
|
62
|
+
return { scope: "repo", repository };
|
|
63
|
+
}
|
|
64
|
+
case "global":
|
|
65
|
+
if (selection.acknowledgeGlobal !== true) {
|
|
66
|
+
throw new Error("global scope requires a separate operator acknowledgement");
|
|
67
|
+
}
|
|
68
|
+
return selection;
|
|
69
|
+
case "runtime": {
|
|
70
|
+
const runtime = normalizeNamedIdentity(selection.runtime, "runtime");
|
|
71
|
+
if (!(source.runtimeIds ?? []).includes(runtime.key)) {
|
|
72
|
+
throw new Error(`runtime identity '${runtime.key}' does not match the promotion source`);
|
|
73
|
+
}
|
|
74
|
+
return { scope: "runtime", runtime };
|
|
75
|
+
}
|
|
76
|
+
case "agent": {
|
|
77
|
+
const agent = normalizeNamedIdentity(selection.agent, "agent");
|
|
78
|
+
if (!(source.agentIds ?? []).includes(agent.key)) {
|
|
79
|
+
throw new Error(`agent identity '${agent.key}' does not match the promotion source`);
|
|
80
|
+
}
|
|
81
|
+
return { scope: "agent", agent };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function memoryRuntimeIdentity(key: string): MemoryRuntimeIdentity {
|
|
87
|
+
return normalizeNamedIdentity({ kind: "runtime", key }, "runtime");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function memoryAgentIdentity(key: string): MemoryAgentIdentity {
|
|
91
|
+
return normalizeNamedIdentity({ kind: "agent", key }, "agent");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Create one reviewable proposal from a selected non-private task-bank entry. */
|
|
95
|
+
export async function proposeMemoryPromotion(
|
|
96
|
+
dataDir: string,
|
|
97
|
+
source: MemoryPromotionSource,
|
|
98
|
+
selection: MemoryScopeSelection,
|
|
99
|
+
now: Date = new Date(),
|
|
100
|
+
): Promise<MemoryProposalResult> {
|
|
101
|
+
validatePromotionSource(source);
|
|
102
|
+
const validatedScope = validateMemoryScopeSelection(selection, {
|
|
103
|
+
runtimeIds: source.runtimeIds ?? [],
|
|
104
|
+
agentIds: source.agentIds ?? [],
|
|
105
|
+
});
|
|
106
|
+
const record = memoryRecordFromPromotion(source, validatedScope, now);
|
|
107
|
+
const existing = (await loadMemoryRecords(dataDir)).find((candidate) => candidate.id === record.id);
|
|
108
|
+
if (existing !== undefined) return { record: existing, created: false };
|
|
109
|
+
await upsertMemoryRecord(dataDir, record);
|
|
110
|
+
return { record, created: true };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function memoryRecordFromPromotion(
|
|
114
|
+
source: MemoryPromotionSource,
|
|
115
|
+
selection: MemoryScopeSelection,
|
|
116
|
+
now: Date = new Date(),
|
|
117
|
+
): MemoryRecord {
|
|
118
|
+
validatePromotionSource(source);
|
|
119
|
+
const entryKind = source.entry.kind;
|
|
120
|
+
if (entryKind === "status") throw new Error("private task-memory status cannot be promoted");
|
|
121
|
+
const validatedScope = validateMemoryScopeSelection(selection, {
|
|
122
|
+
runtimeIds: source.runtimeIds ?? [],
|
|
123
|
+
agentIds: source.agentIds ?? [],
|
|
124
|
+
});
|
|
125
|
+
const tally = createRedactionTally();
|
|
126
|
+
const lesson = redactPromotionText(source.entry.content, tally).replace(/\s+/gu, " ").trim();
|
|
127
|
+
const sourceFields = new Set(source.redaction?.sourceFields ?? []);
|
|
128
|
+
if (lesson !== source.entry.content) sourceFields.add("content");
|
|
129
|
+
const replacementCount = (source.redaction?.replacementCount ?? 0) + tally.count;
|
|
130
|
+
const scopeKey = memoryScopeIdentityKey(validatedScope);
|
|
131
|
+
const record: MemoryRecord = {
|
|
132
|
+
id: promotedMemoryId({
|
|
133
|
+
sourceKind: source.kind,
|
|
134
|
+
sessionId: source.sessionId,
|
|
135
|
+
entryId: source.entry.id,
|
|
136
|
+
entryKind,
|
|
137
|
+
evidenceRefs: uniqueStrings(source.evidenceRefs),
|
|
138
|
+
lesson,
|
|
139
|
+
scopeKey,
|
|
140
|
+
}),
|
|
141
|
+
scope: validatedScope.scope,
|
|
142
|
+
key: `promotion:${source.kind}:${source.sessionId}:${source.entry.id}`,
|
|
143
|
+
lesson,
|
|
144
|
+
evidenceRefs: uniqueStrings(source.evidenceRefs),
|
|
145
|
+
appliesWhen: scopeApplicability(validatedScope),
|
|
146
|
+
avoidWhen: [],
|
|
147
|
+
confidence: 0.6,
|
|
148
|
+
createdAt: now.toISOString(),
|
|
149
|
+
approved: false,
|
|
150
|
+
provenance: {
|
|
151
|
+
sourceKind: source.kind,
|
|
152
|
+
sourceSessionId: source.sessionId,
|
|
153
|
+
sourceEntryId: source.entry.id,
|
|
154
|
+
sourceEntryKind: entryKind,
|
|
155
|
+
sourceEntryCreatedAt: source.entry.createdAt,
|
|
156
|
+
sourceEntryLastTouchedAt: source.entry.lastTouchedAt,
|
|
157
|
+
redaction: {
|
|
158
|
+
appliedBeforePersistence: true,
|
|
159
|
+
replacementCount,
|
|
160
|
+
sourceFields: [...sourceFields].sort(compareStrings),
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
applyScopeIdentity(record, validatedScope);
|
|
165
|
+
const validated = validateMemoryRecord(record);
|
|
166
|
+
if (!validated.valid) {
|
|
167
|
+
throw new Error(
|
|
168
|
+
`promoted memory record invalid: ${validated.issues.map((issue) => `${issue.path}: ${issue.message}`).join("; ")}`,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
return validated.record;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function applyScopeIdentity(record: MemoryRecord, selection: MemoryScopeSelection): void {
|
|
175
|
+
if (selection.scope === "repo") record.repository = { ...selection.repository };
|
|
176
|
+
if (selection.scope === "runtime") record.runtime = { ...selection.runtime };
|
|
177
|
+
if (selection.scope === "agent") record.agent = { ...selection.agent };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function memoryScopeIdentityKey(selection: MemoryScopeSelection): string {
|
|
181
|
+
switch (selection.scope) {
|
|
182
|
+
case "repo":
|
|
183
|
+
return `repo:${selection.repository.kind}:${selection.repository.key}`;
|
|
184
|
+
case "global":
|
|
185
|
+
return "global:acknowledged";
|
|
186
|
+
case "runtime":
|
|
187
|
+
return `runtime:${selection.runtime.key}`;
|
|
188
|
+
case "agent":
|
|
189
|
+
return `agent:${selection.agent.key}`;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function validatePromotionSource(source: MemoryPromotionSource): void {
|
|
194
|
+
if (!validSourceValue(source.sessionId)) throw new Error("promotion requires a valid source session id");
|
|
195
|
+
if (source.evidenceRefs.length === 0 || source.evidenceRefs.some((value) => !validSourceValue(value))) {
|
|
196
|
+
throw new Error("promotion requires at least one valid source evidence ref");
|
|
197
|
+
}
|
|
198
|
+
if (source.entry.kind === "status") throw new Error("private task-memory status cannot be promoted");
|
|
199
|
+
if (source.entry.kind !== "knowledge" && source.entry.kind !== "procedural") {
|
|
200
|
+
throw new Error("promotion requires a knowledge or procedural task-memory entry");
|
|
201
|
+
}
|
|
202
|
+
if (!validSourceValue(source.entry.id) || source.entry.content.trim().length === 0) {
|
|
203
|
+
throw new Error("promotion requires a valid task-memory entry");
|
|
204
|
+
}
|
|
205
|
+
for (const runtimeId of source.runtimeIds ?? []) memoryRuntimeIdentity(runtimeId);
|
|
206
|
+
for (const agentId of source.agentIds ?? []) memoryAgentIdentity(agentId);
|
|
207
|
+
if (source.redaction !== undefined) {
|
|
208
|
+
if (!Number.isInteger(source.redaction.replacementCount) || source.redaction.replacementCount < 0) {
|
|
209
|
+
throw new Error("promotion source redaction count must be a non-negative integer");
|
|
210
|
+
}
|
|
211
|
+
if (source.redaction.sourceFields.some((field) => !validSourceValue(field))) {
|
|
212
|
+
throw new Error("promotion source redaction fields must be valid non-empty strings");
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function normalizeNamedIdentity<T extends "runtime" | "agent">(
|
|
218
|
+
identity: { kind: T; key: string },
|
|
219
|
+
kind: T,
|
|
220
|
+
): { kind: T; key: string } {
|
|
221
|
+
if (identity.kind !== kind || !validNamedIdentityKey(identity.key)) {
|
|
222
|
+
throw new Error(`${kind} scope requires a valid ${kind} identity`);
|
|
223
|
+
}
|
|
224
|
+
return { kind, key: identity.key };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function validNamedIdentityKey(value: string): boolean {
|
|
228
|
+
return value.length > 0 && value.length <= 256 && value.trim() === value && !/[\0\r\n\t ]/u.test(value);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function validSourceValue(value: string): boolean {
|
|
232
|
+
return value.length > 0 && value.length <= 1_024 && value.trim() === value && !/[\0\r\n]/u.test(value);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function scopeApplicability(selection: MemoryScopeSelection): string[] {
|
|
236
|
+
switch (selection.scope) {
|
|
237
|
+
case "repo":
|
|
238
|
+
return [`repository:${selection.repository.kind}:${selection.repository.key}`];
|
|
239
|
+
case "global":
|
|
240
|
+
return [];
|
|
241
|
+
case "runtime":
|
|
242
|
+
return [`runtime:${selection.runtime.key}`];
|
|
243
|
+
case "agent":
|
|
244
|
+
return [`agent:${selection.agent.key}`];
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function promotedMemoryId(value: {
|
|
249
|
+
sourceKind: MemoryPromotionSource["kind"];
|
|
250
|
+
sessionId: string;
|
|
251
|
+
entryId: string;
|
|
252
|
+
entryKind: TaskMemoryRenderableClass;
|
|
253
|
+
evidenceRefs: string[];
|
|
254
|
+
lesson: string;
|
|
255
|
+
scopeKey: string;
|
|
256
|
+
}): string {
|
|
257
|
+
const digest = createHash("sha256").update(JSON.stringify(value), "utf8").digest("hex").slice(0, 16);
|
|
258
|
+
return `mem-${digest}`;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function uniqueStrings(values: ReadonlyArray<string>): string[] {
|
|
262
|
+
return [...new Set(values)].sort(compareStrings);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function redactPromotionText(text: string, tally: ReturnType<typeof createRedactionTally>): string {
|
|
266
|
+
const markers: string[] = [];
|
|
267
|
+
const masked = text.replace(/\[redacted:[a-z-]+\]/gu, (marker) => {
|
|
268
|
+
const token = `\uE000${String.fromCharCode(0xe100 + markers.length)}`;
|
|
269
|
+
markers.push(marker);
|
|
270
|
+
return token;
|
|
271
|
+
});
|
|
272
|
+
let redacted = redactSecretsText(masked, tally);
|
|
273
|
+
for (let index = 0; index < markers.length; index += 1) {
|
|
274
|
+
redacted = redacted.replaceAll(`\uE000${String.fromCharCode(0xe100 + index)}`, markers[index] ?? "");
|
|
275
|
+
}
|
|
276
|
+
return redacted;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function compareStrings(left: string, right: string): number {
|
|
280
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
281
|
+
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { estimateMemoryTokens, selectApprovedMemory } from "./operations.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
MemoryAgentIdentity,
|
|
4
|
+
MemoryRecord,
|
|
5
|
+
MemoryRepositoryIdentity,
|
|
6
|
+
MemoryRuntimeIdentity,
|
|
7
|
+
MemoryScope,
|
|
8
|
+
} from "./types.js";
|
|
3
9
|
|
|
4
10
|
export const MEMORY_PROMPT_DEFAULT_TOKEN_BUDGET = 400;
|
|
5
11
|
export const MEMORY_PROMPT_DEFAULT_MAX_ITEMS = 5;
|
|
@@ -20,6 +26,10 @@ export interface MemoryPromptOptions {
|
|
|
20
26
|
maxItems?: number;
|
|
21
27
|
/** Missing or unknown identity leaves global memory eligible but excludes repo memory. */
|
|
22
28
|
activeRepository?: MemoryRepositoryIdentity | null;
|
|
29
|
+
/** Missing or unknown identity excludes runtime-scoped memory. */
|
|
30
|
+
activeRuntime?: MemoryRuntimeIdentity | null;
|
|
31
|
+
/** Missing or unknown identity excludes agent-scoped memory. */
|
|
32
|
+
activeAgent?: MemoryAgentIdentity | null;
|
|
23
33
|
}
|
|
24
34
|
|
|
25
35
|
/**
|
|
@@ -40,6 +50,8 @@ export function selectMemoryForPrompt(
|
|
|
40
50
|
scopes,
|
|
41
51
|
tokenBudget,
|
|
42
52
|
activeRepository: options.activeRepository ?? null,
|
|
53
|
+
activeRuntime: options.activeRuntime ?? null,
|
|
54
|
+
activeAgent: options.activeAgent ?? null,
|
|
43
55
|
});
|
|
44
56
|
return selected.slice(0, maxItems);
|
|
45
57
|
}
|
|
@@ -67,11 +79,19 @@ export function renderMemoryPromptSection(records: ReadonlyArray<MemoryRecord>):
|
|
|
67
79
|
}
|
|
68
80
|
|
|
69
81
|
function renderApplicability(record: MemoryRecord): string {
|
|
70
|
-
if (record.scope
|
|
71
|
-
|
|
72
|
-
|
|
82
|
+
if (record.scope === "repo") {
|
|
83
|
+
if (record.repository !== undefined) {
|
|
84
|
+
return `scope=repo, repository=${JSON.stringify(`${record.repository.kind}:${record.repository.key}`)}`;
|
|
85
|
+
}
|
|
86
|
+
return "scope=repo, repository=unknown";
|
|
73
87
|
}
|
|
74
|
-
|
|
88
|
+
if (record.scope === "runtime") {
|
|
89
|
+
return `scope=runtime, runtime=${JSON.stringify(record.runtime?.key ?? "unknown")}`;
|
|
90
|
+
}
|
|
91
|
+
if (record.scope === "agent") {
|
|
92
|
+
return `scope=agent, agent=${JSON.stringify(record.agent?.key ?? "unknown")}`;
|
|
93
|
+
}
|
|
94
|
+
return `scope=${record.scope}`;
|
|
75
95
|
}
|
|
76
96
|
|
|
77
97
|
/** Convenience for callers that want a single end-to-end build step. */
|
|
@@ -2,8 +2,15 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import type { EvidenceFinding, EvidenceOverview, EvidenceTag } from "../evidence/index.js";
|
|
3
3
|
import { inspectEvidence } from "../evidence/index.js";
|
|
4
4
|
import { canonicalMemoryRepositoryIdentity } from "./operations.js";
|
|
5
|
+
import {
|
|
6
|
+
applyScopeIdentity,
|
|
7
|
+
type MemoryScopeSelection,
|
|
8
|
+
memoryScopeIdentityKey,
|
|
9
|
+
validateMemoryScopeSelection,
|
|
10
|
+
} from "./promotion.js";
|
|
5
11
|
import { loadMemoryRecords, upsertMemoryRecord } from "./store.js";
|
|
6
12
|
import type { MemoryProposalResult, MemoryRecord, MemoryRepositoryIdentity, MemoryScope } from "./types.js";
|
|
13
|
+
import { validateMemoryRecord } from "./validate.js";
|
|
7
14
|
|
|
8
15
|
const LESSON_MAX_CHARS = 240;
|
|
9
16
|
const APPLY_MAX_CHARS = 160;
|
|
@@ -23,12 +30,16 @@ const TAG_PRIORITY = [
|
|
|
23
30
|
"unknown",
|
|
24
31
|
] as const satisfies ReadonlyArray<EvidenceTag>;
|
|
25
32
|
|
|
26
|
-
export async function proposeMemoryFromEvidence(
|
|
33
|
+
export async function proposeMemoryFromEvidence(
|
|
34
|
+
dataDir: string,
|
|
35
|
+
evidenceId: string,
|
|
36
|
+
selection?: MemoryScopeSelection,
|
|
37
|
+
): Promise<MemoryProposalResult> {
|
|
27
38
|
const evidence = await inspectEvidence(dataDir, evidenceId);
|
|
28
|
-
const
|
|
39
|
+
const record = memoryRecordFromEvidence(evidence.overview, evidence.findings, selection);
|
|
40
|
+
const existing = (await loadMemoryRecords(dataDir)).find((candidate) => candidate.id === record.id);
|
|
29
41
|
if (existing !== undefined) return { record: existing, created: false };
|
|
30
42
|
|
|
31
|
-
const record = memoryRecordFromEvidence(evidence.overview, evidence.findings);
|
|
32
43
|
await upsertMemoryRecord(dataDir, record);
|
|
33
44
|
return { record, created: true };
|
|
34
45
|
}
|
|
@@ -41,13 +52,24 @@ export function memoryIdFromEvidence(evidenceId: string): string {
|
|
|
41
52
|
export function memoryRecordFromEvidence(
|
|
42
53
|
overview: EvidenceOverview,
|
|
43
54
|
findings: ReadonlyArray<EvidenceFinding>,
|
|
55
|
+
selection?: MemoryScopeSelection,
|
|
44
56
|
): MemoryRecord {
|
|
45
57
|
const tags = overview.tags;
|
|
46
58
|
const primaryTag = primaryEvidenceTag(tags);
|
|
47
59
|
const repository = inferRepository(overview);
|
|
48
|
-
const
|
|
60
|
+
const validatedSelection =
|
|
61
|
+
selection === undefined
|
|
62
|
+
? undefined
|
|
63
|
+
: validateMemoryScopeSelection(selection, {
|
|
64
|
+
runtimeIds: overview.runtimeIds,
|
|
65
|
+
agentIds: overview.agentIds,
|
|
66
|
+
});
|
|
67
|
+
const scope = validatedSelection?.scope ?? inferScope(overview, repository);
|
|
49
68
|
const record: MemoryRecord = {
|
|
50
|
-
id:
|
|
69
|
+
id:
|
|
70
|
+
validatedSelection === undefined
|
|
71
|
+
? memoryIdFromEvidence(overview.evidenceId)
|
|
72
|
+
: memoryIdFromEvidenceScope(overview.evidenceId, memoryScopeIdentityKey(validatedSelection)),
|
|
51
73
|
scope,
|
|
52
74
|
key: `evidence:${overview.evidenceId}`,
|
|
53
75
|
lesson: truncateText(buildLesson(overview, findings, primaryTag), LESSON_MAX_CHARS),
|
|
@@ -57,9 +79,31 @@ export function memoryRecordFromEvidence(
|
|
|
57
79
|
confidence: confidenceForEvidence(overview, findings),
|
|
58
80
|
createdAt: overview.generatedAt,
|
|
59
81
|
approved: false,
|
|
82
|
+
provenance: {
|
|
83
|
+
sourceKind: "evidence",
|
|
84
|
+
evidenceId: overview.evidenceId,
|
|
85
|
+
...(overview.sessionId === null ? {} : { sourceSessionId: overview.sessionId }),
|
|
86
|
+
},
|
|
60
87
|
};
|
|
61
|
-
if (
|
|
62
|
-
|
|
88
|
+
if (validatedSelection !== undefined) applyScopeIdentity(record, validatedSelection);
|
|
89
|
+
else if (scope === "repo" && repository !== null) record.repository = repository;
|
|
90
|
+
else if (scope === "runtime" && overview.runtimeIds[0] !== undefined) {
|
|
91
|
+
record.runtime = { kind: "runtime", key: overview.runtimeIds[0] };
|
|
92
|
+
} else if (scope === "agent" && overview.agentIds[0] !== undefined) {
|
|
93
|
+
record.agent = { kind: "agent", key: overview.agentIds[0] };
|
|
94
|
+
}
|
|
95
|
+
const validated = validateMemoryRecord(record);
|
|
96
|
+
if (!validated.valid) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`evidence memory record invalid: ${validated.issues.map((issue) => `${issue.path}: ${issue.message}`).join("; ")}`,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return validated.record;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function memoryIdFromEvidenceScope(evidenceId: string, scopeKey: string): string {
|
|
105
|
+
const digest = createHash("sha256").update(`${evidenceId}\n${scopeKey}`, "utf8").digest("hex").slice(0, 16);
|
|
106
|
+
return `mem-${digest}`;
|
|
63
107
|
}
|
|
64
108
|
|
|
65
109
|
/**
|
|
@@ -37,8 +37,9 @@ export interface SaveTaskMemoryOptions {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Per-session execution memory.
|
|
41
|
-
*
|
|
40
|
+
* Per-session execution memory. The bank stays transient and authoritative
|
|
41
|
+
* for one active task. Selected non-private entries can enter the separate
|
|
42
|
+
* durable store only through the reviewed promotion service.
|
|
42
43
|
*/
|
|
43
44
|
export class TaskMemoryBank {
|
|
44
45
|
readonly #knowledgeCap: number;
|