@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
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import { resolve } from "node:path";
|
|
1
|
+
import { isAbsolute, relative, resolve } from "node:path";
|
|
2
2
|
import type { DispatchPlanTaskResolution, DispatchRequest } from "../domains/dispatch/contract.js";
|
|
3
3
|
import type { ExecutionPlan } from "../domains/dispatch/execution-plan.js";
|
|
4
4
|
import { gateDeciderAgentId } from "../domains/dispatch/execution-role.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
COUNCIL_JUDGE_PROMPT,
|
|
7
|
+
JUDGE_GATE_PROMPT,
|
|
8
|
+
REVIEWER_GATE_PROMPT,
|
|
9
|
+
} from "../domains/dispatch/gate-role-prompts.js";
|
|
10
|
+
import { normalizeDispatchIntent } from "../domains/dispatch/intent.js";
|
|
6
11
|
import { approvedRouteCandidates } from "../domains/dispatch/route-approval.js";
|
|
7
12
|
import { defaultRoutingIntent } from "../domains/dispatch/routing-intent.js";
|
|
8
13
|
import type { DispatchFailoverMode } from "../domains/dispatch/validation.js";
|
|
@@ -29,12 +34,15 @@ import {
|
|
|
29
34
|
} from "./dispatch-scout-admission.js";
|
|
30
35
|
import type {
|
|
31
36
|
DispatchCompeteSettings,
|
|
37
|
+
DispatchCouncilSettings,
|
|
32
38
|
DispatchExecutionSnapshot,
|
|
33
39
|
DispatchMode,
|
|
34
40
|
DispatchReviewSettings,
|
|
35
41
|
DispatchToolDeps,
|
|
36
42
|
} from "./dispatch-types.js";
|
|
37
43
|
import type { ToolSpec } from "./registry.js";
|
|
44
|
+
import { gitCheckoutRoot } from "./task-worktree.js";
|
|
45
|
+
import { discoverDeclaredChecks } from "./verify/scripts.js";
|
|
38
46
|
|
|
39
47
|
/**
|
|
40
48
|
* The six identity-sensitive stores which bind synchronous admission to the
|
|
@@ -68,6 +76,64 @@ const COMPETE_SINGLE_TASK_MESSAGE = "dispatch: compete requires exactly one task
|
|
|
68
76
|
const COMPETE_NO_REVIEW_MESSAGE = "dispatch: compete has its own judge and cannot combine with review";
|
|
69
77
|
const COMPETE_MIN_CANDIDATES = 2;
|
|
70
78
|
const COMPETE_MAX_CANDIDATES = 4;
|
|
79
|
+
const COUNCIL_LABEL = /^[a-z][a-z0-9_-]{0,31}$/u;
|
|
80
|
+
|
|
81
|
+
function councilSettingsFromArgs(
|
|
82
|
+
args: Record<string, unknown>,
|
|
83
|
+
deps: DispatchToolDeps,
|
|
84
|
+
): { ok: true; council: DispatchCouncilSettings } | { ok: false; message: string } {
|
|
85
|
+
const rosterName = stringArg(args, "roster");
|
|
86
|
+
const hasMembers = Object.hasOwn(args, "members");
|
|
87
|
+
if ((rosterName === undefined) === !hasMembers) {
|
|
88
|
+
return { ok: false, message: "dispatch: council requires exactly one of roster or members" };
|
|
89
|
+
}
|
|
90
|
+
let members: DispatchCouncilSettings["members"];
|
|
91
|
+
if (rosterName !== undefined) {
|
|
92
|
+
const roster = deps.getWorkerRosters?.()[rosterName];
|
|
93
|
+
if (roster === undefined) return { ok: false, message: `council_roster_unknown: ${rosterName}` };
|
|
94
|
+
members = roster.members.map((member) => ({ ...member }));
|
|
95
|
+
} else {
|
|
96
|
+
if (!Array.isArray(args.members)) return { ok: false, message: "council_members_out_of_range" };
|
|
97
|
+
members = [];
|
|
98
|
+
for (const raw of args.members) {
|
|
99
|
+
if (!isRecord(raw)) return { ok: false, message: "council_members_out_of_range" };
|
|
100
|
+
const label = stringArg(raw, "label");
|
|
101
|
+
const target = stringArg(raw, "target");
|
|
102
|
+
if (label === undefined || target === undefined || !COUNCIL_LABEL.test(label)) {
|
|
103
|
+
return { ok: false, message: "council_members_out_of_range" };
|
|
104
|
+
}
|
|
105
|
+
const model = stringArg(raw, "model");
|
|
106
|
+
const thinking = stringArg(raw, "thinking");
|
|
107
|
+
members.push({ label, target, ...(model ? { model } : {}), ...(thinking ? { thinking } : {}) });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (members.length < 2 || members.length > 5) return { ok: false, message: "council_members_out_of_range" };
|
|
111
|
+
const labels = new Set<string>();
|
|
112
|
+
for (const member of members) {
|
|
113
|
+
if (labels.has(member.label)) return { ok: false, message: `council_member_label_duplicate: ${member.label}` };
|
|
114
|
+
labels.add(member.label);
|
|
115
|
+
}
|
|
116
|
+
const synthesis = args.synthesis === undefined ? "none" : args.synthesis;
|
|
117
|
+
if (synthesis !== "none" && synthesis !== "judge" && synthesis !== "vote") {
|
|
118
|
+
return { ok: false, message: "dispatch: synthesis must be none, judge, or vote" };
|
|
119
|
+
}
|
|
120
|
+
if (args.judge !== undefined && synthesis !== "judge") {
|
|
121
|
+
return { ok: false, message: "council_synthesis_requires_judge_settings" };
|
|
122
|
+
}
|
|
123
|
+
const rounds = args.rounds === undefined ? 1 : args.rounds;
|
|
124
|
+
if (!Number.isInteger(rounds) || Number(rounds) < 1 || Number(rounds) > 3) {
|
|
125
|
+
return { ok: false, message: "dispatch: rounds must be an integer 1..3" };
|
|
126
|
+
}
|
|
127
|
+
const judge = isRecord(args.judge)
|
|
128
|
+
? Object.fromEntries(
|
|
129
|
+
["agent", "model", "target", "node"].flatMap((key) => {
|
|
130
|
+
const value = stringArg(args.judge as Record<string, unknown>, key);
|
|
131
|
+
return value === undefined ? [] : [[key, value]];
|
|
132
|
+
}),
|
|
133
|
+
)
|
|
134
|
+
: undefined;
|
|
135
|
+
return { ok: true, council: { members, synthesis, rounds: Number(rounds), ...(judge ? { judge } : {}) } };
|
|
136
|
+
}
|
|
71
137
|
|
|
72
138
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
73
139
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -165,6 +231,28 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
|
|
|
165
231
|
approvedAuthorities: ["read-only", "verification", "artifact-write", "workspace-edit"],
|
|
166
232
|
authorityBasis: deps.getAutonomy?.() === "full-auto" ? "full-auto-policy" : "operator-plan-approval",
|
|
167
233
|
},
|
|
234
|
+
resolveIntent(rawIntent, cwd) {
|
|
235
|
+
const discovery = discoverDeclaredChecks(cwd);
|
|
236
|
+
if (!discovery.ok) return { ok: false, message: `verification_catalog_invalid: ${discovery.reason}` };
|
|
237
|
+
const declared = discovery.sources.flatMap((source) => source.checks);
|
|
238
|
+
const byId = new Map(declared.map((check) => [check.id, check]));
|
|
239
|
+
const normalized = normalizeDispatchIntent(rawIntent, byId);
|
|
240
|
+
if (!normalized.ok) return { ok: false, message: `${normalized.reason}: ${normalized.message}` };
|
|
241
|
+
return {
|
|
242
|
+
ok: true,
|
|
243
|
+
intent: normalized.intent,
|
|
244
|
+
resolvedVerification: normalized.intent.verification.map((entry) => {
|
|
245
|
+
const check = byId.get(entry.check);
|
|
246
|
+
if (check === undefined) throw new Error(`resolved verification check '${entry.check}' disappeared`);
|
|
247
|
+
return {
|
|
248
|
+
check: entry.check,
|
|
249
|
+
argv: [...check.command],
|
|
250
|
+
cwd: resolve(process.cwd(), check.cwd),
|
|
251
|
+
timeoutMs: entry.timeoutMs,
|
|
252
|
+
};
|
|
253
|
+
}),
|
|
254
|
+
};
|
|
255
|
+
},
|
|
168
256
|
});
|
|
169
257
|
const trustExecution = (args: Record<string, unknown>, snapshot: DispatchExecutionSnapshot) => {
|
|
170
258
|
state.trustedExecutionSnapshots.set(args, deepFreeze(structuredClone(snapshot)));
|
|
@@ -172,11 +260,15 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
|
|
|
172
260
|
};
|
|
173
261
|
const dispatchExecutionSnapshot = (
|
|
174
262
|
args: Record<string, unknown>,
|
|
175
|
-
fields: Pick<
|
|
263
|
+
fields: Pick<
|
|
264
|
+
DispatchExecutionSnapshot & { kind: "dispatch" },
|
|
265
|
+
"requests" | "mode" | "review" | "compete" | "council"
|
|
266
|
+
>,
|
|
176
267
|
): DispatchExecutionSnapshot => ({
|
|
177
268
|
kind: "dispatch",
|
|
178
269
|
planView: describeDispatchPlan(args),
|
|
179
270
|
...fields,
|
|
271
|
+
writers: args.writers === 1 ? 1 : undefined,
|
|
180
272
|
detach: args.detach === true,
|
|
181
273
|
timeoutMs: timeoutMsArg(args),
|
|
182
274
|
maxOutputBytes: maxOutputBytesArg(args),
|
|
@@ -217,6 +309,9 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
|
|
|
217
309
|
): ResolvedPlanTask => {
|
|
218
310
|
const resolution = deps.dispatch.preview?.(request);
|
|
219
311
|
if (resolution === undefined) throw new Error("dispatch preview is unavailable");
|
|
312
|
+
if (request.resolvedVerification?.length && resolution.runtimeId === "claude-code") {
|
|
313
|
+
throw new Error("verification_unsupported_runtime: claude-code subprocess dispatch cannot run host verification");
|
|
314
|
+
}
|
|
220
315
|
const pinned = request.node !== undefined || request.target !== undefined || request.model !== undefined;
|
|
221
316
|
const approvedCandidates =
|
|
222
317
|
pinned || request.failover !== "approved"
|
|
@@ -229,6 +324,15 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
|
|
|
229
324
|
agent: resolution.agentId,
|
|
230
325
|
task: request.task,
|
|
231
326
|
...(request.briefing !== undefined ? { briefing: request.briefing } : {}),
|
|
327
|
+
...(request.worktree === true
|
|
328
|
+
? {
|
|
329
|
+
worktree: true as const,
|
|
330
|
+
apply: request.apply ?? "merge",
|
|
331
|
+
...(gitCheckoutRoot(resolve(request.cwd ?? process.cwd())) === null
|
|
332
|
+
? {}
|
|
333
|
+
: { worktreeDestination: gitCheckoutRoot(resolve(request.cwd ?? process.cwd())) as string }),
|
|
334
|
+
}
|
|
335
|
+
: {}),
|
|
232
336
|
target: resolution.targetId,
|
|
233
337
|
model: resolution.wireModelId,
|
|
234
338
|
node: resolution.node.id,
|
|
@@ -248,6 +352,10 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
|
|
|
248
352
|
...(failover === "approved" ? { allowedCandidates: approvedCandidates.map((candidate) => ({ ...candidate })) } : {}),
|
|
249
353
|
role,
|
|
250
354
|
position,
|
|
355
|
+
...(request.intent !== undefined ? { intent: structuredClone(request.intent) } : {}),
|
|
356
|
+
...(request.resolvedVerification !== undefined
|
|
357
|
+
? { resolvedVerification: request.resolvedVerification.map((check) => ({ ...check, argv: [...check.argv] })) }
|
|
358
|
+
: {}),
|
|
251
359
|
};
|
|
252
360
|
state.taskResolutions.set(task, resolution);
|
|
253
361
|
return task;
|
|
@@ -269,6 +377,8 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
|
|
|
269
377
|
if (topology === "fleet") return task.wave ?? index;
|
|
270
378
|
if (topology === "parallel" || topology === "detached") return 0;
|
|
271
379
|
if (topology === "compete") return task.role === "judge" ? 1 : 0;
|
|
380
|
+
if (topology === "council")
|
|
381
|
+
return task.role === "synthesis" ? (task.council?.rounds ?? 1) : (task.council?.round ?? 1) - 1;
|
|
272
382
|
return index;
|
|
273
383
|
};
|
|
274
384
|
const markReservedPlan = (args: Record<string, unknown>, artifact: ResolvedDispatchPlanArtifact) => {
|
|
@@ -286,7 +396,7 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
|
|
|
286
396
|
};
|
|
287
397
|
});
|
|
288
398
|
const reservation = deps.dispatch.reservations.prepare({
|
|
289
|
-
topology: artifact.topology === "fleet" ? "parallel" : artifact.topology,
|
|
399
|
+
topology: artifact.topology === "fleet" || artifact.topology === "council" ? "parallel" : artifact.topology,
|
|
290
400
|
tasks,
|
|
291
401
|
});
|
|
292
402
|
try {
|
|
@@ -333,6 +443,7 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
|
|
|
333
443
|
mode: "parallel",
|
|
334
444
|
review: undefined,
|
|
335
445
|
compete: undefined,
|
|
446
|
+
council: undefined,
|
|
336
447
|
}),
|
|
337
448
|
);
|
|
338
449
|
state.trustedExecutionPlans.set(marked, deepFreeze(structuredClone(prepared.executionPlan)));
|
|
@@ -375,10 +486,13 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
|
|
|
375
486
|
}
|
|
376
487
|
const parsed = parseRequests(args);
|
|
377
488
|
if (!parsed.ok) return shapeRejection(args, parsed.message);
|
|
378
|
-
if (
|
|
489
|
+
if (
|
|
490
|
+
args.mode !== undefined &&
|
|
491
|
+
!["parallel", "sequential", "pipeline", "compete", "council"].includes(String(args.mode))
|
|
492
|
+
) {
|
|
379
493
|
return shapeRejection(
|
|
380
494
|
args,
|
|
381
|
-
`dispatch: mode must be parallel, sequential, pipeline, or
|
|
495
|
+
`dispatch: mode must be parallel, sequential, pipeline, compete, or council; got '${String(args.mode)}'`,
|
|
382
496
|
);
|
|
383
497
|
}
|
|
384
498
|
const mode: DispatchMode =
|
|
@@ -388,7 +502,30 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
|
|
|
388
502
|
? "pipeline"
|
|
389
503
|
: args.mode === "compete"
|
|
390
504
|
? "compete"
|
|
391
|
-
: "
|
|
505
|
+
: args.mode === "council"
|
|
506
|
+
? "council"
|
|
507
|
+
: "parallel";
|
|
508
|
+
if (args.writers !== undefined && args.writers !== 1) {
|
|
509
|
+
return shapeRejection(args, "dispatch: writers must be 1 when present");
|
|
510
|
+
}
|
|
511
|
+
if (args.writers === 1 && mode !== "parallel") {
|
|
512
|
+
return shapeRejection(args, "dispatch: writers is supported only for parallel dispatch");
|
|
513
|
+
}
|
|
514
|
+
const parentCheckout = gitCheckoutRoot(process.cwd());
|
|
515
|
+
for (const request of parsed.requests) {
|
|
516
|
+
if (request.worktree !== true) continue;
|
|
517
|
+
if (mode === "compete") return shapeRejection(args, "worktree_compete_incompatible");
|
|
518
|
+
if (parentCheckout === null) return shapeRejection(args, "worktree_non_git_checkout");
|
|
519
|
+
const spec = deps.getAgentSpecs().find((candidate) => candidate.id === request.agentId);
|
|
520
|
+
if (spec?.capabilityClass === "read-only") return shapeRejection(args, "worktree_read_only_agent");
|
|
521
|
+
if (request.cwd !== undefined) {
|
|
522
|
+
const requested = resolve(request.cwd);
|
|
523
|
+
const rel = relative(parentCheckout, requested);
|
|
524
|
+
if (rel === ".." || rel.startsWith("../") || isAbsolute(rel)) {
|
|
525
|
+
return shapeRejection(args, "worktree_cwd_outside_checkout");
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
392
529
|
const reviewResult = reviewSettingsFromArgs(args);
|
|
393
530
|
if (!reviewResult.ok) return shapeRejection(args, reviewResult.message);
|
|
394
531
|
if (reviewResult.review !== undefined) {
|
|
@@ -397,17 +534,35 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
|
|
|
397
534
|
if (parsed.requests.length !== 1 || parsed.requests[0] === undefined) {
|
|
398
535
|
return shapeRejection(args, REVIEW_SINGLE_TASK_MESSAGE);
|
|
399
536
|
}
|
|
537
|
+
if (parsed.requests.some((request) => (request.resolvedVerification?.length ?? 0) > 0)) {
|
|
538
|
+
return shapeRejection(args, "verification_unsupported_for_mode: review requests cannot run host verification");
|
|
539
|
+
}
|
|
400
540
|
}
|
|
401
541
|
if (mode === "compete" && (parsed.requests.length !== 1 || parsed.requests[0] === undefined)) {
|
|
402
542
|
return shapeRejection(args, COMPETE_SINGLE_TASK_MESSAGE);
|
|
403
543
|
}
|
|
544
|
+
if (mode === "compete" && parsed.requests.some((request) => (request.resolvedVerification?.length ?? 0) > 0)) {
|
|
545
|
+
return shapeRejection(args, "verification_unsupported_for_mode: compete requests cannot run host verification");
|
|
546
|
+
}
|
|
404
547
|
const competeResult = mode === "compete" ? competeSettingsFromArgs(args) : undefined;
|
|
405
548
|
if (competeResult !== undefined && !competeResult.ok) return shapeRejection(args, competeResult.message);
|
|
549
|
+
const councilResult = mode === "council" ? councilSettingsFromArgs(args, deps) : undefined;
|
|
550
|
+
if (councilResult !== undefined && !councilResult.ok) return shapeRejection(args, councilResult.message);
|
|
551
|
+
if (mode === "council") {
|
|
552
|
+
if (parsed.requests.length !== 1 || parsed.requests[0] === undefined) {
|
|
553
|
+
return shapeRejection(args, "dispatch: council requires exactly one task");
|
|
554
|
+
}
|
|
555
|
+
if (reviewResult.review !== undefined) return shapeRejection(args, "dispatch: council cannot combine with review");
|
|
556
|
+
if ((parsed.requests[0].resolvedVerification?.length ?? 0) > 0) {
|
|
557
|
+
return shapeRejection(args, "council_verification_unsupported");
|
|
558
|
+
}
|
|
559
|
+
}
|
|
406
560
|
const snapshotFields = {
|
|
407
561
|
requests: parsed.requests,
|
|
408
562
|
mode,
|
|
409
563
|
review: reviewResult.review,
|
|
410
564
|
compete: competeResult?.ok === true ? competeResult.compete : undefined,
|
|
565
|
+
council: councilResult?.ok === true ? councilResult.council : undefined,
|
|
411
566
|
};
|
|
412
567
|
if (deps.dispatch.preview === undefined) {
|
|
413
568
|
const marked = markPrepared(args);
|
|
@@ -480,6 +635,72 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
|
|
|
480
635
|
1,
|
|
481
636
|
),
|
|
482
637
|
);
|
|
638
|
+
} else if (mode === "council") {
|
|
639
|
+
const council = councilResult?.ok === true ? councilResult.council : undefined;
|
|
640
|
+
const base = parsed.requests[0];
|
|
641
|
+
if (council === undefined || base === undefined)
|
|
642
|
+
throw new Error("dispatch: council admission settings are unavailable");
|
|
643
|
+
const subjects: Array<{ runId: string; digest: null }> = [];
|
|
644
|
+
for (let round = 1; round <= council.rounds; round += 1) {
|
|
645
|
+
for (const [index, member] of council.members.entries()) {
|
|
646
|
+
const memberRequest: DispatchRequest = {
|
|
647
|
+
...base,
|
|
648
|
+
executionRole: "researcher",
|
|
649
|
+
autonomy: "read-only",
|
|
650
|
+
toolProfile: "council-read-only",
|
|
651
|
+
target: member.target,
|
|
652
|
+
...(member.model ? { model: member.model } : {}),
|
|
653
|
+
...(member.thinking ? { thinkingLevel: member.thinking as NonNullable<DispatchRequest["thinkingLevel"]> } : {}),
|
|
654
|
+
gate: { role: "member", group: "plan-preview", cycle: round },
|
|
655
|
+
};
|
|
656
|
+
let task: ResolvedPlanTask;
|
|
657
|
+
try {
|
|
658
|
+
task = resolveTask(memberRequest, "member", (round - 1) * council.members.length + index + 1);
|
|
659
|
+
} catch (error) {
|
|
660
|
+
return shapeRejection(
|
|
661
|
+
args,
|
|
662
|
+
`council_member_target_unknown: ${member.label}: ${error instanceof Error ? error.message : String(error)}`,
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
if (task.node !== "local" || task.nodeKind !== "local") {
|
|
666
|
+
return shapeRejection(args, `council_member_remote_node: ${member.label}`);
|
|
667
|
+
}
|
|
668
|
+
task.council = {
|
|
669
|
+
label: member.label,
|
|
670
|
+
...(member.color ? { color: member.color } : {}),
|
|
671
|
+
round,
|
|
672
|
+
rounds: council.rounds,
|
|
673
|
+
synthesis: council.synthesis,
|
|
674
|
+
};
|
|
675
|
+
if (round === council.rounds) subjects.push({ runId: `plan-member-${member.label}`, digest: null });
|
|
676
|
+
tasks.push(task);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
if (council.synthesis === "judge") {
|
|
680
|
+
const judgeRequest: DispatchRequest = {
|
|
681
|
+
agentId: council.judge?.agent ?? base.agentId,
|
|
682
|
+
executionRole: "judge",
|
|
683
|
+
task: "Plan-time capability check for council synthesis.",
|
|
684
|
+
systemPrompt: COUNCIL_JUDGE_PROMPT,
|
|
685
|
+
autonomy: "read-only",
|
|
686
|
+
toolProfile: "council-read-only",
|
|
687
|
+
gate: { role: "synthesis", group: "plan-preview", cycle: council.rounds, subjects },
|
|
688
|
+
...(council.judge?.node ? { node: council.judge.node } : {}),
|
|
689
|
+
...(council.judge?.model ? { model: council.judge.model } : {}),
|
|
690
|
+
...(council.judge?.target ? { target: council.judge.target } : {}),
|
|
691
|
+
};
|
|
692
|
+
const judgeTask = resolveTask(judgeRequest, "synthesis", 1);
|
|
693
|
+
if (judgeTask.node !== "local" || judgeTask.nodeKind !== "local") {
|
|
694
|
+
return shapeRejection(args, "council_member_remote_node: judge");
|
|
695
|
+
}
|
|
696
|
+
judgeTask.council = {
|
|
697
|
+
label: "synthesis",
|
|
698
|
+
round: council.rounds,
|
|
699
|
+
rounds: council.rounds,
|
|
700
|
+
synthesis: council.synthesis,
|
|
701
|
+
};
|
|
702
|
+
tasks.push(judgeTask);
|
|
703
|
+
}
|
|
483
704
|
} else {
|
|
484
705
|
for (const [index, request] of parsed.requests.entries()) tasks.push(resolveTask(request, "task", index + 1));
|
|
485
706
|
}
|
|
@@ -490,7 +711,20 @@ export function createDispatchAdmissionController(deps: DispatchToolDeps): Dispa
|
|
|
490
711
|
topology === "compete" ||
|
|
491
712
|
tasks.some((task) => task.node !== "local" || task.failover === "approved");
|
|
492
713
|
if (!planScale) {
|
|
493
|
-
const marked =
|
|
714
|
+
const marked = parsed.requests.some((request) => request.intent !== undefined)
|
|
715
|
+
? markPrepared(
|
|
716
|
+
withResolvedDispatchPlan(args, {
|
|
717
|
+
version: 3,
|
|
718
|
+
topology,
|
|
719
|
+
source: null,
|
|
720
|
+
maxWorkers: null,
|
|
721
|
+
onFailure: null,
|
|
722
|
+
tasks,
|
|
723
|
+
costCeilingUsd: resolvedCostCeiling(),
|
|
724
|
+
deadlineMs: null,
|
|
725
|
+
}),
|
|
726
|
+
)
|
|
727
|
+
: markPrepared(args);
|
|
494
728
|
return trustExecution(marked, dispatchExecutionSnapshot(marked, snapshotFields));
|
|
495
729
|
}
|
|
496
730
|
const marked = markReservedPlan(args, {
|
|
@@ -2,13 +2,22 @@
|
|
|
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";
|
|
8
|
+
import type { DispatchIntent } from "../domains/dispatch/intent.js";
|
|
7
9
|
import { parseRoutingIntent } from "../domains/dispatch/routing-intent.js";
|
|
8
10
|
import { DISPATCH_BRIEFING_MAX_BYTES, type JobThinkingLevel } from "../domains/dispatch/validation.js";
|
|
9
11
|
import { isToolProfileName, TOOL_PROFILE_NAMES } from "./profiles.js";
|
|
10
12
|
|
|
11
13
|
const DEFAULT_AGENT_ID = "coder";
|
|
14
|
+
/**
|
|
15
|
+
* The agent a council seats when the caller names none. Council admission pins
|
|
16
|
+
* every member to the `council-read-only` tool profile, and `coder` requires a
|
|
17
|
+
* write tool, so the ordinary default would fail admission for every member.
|
|
18
|
+
* `researcher` is the builtin read-only answerer.
|
|
19
|
+
*/
|
|
20
|
+
const COUNCIL_DEFAULT_AGENT_ID = "researcher";
|
|
12
21
|
|
|
13
22
|
/**
|
|
14
23
|
* Baseline recipe per task shape for `agent:"auto"`.
|
|
@@ -68,6 +77,12 @@ export interface DispatchArgumentParserOptions {
|
|
|
68
77
|
approvedAuthorities: ReadonlyArray<AgentAutomationAuthority>;
|
|
69
78
|
authorityBasis: "operator-plan-approval" | "full-auto-policy";
|
|
70
79
|
};
|
|
80
|
+
resolveIntent?: (
|
|
81
|
+
rawIntent: unknown,
|
|
82
|
+
cwd: string | undefined,
|
|
83
|
+
) =>
|
|
84
|
+
| { ok: true; intent: DispatchIntent; resolvedVerification: NonNullable<DispatchRequest["resolvedVerification"]> }
|
|
85
|
+
| { ok: false; message: string };
|
|
71
86
|
}
|
|
72
87
|
|
|
73
88
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
@@ -99,7 +114,8 @@ function dispatchRequestFromArgs(
|
|
|
99
114
|
const task = stringArg(args, "task");
|
|
100
115
|
if (!task) return { ok: false, message: "missing task (pass list:true to see available agents)" };
|
|
101
116
|
if (Object.hasOwn(args, "agent_id")) return { ok: false, message: "agent_id is unsupported; use agent" };
|
|
102
|
-
const requestedAgent =
|
|
117
|
+
const requestedAgent =
|
|
118
|
+
stringArg(args, "agent") ?? (args.mode === "council" ? COUNCIL_DEFAULT_AGENT_ID : DEFAULT_AGENT_ID);
|
|
103
119
|
const auto = requestedAgent === "auto";
|
|
104
120
|
const agentId = auto ? autoBaselineAgentId(task, options.hasAgent) : requestedAgent;
|
|
105
121
|
const request: DispatchRequest = {
|
|
@@ -149,6 +165,47 @@ function dispatchRequestFromArgs(
|
|
|
149
165
|
request.requiredCapabilities = routing.intent.requiredCapabilities;
|
|
150
166
|
const cwd = stringArg(args, "cwd");
|
|
151
167
|
if (cwd) request.cwd = cwd;
|
|
168
|
+
if (args.worktree !== undefined) {
|
|
169
|
+
if (args.worktree !== true) return { ok: false, message: "worktree must be true when present" };
|
|
170
|
+
request.worktree = true;
|
|
171
|
+
}
|
|
172
|
+
if (args.apply !== undefined) {
|
|
173
|
+
if (args.apply !== "merge" && args.apply !== "preserve")
|
|
174
|
+
return { ok: false, message: "apply must be merge or preserve" };
|
|
175
|
+
if (request.worktree !== true) return { ok: false, message: "apply requires worktree: true" };
|
|
176
|
+
request.apply = args.apply;
|
|
177
|
+
}
|
|
178
|
+
if (Object.hasOwn(args, "gate") && isRecord(args.intent) && Object.hasOwn(args.intent, "verification")) {
|
|
179
|
+
return { ok: false, message: "gate_and_intent_verification_conflict: gate cannot combine with intent.verification" };
|
|
180
|
+
}
|
|
181
|
+
let rawIntent = args.intent;
|
|
182
|
+
if (Object.hasOwn(args, "gate")) {
|
|
183
|
+
if (typeof args.gate !== "string" || args.gate.trim().length === 0) {
|
|
184
|
+
return { ok: false, message: "gate must be a non-empty declared check id" };
|
|
185
|
+
}
|
|
186
|
+
rawIntent = { ...(isRecord(rawIntent) ? rawIntent : {}), verification: [{ check: args.gate.trim() }] };
|
|
187
|
+
}
|
|
188
|
+
if (rawIntent !== undefined) {
|
|
189
|
+
if (options.resolveIntent === undefined) return { ok: false, message: "intent resolver is unavailable" };
|
|
190
|
+
const resolved = options.resolveIntent(rawIntent, cwd);
|
|
191
|
+
if (!resolved.ok) return resolved;
|
|
192
|
+
request.intent = resolved.intent;
|
|
193
|
+
if (resolved.resolvedVerification.length > 0) request.resolvedVerification = resolved.resolvedVerification;
|
|
194
|
+
if (resolved.intent.writeRoots.length > 0) {
|
|
195
|
+
const legacy = Array.isArray(args.writeRoots)
|
|
196
|
+
? args.writeRoots.filter((entry): entry is string => typeof entry === "string")
|
|
197
|
+
: undefined;
|
|
198
|
+
if (legacy !== undefined) {
|
|
199
|
+
const left = [...new Set(legacy)].sort();
|
|
200
|
+
if (JSON.stringify(left) !== JSON.stringify(resolved.intent.writeRoots)) {
|
|
201
|
+
return { ok: false, message: "intent_write_roots_contradiction" };
|
|
202
|
+
}
|
|
203
|
+
request.writeRoots = legacy;
|
|
204
|
+
} else {
|
|
205
|
+
request.writeRoots = resolved.intent.writeRoots;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
152
209
|
if ("persona" in args && args.persona !== undefined) {
|
|
153
210
|
if (typeof args.persona !== "string") return { ok: false, message: "persona must be a string" };
|
|
154
211
|
const persona = args.persona.trim();
|
|
@@ -171,6 +228,13 @@ function dispatchRequestFromArgs(
|
|
|
171
228
|
}
|
|
172
229
|
request.thinkingLevel = thinkingLevel as JobThinkingLevel;
|
|
173
230
|
}
|
|
231
|
+
if (args.budget !== undefined) {
|
|
232
|
+
try {
|
|
233
|
+
request.budget = cloneDispatchBudgetRequest(args.budget);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
return { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
236
|
+
}
|
|
237
|
+
}
|
|
174
238
|
return { ok: true, request };
|
|
175
239
|
}
|
|
176
240
|
|
|
@@ -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
|
+
}
|