@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
package/src/tools/bash.ts
CHANGED
|
@@ -3,87 +3,124 @@ import { BASH_HARD_CAP_BYTES, combineBashOutput, runBashCommand } from "../core/
|
|
|
3
3
|
import { resolveSafeCwd } from "../core/safe-exec.js";
|
|
4
4
|
import { ToolNames } from "../core/tool-names.js";
|
|
5
5
|
import { expandPath } from "./path-utils.js";
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { toolPresentationPolicy } from "./presentation.js";
|
|
7
|
+
import type { ToolResult, ToolResultDetails, ToolSpec } from "./registry.js";
|
|
8
|
+
import {
|
|
9
|
+
deterministicDiagnosticSummary,
|
|
10
|
+
type NormalizedToolResultDisposition,
|
|
11
|
+
type ToolResultContextDisposition,
|
|
12
|
+
type ToolResultDisposition,
|
|
13
|
+
} from "./result-disposition.js";
|
|
14
|
+
import { DEFAULT_MAX_LINES, truncateTail } from "./truncate.js";
|
|
15
|
+
import { byteLength } from "./truncate-utf8.js";
|
|
9
16
|
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// output is spilled to an offload file before truncating, so nothing is lost.
|
|
17
|
+
// The registry's bounded model projection and operator presentation share this
|
|
18
|
+
// cap. Both are tail-biased for Bash because diagnostics usually land last.
|
|
13
19
|
const BASH_DISPLAY_MAX_BYTES = 16 * 1024;
|
|
14
|
-
|
|
15
|
-
// fits under the registry's per-tool bash budget without a second (head-first)
|
|
16
|
-
// re-truncation cutting the tail we just preserved.
|
|
17
|
-
const BASH_TAIL_NOTE_RESERVE = 512;
|
|
20
|
+
export type BashOutputPolicy = "full" | "bounded" | "summary" | "metadata-only";
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
const BASH_OUTPUT_POLICIES = new Set<BashOutputPolicy>(["full", "bounded", "summary", "metadata-only"]);
|
|
23
|
+
|
|
24
|
+
function bashContextDisposition(policy: BashOutputPolicy): ToolResultContextDisposition & { maxBytes: number } {
|
|
25
|
+
if (policy === "full") {
|
|
26
|
+
return { mode: "full", maxBytes: BASH_DISPLAY_MAX_BYTES, downgradeExcerpt: "tail" };
|
|
27
|
+
}
|
|
28
|
+
if (policy === "summary") {
|
|
29
|
+
return {
|
|
30
|
+
mode: "summary",
|
|
31
|
+
maxBytes: BASH_DISPLAY_MAX_BYTES,
|
|
32
|
+
strategy: "diagnostic",
|
|
33
|
+
redact: true,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (policy === "metadata-only") return { mode: "metadata-only", maxBytes: BASH_DISPLAY_MAX_BYTES };
|
|
37
|
+
return { mode: "bounded", maxBytes: BASH_DISPLAY_MAX_BYTES, excerpt: "tail" };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Canonical default attached by the builtin catalog and reused by direct registries. */
|
|
41
|
+
export const BASH_DEFAULT_RESULT_DISPOSITION: ToolResultDisposition = {
|
|
42
|
+
presentation: {
|
|
43
|
+
...toolPresentationPolicy(ToolNames.Bash, undefined),
|
|
44
|
+
maxBytes: BASH_DISPLAY_MAX_BYTES,
|
|
45
|
+
overflow: "tail",
|
|
46
|
+
},
|
|
47
|
+
context: bashContextDisposition("bounded"),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/** Pure, idempotent normalization used by registry admission and direct calls. */
|
|
51
|
+
export function normalizeBashArguments(args: Record<string, unknown>): Record<string, unknown> {
|
|
52
|
+
return args.output_policy === undefined ? { ...args, output_policy: "bounded" } : args;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function bashOutputPolicy(args: Record<string, unknown>): BashOutputPolicy | null {
|
|
56
|
+
const value = args.output_policy;
|
|
57
|
+
return typeof value === "string" && BASH_OUTPUT_POLICIES.has(value as BashOutputPolicy)
|
|
58
|
+
? (value as BashOutputPolicy)
|
|
59
|
+
: null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function resolveBashResultDisposition(
|
|
63
|
+
args: Record<string, unknown>,
|
|
64
|
+
declared: ToolResultDisposition | undefined = BASH_DEFAULT_RESULT_DISPOSITION,
|
|
65
|
+
): ToolResultDisposition {
|
|
66
|
+
const policy = bashOutputPolicy(args) ?? "bounded";
|
|
67
|
+
const base = declared ?? BASH_DEFAULT_RESULT_DISPOSITION;
|
|
68
|
+
return { presentation: base.presentation, context: bashContextDisposition(policy) };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function normalizedBashDisposition(policy: BashOutputPolicy): NormalizedToolResultDisposition {
|
|
72
|
+
return {
|
|
73
|
+
presentation: { ...BASH_DEFAULT_RESULT_DISPOSITION.presentation, maxBytes: BASH_DISPLAY_MAX_BYTES },
|
|
74
|
+
context: bashContextDisposition(policy),
|
|
75
|
+
};
|
|
22
76
|
}
|
|
23
77
|
|
|
24
78
|
/** Bound a cumulative live snapshot without writing an offload file per tick. */
|
|
25
|
-
function shapeBashProgress(rawOutput: string): ToolResult {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
79
|
+
function shapeBashProgress(rawOutput: string, outputBytes: number, policy: BashOutputPolicy): ToolResult {
|
|
80
|
+
const disposition = normalizedBashDisposition(policy);
|
|
81
|
+
let output: string;
|
|
82
|
+
if (policy === "metadata-only") {
|
|
83
|
+
output = `bash: running; captured ${outputBytes} bytes; stdout/stderr omitted by metadata-only policy`;
|
|
84
|
+
} else if (policy === "summary") {
|
|
85
|
+
output = deterministicDiagnosticSummary(rawOutput, BASH_DISPLAY_MAX_BYTES, true).text;
|
|
86
|
+
} else {
|
|
87
|
+
output = truncateTail(rawOutput, {
|
|
88
|
+
maxLines: DEFAULT_MAX_LINES,
|
|
89
|
+
maxBytes: disposition.context.maxBytes,
|
|
90
|
+
}).content;
|
|
91
|
+
}
|
|
31
92
|
return {
|
|
32
93
|
kind: "ok",
|
|
33
|
-
output
|
|
94
|
+
output,
|
|
34
95
|
details: {
|
|
35
96
|
resultSize: {
|
|
36
|
-
bytes,
|
|
37
|
-
shownBytes:
|
|
97
|
+
bytes: outputBytes,
|
|
98
|
+
shownBytes: byteLength(output),
|
|
38
99
|
maxBytes: BASH_DISPLAY_MAX_BYTES,
|
|
39
|
-
truncated:
|
|
40
|
-
policy
|
|
100
|
+
truncated: byteLength(rawOutput) > byteLength(output),
|
|
101
|
+
policy,
|
|
41
102
|
},
|
|
42
103
|
},
|
|
43
104
|
};
|
|
44
105
|
}
|
|
45
106
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
// `details.resultSize.offloadPath` tells the registry result-shaper to leave
|
|
49
|
-
// this already-shaped (tail-biased) output alone instead of re-truncating it
|
|
50
|
-
// head-first.
|
|
51
|
-
function shapeBashOutput(
|
|
107
|
+
function bashResultDetails(
|
|
108
|
+
result: Awaited<ReturnType<typeof runBashCommand>>,
|
|
52
109
|
rawOutput: string,
|
|
53
|
-
|
|
54
|
-
):
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
: `lines ${startLine}-${truncation.totalLines} of ${truncation.totalLines}`;
|
|
67
|
-
const location = offloadPath !== null ? ` Full output saved to ${offloadPath}; read it with offset/limit.` : "";
|
|
68
|
-
const note = `[Output tail-truncated: showing ${scope} (${formatSize(BASH_DISPLAY_MAX_BYTES)} display limit).${location}]`;
|
|
69
|
-
const details: ToolResultDetails = {
|
|
70
|
-
resultSize: {
|
|
71
|
-
bytes: totalBytes,
|
|
72
|
-
shownBytes: truncation.outputBytes,
|
|
73
|
-
maxBytes: BASH_DISPLAY_MAX_BYTES,
|
|
74
|
-
truncated: true,
|
|
75
|
-
policy: "tail",
|
|
76
|
-
followUpHint: "Read the full-output offload file with offset/limit, or re-run a narrower command.",
|
|
77
|
-
...(offloadPath !== null ? { offloadPath } : {}),
|
|
78
|
-
},
|
|
110
|
+
outcome: "success" | "nonzero" | "timeout" | "abort" | "output-cap",
|
|
111
|
+
): ToolResultDetails {
|
|
112
|
+
return {
|
|
113
|
+
outcome,
|
|
114
|
+
exitCode: result.exitCode,
|
|
115
|
+
signal: result.signal,
|
|
116
|
+
timedOut: result.timedOut,
|
|
117
|
+
aborted: result.aborted,
|
|
118
|
+
outputCapped: result.outputCapped,
|
|
119
|
+
outputBytes: result.outputBytes,
|
|
120
|
+
retainedBytes: byteLength(rawOutput),
|
|
121
|
+
stdoutBytes: byteLength(result.stdout),
|
|
122
|
+
stderrBytes: byteLength(result.stderr),
|
|
79
123
|
};
|
|
80
|
-
return { text: `${truncation.content}\n\n${note}`, details };
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function withDetails(base: ToolResult, details: ToolResultDetails | undefined): ToolResult {
|
|
84
|
-
if (details === undefined) return base;
|
|
85
|
-
if (base.kind === "ok") return { ...base, details };
|
|
86
|
-
return { ...base, details };
|
|
87
124
|
}
|
|
88
125
|
|
|
89
126
|
// A bash command whose first word is a plain file/dir observer has a
|
|
@@ -120,7 +157,7 @@ function observeToolsNudge(command: string, sessionId: string | undefined): stri
|
|
|
120
157
|
export const bashTool: ToolSpec = {
|
|
121
158
|
name: ToolNames.Bash,
|
|
122
159
|
description:
|
|
123
|
-
"Execute a bash command and
|
|
160
|
+
"Execute a bash command inside the session workspace. output_policy controls model context: bounded keeps the diagnostic tail and is the default; summary keeps deterministic redacted diagnostics; metadata-only keeps facts and retrieval; full is admitted only within the result budget.",
|
|
124
161
|
parameters: Type.Object({
|
|
125
162
|
command: Type.String({ description: "Bash command to execute." }),
|
|
126
163
|
cwd: Type.Optional(
|
|
@@ -130,13 +167,30 @@ export const bashTool: ToolSpec = {
|
|
|
130
167
|
}),
|
|
131
168
|
),
|
|
132
169
|
timeout_ms: Type.Optional(Type.Number({ description: "Timeout in milliseconds." })),
|
|
170
|
+
output_policy: Type.Optional(
|
|
171
|
+
Type.Union([Type.Literal("full"), Type.Literal("bounded"), Type.Literal("summary"), Type.Literal("metadata-only")], {
|
|
172
|
+
description:
|
|
173
|
+
"Model-context disposition. Omit for bounded tail output. Use summary for noisy runs, metadata-only when only status and retrieval matter, and full only for known-small output.",
|
|
174
|
+
}),
|
|
175
|
+
),
|
|
133
176
|
}),
|
|
134
177
|
baseActionClass: "execute",
|
|
135
178
|
executionMode: "sequential",
|
|
179
|
+
prepareArguments: normalizeBashArguments,
|
|
180
|
+
resolveResultDisposition: resolveBashResultDisposition,
|
|
136
181
|
async run(args, options): Promise<ToolResult> {
|
|
182
|
+
args = normalizeBashArguments(args);
|
|
137
183
|
if (typeof args.command !== "string" || args.command.length === 0) {
|
|
138
184
|
return { kind: "error", message: "bash: missing command argument" };
|
|
139
185
|
}
|
|
186
|
+
const outputPolicy = bashOutputPolicy(args);
|
|
187
|
+
if (outputPolicy === null) {
|
|
188
|
+
return {
|
|
189
|
+
kind: "error",
|
|
190
|
+
message: "bash: output_policy must be one of full, bounded, summary, or metadata-only (omit it for bounded)",
|
|
191
|
+
details: { outcome: "invalid-arguments", exitCode: null },
|
|
192
|
+
};
|
|
193
|
+
}
|
|
140
194
|
const cwdArg = typeof args.cwd === "string" && args.cwd.length > 0 ? args.cwd : undefined;
|
|
141
195
|
// Pin the child's cwd inside the session workspace in the tool itself.
|
|
142
196
|
// The safety net blocks escaping cwd arguments at admission; this is the
|
|
@@ -161,41 +215,49 @@ export const bashTool: ToolSpec = {
|
|
|
161
215
|
};
|
|
162
216
|
if (options?.onUpdate !== undefined) {
|
|
163
217
|
runOptions.onUpdate = (progress) => {
|
|
164
|
-
options.onUpdate?.(shapeBashProgress(combineBashOutput(progress)));
|
|
218
|
+
options.onUpdate?.(shapeBashProgress(combineBashOutput(progress), progress.outputBytes, outputPolicy));
|
|
165
219
|
};
|
|
166
220
|
}
|
|
167
221
|
const result = await runBashCommand(args.command, runOptions);
|
|
168
222
|
const { error, aborted, timedOut, outputCapped } = result;
|
|
223
|
+
const rawOutput = combineBashOutput(result);
|
|
224
|
+
const output = rawOutput.trim();
|
|
169
225
|
if (aborted) {
|
|
170
|
-
|
|
226
|
+
const status = "bash: command aborted";
|
|
227
|
+
return {
|
|
228
|
+
kind: "error",
|
|
229
|
+
message: output.length > 0 ? `${output}\n\n${status}` : status,
|
|
230
|
+
details: bashResultDetails(result, rawOutput, "abort"),
|
|
231
|
+
};
|
|
171
232
|
}
|
|
172
|
-
const shaped = shapeBashOutput(combineBashOutput(result), options);
|
|
173
|
-
const output = shaped.text.trim();
|
|
174
233
|
if (timedOut) {
|
|
175
234
|
const status = `bash: command timed out after ${timeout}ms`;
|
|
176
|
-
return
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
235
|
+
return {
|
|
236
|
+
kind: "error",
|
|
237
|
+
message: output.length > 0 ? `${output}\n\n${status}` : status,
|
|
238
|
+
details: bashResultDetails(result, rawOutput, "timeout"),
|
|
239
|
+
};
|
|
180
240
|
}
|
|
181
241
|
if (outputCapped) {
|
|
182
242
|
const status = `bash: command output exceeded ${BASH_HARD_CAP_BYTES} bytes and was stopped`;
|
|
183
|
-
return
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
243
|
+
return {
|
|
244
|
+
kind: "error",
|
|
245
|
+
message: output.length > 0 ? `${output}\n\n${status}` : status,
|
|
246
|
+
details: bashResultDetails(result, rawOutput, "output-cap"),
|
|
247
|
+
};
|
|
187
248
|
}
|
|
188
249
|
if (error) {
|
|
189
250
|
const code = typeof error.code === "number" ? error.code : (error as { code?: string }).code;
|
|
190
251
|
const status = `bash: command failed (exit ${code ?? "?"})`;
|
|
191
252
|
const message = output.length > 0 ? `${output}\n\n${status}` : `${status}: ${error.message}`;
|
|
192
|
-
return
|
|
253
|
+
return { kind: "error", message, details: bashResultDetails(result, rawOutput, "nonzero") };
|
|
193
254
|
}
|
|
194
|
-
const body =
|
|
195
|
-
return
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
255
|
+
const body = rawOutput.length > 0 ? rawOutput : "(no output)";
|
|
256
|
+
return {
|
|
257
|
+
kind: "ok",
|
|
258
|
+
output: `${body}${observeToolsNudge(args.command, options?.sessionId)}`,
|
|
259
|
+
details: bashResultDetails(result, rawOutput, "success"),
|
|
260
|
+
};
|
|
199
261
|
} catch (err) {
|
|
200
262
|
const msg = err instanceof Error ? err.message : String(err);
|
|
201
263
|
return { kind: "error", message: `bash: ${msg}` };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { BASH_HARD_CAP_BYTES } from "../core/bash-exec.js";
|
|
1
2
|
import { type ToolName, ToolNames } from "../core/tool-names.js";
|
|
3
|
+
import { BASH_DEFAULT_RESULT_DISPOSITION } from "./bash.js";
|
|
2
4
|
import { OBSERVATION_POLICY_SLACK_BYTES, OBSERVE_SELF_CAPS } from "./observation.js";
|
|
3
5
|
import { toolPresentationPolicy } from "./presentation.js";
|
|
4
6
|
import { readMaxBytes } from "./read.js";
|
|
@@ -93,7 +95,7 @@ const TOOL_METADATA: Readonly<Record<string, ToolMetadata>> = {
|
|
|
93
95
|
),
|
|
94
96
|
costLatency: "local_fast",
|
|
95
97
|
promptHint:
|
|
96
|
-
'Call context with scope="skills" to list installed and marketplace skills; when one matches the task, or the operator names a skill or asks how one works, suggest the operator run /skill <name> (a marketplace skill is offered for install) and never load it uninvited. When the user message carries a skill request, first load that skill via context (scope="skills", name=<skill>) before doing anything else.',
|
|
98
|
+
'Call context with scope="skills" to list installed and marketplace skills; when one matches the task, or the operator names a skill or asks how one works, suggest the operator run /skill <name> (a marketplace skill is offered for install) and never load it uninvited. When the user message carries a skill request, first load that skill via context (scope="skills", name=<skill>) before doing anything else. When an [evicted ...] marker names content you need, recall it with context(scope="recall", ref=...); re-read the file only when the marker says it changed.',
|
|
97
99
|
},
|
|
98
100
|
[ToolNames.CredentialPresent]: {
|
|
99
101
|
objective: "Check whether a credential key is present without returning its value.",
|
|
@@ -121,15 +123,19 @@ const TOOL_METADATA: Readonly<Record<string, ToolMetadata>> = {
|
|
|
121
123
|
resultSizePolicy: exactMutationPolicy,
|
|
122
124
|
costLatency: "local_fast",
|
|
123
125
|
},
|
|
124
|
-
// EXECUTE: the safe-exec spine (
|
|
126
|
+
// EXECUTE: the safe-exec spine (canonical shaping offloads Bash overflow).
|
|
125
127
|
[ToolNames.Bash]: {
|
|
126
128
|
objective: "Execute an explicit shell command when narrower tools are insufficient.",
|
|
127
129
|
uiLabel: "Shell",
|
|
128
130
|
retrySafety: "unknown",
|
|
129
|
-
resultSizePolicy:
|
|
130
|
-
"Use a narrower command or a dedicated verification/read/search tool to inspect omitted output.",
|
|
131
|
-
|
|
131
|
+
resultSizePolicy: {
|
|
132
|
+
...summaryPolicy("Use a narrower command or a dedicated verification/read/search tool to inspect omitted output."),
|
|
133
|
+
offloadMaxBytes: BASH_HARD_CAP_BYTES,
|
|
134
|
+
},
|
|
135
|
+
resultDisposition: BASH_DEFAULT_RESULT_DISPOSITION,
|
|
132
136
|
costLatency: "local_slow",
|
|
137
|
+
promptHint:
|
|
138
|
+
"Bash output_policy defaults to bounded diagnostic tail. Use summary for noisy commands, metadata-only when only outcome and retrieval matter, and full only when output is known to fit the bounded result budget.",
|
|
133
139
|
},
|
|
134
140
|
[ToolNames.Git]: {
|
|
135
141
|
objective: "Read-only git inspection: status, diff, or log.",
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { type Dirent, readdirSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import type { ContextRecalledPayload } from "../../core/bus-events.js";
|
|
3
4
|
import { SKILL_SUGGESTION_ANCHOR } from "../../core/skill-activation.js";
|
|
4
5
|
import { ToolNames } from "../../core/tool-names.js";
|
|
6
|
+
import { foldWorkingSet } from "../../domains/context/working-set/fold.js";
|
|
7
|
+
import {
|
|
8
|
+
buildRecallFields,
|
|
9
|
+
recallErrorMessage,
|
|
10
|
+
recallParentTurnId,
|
|
11
|
+
resolveRecall,
|
|
12
|
+
} from "../../domains/context/working-set/recall.js";
|
|
5
13
|
import {
|
|
6
14
|
checkSkillDrift,
|
|
7
15
|
discoverMarketplaceSkills,
|
|
@@ -11,6 +19,8 @@ import {
|
|
|
11
19
|
modelVisibleSkills,
|
|
12
20
|
type Skill,
|
|
13
21
|
} from "../../domains/resources/index.js";
|
|
22
|
+
import type { SessionEntryInput } from "../../domains/session/contract.js";
|
|
23
|
+
import type { SessionEntry } from "../../domains/session/entries.js";
|
|
14
24
|
import type { WorkspaceSnapshot } from "../../domains/session/workspace/index.js";
|
|
15
25
|
import {
|
|
16
26
|
finalizeObservation,
|
|
@@ -30,7 +40,8 @@ import { contextToolSurface } from "./surface.js";
|
|
|
30
40
|
* workspace snapshot, scope=docs retrieves cited sections from Clio's bundled
|
|
31
41
|
* documentation, scope=skills lists available skills or loads a requested
|
|
32
42
|
* skill body (the skill-activation and pending-request contracts are
|
|
33
|
-
* unchanged from the absorbed read_skill tool)
|
|
43
|
+
* unchanged from the absorbed read_skill tool), scope=recall readmits an
|
|
44
|
+
* evicted tool-result body by ref and records the `contextRecall` entry.
|
|
34
45
|
*/
|
|
35
46
|
|
|
36
47
|
const DEFAULT_TREE_ENTRIES = 50;
|
|
@@ -42,6 +53,17 @@ export interface ContextWorkspaceDeps {
|
|
|
42
53
|
saveSnapshot(snapshot: WorkspaceSnapshot): void;
|
|
43
54
|
}
|
|
44
55
|
|
|
56
|
+
/** Ledger access for scope=recall: read the full ledger, fold it at the live leaf, append the recall record. */
|
|
57
|
+
export interface ContextSessionDeps {
|
|
58
|
+
hasSession(): boolean;
|
|
59
|
+
readEntries(): ReadonlyArray<SessionEntry>;
|
|
60
|
+
/** The live append point (`/tree` pin or tree leaf); undefined lets the fold infer it. */
|
|
61
|
+
activeLeafTurnId(): string | undefined;
|
|
62
|
+
appendEntry(entry: SessionEntryInput): SessionEntry;
|
|
63
|
+
/** Called after the recall entry is recorded; the orchestrator publishes it as BusChannels.ContextRecalled. */
|
|
64
|
+
onRecalled?: (payload: ContextRecalledPayload) => void;
|
|
65
|
+
}
|
|
66
|
+
|
|
45
67
|
export interface ContextToolDeps {
|
|
46
68
|
getCwd?: () => string;
|
|
47
69
|
getSkillLoaderOptions?: () => Pick<
|
|
@@ -50,6 +72,8 @@ export interface ContextToolDeps {
|
|
|
50
72
|
>;
|
|
51
73
|
/** Absent in worker registries without a session; scope=workspace errors cleanly. */
|
|
52
74
|
workspace?: ContextWorkspaceDeps;
|
|
75
|
+
/** Absent in worker registries without a session; scope=recall errors cleanly. */
|
|
76
|
+
session?: ContextSessionDeps;
|
|
53
77
|
/**
|
|
54
78
|
* Whether scope=skills may list marketplace entries beside installed
|
|
55
79
|
* skills. Worker registries set false: a worker can neither install a
|
|
@@ -144,7 +168,7 @@ function policyIsRecipeBound(policy: { requests: ReadonlyArray<{ source: string
|
|
|
144
168
|
// load it (only the operator activates), so its move is suggest-and-wait.
|
|
145
169
|
const NO_PENDING_SKILL_DENIAL =
|
|
146
170
|
"context: no pending skill request is active this turn; only the operator can activate a skill, so do not retry this load. " +
|
|
147
|
-
`If a listed skill matches the task, open your reply with the line \`${SKILL_SUGGESTION_ANCHOR}\` and
|
|
171
|
+
`If a listed skill matches the task, open your reply with the line \`${SKILL_SUGGESTION_ANCHOR}\` and continue the task without it; only the operator can run it. Otherwise continue without skills.`;
|
|
148
172
|
|
|
149
173
|
function pendingSkillPolicyError(name: string, options: ToolInvokeOptions | undefined): string | null {
|
|
150
174
|
const policy = options?.pendingSkillPolicy;
|
|
@@ -263,7 +287,7 @@ function renderSkillsList(
|
|
|
263
287
|
// template where they skip conditional prose in the header.
|
|
264
288
|
lines.push(
|
|
265
289
|
"",
|
|
266
|
-
`If one skill above matches the current task, begin your reply with the line \`${SKILL_SUGGESTION_ANCHOR}\` (a comma-separated sequence, in order, when several compose)
|
|
290
|
+
`If one skill above matches the current task, begin your reply with the line \`${SKILL_SUGGESTION_ANCHOR}\` (a comma-separated sequence, in order, when several compose), then continue the task in the same turn without it; only the operator can run it. If none match, do not mention skills.`,
|
|
267
291
|
);
|
|
268
292
|
return lines.join("\n");
|
|
269
293
|
}
|
|
@@ -482,13 +506,90 @@ function runSkillsScope(
|
|
|
482
506
|
});
|
|
483
507
|
}
|
|
484
508
|
|
|
509
|
+
/**
|
|
510
|
+
* scope=recall: the body goes back through the observation envelope like any
|
|
511
|
+
* OBSERVE result, so the per-turn pool and the self cap still apply; an
|
|
512
|
+
* oversize body is offloaded by the envelope and the notice carries the
|
|
513
|
+
* pointer. A body whose original result was itself offloaded already ends in
|
|
514
|
+
* that tool's own `full: <path>` pointer, which is what the model gets back;
|
|
515
|
+
* the file is never inlined. The `contextRecall` entry is appended before the
|
|
516
|
+
* result returns; it is the churn record, not an un-eviction, so the marker
|
|
517
|
+
* and the prefix cache stay where they are.
|
|
518
|
+
*/
|
|
519
|
+
function runRecallScope(
|
|
520
|
+
deps: ContextToolDeps,
|
|
521
|
+
args: Record<string, unknown>,
|
|
522
|
+
reservation: ObservationReservation,
|
|
523
|
+
options: ToolInvokeOptions | undefined,
|
|
524
|
+
): ToolResult {
|
|
525
|
+
const session = deps.session;
|
|
526
|
+
if (!session?.hasSession()) {
|
|
527
|
+
return { kind: "error", message: "context: recall scope requires a bound session; none is active here" };
|
|
528
|
+
}
|
|
529
|
+
const ref = typeof args.ref === "string" ? args.ref.trim() : "";
|
|
530
|
+
if (ref.length === 0) {
|
|
531
|
+
return {
|
|
532
|
+
kind: "error",
|
|
533
|
+
message: "context: recall scope requires ref=<turnId>, the ref named in the [evicted ...] marker",
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
const entries = session.readEntries();
|
|
537
|
+
const leaf = session.activeLeafTurnId();
|
|
538
|
+
const view = foldWorkingSet(entries, leaf);
|
|
539
|
+
const resolved = resolveRecall(entries, view, ref, leaf);
|
|
540
|
+
if (!resolved.ok) return { kind: "error", message: `context: ${recallErrorMessage(resolved.error, entries, view)}` };
|
|
541
|
+
const { result } = resolved;
|
|
542
|
+
const fields = buildRecallFields(result, {
|
|
543
|
+
trigger: "tool",
|
|
544
|
+
...(options?.toolCallId ? { toolCallId: options.toolCallId } : {}),
|
|
545
|
+
});
|
|
546
|
+
// The recall record parents onto the live leaf so the fold sees it on
|
|
547
|
+
// this branch and only this branch.
|
|
548
|
+
const parentTurnId = recallParentTurnId(entries, leaf);
|
|
549
|
+
let recorded: SessionEntry;
|
|
550
|
+
try {
|
|
551
|
+
recorded = session.appendEntry({ ...fields, parentTurnId });
|
|
552
|
+
} catch (err) {
|
|
553
|
+
return {
|
|
554
|
+
kind: "error",
|
|
555
|
+
message: `context: recall of ${result.ref.entry} could not be recorded: ${err instanceof Error ? err.message : String(err)}`,
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
session.onRecalled?.({ ref: result.ref.entry, trigger: "tool", tokensReadmitted: result.tokens, at: Date.now() });
|
|
559
|
+
const evictedState = view.evicted.get(result.ref.entry);
|
|
560
|
+
const truncation = truncateHead(result.body, {
|
|
561
|
+
maxBytes: reservation.callCapBytes,
|
|
562
|
+
maxLines: Number.MAX_SAFE_INTEGER,
|
|
563
|
+
});
|
|
564
|
+
return finalizeObservation({
|
|
565
|
+
tool: ToolNames.Context,
|
|
566
|
+
unit: "results",
|
|
567
|
+
output: truncation.content,
|
|
568
|
+
...(truncation.truncated ? { fullOutput: result.body } : {}),
|
|
569
|
+
shownCount: 1,
|
|
570
|
+
totalCount: 1,
|
|
571
|
+
truncated: truncation.truncated,
|
|
572
|
+
details: {
|
|
573
|
+
recall: {
|
|
574
|
+
ref: result.ref.entry,
|
|
575
|
+
tokensReadmitted: result.tokens,
|
|
576
|
+
recallTurnId: recorded.turnId,
|
|
577
|
+
...(evictedState ? { reason: evictedState.reason, evictedAtTurnId: evictedState.evictedAtTurnId } : {}),
|
|
578
|
+
...(result.offloadPath !== undefined ? { offloadPath: result.offloadPath } : {}),
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
reservation,
|
|
582
|
+
...(options ? { options } : {}),
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
|
|
485
586
|
export function createContextTool(deps: ContextToolDeps = {}): ToolSpec {
|
|
486
587
|
return {
|
|
487
588
|
...contextToolSurface,
|
|
488
589
|
async run(args, options): Promise<ToolResult> {
|
|
489
590
|
const scope = typeof args.scope === "string" ? args.scope : "";
|
|
490
|
-
if (scope !== "workspace" && scope !== "docs" && scope !== "skills") {
|
|
491
|
-
return { kind: "error", message: `context: scope must be workspace, docs, or
|
|
591
|
+
if (scope !== "workspace" && scope !== "docs" && scope !== "skills" && scope !== "recall") {
|
|
592
|
+
return { kind: "error", message: `context: scope must be workspace, docs, skills, or recall; got '${scope}'` };
|
|
492
593
|
}
|
|
493
594
|
const selfCap =
|
|
494
595
|
scope === "docs"
|
|
@@ -508,6 +609,7 @@ export function createContextTool(deps: ContextToolDeps = {}): ToolSpec {
|
|
|
508
609
|
}
|
|
509
610
|
if (scope === "workspace") return runWorkspaceScope(deps, reservation, options);
|
|
510
611
|
if (scope === "docs") return runDocsScope(args, reservation, options);
|
|
612
|
+
if (scope === "recall") return runRecallScope(deps, args, reservation, options);
|
|
511
613
|
return runSkillsScope(deps, args, reservation, options);
|
|
512
614
|
},
|
|
513
615
|
};
|
|
@@ -6,12 +6,13 @@ import type { ToolSurface } from "../lazy-tool.js";
|
|
|
6
6
|
export const contextToolSurface = {
|
|
7
7
|
name: ToolNames.Context,
|
|
8
8
|
description:
|
|
9
|
-
"Environment context: scope=workspace returns the git/project snapshot, scope=docs searches Clio's bundled documentation (omit query to list the corpus), scope=skills lists installed and marketplace skills or loads an installed one by name. For repository code and the repo's generated wiki use code_nav (mode=wiki).",
|
|
9
|
+
"Environment context: scope=workspace returns the git/project snapshot, scope=docs searches Clio's bundled documentation (omit query to list the corpus), scope=skills lists installed and marketplace skills or loads an installed one by name, scope=recall returns the exact body of an evicted tool result by ref (the turnId named in an [evicted ...] marker). For repository code and the repo's generated wiki use code_nav (mode=wiki).",
|
|
10
10
|
parameters: Type.Object({
|
|
11
|
-
scope: StringEnum(["workspace", "docs", "skills"], { description: "Context source." }),
|
|
11
|
+
scope: StringEnum(["workspace", "docs", "skills", "recall"], { description: "Context source." }),
|
|
12
12
|
query: Type.Optional(Type.String({ description: "scope=docs: question or terms; omit to list the corpus." })),
|
|
13
13
|
name: Type.Optional(Type.String({ description: "scope=skills: skill name to load; omit to list." })),
|
|
14
14
|
limit: Type.Optional(Type.Number({ description: "scope=docs: max sections (default 5, max 12)." })),
|
|
15
|
+
ref: Type.Optional(Type.String({ description: "scope=recall: ref of the evicted item, as named in its marker." })),
|
|
15
16
|
include_tree: Type.Optional(Type.Boolean({ description: "scope=skills: list files under the skill base_dir." })),
|
|
16
17
|
}),
|
|
17
18
|
baseActionClass: "read",
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { ContextRecalledPayload } from "../core/bus-events.js";
|
|
1
2
|
import type { LoadSkillsInput } from "../domains/resources/index.js";
|
|
2
3
|
import type { SessionContract } from "../domains/session/contract.js";
|
|
4
|
+
import type { SessionEntry } from "../domains/session/entries.js";
|
|
3
5
|
import { createTaskBoardStore, type TaskBoardStore } from "../domains/session/task-board.js";
|
|
4
6
|
import type { UserTasksStore } from "../domains/user-tasks/store.js";
|
|
5
7
|
import type { AgentLedgerPort } from "../worker/protocol.js";
|
|
@@ -28,6 +30,10 @@ import { writeTool } from "./write.js";
|
|
|
28
30
|
|
|
29
31
|
export interface CoreToolBootstrapDeps {
|
|
30
32
|
session?: SessionContract;
|
|
33
|
+
/** Full ledger of the current session; context(scope=recall) folds it. Absent in worker registries. */
|
|
34
|
+
readSessionEntries?: () => ReadonlyArray<SessionEntry>;
|
|
35
|
+
/** Publishes a successful context(scope=recall) on the bus; absent where no bus is wired. */
|
|
36
|
+
onContextRecalled?: (payload: ContextRecalledPayload) => void;
|
|
31
37
|
askUser?: AskUserHandler;
|
|
32
38
|
taskBoard?: TaskBoardStore;
|
|
33
39
|
userTasks?: UserTasksStore;
|
|
@@ -108,6 +114,7 @@ export function registerCoreTools(registry: ToolRegistry, deps: CoreToolBootstra
|
|
|
108
114
|
...builtin(credentialPresentTool, { path: "src/tools/credential-present.ts", scope: "core" }),
|
|
109
115
|
});
|
|
110
116
|
const session = deps.session;
|
|
117
|
+
const readSessionEntries = deps.readSessionEntries;
|
|
111
118
|
registry.register({
|
|
112
119
|
...builtin(
|
|
113
120
|
lazyTool(contextToolSurface, async () => {
|
|
@@ -116,6 +123,20 @@ export function registerCoreTools(registry: ToolRegistry, deps: CoreToolBootstra
|
|
|
116
123
|
const { probeWorkspace } = await import("../domains/session/workspace/index.js");
|
|
117
124
|
return createContextTool({
|
|
118
125
|
...skillToolDeps,
|
|
126
|
+
...(readSessionEntries
|
|
127
|
+
? {
|
|
128
|
+
session: {
|
|
129
|
+
hasSession: () => session.current() !== null,
|
|
130
|
+
readEntries: readSessionEntries,
|
|
131
|
+
activeLeafTurnId: () => {
|
|
132
|
+
const meta = session.current();
|
|
133
|
+
return meta ? (session.tree(meta.id).leafId ?? undefined) : undefined;
|
|
134
|
+
},
|
|
135
|
+
appendEntry: (entry) => session.appendEntry(entry),
|
|
136
|
+
...(deps.onContextRecalled ? { onRecalled: deps.onContextRecalled } : {}),
|
|
137
|
+
},
|
|
138
|
+
}
|
|
139
|
+
: {}),
|
|
119
140
|
workspace: {
|
|
120
141
|
hasSession: () => session.current() !== null,
|
|
121
142
|
getSnapshot: () => session.current()?.workspace ?? null,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import type { AgentAutomationAuthority } from "../domains/agents/spec.js";
|
|
4
4
|
import { type AgentTaskType, classifyAgentTask } from "../domains/dispatch/agent-candidates.js";
|
|
5
|
+
import { cloneDispatchBudgetRequest } from "../domains/dispatch/budget-envelope.js";
|
|
5
6
|
import type { DispatchRequest } from "../domains/dispatch/contract.js";
|
|
6
7
|
import { type AgentRoleFactsResolver, requestExecutionRole } from "../domains/dispatch/execution-role.js";
|
|
7
8
|
import { parseRoutingIntent } from "../domains/dispatch/routing-intent.js";
|
|
@@ -171,6 +172,13 @@ function dispatchRequestFromArgs(
|
|
|
171
172
|
}
|
|
172
173
|
request.thinkingLevel = thinkingLevel as JobThinkingLevel;
|
|
173
174
|
}
|
|
175
|
+
if (args.budget !== undefined) {
|
|
176
|
+
try {
|
|
177
|
+
request.budget = cloneDispatchBudgetRequest(args.budget);
|
|
178
|
+
} catch (error) {
|
|
179
|
+
return { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
180
|
+
}
|
|
181
|
+
}
|
|
174
182
|
return { ok: true, request };
|
|
175
183
|
}
|
|
176
184
|
|
|
@@ -1,6 +1,25 @@
|
|
|
1
|
+
import { responseModelIdObservationFromRecord } from "../core/response-model-id.js";
|
|
1
2
|
import { durableAssistantTextFromEvent } from "../domains/dispatch/event-pump.js";
|
|
3
|
+
import type { RunReceipt } from "../domains/dispatch/types.js";
|
|
2
4
|
|
|
3
5
|
/** Return the durable final assistant text carried by a worker event. */
|
|
4
6
|
export function assistantTextFromEvent(event: unknown): string {
|
|
5
7
|
return durableAssistantTextFromEvent(event).trim();
|
|
6
8
|
}
|
|
9
|
+
|
|
10
|
+
/** Human projection of the response model-id observations carried by a receipt. */
|
|
11
|
+
export function receiptResponseModelIdObservationLabel(receipt: Pick<RunReceipt, "upstreamResponses">): string | null {
|
|
12
|
+
const responses = receipt.upstreamResponses ?? [];
|
|
13
|
+
if (responses.length === 0) return null;
|
|
14
|
+
const labels = responses.map((response) => {
|
|
15
|
+
const observation = responseModelIdObservationFromRecord(
|
|
16
|
+
response as unknown as Record<string, unknown>,
|
|
17
|
+
"legacy-difference-only",
|
|
18
|
+
);
|
|
19
|
+
if (observation.state === "reported") return `reported:${observation.reportedModelId}`;
|
|
20
|
+
if (observation.state === "not-reported") return "not-reported";
|
|
21
|
+
if (observation.state === "not-observed") return "not-observed";
|
|
22
|
+
return `legacy-difference-only:${observation.differingModelId ?? "none"}`;
|
|
23
|
+
});
|
|
24
|
+
return `response_model_id_observation=${labels.join(",")}`;
|
|
25
|
+
}
|