@iowarp/clio-coder 0.3.4 → 0.3.7
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 +65 -2
- package/CONTRIBUTING.md +6 -6
- package/README.md +16 -5
- package/dist/{acp-S5R4RR5B.js → acp-SK4MD6MM.js} +11 -11
- package/dist/{agents-P6DMMVZY.js → agents-2FN2K6ME.js} +33 -26
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-2XCZLPKS.js → auth-QIYZWM5I.js} +15 -15
- package/dist/{chunk-EKMEHE4H.js → chunk-33YXPOE3.js} +2 -3
- package/dist/{chunk-VAWWTKDP.js → chunk-3HAPLH5M.js} +11 -11
- package/dist/{chunk-YCWGATWI.js → chunk-465YSENW.js} +3 -3
- package/dist/{chunk-4OC57DA6.js → chunk-4DGYLA73.js} +53 -2
- package/dist/{chunk-UZHIZC5S.js → chunk-4DWFMQDR.js} +61 -76
- package/dist/{chunk-ZWMF7253.js → chunk-5C3AQNDW.js} +328 -9
- package/dist/{chunk-22NAGB7X.js → chunk-5C77SEEY.js} +5 -94
- package/dist/{chunk-WPQLXFOZ.js → chunk-5FR74PWO.js} +3 -2
- package/dist/{chunk-35MKKU5R.js → chunk-5UJ6ECTS.js} +18 -10
- package/dist/{chunk-BRXQQJFP.js → chunk-6M7VS3J3.js} +571 -50
- package/dist/{chunk-QQK64KLB.js → chunk-6TUKSZVF.js} +141 -23
- package/dist/{chunk-N4CZJQRK.js → chunk-AB4XIIVB.js} +8 -6
- package/dist/{chunk-KRPY7NTG.js → chunk-BMWK7ZIZ.js} +14 -20
- package/dist/{chunk-4BPJXDWC.js → chunk-C4JBQ5SR.js} +30 -14
- package/dist/{chunk-ZYKPLLNQ.js → chunk-CEYBNUGC.js} +821 -83
- package/dist/{chunk-VEZEGCGW.js → chunk-D4MDIG46.js} +20 -18
- package/dist/chunk-DJNLUABN.js +843 -0
- package/dist/{chunk-BP4OYD6A.js → chunk-DMD2AGVS.js} +21 -2
- package/dist/{chunk-KOHPCX4K.js → chunk-DOOEX22V.js} +2 -2
- package/dist/chunk-DQA7QLMD.js +123 -0
- package/dist/chunk-DR52UMZW.js +21 -0
- package/dist/{chunk-3HZ5RWN2.js → chunk-EBEFWSGL.js} +9 -7
- package/dist/{chunk-EDRHSCIE.js → chunk-EELBMBT6.js} +128 -13
- package/dist/{chunk-HV5X7OR2.js → chunk-EOOQZZDE.js} +16 -14
- package/dist/{chunk-WR67VIZY.js → chunk-FOT2FX5J.js} +63 -5
- package/dist/{chunk-BPGS2WCQ.js → chunk-GEYXPTRF.js} +2 -1
- package/dist/{chunk-FYYLNIL5.js → chunk-GH5622CP.js} +2 -2
- package/dist/{chunk-BEY543CS.js → chunk-GOXNB3AO.js} +5 -2
- package/dist/chunk-GWS3VEIW.js +195 -0
- package/dist/{chunk-G4BMMOKF.js → chunk-HVDIIIQW.js} +2 -2
- package/dist/chunk-HWUFFB6L.js +83 -0
- package/dist/{chunk-X6COSD2O.js → chunk-J7PIKKWC.js} +8 -436
- package/dist/{chunk-NILBFAPG.js → chunk-JNXPYBB4.js} +2 -2
- package/dist/{chunk-4VP4KH3K.js → chunk-JRIO5UD2.js} +4 -4
- package/dist/{chunk-K6WL7QZT.js → chunk-JTSEDYVQ.js} +7 -7
- package/dist/{chunk-QKMUKYO7.js → chunk-KCMKRQX4.js} +236 -84
- package/dist/chunk-KZ2H5X4G.js +1026 -0
- package/dist/{chunk-A2GZF7DC.js → chunk-LADCF22A.js} +13 -13
- package/dist/chunk-LCGCVYZ4.js +57 -0
- package/dist/chunk-M4AKACEO.js +382 -0
- package/dist/{chunk-POHLU5DW.js → chunk-M6L6IDJG.js} +3 -3
- package/dist/{chunk-4JUF2NNX.js → chunk-MXI6J5JF.js} +7 -7
- package/dist/{chunk-X4RCMKVQ.js → chunk-NDINPTJ4.js} +2 -2
- package/dist/{chunk-TTNYS3EA.js → chunk-OB5HIGJY.js} +1 -1
- package/dist/{chunk-7RXG6QRZ.js → chunk-OBMAI2DP.js} +61 -840
- package/dist/{chunk-5M54SPOL.js → chunk-ODFEOB4F.js} +161 -5
- package/dist/chunk-PD3MESLB.js +242 -0
- package/dist/{chunk-ED4KHGC3.js → chunk-PPAMZ32Z.js} +9 -2
- package/dist/{chunk-VMNQ6OZA.js → chunk-QCTRSGHQ.js} +963 -786
- package/dist/chunk-RVG5JXAL.js +41 -0
- package/dist/{chunk-RD5U66HV.js → chunk-SROCI7ZU.js} +7 -7
- package/dist/{chunk-MFFY33HR.js → chunk-THKY7CD7.js} +466 -205
- package/dist/{chunk-34475P3I.js → chunk-TSHXZTOQ.js} +5 -4
- package/dist/{chunk-PCZJO5TI.js → chunk-UFQ3F4FW.js} +13 -178
- package/dist/{chunk-AD2SYQYC.js → chunk-UHXRNZ2J.js} +121 -3
- package/dist/chunk-UND3GU2L.js +103 -0
- package/dist/{chunk-QQL5RT5M.js → chunk-UUANF5CR.js} +2323 -2114
- package/dist/{chunk-VJWL6YS5.js → chunk-UUVG37B4.js} +2 -2
- package/dist/chunk-UVDSQ6LW.js +472 -0
- package/dist/{chunk-QWU7ZBO7.js → chunk-VQNODYQ4.js} +215 -56
- package/dist/chunk-VREKEFLL.js +37 -0
- package/dist/{chunk-2TZWSW76.js → chunk-WHGPSPT5.js} +2 -2
- package/dist/{chunk-TW3WDMVS.js → chunk-WHJYKASB.js} +2 -2
- package/dist/{chunk-MEQ45TQ4.js → chunk-WJHBC77E.js} +21 -7
- package/dist/{chunk-HXG4IURW.js → chunk-X2KV5FXT.js} +2 -2
- package/dist/{chunk-YHZX5GEU.js → chunk-XAKHZX5N.js} +2 -2
- package/dist/{chunk-2LZI5CAG.js → chunk-XEGB6BCN.js} +228 -36
- package/dist/{chunk-E25LMLRW.js → chunk-YD734TPH.js} +2 -2
- package/dist/{verifiers-4UUM6TEE.js → chunk-YTYFXUI3.js} +121 -372
- package/dist/{chunk-3JLKSKD7.js → chunk-ZGH7FGS5.js} +17 -7
- package/dist/{chunk-VSNATDE6.js → chunk-ZZMN5OM4.js} +2 -2
- package/dist/cli/index.js +34 -32
- package/dist/{clio-J5JIOIDS.js → clio-WBVQEBKO.js} +7 -7
- package/dist/{code-nav-AXCXSBHX.js → code-nav-FGGFIE7L.js} +7 -7
- package/dist/codewiki/build-worker.js +4 -4
- package/dist/{components-KELWS457.js → components-F7OEATSO.js} +5 -5
- package/dist/{config-OEBMIN2U.js → config-TRBL3RCF.js} +48 -41
- package/dist/{configure-PUQOSIXQ.js → configure-OLCVPHNM.js} +17 -17
- package/dist/{context-URSXPBCK.js → context-MJIJ6GOX.js} +12 -12
- package/dist/{context-EKDCKUUZ.js → context-WFPKQSM6.js} +26 -9
- package/dist/{context-MGSE4Z2T.js → context-XEWE3MOJ.js} +44 -37
- package/dist/{context-clear-KDAJRNUK.js → context-clear-KNOS2JPB.js} +44 -37
- package/dist/{context-index-BZ4UYMTC.js → context-index-SSR5ECNE.js} +3 -3
- package/dist/{context-working-set-SBKMPPI2.js → context-working-set-EUXAZI6N.js} +14 -13
- package/dist/{dispatch-runner-MSWN72NK.js → dispatch-runner-B7MTOVKL.js} +321 -60
- package/dist/{docs-2C2LTVT2.js → docs-FLJTIDSE.js} +5 -5
- package/dist/{doctor-7BSE27PJ.js → doctor-RN4YKO2X.js} +15 -15
- package/dist/{eval-IZGDOO4H.js → eval-RUBJVSNQ.js} +52 -236
- package/dist/{evidence-SR7WXB5B.js → evidence-JZNBUOQZ.js} +39 -33
- package/dist/{evolve-K7VE2CBX.js → evolve-FJVC4KKI.js} +39 -33
- package/dist/{extensions-QVDOHDGJ.js → extensions-IQL36S7K.js} +5 -5
- package/dist/{fleet-7XMJNQNF.js → fleet-BDKYJFCP.js} +243 -370
- package/dist/fleet-commands-ZFIWZSB3.js +70 -0
- package/dist/fleet-graph-Y6HPXIVF.js +125 -0
- package/dist/fleet-new-RDVJLHHH.js +48 -0
- package/dist/{fleet-preflight-AQNAH644.js → fleet-preflight-BHSNPBMH.js} +2 -2
- package/dist/fleet-validate-BIYREGIK.js +79 -0
- package/dist/{init-JGNPAYXT.js → init-LQUB5COQ.js} +57 -48
- package/dist/library-NJAHIGG4.js +217 -0
- package/dist/memory-OG6HOYKM.js +472 -0
- package/dist/{models-ZMMLFJNN.js → models-5ZG5XY7J.js} +23 -22
- package/dist/{monitor-2F3T5KHP.js → monitor-TJ7AMTGB.js} +69 -35
- package/dist/{orchestrator-ORHT43JB.js → orchestrator-WZYB54DM.js} +4868 -1189
- package/dist/{paths-UXLN5YYZ.js → paths-XUC7GS6E.js} +5 -5
- package/dist/{reset-NXGTYNUO.js → reset-PXQT45IY.js} +8 -8
- package/dist/{run-RF4WJGMT.js → run-FQ74YF62.js} +82 -62
- package/dist/{share-UT3W6E4M.js → share-FW7SVCL3.js} +34 -10
- package/dist/{skills-PSACKC5Q.js → skills-7E7IRB3R.js} +25 -9
- package/dist/{skills-eval-WJSI55RZ.js → skills-eval-LI75W6OK.js} +43 -35
- package/dist/{targets-PIIRAOYS.js → targets-4CIFKCTW.js} +27 -24
- package/dist/{terminal-lease-ULWXWNVY.js → terminal-lease-WUZY7ZV5.js} +5 -4
- package/dist/{uninstall-FZCQCDKC.js → uninstall-7FV7IP4E.js} +5 -5
- package/dist/{upgrade-346TZ6AV.js → upgrade-K2HVIVMQ.js} +21 -20
- package/dist/{usage-6KKXR32N.js → usage-GTZELZQX.js} +159 -59
- package/dist/verifiers-RLAHT27O.js +336 -0
- package/dist/{verify-X5HDROLA.js → verify-BX3BRKH5.js} +7 -6
- package/dist/{wiki-generate-7STOCIFZ.js → wiki-generate-ASIFASCN.js} +58 -48
- package/dist/worker/entry.js +98 -84
- package/dist/{workspace-G4ZWUIPR.js → workspace-ZJ6BFM3Q.js} +4 -4
- package/docs/README.md +4 -3
- 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 +10 -6
- package/docs/built-in-agents.md +26 -2
- package/docs/capacity-and-scheduling.md +1 -1
- package/docs/commands-and-modes.md +90 -8
- package/docs/configuration-and-targets.md +90 -2
- package/docs/context-engine.md +4 -2
- package/docs/context-working-set.md +4 -4
- package/docs/development-pipeline.md +1 -1
- package/docs/dispatch-architecture-rationale.md +1 -1
- package/docs/documentation-coverage.md +4 -4
- package/docs/documentation-guide.md +4 -4
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +4 -45
- package/docs/evidence-and-memory.md +70 -10
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +4 -1
- package/docs/extensions-and-sharing.md +6 -2
- package/docs/fleet-demo-runbook.md +2 -2
- package/docs/fleet-dispatch.md +224 -11
- package/docs/git-commit-provenance.md +2 -2
- package/docs/glossary.md +1 -1
- package/docs/installation-and-lifecycle.md +2 -2
- package/docs/middleware-and-components.md +20 -2
- package/docs/model-catalog.md +1 -1
- package/docs/observability.md +55 -8
- package/docs/proactive-memory.md +26 -16
- package/docs/prompt-envelope-and-tools.md +4 -2
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +83 -65
- package/docs/resource-library.md +59 -0
- package/docs/safety-model.md +29 -7
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +37 -1
- package/docs/skills-marketplace.md +16 -3
- package/docs/tool-usage.md +14 -7
- 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 +3 -3
- package/package.json +7 -4
- package/src/cli/agents.ts +2 -3
- package/src/cli/argv.ts +14 -1
- package/src/cli/fleet-commands.ts +37 -0
- package/src/cli/fleet-graph.ts +102 -0
- package/src/cli/fleet-new.ts +36 -0
- package/src/cli/fleet-preflight.ts +121 -0
- package/src/cli/fleet-validate.ts +30 -0
- package/src/cli/fleet.ts +188 -335
- package/src/cli/index.ts +4 -2
- package/src/cli/library.ts +190 -0
- 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/share.ts +13 -1
- package/src/cli/targets.ts +12 -3
- package/src/cli/usage.ts +160 -20
- package/src/core/bus-events.ts +7 -0
- package/src/core/commit-attribution.ts +4 -4
- package/src/core/config.ts +130 -0
- package/src/core/defaults.ts +81 -0
- package/src/core/response-model-id.ts +134 -0
- package/src/core/toml.ts +62 -0
- package/src/core/workspace-files.ts +0 -1
- package/src/domains/agents/builtins/architect.md +2 -1
- package/src/domains/agents/builtins/oracle.md +33 -0
- package/src/domains/agents/catalog.ts +18 -5
- package/src/domains/agents/fleet-contract.ts +278 -16
- package/src/domains/agents/index.ts +14 -0
- package/src/domains/agents/recipe.ts +54 -14
- package/src/domains/agents/result-contract.ts +242 -5
- package/src/domains/config/classify.ts +4 -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/policies/index.ts +3 -4
- package/src/domains/dispatch/active-route-planner.ts +14 -0
- package/src/domains/dispatch/backoff.ts +2 -1
- package/src/domains/dispatch/budget-envelope.ts +396 -0
- package/src/domains/dispatch/capability-match.ts +1 -0
- package/src/domains/dispatch/checkout-writer-lease.ts +175 -0
- package/src/domains/dispatch/contract.ts +36 -0
- package/src/domains/dispatch/delegation-plan.ts +167 -0
- package/src/domains/dispatch/execution-plan.ts +76 -5
- package/src/domains/dispatch/execution-role.ts +3 -1
- package/src/domains/dispatch/execution-scheduler.ts +183 -67
- package/src/domains/dispatch/extension.ts +339 -36
- package/src/domains/dispatch/fleet-gate.ts +14 -0
- package/src/domains/dispatch/fleet-plan.ts +63 -3
- package/src/domains/dispatch/fleet-run.ts +737 -0
- package/src/domains/dispatch/gate-role-prompts.ts +9 -0
- package/src/domains/dispatch/host-verification.ts +178 -0
- package/src/domains/dispatch/index.ts +38 -0
- package/src/domains/dispatch/intent.ts +159 -0
- package/src/domains/dispatch/orphan-recovery.ts +1 -0
- package/src/domains/dispatch/receipt-integrity.ts +12 -4
- package/src/domains/dispatch/state.ts +37 -3
- package/src/domains/dispatch/types.ts +61 -9
- package/src/domains/dispatch/validation.ts +80 -6
- 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/trust-status.ts +10 -1
- 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/index.ts +15 -0
- package/src/domains/middleware/memory-intervention.ts +35 -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 +43 -1
- package/src/domains/middleware/types.ts +10 -0
- package/src/domains/middleware/watchdog.ts +281 -0
- package/src/domains/observability/contract.ts +9 -2
- package/src/domains/observability/cost.ts +31 -4
- package/src/domains/observability/extension.ts +2 -2
- package/src/domains/observability/index.ts +10 -0
- package/src/domains/observability/out-of-turn-usage.ts +223 -0
- 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/resources/index.ts +20 -0
- package/src/domains/resources/library.ts +326 -0
- package/src/domains/resources/skills/marketplace.ts +37 -12
- package/src/domains/safety/call-target.ts +211 -14
- package/src/domains/safety/decision-presentation.ts +268 -0
- package/src/domains/safety/redaction.ts +73 -0
- package/src/domains/session/context-ledger.ts +10 -1
- package/src/domains/session/decision-board.ts +4 -0
- package/src/domains/session/entries.ts +3 -0
- package/src/domains/session/handoff.ts +629 -0
- package/src/domains/session/history.ts +68 -19
- package/src/domains/session/usage.ts +24 -7
- package/src/domains/share/archive.ts +67 -2
- package/src/engine/acp/event-mapper.ts +7 -0
- package/src/engine/acp/server.ts +29 -2
- 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/worker-events.ts +4 -3
- package/src/engine/worker-runtime.ts +59 -54
- package/src/entry/orchestrator.ts +55 -1
- package/src/interactive/bus-notices.ts +26 -0
- package/src/interactive/chat-loop-messages.ts +22 -0
- package/src/interactive/chat-loop.ts +248 -1
- package/src/interactive/chat-renderer.ts +41 -3
- package/src/interactive/clio-editor.ts +44 -7
- package/src/interactive/context-overlay.ts +43 -5
- package/src/interactive/cost-overlay.ts +70 -11
- package/src/interactive/council-dispatch.ts +30 -0
- package/src/interactive/council-grid.ts +213 -0
- package/src/interactive/council.ts +99 -0
- package/src/interactive/dispatch-board.ts +471 -50
- package/src/interactive/fleet-run-preview.ts +307 -0
- package/src/interactive/footer/notifications.ts +219 -0
- package/src/interactive/footer/widgets.ts +13 -0
- package/src/interactive/handoff-round.ts +56 -0
- package/src/interactive/interactive-application.ts +49 -2
- package/src/interactive/interactive-event-projection.ts +9 -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 +52 -2
- package/src/interactive/interactive-subscriptions.ts +14 -2
- package/src/interactive/memory-overlay.ts +89 -4
- package/src/interactive/oracle.ts +179 -0
- package/src/interactive/overlay-ask-user-lifecycle.ts +7 -1
- package/src/interactive/overlay-frame.ts +5 -2
- package/src/interactive/overlay-general-openers.ts +230 -2
- package/src/interactive/overlay-key-routing.ts +58 -2
- package/src/interactive/overlay-lifecycle.ts +52 -5
- package/src/interactive/overlay-permission-lifecycle.ts +33 -8
- package/src/interactive/overlay-resource-openers.ts +11 -3
- package/src/interactive/overlay-session-lifecycle.ts +234 -2
- 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/overlays/fleet-run-approval.ts +208 -0
- package/src/interactive/overlays/handoff-review.ts +185 -0
- package/src/interactive/overlays/library-install-confirm.ts +151 -0
- package/src/interactive/overlays/list-overlay.ts +168 -2
- package/src/interactive/overlays/settings.ts +101 -4
- package/src/interactive/overlays/side-question.ts +139 -0
- package/src/interactive/overlays/skills-hub.ts +401 -15
- package/src/interactive/permission-hint.ts +35 -0
- package/src/interactive/permission-overlay.ts +95 -45
- package/src/interactive/renderers/tool-execution.ts +19 -49
- package/src/interactive/session-last-turn.ts +8 -1
- package/src/interactive/session-usage-reseed.ts +36 -10
- package/src/interactive/side-question.ts +171 -0
- package/src/interactive/slash-commands.ts +434 -7
- package/src/interactive/slash-spec.ts +19 -6
- 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/theme/tokens.ts +30 -0
- package/src/interactive/turn-context.ts +96 -23
- package/src/interactive/turn-middleware.ts +16 -1
- package/src/interactive/turn-runtime.ts +37 -8
- package/src/interactive/turn-state.ts +3 -0
- package/src/interactive/watchdog-run.ts +75 -0
- package/src/interactive/worker-progress.ts +440 -0
- package/src/interactive/worker-share.ts +56 -1
- package/src/interactive/worker-stream.ts +58 -110
- package/src/tools/agent-tools.ts +28 -3
- package/src/tools/ask-user.ts +21 -1
- package/src/tools/bootstrap.ts +3 -0
- package/src/tools/compete-worktrees.ts +13 -79
- package/src/tools/context/index.ts +2 -2
- package/src/tools/dispatch-admission.ts +242 -8
- package/src/tools/dispatch-arguments.ts +65 -1
- package/src/tools/dispatch-event-text.ts +19 -0
- package/src/tools/dispatch-plan.ts +136 -6
- package/src/tools/dispatch-runner.ts +319 -13
- package/src/tools/dispatch-types.ts +20 -1
- package/src/tools/dispatch.ts +96 -3
- package/src/tools/monitor.ts +31 -0
- package/src/tools/profiles.ts +18 -4
- package/src/tools/registry.ts +15 -5
- package/src/tools/result-disposition.ts +156 -0
- package/src/tools/result-shaping.ts +59 -1
- package/src/tools/task-worktree.ts +238 -0
- package/src/tools/verify/authoring.ts +116 -55
- package/src/tools/verify/scripts.ts +62 -0
- package/src/tools/worker-evidence.ts +21 -1
- package/src/worker/spec-contract.ts +44 -3
- package/dist/chunk-EFADSJET.js +0 -18
- package/dist/chunk-HC4CLZ2Y.js +0 -68
- package/dist/memory-4ALKDJ4Q.js +0 -246
- package/src/domains/eval/metrics/chaos-stream.ts +0 -93
|
@@ -48,21 +48,15 @@ function collapseWhitespace(text: string): string {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
|
-
* Pull the first non-empty piece of
|
|
52
|
-
*
|
|
53
|
-
*
|
|
51
|
+
* Pull the first non-empty piece of text out of a message payload. Structured
|
|
52
|
+
* message payloads may contain a bare string, a text property, or pi-ai
|
|
53
|
+
* content blocks.
|
|
54
54
|
*/
|
|
55
|
-
function
|
|
56
|
-
if (typeof payload === "string")
|
|
57
|
-
const collapsed = collapseWhitespace(payload);
|
|
58
|
-
return collapsed.length > 0 ? collapsed : null;
|
|
59
|
-
}
|
|
55
|
+
function rawMessageText(payload: unknown): string | null {
|
|
56
|
+
if (typeof payload === "string") return payload.trim().length > 0 ? payload : null;
|
|
60
57
|
if (!payload || typeof payload !== "object") return null;
|
|
61
58
|
const obj = payload as Record<string, unknown>;
|
|
62
|
-
if (typeof obj.text === "string")
|
|
63
|
-
const collapsed = collapseWhitespace(obj.text);
|
|
64
|
-
if (collapsed.length > 0) return collapsed;
|
|
65
|
-
}
|
|
59
|
+
if (typeof obj.text === "string" && obj.text.trim().length > 0) return obj.text;
|
|
66
60
|
if (Array.isArray(obj.content)) {
|
|
67
61
|
const parts: string[] = [];
|
|
68
62
|
for (const part of obj.content) {
|
|
@@ -75,14 +69,65 @@ function extractUserText(payload: unknown): string | null {
|
|
|
75
69
|
parts.push((part as { text: string }).text);
|
|
76
70
|
}
|
|
77
71
|
}
|
|
78
|
-
const joined =
|
|
79
|
-
if (joined.length > 0) return joined;
|
|
72
|
+
const joined = parts.join("\n");
|
|
73
|
+
if (joined.trim().length > 0) return joined;
|
|
80
74
|
}
|
|
81
75
|
return null;
|
|
82
76
|
}
|
|
83
77
|
|
|
78
|
+
function extractMessageText(payload: unknown): string | null {
|
|
79
|
+
const raw = rawMessageText(payload);
|
|
80
|
+
if (raw === null) return null;
|
|
81
|
+
const collapsed = collapseWhitespace(raw);
|
|
82
|
+
return collapsed.length > 0 ? collapsed : null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* What the operator typed for a user turn, for the picker preview.
|
|
87
|
+
*
|
|
88
|
+
* The persisted text is the composed prompt: a `<system-reminder>` block and
|
|
89
|
+
* any `[Skill request]` preamble ride ahead of the operator's words as visible
|
|
90
|
+
* text the model receives. Reading that verbatim made every row of the
|
|
91
|
+
* `/resume` picker read `<system-reminder> [Skills] 9 installed…`, so sessions
|
|
92
|
+
* were indistinguishable and the type-to-filter matched them all (issue #188).
|
|
93
|
+
* Entries written since the operator text was persisted carry it as
|
|
94
|
+
* `operatorText`; older ones drop the leading scaffolding. Null when nothing
|
|
95
|
+
* operator-authored remains, so the caller moves on to the next turn.
|
|
96
|
+
*/
|
|
97
|
+
function operatorTextOfUserPayload(payload: unknown): string | null {
|
|
98
|
+
if (
|
|
99
|
+
payload &&
|
|
100
|
+
typeof payload === "object" &&
|
|
101
|
+
typeof (payload as { operatorText?: unknown }).operatorText === "string"
|
|
102
|
+
) {
|
|
103
|
+
const collapsed = collapseWhitespace((payload as { operatorText: string }).operatorText);
|
|
104
|
+
return collapsed.length > 0 ? collapsed : null;
|
|
105
|
+
}
|
|
106
|
+
// Strip before collapsing: the preamble's line structure is what the
|
|
107
|
+
// patterns anchor on.
|
|
108
|
+
const text = rawMessageText(payload);
|
|
109
|
+
if (text === null) return null;
|
|
110
|
+
const stripped = collapseWhitespace(stripInjectedPreamble(text));
|
|
111
|
+
return stripped.length > 0 ? stripped : null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const LEADING_SYSTEM_REMINDER = /^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*/u;
|
|
115
|
+
const LEADING_SKILL_REQUEST =
|
|
116
|
+
/^\s*\[Skill request\][\s\S]*?Only these pending skill names are allowed this turn\.[^\n]*\s*/u;
|
|
117
|
+
|
|
118
|
+
function stripInjectedPreamble(text: string): string {
|
|
119
|
+
let current = text;
|
|
120
|
+
for (;;) {
|
|
121
|
+
const next = current.replace(LEADING_SYSTEM_REMINDER, "").replace(LEADING_SKILL_REQUEST, "");
|
|
122
|
+
if (next === current) return current;
|
|
123
|
+
current = next;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
84
127
|
interface ScanResult {
|
|
85
128
|
firstUserMessage: string | null;
|
|
129
|
+
/** The first assistant text, the preview when no turn carries operator words. */
|
|
130
|
+
firstAssistantMessage: string | null;
|
|
86
131
|
messageCount: number;
|
|
87
132
|
lastTimestamp: string | null;
|
|
88
133
|
name: string | null;
|
|
@@ -92,6 +137,7 @@ interface ScanResult {
|
|
|
92
137
|
function scanCurrentJsonl(currentPath: string): ScanResult {
|
|
93
138
|
const result: ScanResult = {
|
|
94
139
|
firstUserMessage: null,
|
|
140
|
+
firstAssistantMessage: null,
|
|
95
141
|
messageCount: 0,
|
|
96
142
|
lastTimestamp: null,
|
|
97
143
|
name: null,
|
|
@@ -106,10 +152,14 @@ function scanCurrentJsonl(currentPath: string): ScanResult {
|
|
|
106
152
|
if (parsed.kind === "message" && parsed.role === "user") {
|
|
107
153
|
result.messageCount += 1;
|
|
108
154
|
if (result.firstUserMessage === null) {
|
|
109
|
-
const text =
|
|
155
|
+
const text = operatorTextOfUserPayload(parsed.payload);
|
|
110
156
|
if (text !== null) result.firstUserMessage = text;
|
|
111
157
|
}
|
|
112
158
|
}
|
|
159
|
+
if (parsed.kind === "message" && parsed.role === "assistant" && result.firstAssistantMessage === null) {
|
|
160
|
+
const text = extractMessageText(parsed.payload);
|
|
161
|
+
if (text !== null) result.firstAssistantMessage = text;
|
|
162
|
+
}
|
|
113
163
|
if (parsed.kind === "sessionInfo") {
|
|
114
164
|
const info = parsed as SessionInfoEntry;
|
|
115
165
|
if (info.name !== undefined) {
|
|
@@ -139,11 +189,10 @@ function enrichMetaForListing(meta: SessionMeta, currentPath: string): void {
|
|
|
139
189
|
if (scan.name) meta.name = scan.name;
|
|
140
190
|
const labelValues = [...scan.labels.values()].map((entry) => entry.label.trim()).filter((label) => label.length > 0);
|
|
141
191
|
if (labelValues.length > 0) meta.labels = labelValues;
|
|
142
|
-
|
|
192
|
+
const preview = scan.firstUserMessage ?? scan.firstAssistantMessage;
|
|
193
|
+
if (preview) {
|
|
143
194
|
meta.firstMessagePreview =
|
|
144
|
-
|
|
145
|
-
? `${scan.firstUserMessage.slice(0, PREVIEW_MAX_CHARS - 1)}…`
|
|
146
|
-
: scan.firstUserMessage;
|
|
195
|
+
preview.length > PREVIEW_MAX_CHARS ? `${preview.slice(0, PREVIEW_MAX_CHARS - 1)}…` : preview;
|
|
147
196
|
}
|
|
148
197
|
if (scan.messageCount > 0) meta.messageCount = scan.messageCount;
|
|
149
198
|
const fallbackMtime = readMtimeIso(currentPath);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Fold a session ledger's assistant turns into the per-call usage the rest of
|
|
3
3
|
* Clio reports: tokens in and out, cache reads and writes, reasoning tokens,
|
|
4
|
-
* and provider-reported cost, attributed to the target and
|
|
5
|
-
*
|
|
4
|
+
* and provider-reported cost, attributed to the target and observed model id
|
|
5
|
+
* for each call.
|
|
6
6
|
*
|
|
7
7
|
* This lives in the session domain because the ledger is the only durable
|
|
8
8
|
* record of what a session spent, and three surfaces read it: the `/cost`
|
|
@@ -19,12 +19,22 @@
|
|
|
19
19
|
* counting it would add an API call worth nothing.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
+
import {
|
|
23
|
+
attributedModelId,
|
|
24
|
+
type ResponseModelIdObservation,
|
|
25
|
+
responseModelIdObservationFromRecord,
|
|
26
|
+
} from "../../core/response-model-id.js";
|
|
22
27
|
import type { SessionEntry } from "./entries.js";
|
|
23
28
|
|
|
24
29
|
/** One completed assistant API call, as the ledger recorded it. */
|
|
25
30
|
export interface LedgerUsageCall {
|
|
26
31
|
providerId: string;
|
|
27
|
-
|
|
32
|
+
/** Model id the accounting row uses, or `unknown` when an observed response omitted it. */
|
|
33
|
+
attributedModelId: string;
|
|
34
|
+
/** The id the session asked for (the configured model, or the message's own `model`). */
|
|
35
|
+
requestedModelId: string;
|
|
36
|
+
/** Direct presence observation, with the pre-#193 difference-only shape labeled separately. */
|
|
37
|
+
responseModelIdObservation: ResponseModelIdObservation;
|
|
28
38
|
input: number;
|
|
29
39
|
output: number;
|
|
30
40
|
cacheRead: number;
|
|
@@ -71,8 +81,8 @@ function stringAt(source: Record<string, unknown>, ...keys: string[]): string |
|
|
|
71
81
|
* payload instead split one endpoint into two blocks in `/cost`, so a single
|
|
72
82
|
* `node-a` target on `llamacpp` rendered as two providers whose turn counts
|
|
73
83
|
* diverged with every resume. `modelChange` rows are replayed in order so a
|
|
74
|
-
* session that switched targets mid-way attributes each call to the
|
|
75
|
-
*
|
|
84
|
+
* session that switched targets mid-way attributes each call to the active
|
|
85
|
+
* target.
|
|
76
86
|
*/
|
|
77
87
|
export function ledgerUsageCalls(
|
|
78
88
|
entries: ReadonlyArray<SessionEntry>,
|
|
@@ -92,7 +102,9 @@ export function ledgerUsageCalls(
|
|
|
92
102
|
if (!usage || usage.totalTokens <= 0) continue;
|
|
93
103
|
calls.push({
|
|
94
104
|
providerId: currentTarget ?? "unknown",
|
|
95
|
-
|
|
105
|
+
attributedModelId: currentModel ?? "unknown",
|
|
106
|
+
requestedModelId: currentModel ?? "unknown",
|
|
107
|
+
responseModelIdObservation: { state: "not-observed" },
|
|
96
108
|
input: usage.input,
|
|
97
109
|
output: usage.output,
|
|
98
110
|
cacheRead: usage.cacheRead,
|
|
@@ -132,9 +144,14 @@ export function ledgerUsageCalls(
|
|
|
132
144
|
if (totalTokens === 0) continue;
|
|
133
145
|
const cost = usage.cost;
|
|
134
146
|
const costUsd = cost && typeof cost === "object" ? numberAt(cost as Record<string, unknown>, "total") : 0;
|
|
147
|
+
const requestedModelId = currentModel ?? stringAt(record, "model") ?? "unknown";
|
|
148
|
+
const differingResponseModelId = stringAt(record, "responseModel");
|
|
149
|
+
const responseModelIdObservation = responseModelIdObservationFromRecord(record, "legacy-difference-only");
|
|
135
150
|
calls.push({
|
|
136
151
|
providerId: currentTarget ?? stringAt(record, "provider", "api") ?? "unknown",
|
|
137
|
-
|
|
152
|
+
attributedModelId: attributedModelId(responseModelIdObservation, requestedModelId, differingResponseModelId),
|
|
153
|
+
requestedModelId,
|
|
154
|
+
responseModelIdObservation,
|
|
138
155
|
input,
|
|
139
156
|
output,
|
|
140
157
|
cacheRead,
|
|
@@ -11,9 +11,16 @@ import {
|
|
|
11
11
|
safeResourceWrite,
|
|
12
12
|
} from "../../core/safe-resource-write.js";
|
|
13
13
|
import { clioConfigDir, resolveClioDirs } from "../../core/xdg.js";
|
|
14
|
+
import { parseFrontmatter } from "../agents/frontmatter.js";
|
|
15
|
+
import {
|
|
16
|
+
assertAgentSpecPolicy,
|
|
17
|
+
normalizeAgentSpec,
|
|
18
|
+
parseAgentRecipeSchema,
|
|
19
|
+
parseFleetContract,
|
|
20
|
+
} from "../agents/index.js";
|
|
14
21
|
|
|
15
22
|
export type ShareScope = "project" | "user";
|
|
16
|
-
export type ShareEntryType = "project-context" | "prompt" | "skill" | "settings" | "extension";
|
|
23
|
+
export type ShareEntryType = "project-context" | "prompt" | "skill" | "agent" | "fleet" | "settings" | "extension";
|
|
17
24
|
|
|
18
25
|
export interface ShareArchiveFile {
|
|
19
26
|
type: ShareEntryType;
|
|
@@ -61,6 +68,8 @@ export interface ShareExportOptions {
|
|
|
61
68
|
includeContext?: boolean;
|
|
62
69
|
includePrompts?: boolean;
|
|
63
70
|
includeSkills?: boolean;
|
|
71
|
+
includeAgents?: boolean;
|
|
72
|
+
includeFleets?: boolean;
|
|
64
73
|
includeSettings?: boolean;
|
|
65
74
|
includeExtensions?: boolean;
|
|
66
75
|
}
|
|
@@ -206,7 +215,13 @@ function defaultedIncludes(
|
|
|
206
215
|
): Required<
|
|
207
216
|
Pick<
|
|
208
217
|
ShareExportOptions,
|
|
209
|
-
|
|
218
|
+
| "includeContext"
|
|
219
|
+
| "includePrompts"
|
|
220
|
+
| "includeSkills"
|
|
221
|
+
| "includeAgents"
|
|
222
|
+
| "includeFleets"
|
|
223
|
+
| "includeSettings"
|
|
224
|
+
| "includeExtensions"
|
|
210
225
|
>
|
|
211
226
|
> {
|
|
212
227
|
// True when the caller named at least one include flag explicitly. In that
|
|
@@ -216,12 +231,16 @@ function defaultedIncludes(
|
|
|
216
231
|
options.includeContext !== undefined ||
|
|
217
232
|
options.includePrompts !== undefined ||
|
|
218
233
|
options.includeSkills !== undefined ||
|
|
234
|
+
options.includeAgents !== undefined ||
|
|
235
|
+
options.includeFleets !== undefined ||
|
|
219
236
|
options.includeSettings !== undefined ||
|
|
220
237
|
options.includeExtensions !== undefined;
|
|
221
238
|
return {
|
|
222
239
|
includeContext: hasExplicitInclude ? options.includeContext === true : true,
|
|
223
240
|
includePrompts: hasExplicitInclude ? options.includePrompts === true : true,
|
|
224
241
|
includeSkills: hasExplicitInclude ? options.includeSkills === true : true,
|
|
242
|
+
includeAgents: hasExplicitInclude ? options.includeAgents === true : true,
|
|
243
|
+
includeFleets: hasExplicitInclude ? options.includeFleets === true : true,
|
|
225
244
|
includeSettings: hasExplicitInclude ? options.includeSettings === true : true,
|
|
226
245
|
includeExtensions: hasExplicitInclude ? options.includeExtensions === true : true,
|
|
227
246
|
};
|
|
@@ -263,6 +282,18 @@ export function createShareArchive(options: ShareExportOptions = {}): ClioShareA
|
|
|
263
282
|
addTree(files, "skill", scope, root, `${scope}/skills`);
|
|
264
283
|
}
|
|
265
284
|
}
|
|
285
|
+
if (includes.includeAgents) {
|
|
286
|
+
for (const scope of scopes) {
|
|
287
|
+
const root = scope === "user" ? path.join(clioConfigDir(), "agents") : path.join(cwd, ".clio-coder", "agents");
|
|
288
|
+
addTree(files, "agent", scope, root, `${scope}/agents`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (includes.includeFleets) {
|
|
292
|
+
for (const scope of scopes) {
|
|
293
|
+
const root = scope === "user" ? path.join(clioConfigDir(), "fleets") : path.join(cwd, ".clio-coder", "fleets");
|
|
294
|
+
addTree(files, "fleet", scope, root, `${scope}/fleets`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
266
297
|
if (includes.includeExtensions) {
|
|
267
298
|
for (const scope of scopes) {
|
|
268
299
|
const root =
|
|
@@ -313,9 +344,19 @@ function parseArchive(raw: unknown): ClioShareArchive {
|
|
|
313
344
|
throw new Error("share archive manifest is malformed");
|
|
314
345
|
}
|
|
315
346
|
const archive = raw as unknown as ClioShareArchive;
|
|
347
|
+
const allowedTypes = new Set<ShareEntryType>([
|
|
348
|
+
"project-context",
|
|
349
|
+
"prompt",
|
|
350
|
+
"skill",
|
|
351
|
+
"agent",
|
|
352
|
+
"fleet",
|
|
353
|
+
"settings",
|
|
354
|
+
"extension",
|
|
355
|
+
]);
|
|
316
356
|
for (const file of archive.files) {
|
|
317
357
|
if (
|
|
318
358
|
!isRecord(file) ||
|
|
359
|
+
!allowedTypes.has(file.type as ShareEntryType) ||
|
|
319
360
|
typeof file.archivePath !== "string" ||
|
|
320
361
|
typeof file.relativePath !== "string" ||
|
|
321
362
|
typeof file.sha256 !== "string" ||
|
|
@@ -392,6 +433,10 @@ function targetRootForFile(entry: ShareArchiveFile, options: ShareImportOptions)
|
|
|
392
433
|
return scope === "user"
|
|
393
434
|
? { root: path.join(config, "skills"), containmentRoot: config, scope }
|
|
394
435
|
: { root: path.join(cwd, ".clio-coder", "skills"), containmentRoot: cwd, scope };
|
|
436
|
+
case "agent":
|
|
437
|
+
return { root: path.join(config, "agents"), containmentRoot: config, scope: "user" };
|
|
438
|
+
case "fleet":
|
|
439
|
+
return { root: path.join(config, "fleets"), containmentRoot: config, scope: "user" };
|
|
395
440
|
case "extension":
|
|
396
441
|
return scope === "user"
|
|
397
442
|
? { root: path.join(config, "extensions"), containmentRoot: config, scope }
|
|
@@ -563,6 +608,26 @@ function prepareShareImport(filePath: string, options: ShareImportOptions = {}):
|
|
|
563
608
|
}
|
|
564
609
|
for (const targetInfo of preflight.targets) {
|
|
565
610
|
const { entry, target, scope, buffer } = targetInfo;
|
|
611
|
+
if (entry.type === "fleet") {
|
|
612
|
+
try {
|
|
613
|
+
parseFleetContract(buffer.toString("utf8"), target);
|
|
614
|
+
} catch (error) {
|
|
615
|
+
diagnostics.push({ type: "error", message: error instanceof Error ? error.message : String(error), path: target });
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
if (entry.type === "agent") {
|
|
620
|
+
try {
|
|
621
|
+
const parsed = parseFrontmatter(buffer.toString("utf8"), target);
|
|
622
|
+
const id = path.basename(target, ".md");
|
|
623
|
+
assertAgentSpecPolicy(
|
|
624
|
+
normalizeAgentSpec(parseAgentRecipeSchema({ id, source: "user", filepath: target, ...parsed })),
|
|
625
|
+
);
|
|
626
|
+
} catch (error) {
|
|
627
|
+
diagnostics.push({ type: "error", message: error instanceof Error ? error.message : String(error), path: target });
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
566
631
|
if (entry.type === "settings") {
|
|
567
632
|
diagnostics.push(...settingsPlan(buffer, options));
|
|
568
633
|
actions.push({ action: "settings", type: entry.type, scope, path: target });
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { performance } from "node:perf_hooks";
|
|
2
|
+
import { describeCallAction } from "../../domains/safety/call-target.js";
|
|
2
3
|
import type { AgentEvent, AgentMessage } from "../types.js";
|
|
3
4
|
import type { ClioWorkerEvent } from "../worker-events.js";
|
|
4
5
|
import type { AcpPromptResponse, AcpSessionUpdateParams, AcpToolCallUpdate } from "./types.js";
|
|
@@ -111,12 +112,17 @@ export class AcpEventMapper {
|
|
|
111
112
|
// keeps the monotonic twin, which is what the duration below spans.
|
|
112
113
|
const startedAt = Date.now();
|
|
113
114
|
this.toolStarts.set(toolCallId, performance.now());
|
|
115
|
+
// A peer's `rawInput` is its own argument object and never reaches an
|
|
116
|
+
// operator surface. The descriptor composed from it here does.
|
|
117
|
+
const action = describeCallAction(update.kind ?? title, update.rawInput);
|
|
114
118
|
out.push({
|
|
115
119
|
type: "clio_tool_start",
|
|
116
120
|
payload: {
|
|
117
121
|
tool: update.kind ?? title,
|
|
122
|
+
toolCallId,
|
|
118
123
|
posture: "operating",
|
|
119
124
|
startedAt,
|
|
125
|
+
...(action !== null ? { action } : {}),
|
|
120
126
|
},
|
|
121
127
|
});
|
|
122
128
|
out.push({
|
|
@@ -142,6 +148,7 @@ export class AcpEventMapper {
|
|
|
142
148
|
type: "clio_tool_finish",
|
|
143
149
|
payload: {
|
|
144
150
|
tool: update.kind ?? title,
|
|
151
|
+
toolCallId,
|
|
145
152
|
posture: "operating",
|
|
146
153
|
durationMs: Math.round(performance.now() - startedAtClock),
|
|
147
154
|
outcome: isError ? "error" : "ok",
|
package/src/engine/acp/server.ts
CHANGED
|
@@ -5,12 +5,18 @@ import { BusChannels, type LoopBlockedPayload } from "../../core/bus-events.js";
|
|
|
5
5
|
import { DEFAULT_DELEGATION_PERMISSION_TIMEOUT_MS } from "../../core/defaults.js";
|
|
6
6
|
import type { SafeEventBus } from "../../core/event-bus.js";
|
|
7
7
|
import { MAX_TIMER_DELAY_MS } from "../../core/timers.js";
|
|
8
|
+
import { ToolNames } from "../../core/tool-names.js";
|
|
8
9
|
import type { ProvidersContract } from "../../domains/providers/contract.js";
|
|
9
10
|
import { isOrchestratorEligibleRuntime } from "../../domains/providers/eligibility.js";
|
|
10
11
|
import { type AutonomyLevel, DEFAULT_AUTONOMY_LEVEL } from "../../domains/safety/autonomy.js";
|
|
12
|
+
import {
|
|
13
|
+
classifyDecisionPresentation,
|
|
14
|
+
decisionFactsForPermission,
|
|
15
|
+
} from "../../domains/safety/decision-presentation.js";
|
|
11
16
|
import type { SessionContract, SessionMeta } from "../../domains/session/contract.js";
|
|
12
17
|
import type { MessageEntry, SessionEntry } from "../../domains/session/entries.js";
|
|
13
18
|
import { filterEntriesToActivePath } from "../../domains/session/tree/active-path.js";
|
|
19
|
+
import { askUserExposure } from "../../tools/ask-user.js";
|
|
14
20
|
import type { ToolRegistry } from "../../tools/registry.js";
|
|
15
21
|
import { toolResultPresentationText } from "../../tools/result-disposition.js";
|
|
16
22
|
import type { AgentMessage } from "../types.js";
|
|
@@ -1265,6 +1271,19 @@ function installPermissionBridge(input: {
|
|
|
1265
1271
|
const queuedRequestDetails = new Map<string, { tool: string; actionClass: string }>();
|
|
1266
1272
|
const unregister = input.toolRegistry.onPermissionRequired((call, decision, meta) => {
|
|
1267
1273
|
if (queuedRequestIds.has(meta.requestId)) return;
|
|
1274
|
+
const presentation = classifyDecisionPresentation(
|
|
1275
|
+
decisionFactsForPermission({
|
|
1276
|
+
tool: call.tool,
|
|
1277
|
+
actionClass: decision.classification.actionClass,
|
|
1278
|
+
axis: meta.axis.startsWith("net:")
|
|
1279
|
+
? { kind: "safety-net", ruleId: meta.axis.slice("net:".length) || "unknown" }
|
|
1280
|
+
: { kind: "autonomy", level: meta.axis.slice("autonomy:".length) || DEFAULT_AUTONOMY_LEVEL },
|
|
1281
|
+
origin: { kind: "main" },
|
|
1282
|
+
...(call.tool === ToolNames.AskUser ? { exposure: askUserExposure(call.args) } : {}),
|
|
1283
|
+
}),
|
|
1284
|
+
);
|
|
1285
|
+
const approveAction = presentation.requiredActions.find((action) => action.id === "approve-once");
|
|
1286
|
+
const denyAction = presentation.requiredActions.find((action) => action.id === "deny");
|
|
1268
1287
|
queuedRequestIds.add(meta.requestId);
|
|
1269
1288
|
queuedRequestDetails.set(meta.requestId, {
|
|
1270
1289
|
tool: call.tool,
|
|
@@ -1381,8 +1400,16 @@ function installPermissionBridge(input: {
|
|
|
1381
1400
|
...(snapshot.locations !== undefined ? { locations: snapshot.locations } : {}),
|
|
1382
1401
|
},
|
|
1383
1402
|
options: [
|
|
1384
|
-
{
|
|
1385
|
-
|
|
1403
|
+
{
|
|
1404
|
+
optionId: "allow-once",
|
|
1405
|
+
name: approveAction?.label ?? "Approve once",
|
|
1406
|
+
kind: "allow_once",
|
|
1407
|
+
},
|
|
1408
|
+
{
|
|
1409
|
+
optionId: "reject-once",
|
|
1410
|
+
name: denyAction?.label ?? "Deny this request",
|
|
1411
|
+
kind: "reject_once",
|
|
1412
|
+
},
|
|
1386
1413
|
],
|
|
1387
1414
|
},
|
|
1388
1415
|
input.permissionTimeoutMs,
|
|
@@ -130,6 +130,25 @@ async function loadOwnedInstance(
|
|
|
130
130
|
return instanceId;
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Residency runs before every request, and the same co-residency facts held
|
|
135
|
+
* every turn, so the peer warning printed once per turn (issue #185). Each
|
|
136
|
+
* distinct fact is said once per process; a new target, model, or peer set is
|
|
137
|
+
* a new fact.
|
|
138
|
+
*/
|
|
139
|
+
const announcedResidencyFacts = new Set<string>();
|
|
140
|
+
|
|
141
|
+
function emitResidencyNoticeOnce(key: string, notice: Parameters<typeof emitResidencyNotice>[0]): void {
|
|
142
|
+
if (announcedResidencyFacts.has(key)) return;
|
|
143
|
+
announcedResidencyFacts.add(key);
|
|
144
|
+
emitResidencyNotice(notice);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Test seam: forget which residency facts were announced. */
|
|
148
|
+
export function resetAnnouncedResidencyFacts(): void {
|
|
149
|
+
announcedResidencyFacts.clear();
|
|
150
|
+
}
|
|
151
|
+
|
|
133
152
|
export async function ensureLmStudioResidency(
|
|
134
153
|
model: Model<"openai-completions">,
|
|
135
154
|
options: { apiKey?: string; signal?: AbortSignal } = {},
|
|
@@ -155,7 +174,7 @@ export async function ensureLmStudioResidency(
|
|
|
155
174
|
);
|
|
156
175
|
}
|
|
157
176
|
if (resolution.wireModelId !== model.id) {
|
|
158
|
-
|
|
177
|
+
emitResidencyNoticeOnce(`resolved|${info.targetId}|${model.id}|${resolution.wireModelId}`, {
|
|
159
178
|
kind: "co-resident",
|
|
160
179
|
level: "info",
|
|
161
180
|
targetId: info.targetId,
|
|
@@ -166,14 +185,16 @@ export async function ensureLmStudioResidency(
|
|
|
166
185
|
});
|
|
167
186
|
}
|
|
168
187
|
if (resolution.peerTargets.length > 0) {
|
|
169
|
-
|
|
188
|
+
const peers = resolution.peerTargets.join(", ");
|
|
189
|
+
const requested = resolution.wireModelId === model.id ? "" : ` (requested '${model.id}')`;
|
|
190
|
+
emitResidencyNoticeOnce(`peer|${info.targetId}|${model.id}|${resolution.wireModelId}|${peers}`, {
|
|
170
191
|
kind: "co-resident",
|
|
171
192
|
level: "warning",
|
|
172
193
|
targetId: info.targetId,
|
|
173
194
|
runtimeId: "lmstudio",
|
|
174
195
|
model: resolution.wireModelId,
|
|
175
|
-
message: `LM Studio instance '${resolution.wireModelId}' is also loaded on ${
|
|
176
|
-
detail: {
|
|
196
|
+
message: `LM Studio instance '${resolution.wireModelId}'${requested} is also loaded on ${peers}; a request may be served by that LM Link peer, and the footer and usage ledger name the id that answered when it differs.`,
|
|
197
|
+
detail: { requestedModel: model.id, wireModel: resolution.wireModelId, peerTargets: peers },
|
|
177
198
|
});
|
|
178
199
|
}
|
|
179
200
|
if (!load || Object.keys(load).length === 0 || resolution.instance) return resolution.wireModelId;
|