@iowarp/clio-coder 0.3.8 → 0.4.0
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 +102 -0
- package/NOTICE +33 -0
- package/README.md +12 -3
- package/dist/{acp-U67UHUK2.js → acp-G5WJBNCT.js} +13 -12
- package/dist/{agents-YU6SGALZ.js → agents-FMV2Q5G4.js} +41 -36
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-5ZPJOIVG.js → auth-3IDSJEIK.js} +18 -18
- package/dist/{builtins-C6JMZVV6.js → builtins-XCZWXSC7.js} +5 -5
- package/dist/{chunk-IFBNV6H6.js → chunk-2ANTL7MR.js} +3 -3
- package/dist/{chunk-5FR74PWO.js → chunk-2JDWVJND.js} +2 -2
- package/dist/{chunk-XWSF374K.js → chunk-2OQE55CK.js} +3 -3
- package/dist/{chunk-5H3GB5BO.js → chunk-32KWKNSF.js} +8 -384
- package/dist/{chunk-KTYTFRMB.js → chunk-36EJLSQQ.js} +34 -36
- package/dist/{chunk-FHJEP5SW.js → chunk-3BT2XMV4.js} +19 -13
- package/dist/chunk-3DPEIQKN.js +113 -0
- package/dist/{chunk-GU2UIAFZ.js → chunk-3URVFKWK.js} +7 -7
- package/dist/{chunk-WEH5XRJQ.js → chunk-3XML7CDN.js} +3 -3
- package/dist/chunk-42FMPA75.js +101 -0
- package/dist/{chunk-A2NJGIB3.js → chunk-5LXZXPKX.js} +2 -2
- package/dist/{chunk-VCBR6CU7.js → chunk-5PSMVOLM.js} +2 -2
- package/dist/{chunk-NMPKI6XL.js → chunk-6DB53AJS.js} +203 -25
- package/dist/{chunk-3BINW3FP.js → chunk-76ONBSIA.js} +2 -2
- package/dist/{chunk-26LEYJZH.js → chunk-7MCTRUCE.js} +2 -2
- package/dist/{chunk-TYPGUK6W.js → chunk-AB44T6BB.js} +111 -5
- package/dist/{chunk-K4XHGFR5.js → chunk-B7OBL7PK.js} +317 -721
- package/dist/{chunk-B5CSFE7B.js → chunk-BBVJUZHB.js} +2 -2
- package/dist/{chunk-EQ63NRB7.js → chunk-BBVYXMFO.js} +2 -2
- package/dist/{chunk-ZVJ5BLO2.js → chunk-BKFJHQCA.js} +154 -16
- package/dist/chunk-BKFM6EJV.js +462 -0
- package/dist/chunk-BMS5RKQY.js +27 -0
- package/dist/{chunk-ZNLWCMVZ.js → chunk-BPKCPIL7.js} +2 -2
- package/dist/{chunk-TLQJPP24.js → chunk-BUMFYQFY.js} +1394 -1349
- package/dist/{chunk-BNAZZHFG.js → chunk-BYP5D4HI.js} +1 -1
- package/dist/chunk-C2LTL2W6.js +2447 -0
- package/dist/{chunk-ME6CCNFO.js → chunk-CODPRO7Q.js} +8 -8
- package/dist/{chunk-E77JEWSD.js → chunk-CTJ4RNAA.js} +7 -37
- package/dist/{chunk-ODFEOB4F.js → chunk-CY6FY24N.js} +26 -8
- package/dist/{chunk-7RFXX52T.js → chunk-DQITNCXG.js} +642 -172
- package/dist/{chunk-TTHACPOM.js → chunk-DYJP44XW.js} +578 -117
- package/dist/{chunk-2HFZQUHL.js → chunk-F4CKPOEQ.js} +18 -8
- package/dist/{chunk-DGSYXYMX.js → chunk-FEFIFZTL.js} +3 -3
- package/dist/{chunk-GWS3VEIW.js → chunk-FWDFM5ZU.js} +24 -3
- package/dist/{chunk-MV3K5QF2.js → chunk-GCSMB2KY.js} +2 -2
- package/dist/chunk-GKF55TAZ.js +391 -0
- package/dist/{chunk-VWZOAB7K.js → chunk-GR5G2PVF.js} +9 -8
- package/dist/{chunk-4DGYLA73.js → chunk-GXNLGKAB.js} +80 -9
- package/dist/chunk-HHV2GANA.js +88 -0
- package/dist/{chunk-IIZWH4XA.js → chunk-HI63TFOG.js} +5 -4
- package/dist/{chunk-WLFILSD5.js → chunk-HJJTYUHX.js} +113 -83
- package/dist/{chunk-TT36MB5S.js → chunk-HLW2MRKE.js} +3 -1
- package/dist/{chunk-PMDBGQSJ.js → chunk-HWHKMHUA.js} +7 -7
- package/dist/chunk-HZHHCK24.js +1631 -0
- package/dist/{chunk-WSB3FPX7.js → chunk-I5VEOC6I.js} +39 -143
- package/dist/chunk-IBEBSCYA.js +564 -0
- package/dist/chunk-IQ7KR472.js +362 -0
- package/dist/{chunk-A3WNZD3P.js → chunk-J4W7KFM7.js} +949 -972
- package/dist/{chunk-TB5666IT.js → chunk-JDG2WCRO.js} +5 -5
- package/dist/{chunk-N22QMJKY.js → chunk-K5C3NCBD.js} +4 -4
- package/dist/{chunk-CGKSTWHD.js → chunk-K6BSR66V.js} +2 -1
- package/dist/{chunk-5C3AQNDW.js → chunk-KFZI4NIL.js} +216 -38
- package/dist/chunk-KMVISBZR.js +132 -0
- package/dist/{chunk-WXY7KU3G.js → chunk-LDQ2ZF2M.js} +2 -2
- package/dist/{chunk-XN3L4EYL.js → chunk-LQ3DZAMX.js} +3 -3
- package/dist/{chunk-U6MBIEMB.js → chunk-LY4S7GJC.js} +173 -144
- package/dist/{chunk-4SPRNWDE.js → chunk-MLKNTWH2.js} +19 -19
- package/dist/{chunk-MVVUPGPW.js → chunk-MXHC5QYU.js} +6 -6
- package/dist/chunk-NEKRRTYW.js +56 -0
- package/dist/{chunk-SPULKLCF.js → chunk-NHCZP4K7.js} +3 -3
- package/dist/chunk-NHLBIGRH.js +1506 -0
- package/dist/chunk-NQQH3YT7.js +302 -0
- package/dist/chunk-NYS75XW5.js +15 -0
- package/dist/{chunk-GN57SG4G.js → chunk-O4XIVISU.js} +10 -8
- package/dist/{chunk-EMYUUSFG.js → chunk-O6TL7WWY.js} +6 -6
- package/dist/chunk-OQBA45DZ.js +97 -0
- package/dist/{chunk-LU7P4LHA.js → chunk-P3FOHJT4.js} +2 -2
- package/dist/chunk-PMZCIOCJ.js +25 -0
- package/dist/{chunk-I4HZDVNP.js → chunk-PQEFIJ36.js} +2 -2
- package/dist/{chunk-J3YUBZWY.js → chunk-QBJA7R7N.js} +62 -6
- package/dist/chunk-QDC3K2U3.js +262 -0
- package/dist/{chunk-2HEJ2F35.js → chunk-QLFS5GO2.js} +22 -10
- package/dist/{chunk-7RGZWPB6.js → chunk-QLL7ILRG.js} +95 -32
- package/dist/{chunk-YS5VLNH5.js → chunk-QREDIESB.js} +6 -6
- package/dist/chunk-QSNYB6ZV.js +195 -0
- package/dist/{chunk-GOXNB3AO.js → chunk-RAPCMZL4.js} +75 -4
- package/dist/chunk-RKKLTLYB.js +45 -0
- package/dist/{chunk-P43ETTHK.js → chunk-SJ5ZKQ4S.js} +2 -2
- package/dist/{chunk-GPIEI3LY.js → chunk-SP2RXXYO.js} +6 -54
- package/dist/chunk-SUCTJL45.js +45 -0
- package/dist/{chunk-DYIM5TJT.js → chunk-SUW5DORT.js} +263 -7
- package/dist/chunk-T56WDKA5.js +183 -0
- package/dist/chunk-TVHHYFHE.js +255 -0
- package/dist/{chunk-FJ3H4MN5.js → chunk-TZ3SGWZZ.js} +3 -3
- package/dist/{chunk-MXKJU4JB.js → chunk-U77AMWDL.js} +91 -10
- package/dist/{chunk-5DHKRSMQ.js → chunk-ULC6OTWO.js} +11 -7
- package/dist/{chunk-RWSI4YD7.js → chunk-UM7N4G5A.js} +33 -12
- package/dist/{chunk-FCSXB6T2.js → chunk-UOSL25KY.js} +14 -2
- package/dist/{chunk-IGWKHNIQ.js → chunk-UXMFQ54G.js} +44 -37
- package/dist/{chunk-HFSBBKSQ.js → chunk-V5DHCITQ.js} +171 -3
- package/dist/{chunk-5WIGXA4T.js → chunk-VAZSBTKF.js} +111 -4
- package/dist/{chunk-VHN4MY6O.js → chunk-VEO4AP2K.js} +2 -2
- package/dist/{chunk-IJ7RPIYJ.js → chunk-VFA6GDY5.js} +65 -4
- package/dist/{chunk-PT7HYKEM.js → chunk-VO2LKSTM.js} +2 -2
- package/dist/chunk-VO67MWHC.js +75 -0
- package/dist/{chunk-XK56QHLX.js → chunk-VPKWYKEY.js} +19 -5
- package/dist/{chunk-TANS5ZJS.js → chunk-VYMXRQI6.js} +36 -22
- package/dist/{chunk-WWCZ5F23.js → chunk-W5VSYASO.js} +77 -16
- package/dist/{chunk-WNIJTQQK.js → chunk-WZR7K7ZX.js} +72 -116
- package/dist/{chunk-5Q2VVUKB.js → chunk-X3YGUTOB.js} +4 -4
- package/dist/chunk-X75E3D2N.js +686 -0
- package/dist/{chunk-VAWNZU7Z.js → chunk-YDFRH54B.js} +4 -4
- package/dist/chunk-YJX4SHTD.js +40 -0
- package/dist/{chunk-ZI647VB5.js → chunk-YPI3QQCF.js} +2 -2
- package/dist/chunk-Z2RR6MAK.js +127 -0
- package/dist/{chunk-FBVTI2TJ.js → chunk-Z4TXYIEG.js} +12 -131
- package/dist/cli/index.js +47 -36
- package/dist/{clio-QVTYJ57A.js → clio-2JXHBBY5.js} +7 -7
- package/dist/{code-nav-FGGFIE7L.js → code-nav-3YYRMYNF.js} +8 -8
- package/dist/{compile-cache-CVJMMODC.js → compile-cache-7FPE6PS3.js} +3 -3
- package/dist/{components-ZFA3SAER.js → components-RYZV4JGP.js} +5 -5
- package/dist/{config-LW5IJFQN.js → config-QZPCMYSO.js} +99 -63
- package/dist/{configure-7XIZCOU4.js → configure-TEGEBYCA.js} +23 -22
- package/dist/{context-Y6Y7QPR6.js → context-AV7OEZ4D.js} +12 -12
- package/dist/{context-L3WL3X7K.js → context-E6H5RNMC.js} +56 -47
- package/dist/{context-N52ZA626.js → context-GSXUE4CT.js} +29 -27
- package/dist/{context-clear-MBQRLSDQ.js → context-clear-SHIBYK6T.js} +55 -46
- package/dist/{context-index-HVMFQHK3.js → context-index-HNG3MOME.js} +2 -2
- package/dist/{context-working-set-GS6DSO7F.js → context-working-set-5ZGKPGZQ.js} +13 -13
- package/dist/{dispatch-runner-22ZCNOM3.js → dispatch-runner-EFMJT4LD.js} +93 -64
- package/dist/{docs-7LQ23DLM.js → docs-23KQS3XK.js} +5 -5
- package/dist/doctor-QOA5FNY5.js +313 -0
- package/dist/{eval-BEC2WHDA.js → eval-TFBYQH4H.js} +2032 -156
- package/dist/eval-inventory-SXH7PDKX.js +316 -0
- package/dist/{evidence-REJUMSKM.js → evidence-ERGESKGN.js} +203 -48
- package/dist/{evolve-PY5ZBA5K.js → evolve-VDXTSYCJ.js} +52 -43
- package/dist/{extensions-HVKU65YU.js → extensions-7BGBHN57.js} +13 -7
- package/dist/{fleet-7WZEWRFA.js → fleet-2RRVDF2V.js} +228 -108
- package/dist/{fleet-commands-UVHWM76J.js → fleet-commands-VJ726XIA.js} +11 -11
- package/dist/fleet-decisions-EPAPM3XJ.js +157 -0
- package/dist/{fleet-graph-6ULH7PES.js → fleet-graph-JF5QOATM.js} +18 -15
- package/dist/fleet-inspect-VLY4S7QM.js +442 -0
- package/dist/{fleet-preflight-J53T6CCE.js → fleet-preflight-AIZUEJOY.js} +5 -5
- package/dist/{fleet-validate-72PC4SLA.js → fleet-validate-AJRPDMDV.js} +22 -19
- package/dist/fleet-verify-JFEL2L3H.js +175 -0
- package/dist/fleet-view-ZCON35AG.js +102 -0
- package/dist/{init-OG3TPGQG.js → init-DN2WWLFE.js} +72 -62
- package/dist/install-XGLBQY5E.js +13 -0
- package/dist/interop-OZBKXAYL.js +114 -0
- package/dist/{library-CNTMPLRF.js → library-YWZG7IMW.js} +21 -18
- package/dist/{memory-6IS7F275.js → memory-I4C4HMLW.js} +54 -45
- package/dist/{models-ENRJDA5W.js → models-CEYXJBO6.js} +33 -30
- package/dist/{monitor-XLDVO7TN.js → monitor-NZ6GCI3P.js} +59 -52
- package/dist/{orchestrator-6KSPYRHA.js → orchestrator-GCGQ4N5I.js} +7827 -7328
- package/dist/panes-HMABYVO4.js +58 -0
- package/dist/panes-KY6W3V2E.js +103 -0
- package/dist/{paths-DBXMZMDU.js → paths-II4K7DNR.js} +5 -5
- package/dist/{reset-RZ4ER727.js → reset-DQ6FGCSH.js} +13 -11
- package/dist/resources-BB3MVJMD.js +111 -0
- package/dist/{run-Y2CNK5RU.js → run-H2GQDUER.js} +119 -87
- package/dist/{share-A55GYP6Z.js → share-GTJN6A5O.js} +20 -17
- package/dist/{skills-ALC5J6AT.js → skills-L55TEW6R.js} +33 -24
- package/dist/{skills-eval-JPBEBYQU.js → skills-eval-XVXPH2JI.js} +67 -56
- package/dist/skills-inventory-S4MXPJFV.js +126 -0
- package/dist/slash-commands-ZSGASKJC.js +77 -0
- package/dist/{steer-GGWFUJUD.js → steer-RZGSCY4R.js} +4 -4
- package/dist/{support-MIETYA5E.js → support-PKEUNNQL.js} +6 -6
- package/dist/{targets-VGNXIR3S.js → targets-NCPZ644J.js} +68 -40
- package/dist/{terminal-lease-WOBR64YA.js → terminal-lease-44SV3YCN.js} +6 -4
- package/dist/tools-DAF3DI3C.js +27 -0
- package/dist/{trace-PNCASAXC.js → trace-FYVW2MQA.js} +207 -10
- package/dist/tui-primitives-2AKXQNZK.js +13 -0
- package/dist/{uninstall-ZJF5H5ZN.js → uninstall-DW2PNOIC.js} +5 -5
- package/dist/{upgrade-FUSUAGHR.js → upgrade-3XPP6OQL.js} +27 -24
- package/dist/{usage-N4MKVHKD.js → usage-3NLHGTU2.js} +114 -62
- package/dist/{verifiers-YAWOJ3H2.js → verifiers-SSQONKRT.js} +172 -13
- package/dist/{verify-LTDHYBGY.js → verify-3U6J7FZI.js} +10 -10
- package/dist/{web-fetch-2YHJ3KTG.js → web-fetch-S7RR6GZ7.js} +3 -3
- package/dist/{wiki-generate-6M7GHTBJ.js → wiki-generate-CEHYGPGQ.js} +75 -65
- package/dist/with-panes-MKB46MPQ.js +782 -0
- package/dist/worker/entry.js +106 -75
- package/docs/README.md +3 -2
- package/docs/acp.md +24 -3
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/artifact-versions.md +9 -1
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +62 -3
- package/docs/commands-and-modes.md +31 -2
- package/docs/configuration-and-targets.md +69 -12
- package/docs/context-engine.md +63 -4
- package/docs/development-pipeline.md +19 -0
- package/docs/dispatch-typed-intent.md +385 -0
- package/docs/documentation-coverage.md +5 -5
- package/docs/documentation-guide.md +1 -1
- package/docs/environment-variables.md +3 -0
- package/docs/eval-runner.md +262 -11
- package/docs/evals-internal.md +72 -2
- package/docs/evidence-and-memory.md +12 -11
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +1 -1
- package/docs/extensions-and-sharing.md +27 -1
- package/docs/fleet-dispatch.md +25 -4
- package/docs/installation-and-lifecycle.md +15 -2
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +10 -1
- package/docs/observability.md +55 -4
- package/docs/proactive-memory.md +127 -14
- package/docs/prompt-envelope-and-tools.md +19 -1
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +19 -3
- package/docs/safety-model.md +2 -2
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +1 -1
- package/docs/skills-marketplace.md +1 -1
- package/docs/tool-usage.md +18 -8
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +88 -1
- package/docs/tui-design.md +1 -1
- package/docs/worker-dispatch-mechanics.md +1 -1
- package/package.json +5 -2
- package/src/cli/acp.ts +6 -2
- package/src/cli/agents.ts +1 -1
- package/src/cli/argv.ts +25 -0
- package/src/cli/config-inspect.ts +33 -6
- package/src/cli/config.ts +1 -1
- package/src/cli/configure.ts +23 -21
- package/src/cli/doctor-panes.ts +124 -0
- package/src/cli/doctor-state-size.ts +82 -0
- package/src/cli/doctor-toolchain.ts +57 -0
- package/src/cli/doctor.ts +22 -1
- package/src/cli/eval-inventory.ts +436 -0
- package/src/cli/eval.ts +93 -16
- package/src/cli/evidence-detail.ts +88 -0
- package/src/cli/evidence-inventory.ts +183 -0
- package/src/cli/evidence.ts +30 -5
- package/src/cli/extensions.ts +5 -1
- package/src/cli/fleet-decisions.ts +69 -0
- package/src/cli/fleet-inspect.ts +334 -0
- package/src/cli/fleet-verify.ts +133 -0
- package/src/cli/fleet-view.ts +810 -0
- package/src/cli/fleet.ts +179 -39
- package/src/cli/index.ts +14 -2
- package/src/cli/interop-inspect.ts +128 -0
- package/src/cli/interop.ts +34 -0
- package/src/cli/panes.ts +35 -0
- package/src/cli/reset.ts +5 -2
- package/src/cli/run.ts +58 -0
- package/src/cli/skills-inventory.ts +185 -0
- package/src/cli/skills.ts +16 -13
- package/src/cli/targets.ts +44 -13
- package/src/cli/tools.ts +321 -0
- package/src/cli/trace-inspect.ts +252 -0
- package/src/cli/trace.ts +85 -5
- package/src/cli/usage.ts +63 -14
- package/src/cli/verifiers-inspect.ts +347 -0
- package/src/cli/verifiers.ts +9 -0
- package/src/core/bus-events.ts +33 -1
- package/src/core/cache-telemetry.ts +42 -0
- package/src/core/config.ts +67 -0
- package/src/core/defaults.ts +124 -8
- package/src/core/endpoint-key.ts +27 -0
- package/src/core/residency-target-key.ts +25 -0
- package/src/core/response-schema.ts +80 -6
- package/src/core/theme-token-hex.ts +43 -0
- package/src/core/tool-names.ts +2 -1
- package/src/core/xdg.ts +1 -1
- package/src/domains/agents/fleets/build-review.md +0 -3
- package/src/domains/agents/fleets/build-test.md +0 -3
- package/src/domains/agents/result-contract-filesystem.ts +32 -0
- package/src/domains/agents/result-contract.ts +164 -35
- package/src/domains/config/classify.ts +6 -0
- package/src/domains/context/codewiki/coordinator.ts +12 -4
- package/src/domains/dispatch/admission-error.ts +9 -0
- package/src/domains/dispatch/admission.ts +52 -14
- package/src/domains/dispatch/capacity-lease.ts +118 -9
- package/src/domains/dispatch/contract.ts +11 -0
- package/src/domains/dispatch/council-topology.ts +398 -0
- package/src/domains/dispatch/execution-plan.ts +44 -4
- package/src/domains/dispatch/extension.ts +378 -82
- package/src/domains/dispatch/fleet-node-prompt.ts +62 -0
- package/src/domains/dispatch/fleet-plan.ts +7 -2
- package/src/domains/dispatch/fleet-run.ts +87 -4
- package/src/domains/dispatch/gate-decisions.ts +11 -1
- package/src/domains/dispatch/gate-role-prompts.ts +9 -0
- package/src/domains/dispatch/gate-topology.ts +289 -0
- package/src/domains/dispatch/heartbeat.ts +32 -8
- package/src/domains/dispatch/index.ts +22 -0
- package/src/domains/dispatch/intent-compatibility.ts +330 -0
- package/src/domains/dispatch/intent.ts +85 -1
- package/src/domains/dispatch/orphan-recovery.ts +5 -0
- package/src/domains/dispatch/reservation-store.ts +139 -11
- package/src/domains/dispatch/run-event-journal-bridge.ts +149 -0
- package/src/domains/dispatch/run-event-journal.ts +598 -0
- package/src/domains/dispatch/state.ts +49 -1
- package/src/domains/dispatch/types.ts +13 -0
- package/src/domains/dispatch/validation.ts +33 -8
- package/src/domains/dispatch/worker-spawn.ts +25 -11
- package/src/domains/dispatch/write-boundary-enforcer.ts +20 -3
- package/src/domains/dispatch/write-boundary.ts +62 -1
- package/src/domains/eval/artifacts/store.ts +62 -0
- package/src/domains/eval/compare/behavioral.ts +224 -0
- package/src/domains/eval/compare/compare.ts +342 -2
- package/src/domains/eval/compare/envelope.ts +128 -0
- package/src/domains/eval/compare/gates.ts +24 -6
- package/src/domains/eval/compare/thresholds.ts +30 -3
- package/src/domains/eval/execution-provenance.ts +240 -0
- package/src/domains/eval/inventory.ts +113 -0
- package/src/domains/eval/metrics/aggregate.ts +136 -0
- package/src/domains/eval/metrics/call-ledger-stream.ts +112 -0
- package/src/domains/eval/metrics/tracked.ts +413 -0
- package/src/domains/eval/provenance.ts +117 -0
- package/src/domains/eval/reports/comparison.ts +128 -0
- package/src/domains/eval/reports/junit.ts +17 -3
- package/src/domains/eval/reports/markdown.ts +3 -3
- package/src/domains/eval/reports/text.ts +14 -0
- package/src/domains/eval/run-compare.ts +20 -0
- package/src/domains/eval/runners/clio-run.ts +127 -0
- package/src/domains/eval/runners/external-command.ts +28 -3
- package/src/domains/eval/schema/adapter.ts +111 -0
- package/src/domains/eval/schema/artifact.ts +20 -0
- package/src/domains/eval/schema/behavioral-metrics.ts +204 -0
- package/src/domains/eval/schema/behavioral.ts +520 -0
- package/src/domains/eval/schema/execution-envelope.ts +194 -0
- package/src/domains/eval/schema/serving.ts +105 -0
- package/src/domains/eval/schema/suite.ts +38 -8
- package/src/domains/eval/schema/validate.ts +58 -3
- package/src/domains/eval/schema/verdict.ts +237 -0
- package/src/domains/eval/suites/resolve.ts +2 -0
- package/src/domains/eval/suites/run.ts +264 -33
- package/src/domains/eval/verifiers/command.ts +2 -1
- package/src/domains/eval/workspaces/temp-copy.ts +145 -13
- package/src/domains/evidence/build.ts +2 -13
- package/src/domains/evidence/eval.ts +2 -12
- package/src/domains/evidence/findings-markdown.ts +33 -0
- package/src/domains/evidence/run-trust.ts +7 -113
- package/src/domains/evidence/store.ts +6 -0
- package/src/domains/evidence/trust-projection.ts +2 -2
- package/src/domains/extensions/compatibility.ts +285 -0
- package/src/domains/extensions/discovery.ts +38 -3
- package/src/domains/extensions/resources.ts +1 -1
- package/src/domains/extensions/state.ts +12 -3
- package/src/domains/extensions/types.ts +2 -0
- package/src/domains/lifecycle/doctor.ts +69 -1
- package/src/domains/memory/index.ts +14 -1
- package/src/domains/memory/task-bank-promotion.ts +64 -0
- package/src/domains/memory/task-memory-policy.ts +82 -17
- package/src/domains/memory/task-memory-spend.ts +131 -0
- package/src/domains/memory/task-memory-status.ts +7 -0
- package/src/domains/memory/task-memory-telemetry.ts +3 -0
- package/src/domains/middleware/index.ts +1 -0
- package/src/domains/middleware/memory-intervention.ts +97 -21
- package/src/domains/middleware/memory-step-endpoint.ts +71 -0
- package/src/domains/mux/contract.ts +434 -0
- package/src/domains/mux/detect.ts +158 -0
- package/src/domains/mux/extension.ts +47 -0
- package/src/domains/mux/index.ts +96 -0
- package/src/domains/mux/manifest.ts +6 -0
- package/src/domains/mux/operations.ts +164 -0
- package/src/domains/mux/pane-registry.ts +90 -0
- package/src/domains/mux/protocol.ts +49 -0
- package/src/domains/mux/socket-client.ts +816 -0
- package/src/domains/mux/types.ts +222 -0
- package/src/domains/mux/viewer-command.ts +59 -0
- package/src/domains/mux/yazi/assets/init.lua +2 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/LICENSE +21 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/README.md +78 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/main.lua +255 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/types.lua +12 -0
- package/src/domains/mux/yazi/assets/yazi.toml +17 -0
- package/src/domains/mux/yazi/event-stream.ts +180 -0
- package/src/domains/mux/yazi/profile.ts +299 -0
- package/src/domains/mux/yazi/session.ts +228 -0
- package/src/domains/mux/yazi/theme.ts +30 -0
- package/src/domains/observability/background-memory-usage.ts +140 -0
- package/src/domains/observability/cost.ts +22 -1
- package/src/domains/observability/index.ts +9 -0
- package/src/domains/observability/out-of-turn-usage.ts +51 -2
- package/src/domains/observability/trace-store.ts +234 -2
- package/src/domains/prompts/compiler.ts +100 -13
- package/src/domains/providers/endpoint-capacity.ts +228 -0
- package/src/domains/providers/endpoint-slots-store.ts +189 -0
- package/src/domains/providers/extension.ts +20 -3
- package/src/domains/providers/index.ts +32 -0
- package/src/domains/providers/model-runtime-capabilities.ts +32 -0
- package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +243 -1
- package/src/domains/providers/runtime-resolution.ts +8 -1
- package/src/domains/providers/runtimes/boot-manifest.ts +1 -0
- package/src/domains/providers/runtimes/builtins.ts +2 -0
- package/src/domains/providers/runtimes/common/probe-helpers.ts +31 -9
- package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp.ts +4 -1
- package/src/domains/providers/runtimes/local-native/lmstudio.ts +4 -1
- package/src/domains/providers/runtimes/local-native/ollama-native.ts +6 -1
- package/src/domains/providers/runtimes/protocol/litellm.ts +375 -0
- package/src/domains/providers/support.ts +1 -0
- package/src/domains/providers/target-model-cache.ts +124 -0
- package/src/domains/providers/types/capability-flags.ts +2 -0
- package/src/domains/providers/types/target-descriptor.ts +2 -0
- package/src/domains/resources/index.ts +3 -0
- package/src/domains/resources/prompts/loader.ts +95 -33
- package/src/domains/resources/skills/loader.ts +33 -0
- package/src/domains/safety/action-classifier.ts +6 -0
- package/src/domains/safety/call-target.ts +52 -0
- package/src/domains/safety/run-effects.ts +35 -4
- package/src/domains/session/context-accounting.ts +52 -1
- package/src/domains/session/context-ledger.ts +37 -13
- package/src/domains/session/index.ts +6 -0
- package/src/domains/session/prompt-cache.ts +140 -0
- package/src/domains/session/prompt-manifest.ts +42 -0
- package/src/domains/toolchain/archive.ts +175 -0
- package/src/domains/toolchain/contract.ts +28 -0
- package/src/domains/toolchain/extension.ts +47 -0
- package/src/domains/toolchain/index.ts +39 -0
- package/src/domains/toolchain/install.ts +327 -0
- package/src/domains/toolchain/manifest.ts +8 -0
- package/src/domains/toolchain/paths.ts +34 -0
- package/src/domains/toolchain/registry.ts +265 -0
- package/src/domains/toolchain/remove.ts +218 -0
- package/src/domains/toolchain/resolve.ts +182 -0
- package/src/domains/toolchain/types.ts +113 -0
- package/src/domains/toolchain/version.ts +88 -0
- package/src/engine/acp/adapter.ts +18 -3
- package/src/engine/acp/server.ts +413 -70
- package/src/engine/acp/types.ts +19 -1
- package/src/engine/ai.ts +35 -0
- package/src/engine/apis/llamacpp-residency.ts +55 -3
- package/src/engine/apis/lmstudio.ts +25 -5
- package/src/engine/apis/ollama-native.ts +2 -1
- package/src/engine/apis/openai-completions.ts +80 -17
- package/src/engine/apis/residency-lock.ts +3 -1
- package/src/engine/apis/residency.ts +34 -1
- package/src/engine/claude/sdk-module.ts +98 -0
- package/src/engine/claude/sdk-runtime.ts +19 -11
- package/src/engine/provider-payload.ts +29 -1
- package/src/engine/tui-primitives.ts +21 -0
- package/src/engine/tui.ts +1 -0
- package/src/engine/worker-runtime.ts +2 -13
- package/src/entry/boot-options.ts +2 -0
- package/src/entry/orchestrator.ts +279 -35
- package/src/entry/panes-activation.ts +31 -0
- package/src/entry/with-panes.ts +20 -0
- package/src/interactive/chat-loop-messages.ts +26 -7
- package/src/interactive/chat-loop.ts +318 -41
- package/src/interactive/chat-panel.ts +62 -8
- package/src/interactive/clio-editor.ts +45 -8
- package/src/interactive/context-activity.ts +5 -1
- package/src/interactive/context-meter.ts +1 -1
- package/src/interactive/context-overlay.ts +41 -10
- package/src/interactive/cost-overlay.ts +66 -6
- package/src/interactive/council-grid.ts +1 -3
- package/src/interactive/council.ts +11 -0
- package/src/interactive/dispatch-board.ts +102 -20
- package/src/interactive/fleet-run-preview.ts +41 -15
- package/src/interactive/handoff-round.ts +41 -2
- package/src/interactive/interactive-application.ts +177 -7
- package/src/interactive/interactive-input-runtime.ts +15 -0
- package/src/interactive/interactive-presentation.ts +4 -0
- package/src/interactive/interactive-shell.ts +20 -17
- package/src/interactive/interactive-slash-runtime.ts +63 -10
- package/src/interactive/memory-overlay.ts +9 -0
- package/src/interactive/modal-marker.ts +170 -0
- package/src/interactive/mutation-preview.ts +295 -0
- package/src/interactive/mux-bridge.ts +214 -0
- package/src/interactive/overlay-frame.ts +58 -2
- package/src/interactive/overlay-general-openers.ts +17 -0
- package/src/interactive/overlay-key-routing.ts +52 -3
- package/src/interactive/overlay-lifecycle.ts +56 -7
- package/src/interactive/overlay-model-selectors.ts +40 -3
- package/src/interactive/overlay-permission-lifecycle.ts +112 -24
- package/src/interactive/overlay-session-lifecycle.ts +73 -9
- package/src/interactive/overlay-transitions.ts +18 -4
- package/src/interactive/overlays/agents.ts +1 -0
- package/src/interactive/overlays/ask-user.ts +227 -49
- package/src/interactive/overlays/auth-dialog.ts +1 -0
- package/src/interactive/overlays/context-reset.ts +1 -0
- package/src/interactive/overlays/cwd-fallback.ts +1 -0
- package/src/interactive/overlays/decisions.ts +11 -11
- package/src/interactive/overlays/extensions.ts +1 -0
- package/src/interactive/overlays/fleet-run-approval.ts +1 -0
- package/src/interactive/overlays/handoff-review.ts +1 -0
- package/src/interactive/overlays/help-reference.ts +6 -0
- package/src/interactive/overlays/interop.ts +1 -0
- package/src/interactive/overlays/library-install-confirm.ts +1 -0
- package/src/interactive/overlays/library-tabs.ts +28 -0
- package/src/interactive/overlays/list-overlay.ts +10 -1
- package/src/interactive/overlays/message-picker.ts +1 -0
- package/src/interactive/overlays/model-scope.ts +86 -0
- package/src/interactive/overlays/model-selector.ts +1 -0
- package/src/interactive/overlays/prompts.ts +12 -1
- package/src/interactive/overlays/session-selector.ts +1 -0
- package/src/interactive/overlays/settings-sections.ts +30 -0
- package/src/interactive/overlays/settings.ts +614 -45
- package/src/interactive/overlays/side-question.ts +1 -0
- package/src/interactive/overlays/skills-hub.ts +3 -11
- package/src/interactive/overlays/tree-selector.ts +1 -0
- package/src/interactive/pane-policy.ts +46 -0
- package/src/interactive/panes-runtime.ts +292 -0
- package/src/interactive/permission-hint.ts +34 -2
- package/src/interactive/permission-overlay.ts +159 -9
- package/src/interactive/prewarm.ts +197 -0
- package/src/interactive/render-trace.ts +162 -15
- package/src/interactive/renderers/compaction-summary.ts +29 -0
- package/src/interactive/renderers/tool-execution.ts +4 -0
- package/src/interactive/renderers/worker-entry.ts +122 -14
- package/src/interactive/side-question.ts +58 -1
- package/src/interactive/slash-commands.ts +251 -15
- package/src/interactive/status/controller.ts +11 -0
- package/src/interactive/status/state-machine.ts +54 -2
- package/src/interactive/status/types.ts +7 -0
- package/src/interactive/tasks-overlay.ts +1 -0
- package/src/interactive/terminal-lease.ts +2 -0
- package/src/interactive/theme/tokens.ts +3 -14
- package/src/interactive/turn-context.ts +346 -33
- package/src/interactive/turn-persistence.ts +14 -4
- package/src/interactive/turn-prewarm.ts +364 -0
- package/src/interactive/turn-queues.ts +7 -4
- package/src/interactive/turn-runtime.ts +8 -1
- package/src/interactive/turn-state.ts +23 -0
- package/src/interactive/view/artifacts.ts +109 -1
- package/src/interactive/view/view-overlay.ts +29 -3
- package/src/interactive/watch-pane.ts +152 -0
- package/src/interactive/worker-progress.ts +7 -1
- package/src/interactive/worker-receipts.ts +19 -1
- package/src/interactive/worker-stream.ts +5 -0
- package/src/interactive/yazi-bridge.ts +444 -0
- package/src/tools/ask-user.ts +43 -2
- package/src/tools/bootstrap.ts +26 -2
- package/src/tools/builtin-tool-catalog.ts +15 -0
- package/src/tools/compete-worktrees.ts +83 -2
- package/src/tools/core-bootstrap.ts +2 -1
- package/src/tools/dispatch-admission.ts +14 -3
- package/src/tools/dispatch-arguments.ts +20 -20
- package/src/tools/dispatch-plan.ts +17 -9
- package/src/tools/dispatch-run-events.ts +134 -19
- package/src/tools/dispatch-runner.ts +29 -7
- package/src/tools/dispatch-scout.ts +1 -1
- package/src/tools/dispatch-types.ts +15 -3
- package/src/tools/dispatch.ts +1 -1
- package/src/tools/executables.ts +17 -14
- package/src/tools/observation.ts +54 -4
- package/src/tools/panes-surface.ts +38 -0
- package/src/tools/panes.ts +112 -0
- package/src/tools/policy.ts +10 -1
- package/src/tools/presentation.ts +1 -0
- package/src/tools/registry.ts +16 -0
- package/dist/chunk-AOCYTWAV.js +0 -449
- package/dist/chunk-HLE42MG7.js +0 -37
- package/dist/chunk-HWUFFB6L.js +0 -83
- package/dist/chunk-JOZYP4GM.js +0 -279
- package/dist/doctor-M7YEDGAE.js +0 -91
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { createHash, randomBytes } from "node:crypto";
|
|
13
|
-
import { type Dirent,
|
|
13
|
+
import { type Dirent, readdirSync, readFileSync } from "node:fs";
|
|
14
14
|
import { isAbsolute, relative, resolve as resolvePath, sep } from "node:path";
|
|
15
|
+
import { performance } from "node:perf_hooks";
|
|
15
16
|
import { BusChannels, type DispatchCompletedPayload, type DispatchRunIdentity } from "../../core/bus-events.js";
|
|
16
17
|
import { DEFAULT_SETTINGS, type DelegationToolGovernance } from "../../core/defaults.js";
|
|
17
18
|
import type { DomainBundle, DomainContext, DomainExtension } from "../../core/domain-loader.js";
|
|
@@ -57,6 +58,7 @@ import {
|
|
|
57
58
|
import type { AgentsContract } from "../agents/contract.js";
|
|
58
59
|
import type { AgentRecipe } from "../agents/recipe.js";
|
|
59
60
|
import { validateRecipeResult } from "../agents/result-contract.js";
|
|
61
|
+
import { nodeResultContractFilesystem } from "../agents/result-contract-filesystem.js";
|
|
60
62
|
import {
|
|
61
63
|
type AgentAudience,
|
|
62
64
|
type AgentCapabilityClass,
|
|
@@ -76,12 +78,16 @@ import { type EffectivePricing, resolveEffectivePricing } from "../providers/cat
|
|
|
76
78
|
import {
|
|
77
79
|
type CapabilityFlags,
|
|
78
80
|
canonicalizeWireModelId,
|
|
81
|
+
type EndpointCapacity,
|
|
82
|
+
endpointCapacityFor,
|
|
83
|
+
endpointCapacityForStatus,
|
|
79
84
|
firstRuntimeResolutionError,
|
|
80
85
|
isDispatchEligibleRuntime,
|
|
81
86
|
type ProvidersContract,
|
|
82
87
|
type ResolvedRuntimeTarget,
|
|
83
88
|
type RuntimeApiFamily,
|
|
84
89
|
type RuntimeDescriptor,
|
|
90
|
+
resolveEndpointCapacities,
|
|
85
91
|
resolveModelCapabilities,
|
|
86
92
|
resolveRuntimeTarget,
|
|
87
93
|
runtimeResolutionWarnings,
|
|
@@ -108,6 +114,7 @@ import {
|
|
|
108
114
|
routeValidationProjection,
|
|
109
115
|
} from "./active-route-planner.js";
|
|
110
116
|
import { admit, createCapacityAdmissionController, createLeaseSlotGuard } from "./admission.js";
|
|
117
|
+
import { AdmissionCanceledError } from "./admission-error.js";
|
|
111
118
|
import { agentRouteCandidates } from "./agent-candidates.js";
|
|
112
119
|
import { AGENT_LEDGER_PROMPT_MAX_CHARS, renderAgentLedger } from "./agent-ledger.js";
|
|
113
120
|
import { publishAgentLedgerEntry, subscribeAgentLedger } from "./agent-ledger-hub.js";
|
|
@@ -166,7 +173,14 @@ import {
|
|
|
166
173
|
} from "./failure-classification.js";
|
|
167
174
|
import { routeFactVerdict } from "./fleet-preflight.js";
|
|
168
175
|
import { competeStanceLiner, isBoundedGateRolePrompt } from "./gate-role-prompts.js";
|
|
169
|
-
import {
|
|
176
|
+
import {
|
|
177
|
+
classifyHeartbeat,
|
|
178
|
+
DEFAULT_HEARTBEAT_SPEC,
|
|
179
|
+
type HeartbeatSpec,
|
|
180
|
+
type HeartbeatStamp,
|
|
181
|
+
type HeartbeatStatus,
|
|
182
|
+
heartbeatMonotonicAt,
|
|
183
|
+
} from "./heartbeat.js";
|
|
170
184
|
import { hostVerificationRejection, runHostVerification } from "./host-verification.js";
|
|
171
185
|
import { renderDispatchIntentRequirements } from "./intent-requirements.js";
|
|
172
186
|
import { adaptJointRouteInput } from "./joint-route-adapter.js";
|
|
@@ -205,6 +219,7 @@ import {
|
|
|
205
219
|
planQueueSlot,
|
|
206
220
|
type ReservationCapacitySnapshot,
|
|
207
221
|
rebindDispatchReservationMember,
|
|
222
|
+
releaseDispatchReservation,
|
|
208
223
|
releaseDispatchReservationMember,
|
|
209
224
|
reservedBudgetUsd,
|
|
210
225
|
reservedPlanPeakSlots,
|
|
@@ -224,6 +239,7 @@ import {
|
|
|
224
239
|
import { createRouteObserver, type RouteObservationHandle, type RouteObserver } from "./route-observer.js";
|
|
225
240
|
import { reduceRouteQuality } from "./route-quality.js";
|
|
226
241
|
import { defaultRoutingIntent } from "./routing-intent.js";
|
|
242
|
+
import { attachRunEventJournalBridge, type RunEventJournalBridge } from "./run-event-journal-bridge.js";
|
|
227
243
|
import { detectRunIdentity } from "./run-identity.js";
|
|
228
244
|
import { type Ledger, newRunId, openLedger } from "./state.js";
|
|
229
245
|
import {
|
|
@@ -286,6 +302,7 @@ import {
|
|
|
286
302
|
type SpawnOptions as WorkerSpawnOptions,
|
|
287
303
|
type WorkerSpec,
|
|
288
304
|
} from "./worker-spawn.js";
|
|
305
|
+
import type { WriteBoundaryAttribution, WriteBoundaryAttributionDowngrade } from "./write-boundary.js";
|
|
289
306
|
|
|
290
307
|
interface RunTokenMeter {
|
|
291
308
|
inputTokens: number;
|
|
@@ -337,7 +354,7 @@ interface ActiveRun {
|
|
|
337
354
|
/** ACP event-inactivity window; null for native runs (heartbeat spec governs those). */
|
|
338
355
|
stallTimeoutMs: number | null;
|
|
339
356
|
lineage: RunLineage;
|
|
340
|
-
heartbeatAt:
|
|
357
|
+
heartbeatAt: HeartbeatStamp | null;
|
|
341
358
|
heartbeatStatus: HeartbeatStatus;
|
|
342
359
|
meter: RunTokenMeter;
|
|
343
360
|
pricing: EffectivePricing["rates"];
|
|
@@ -345,6 +362,12 @@ interface ActiveRun {
|
|
|
345
362
|
finalPromise: Promise<RunReceipt>;
|
|
346
363
|
}
|
|
347
364
|
|
|
365
|
+
interface PendingCapacityAdmission {
|
|
366
|
+
identity: DispatchRunIdentity & { requestOrigin: DispatchRequestOrigin };
|
|
367
|
+
timing: RunPhaseMarks;
|
|
368
|
+
node: RunNodeIdentity | null;
|
|
369
|
+
}
|
|
370
|
+
|
|
348
371
|
interface DispatchFinishContractSnapshot {
|
|
349
372
|
assessment: FinishContractAssessment;
|
|
350
373
|
rigor: Rigor;
|
|
@@ -373,6 +396,8 @@ export interface DispatchBundleOptions {
|
|
|
373
396
|
heartbeatIntervalMs?: number;
|
|
374
397
|
resilienceCooldownMs?: number;
|
|
375
398
|
now?: () => number;
|
|
399
|
+
/** Monotonic clock for heartbeat age and ACP event-inactivity spans. */
|
|
400
|
+
monotonicNow?: () => number;
|
|
376
401
|
/** Immutable per-attempt session settings view; falls back to the shared snapshot. */
|
|
377
402
|
getSettings?: () => EffectiveSettings;
|
|
378
403
|
/** Live hard-block state cloned into each mediated worker spec. */
|
|
@@ -383,6 +408,15 @@ export interface DispatchBundleOptions {
|
|
|
383
408
|
collectReproducibility?: typeof collectReproducibilityMetadata;
|
|
384
409
|
/** Observer injection seam. Production constructs the durable observer. */
|
|
385
410
|
routeObserver?: RouteObserver;
|
|
411
|
+
/**
|
|
412
|
+
* Write the durable run event journal for every run this bundle dispatches.
|
|
413
|
+
* Off by default and turned on by the three composition roots
|
|
414
|
+
* (src/entry/orchestrator.ts, src/cli/run.ts, src/cli/fleet.ts), because the
|
|
415
|
+
* process that owns a bundle also decides who owns the journal file: a
|
|
416
|
+
* composed process routes `registerAllTools`' event registry to
|
|
417
|
+
* `journal: null` so a tool-path run is transcribed once, not twice.
|
|
418
|
+
*/
|
|
419
|
+
journalRunEvents?: boolean;
|
|
386
420
|
}
|
|
387
421
|
|
|
388
422
|
const DEFAULT_HEARTBEAT_INTERVAL_MS = 1000;
|
|
@@ -2397,18 +2431,20 @@ export function createDispatchBundle(
|
|
|
2397
2431
|
return DEFAULT_RESILIENCE_COOLDOWN_MS;
|
|
2398
2432
|
};
|
|
2399
2433
|
const now = options?.now ?? (() => Date.now());
|
|
2434
|
+
const monotonicNow = options?.monotonicNow ?? (() => performance.now());
|
|
2400
2435
|
// Durable evidence owner used by shadow observation and active readiness.
|
|
2401
2436
|
const routeObserver: RouteObserver = options?.routeObserver ?? createRouteObserver({});
|
|
2402
2437
|
|
|
2403
2438
|
let ledger: Ledger | null = null;
|
|
2404
2439
|
let heartbeatTimer: ReturnType<typeof setInterval> | null = null;
|
|
2405
2440
|
const active = new Map<string, ActiveRun>();
|
|
2441
|
+
const pendingCapacity = new Map<string, PendingCapacityAdmission>();
|
|
2406
2442
|
const targetCooldowns = new Map<string, { until: number; reason: string }>();
|
|
2407
2443
|
const ownedReservations = new Set<string>();
|
|
2408
2444
|
/**
|
|
2409
|
-
*
|
|
2410
|
-
*
|
|
2411
|
-
*
|
|
2445
|
+
* Attribution from each finalized run's successful tool calls, newest last.
|
|
2446
|
+
* An incomplete record retains its paths as a lower bound beside the reasons
|
|
2447
|
+
* it cannot be read as a closed list.
|
|
2412
2448
|
*
|
|
2413
2449
|
* Held in memory rather than sealed into the receipt: the only reader is the
|
|
2414
2450
|
* write boundary closing a window seconds later in this process, and a
|
|
@@ -2416,13 +2452,13 @@ export function createDispatchBundle(
|
|
|
2416
2452
|
* Bounded because a long session finalizes many runs and none of this is
|
|
2417
2453
|
* needed once its window has closed.
|
|
2418
2454
|
*/
|
|
2419
|
-
const
|
|
2420
|
-
const
|
|
2421
|
-
|
|
2422
|
-
while (
|
|
2423
|
-
const oldest =
|
|
2455
|
+
const runWriteAttributions = new Map<string, WriteBoundaryAttribution>();
|
|
2456
|
+
const recordRunWriteAttribution = (runId: string, attribution: WriteBoundaryAttribution): void => {
|
|
2457
|
+
runWriteAttributions.set(runId, attribution);
|
|
2458
|
+
while (runWriteAttributions.size > RUN_WRITE_TARGET_HISTORY) {
|
|
2459
|
+
const oldest = runWriteAttributions.keys().next();
|
|
2424
2460
|
if (oldest.done === true) break;
|
|
2425
|
-
|
|
2461
|
+
runWriteAttributions.delete(oldest.value);
|
|
2426
2462
|
}
|
|
2427
2463
|
};
|
|
2428
2464
|
const capacityAdmission = createCapacityAdmissionController({
|
|
@@ -2430,7 +2466,7 @@ export function createDispatchBundle(
|
|
|
2430
2466
|
const settings = getEffectiveSettings();
|
|
2431
2467
|
const nodes: Record<string, number> = { local: configuredGlobalCapacity(settings) };
|
|
2432
2468
|
for (const node of settings?.fleet?.nodes ?? []) nodes[node.id] = node.maxWorkers;
|
|
2433
|
-
return { global: configuredGlobalCapacity(settings), nodes };
|
|
2469
|
+
return { global: configuredGlobalCapacity(settings), nodes, endpoints: configuredEndpointLimits() };
|
|
2434
2470
|
},
|
|
2435
2471
|
now,
|
|
2436
2472
|
reservedPlanPeak: (planId) =>
|
|
@@ -2443,6 +2479,39 @@ export function createDispatchBundle(
|
|
|
2443
2479
|
}),
|
|
2444
2480
|
);
|
|
2445
2481
|
|
|
2482
|
+
/**
|
|
2483
|
+
* Every endpoint the configured fleet can reach.
|
|
2484
|
+
*
|
|
2485
|
+
* Deliberately resolved from the configured targets as well as the probed
|
|
2486
|
+
* statuses. A target whose status has not been built yet contributed no key,
|
|
2487
|
+
* an absent key carries no limit, and reservation planning skips a dimension
|
|
2488
|
+
* it has no limit for, so admission against a single-slot server used to fail
|
|
2489
|
+
* open for whoever asked first after boot.
|
|
2490
|
+
*/
|
|
2491
|
+
function configuredEndpointCapacities(): Readonly<Record<string, EndpointCapacity>> {
|
|
2492
|
+
return resolveEndpointCapacities({
|
|
2493
|
+
statuses: providers.list(),
|
|
2494
|
+
targets: getEffectiveSettings()?.targets ?? [],
|
|
2495
|
+
runtimeFor: (runtimeId) => providers.getRuntime(runtimeId),
|
|
2496
|
+
});
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
function configuredEndpointLimits(): Readonly<Record<string, number>> {
|
|
2500
|
+
return Object.fromEntries(Object.entries(configuredEndpointCapacities()).map(([key, value]) => [key, value.limit]));
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2503
|
+
function endpointCapacityForTarget(targetId: string): EndpointCapacity | null {
|
|
2504
|
+
const status = providers.list().find((entry) => entry.target.id === targetId);
|
|
2505
|
+
const target = status?.target ?? providers.getTarget(targetId);
|
|
2506
|
+
if (target === null || target === undefined) return null;
|
|
2507
|
+
const endpoint =
|
|
2508
|
+
status === undefined
|
|
2509
|
+
? endpointCapacityFor({ target, runtime: providers.getRuntime(target.runtime) })
|
|
2510
|
+
: endpointCapacityForStatus(status);
|
|
2511
|
+
if (endpoint === null) return null;
|
|
2512
|
+
return configuredEndpointCapacities()[endpoint.key] ?? endpoint;
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2446
2515
|
function reservationCapacitySnapshot(settings: EffectiveSettings): ReservationCapacitySnapshot {
|
|
2447
2516
|
const preflight = scheduling.preflight();
|
|
2448
2517
|
// Reservation planning compares against a fresh read, never the display cache.
|
|
@@ -2452,9 +2521,21 @@ export function createDispatchBundle(
|
|
|
2452
2521
|
};
|
|
2453
2522
|
for (const node of settings?.fleet?.nodes ?? [])
|
|
2454
2523
|
nodes[node.id] = { active: usage.nodes[node.id] ?? 0, limit: node.maxWorkers };
|
|
2524
|
+
const endpoints = Object.fromEntries(
|
|
2525
|
+
Object.entries(configuredEndpointLimits()).map(([key, limit]) => [
|
|
2526
|
+
key,
|
|
2527
|
+
{
|
|
2528
|
+
active: usage.endpoints[key] ?? 0,
|
|
2529
|
+
limit,
|
|
2530
|
+
leases: usage.endpointHolders[key]?.leases ?? 0,
|
|
2531
|
+
foregroundStreams: usage.endpointHolders[key]?.foregroundStreams ?? 0,
|
|
2532
|
+
},
|
|
2533
|
+
]),
|
|
2534
|
+
);
|
|
2455
2535
|
return {
|
|
2456
2536
|
global: { active: usage.global, limit: configuredGlobalCapacity(settings) },
|
|
2457
2537
|
nodes,
|
|
2538
|
+
endpoints,
|
|
2458
2539
|
budget: { currentUsd: preflight.currentUsd, ceilingUsd: preflight.ceilingUsd },
|
|
2459
2540
|
};
|
|
2460
2541
|
}
|
|
@@ -2466,6 +2547,7 @@ export function createDispatchBundle(
|
|
|
2466
2547
|
memberId: task.memberId,
|
|
2467
2548
|
wave: task.wave,
|
|
2468
2549
|
nodeId: task.resolution.node.id,
|
|
2550
|
+
...(task.resolution.endpoint !== undefined ? { endpointKey: task.resolution.endpoint.key } : {}),
|
|
2469
2551
|
costUpperBoundUsd: task.resolution.routeApproval?.totalCostUpperBoundUsd ?? task.resolution.costUpperBoundUsd,
|
|
2470
2552
|
})),
|
|
2471
2553
|
capacity: reservationCapacitySnapshot(getEffectiveSettings()),
|
|
@@ -2520,10 +2602,44 @@ export function createDispatchBundle(
|
|
|
2520
2602
|
return scheduling.maxWorkers?.() ?? (configured === "auto" || configured === undefined ? 4 : Math.max(1, configured));
|
|
2521
2603
|
}
|
|
2522
2604
|
|
|
2523
|
-
|
|
2605
|
+
function publishCapacityQueued(
|
|
2606
|
+
identity: DispatchRunIdentity & { requestOrigin: DispatchRequestOrigin },
|
|
2607
|
+
timing: RunPhaseMarks,
|
|
2608
|
+
node: RunNodeIdentity | null,
|
|
2609
|
+
): void {
|
|
2610
|
+
pendingCapacity.set(identity.runId, { identity, timing, node });
|
|
2611
|
+
context.bus.emit(BusChannels.DispatchEnqueued, identity);
|
|
2612
|
+
}
|
|
2613
|
+
|
|
2614
|
+
function publishCapacityAdmissionFailure(
|
|
2615
|
+
identity: DispatchRunIdentity & { requestOrigin: DispatchRequestOrigin },
|
|
2616
|
+
error: unknown,
|
|
2617
|
+
): void {
|
|
2618
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
2619
|
+
const outcome: RunOutcome =
|
|
2620
|
+
error instanceof AdmissionCanceledError
|
|
2621
|
+
? "canceled"
|
|
2622
|
+
: /admission timed out/u.test(detail)
|
|
2623
|
+
? "timed_out"
|
|
2624
|
+
: "denied_by_policy";
|
|
2625
|
+
context.bus.emit(BusChannels.DispatchFailed, {
|
|
2626
|
+
...identity,
|
|
2627
|
+
outcome,
|
|
2628
|
+
outcomeDetail: detail,
|
|
2629
|
+
reason: outcome,
|
|
2630
|
+
});
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
async function admitAssignmentCapacity(
|
|
2634
|
+
req: DispatchRequest,
|
|
2635
|
+
nodeId: string,
|
|
2636
|
+
timing: RunPhaseMarks,
|
|
2637
|
+
endpoint?: EndpointCapacity | null,
|
|
2638
|
+
) {
|
|
2524
2639
|
const queuedAt = now();
|
|
2525
2640
|
timing.queuedAt = new Date(queuedAt).toISOString();
|
|
2526
|
-
const assignmentId =
|
|
2641
|
+
const assignmentId =
|
|
2642
|
+
req.lineage?.rootRunId ?? req.runIdHint ?? `pending-${queuedAt.toString(36)}-${randomBytes(6).toString("hex")}`;
|
|
2527
2643
|
const requestedAt = Date.parse(timing.requestedAt ?? timing.queuedAt);
|
|
2528
2644
|
const deadlineAt = req.assignmentDeadlineAt ?? requestedAt + (req.routingIntent?.deadlineMs ?? 60_000);
|
|
2529
2645
|
if (req.lineage === undefined) await registerAssignment(assignmentId);
|
|
@@ -2538,9 +2654,16 @@ export function createDispatchBundle(
|
|
|
2538
2654
|
const admitted = await capacityAdmission.admit({
|
|
2539
2655
|
assignmentId,
|
|
2540
2656
|
nodeId,
|
|
2657
|
+
...(endpoint !== null && endpoint !== undefined ? { endpointKey: endpoint.key } : {}),
|
|
2541
2658
|
deadlineAt,
|
|
2542
2659
|
...plan,
|
|
2543
|
-
|
|
2660
|
+
// A fleet's first attempt carries lineage and still owns the held
|
|
2661
|
+
// reservation member that admission must transfer into its lease.
|
|
2662
|
+
// Retries carry the same reservation identity after that member was
|
|
2663
|
+
// consumed, so they reacquire/rebind the assignment lease normally.
|
|
2664
|
+
...(req.reservation !== undefined && (req.lineage === undefined || req.lineage.attempt === 0)
|
|
2665
|
+
? { reservation: req.reservation }
|
|
2666
|
+
: {}),
|
|
2544
2667
|
});
|
|
2545
2668
|
timing.admittedAt = new Date(admitted.admittedAt).toISOString();
|
|
2546
2669
|
return admitted.lease;
|
|
@@ -2557,6 +2680,7 @@ export function createDispatchBundle(
|
|
|
2557
2680
|
function rebindReservationSlot(
|
|
2558
2681
|
req: DispatchRequest,
|
|
2559
2682
|
nodeId: string,
|
|
2683
|
+
endpoint: EndpointCapacity | null,
|
|
2560
2684
|
costUsd: number,
|
|
2561
2685
|
settings: EffectiveSettings,
|
|
2562
2686
|
): void {
|
|
@@ -2565,6 +2689,7 @@ export function createDispatchBundle(
|
|
|
2565
2689
|
const rebind = {
|
|
2566
2690
|
...req.reservation,
|
|
2567
2691
|
nodeId,
|
|
2692
|
+
...(endpoint !== null ? { endpointKey: endpoint.key } : {}),
|
|
2568
2693
|
costUpperBoundUsd: req.routeApproval?.totalCostUpperBoundUsd ?? costUsd,
|
|
2569
2694
|
capacity,
|
|
2570
2695
|
nowMs: now(),
|
|
@@ -2672,6 +2797,21 @@ export function createDispatchBundle(
|
|
|
2672
2797
|
|
|
2673
2798
|
type RetryScheduleResult = { scheduled: true } | { scheduled: false; settlementDetail?: string };
|
|
2674
2799
|
|
|
2800
|
+
/** A reserved plan member owns its retry chain independently of the shared fleet root assignment. */
|
|
2801
|
+
function retryChainIsLive(run: ActiveRun): boolean {
|
|
2802
|
+
if (run.aborted) return false;
|
|
2803
|
+
const reservation = run.req.reservation;
|
|
2804
|
+
if (reservation === undefined) return assignments.get(run.lineage.rootRunId)?.status === "running";
|
|
2805
|
+
try {
|
|
2806
|
+
const record = getDispatchReservation(reservation.ownerId);
|
|
2807
|
+
const member = record?.members.find((entry) => entry.memberId === reservation.memberId);
|
|
2808
|
+
return record?.status === "active" && member !== undefined && member.status !== "released";
|
|
2809
|
+
} catch (error) {
|
|
2810
|
+
reportDispatchDiagnostic(`read retry liveness for reservation member ${reservation.memberId}`, error);
|
|
2811
|
+
return false;
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2814
|
+
|
|
2675
2815
|
function maybeScheduleRetry(
|
|
2676
2816
|
run: ActiveRun,
|
|
2677
2817
|
outcome: RunOutcome,
|
|
@@ -2681,7 +2821,7 @@ export function createDispatchBundle(
|
|
|
2681
2821
|
): RetryScheduleResult {
|
|
2682
2822
|
if (draining) return { scheduled: false };
|
|
2683
2823
|
const rootRunId = run.lineage.rootRunId;
|
|
2684
|
-
if (
|
|
2824
|
+
if (!retryChainIsLive(run)) return { scheduled: false };
|
|
2685
2825
|
if (!RETRYABLE_OUTCOMES.has(outcome)) {
|
|
2686
2826
|
retryBackoff.delete(rootRunId);
|
|
2687
2827
|
return { scheduled: false };
|
|
@@ -2828,7 +2968,7 @@ export function createDispatchBundle(
|
|
|
2828
2968
|
reason = "retry",
|
|
2829
2969
|
decision: RetryDecision = decideRetry("internal", run.lineage.attempt, assignmentPolicyFor(run.req).maxRetries),
|
|
2830
2970
|
): Promise<void> {
|
|
2831
|
-
if (draining ||
|
|
2971
|
+
if (draining || !retryChainIsLive(run)) return;
|
|
2832
2972
|
const excludesNode = decision.excludedRouteParts.includes("node");
|
|
2833
2973
|
// Record the failed node so placement can choose an eligible survivor.
|
|
2834
2974
|
const rerouteHops =
|
|
@@ -2846,6 +2986,10 @@ export function createDispatchBundle(
|
|
|
2846
2986
|
depth: run.lineage.depth,
|
|
2847
2987
|
},
|
|
2848
2988
|
};
|
|
2989
|
+
// A run-id hint names only the first attempt (and, for task worktrees,
|
|
2990
|
+
// the worktree it created). A retry shares the assignment lineage but
|
|
2991
|
+
// must receive its own ledger/run identity.
|
|
2992
|
+
delete retryReq.runIdHint;
|
|
2849
2993
|
const reasonKey = retryReasonKey(run.lineage.rootRunId, attempt);
|
|
2850
2994
|
retryReasons.set(reasonKey, reason);
|
|
2851
2995
|
try {
|
|
@@ -3010,8 +3154,8 @@ export function createDispatchBundle(
|
|
|
3010
3154
|
}
|
|
3011
3155
|
}
|
|
3012
3156
|
|
|
3013
|
-
function heartbeatIso(
|
|
3014
|
-
return new Date(
|
|
3157
|
+
function heartbeatIso(heartbeat: HeartbeatStamp): string {
|
|
3158
|
+
return new Date(heartbeat.current).toISOString();
|
|
3015
3159
|
}
|
|
3016
3160
|
|
|
3017
3161
|
function heartbeatRunStatus(status: HeartbeatStatus): RunStatus {
|
|
@@ -3032,7 +3176,7 @@ export function createDispatchBundle(
|
|
|
3032
3176
|
event: {
|
|
3033
3177
|
type: "heartbeat_status",
|
|
3034
3178
|
status,
|
|
3035
|
-
heartbeatAt: run.heartbeatAt ? heartbeatIso(run.heartbeatAt
|
|
3179
|
+
heartbeatAt: run.heartbeatAt ? heartbeatIso(run.heartbeatAt) : null,
|
|
3036
3180
|
},
|
|
3037
3181
|
});
|
|
3038
3182
|
}
|
|
@@ -3050,16 +3194,16 @@ export function createDispatchBundle(
|
|
|
3050
3194
|
*/
|
|
3051
3195
|
function checkActiveHeartbeats(): void {
|
|
3052
3196
|
if (!ledger) return;
|
|
3053
|
-
const
|
|
3197
|
+
const tickMonotonic = monotonicNow();
|
|
3054
3198
|
for (const run of active.values()) {
|
|
3055
3199
|
if (run.aborted || run.stallKilled || !run.heartbeatAt) continue;
|
|
3056
|
-
const
|
|
3057
|
-
if (!Number.isFinite(
|
|
3200
|
+
const heartbeatMonotonic = heartbeatMonotonicAt(run.heartbeatAt);
|
|
3201
|
+
if (!Number.isFinite(heartbeatMonotonic) || !Number.isFinite(run.heartbeatAt.current)) continue;
|
|
3058
3202
|
if (run.runtimeKind === "acp-delegation") {
|
|
3059
|
-
ledger.update(run.runId, { heartbeatAt: heartbeatIso(
|
|
3203
|
+
ledger.update(run.runId, { heartbeatAt: heartbeatIso(run.heartbeatAt) });
|
|
3060
3204
|
const stallMs = run.stallTimeoutMs;
|
|
3061
3205
|
if (stallMs === null || stallMs <= 0) continue;
|
|
3062
|
-
if (
|
|
3206
|
+
if (tickMonotonic - heartbeatMonotonic <= stallMs) continue;
|
|
3063
3207
|
run.stallKilled = true;
|
|
3064
3208
|
run.heartbeatStatus = "dead";
|
|
3065
3209
|
emitHeartbeatStatus(run, "dead");
|
|
@@ -3070,10 +3214,10 @@ export function createDispatchBundle(
|
|
|
3070
3214
|
}
|
|
3071
3215
|
continue;
|
|
3072
3216
|
}
|
|
3073
|
-
const status = classifyHeartbeat(
|
|
3217
|
+
const status = classifyHeartbeat(heartbeatMonotonic, tickMonotonic, heartbeatSpec);
|
|
3074
3218
|
const patch: Partial<RunEnvelope> = {
|
|
3075
3219
|
status: heartbeatRunStatus(status),
|
|
3076
|
-
heartbeatAt: heartbeatIso(
|
|
3220
|
+
heartbeatAt: heartbeatIso(run.heartbeatAt),
|
|
3077
3221
|
};
|
|
3078
3222
|
ledger.update(run.runId, patch);
|
|
3079
3223
|
// Node staleness display feeds off the freshest worker heartbeat.
|
|
@@ -3493,7 +3637,29 @@ export function createDispatchBundle(
|
|
|
3493
3637
|
|
|
3494
3638
|
assertBudgetAdmitsRoute(req, { rates: null, provenance: "unknown" }, settings);
|
|
3495
3639
|
|
|
3496
|
-
const
|
|
3640
|
+
const queuedIdentity =
|
|
3641
|
+
req.lineage === undefined && req.runIdHint !== undefined
|
|
3642
|
+
? {
|
|
3643
|
+
runId: req.runIdHint,
|
|
3644
|
+
agentId: req.agentId,
|
|
3645
|
+
task: req.task,
|
|
3646
|
+
requestOrigin: lifecycle.requestOrigin,
|
|
3647
|
+
targetId,
|
|
3648
|
+
wireModelId,
|
|
3649
|
+
runtimeId,
|
|
3650
|
+
runtimeKind: "acp-delegation" as const,
|
|
3651
|
+
}
|
|
3652
|
+
: null;
|
|
3653
|
+
if (queuedIdentity !== null) publishCapacityQueued(queuedIdentity, timing, null);
|
|
3654
|
+
let capacityLease: Awaited<ReturnType<typeof admitAssignmentCapacity>>;
|
|
3655
|
+
try {
|
|
3656
|
+
capacityLease = await admitAssignmentCapacity(req, "local", timing, null);
|
|
3657
|
+
} catch (error) {
|
|
3658
|
+
if (queuedIdentity !== null) publishCapacityAdmissionFailure(queuedIdentity, error);
|
|
3659
|
+
throw error;
|
|
3660
|
+
} finally {
|
|
3661
|
+
if (queuedIdentity !== null) pendingCapacity.delete(queuedIdentity.runId);
|
|
3662
|
+
}
|
|
3497
3663
|
const leaseSlot = createLeaseSlotGuard(capacityAdmission, capacityLease.leaseId, req.lineage !== undefined);
|
|
3498
3664
|
|
|
3499
3665
|
// Resolve the ledger before starting the ACP process: an external agent
|
|
@@ -3519,6 +3685,8 @@ export function createDispatchBundle(
|
|
|
3519
3685
|
safety,
|
|
3520
3686
|
autonomy: lifecycle.autonomy,
|
|
3521
3687
|
clientVersion: readClioVersion(),
|
|
3688
|
+
now,
|
|
3689
|
+
monotonicNow,
|
|
3522
3690
|
});
|
|
3523
3691
|
} catch (error) {
|
|
3524
3692
|
leaseSlot.release();
|
|
@@ -3699,15 +3867,17 @@ export function createDispatchBundle(
|
|
|
3699
3867
|
runIdForPermissionAudit = envelope.id;
|
|
3700
3868
|
lineage = lineageFor(req, envelope.id);
|
|
3701
3869
|
if (req.lineage === undefined) {
|
|
3702
|
-
|
|
3703
|
-
|
|
3870
|
+
if (capacityLease.assignmentId !== lineage.rootRunId) {
|
|
3871
|
+
capacityAdmission.rename(capacityLease.leaseId, lineage.rootRunId);
|
|
3872
|
+
await renameStoredAssignment(capacityLease.assignmentId, lineage.rootRunId);
|
|
3873
|
+
}
|
|
3704
3874
|
leaseSlot.transferToAssignment();
|
|
3705
3875
|
}
|
|
3706
3876
|
identity = detectRunIdentity();
|
|
3707
3877
|
ledgerRef.update(envelope.id, {
|
|
3708
3878
|
status: "running",
|
|
3709
3879
|
pid: acp.pid,
|
|
3710
|
-
heartbeatAt: heartbeatIso(acp.heartbeatAt
|
|
3880
|
+
heartbeatAt: heartbeatIso(acp.heartbeatAt),
|
|
3711
3881
|
lineage,
|
|
3712
3882
|
identity,
|
|
3713
3883
|
node: LOCAL_RUN_NODE,
|
|
@@ -3726,16 +3896,18 @@ export function createDispatchBundle(
|
|
|
3726
3896
|
// One durable write at start so sibling processes (clio-coder fleet status)
|
|
3727
3897
|
// can observe the running row; finalization persists the terminal state.
|
|
3728
3898
|
await ledgerRef.persist();
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3899
|
+
if (req.lineage !== undefined) {
|
|
3900
|
+
context.bus.emit(BusChannels.DispatchEnqueued, {
|
|
3901
|
+
runId: envelope.id,
|
|
3902
|
+
agentId: req.agentId,
|
|
3903
|
+
task: req.task,
|
|
3904
|
+
requestOrigin: lifecycle.requestOrigin,
|
|
3905
|
+
targetId,
|
|
3906
|
+
wireModelId,
|
|
3907
|
+
runtimeId,
|
|
3908
|
+
runtimeKind: "acp-delegation",
|
|
3909
|
+
});
|
|
3910
|
+
}
|
|
3739
3911
|
context.bus.emit(BusChannels.DispatchStarted, {
|
|
3740
3912
|
runId: envelope.id,
|
|
3741
3913
|
agentId: req.agentId,
|
|
@@ -4104,7 +4276,7 @@ export function createDispatchBundle(
|
|
|
4104
4276
|
cacheReadTokenCount: receiptDraft.cacheReadTokenCount ?? 0,
|
|
4105
4277
|
cacheWriteTokenCount: receiptDraft.cacheWriteTokenCount ?? 0,
|
|
4106
4278
|
reasoningTokenCount: receiptDraft.reasoningTokenCount ?? 0,
|
|
4107
|
-
heartbeatAt: heartbeatIso(acp.heartbeatAt
|
|
4279
|
+
heartbeatAt: heartbeatIso(acp.heartbeatAt),
|
|
4108
4280
|
};
|
|
4109
4281
|
ledgerRef.update(envelope.id, ledgerPatch);
|
|
4110
4282
|
const receipt = ledgerRef.recordReceipt(envelope.id, sealRouteDecision(receiptDraft, routeDecision));
|
|
@@ -4193,6 +4365,10 @@ export function createDispatchBundle(
|
|
|
4193
4365
|
throw new Error(`dispatch: invalid spec: ${validated.errors.join("; ")}`);
|
|
4194
4366
|
}
|
|
4195
4367
|
req = validation.restore(validated.spec);
|
|
4368
|
+
// A top-level run needs its stable identity before it can wait for
|
|
4369
|
+
// capacity. The board can then render the assignment as queued and the
|
|
4370
|
+
// same id becomes the ledger row once its slot opens.
|
|
4371
|
+
if (req.lineage === undefined && req.runIdHint === undefined) req = { ...req, runIdHint: newRunId() };
|
|
4196
4372
|
let activeRouteObservation: RouteObservationHandle | null = null;
|
|
4197
4373
|
if (req.delegationAgentId === undefined) {
|
|
4198
4374
|
const recipe = agents.get(req.agentId);
|
|
@@ -4262,7 +4438,7 @@ export function createDispatchBundle(
|
|
|
4262
4438
|
"dispatch: writeRoots cannot be enforced on an ACP delegation target; the external agent runs its own tool surface. Dispatch to a native or claude-sdk worker.",
|
|
4263
4439
|
);
|
|
4264
4440
|
}
|
|
4265
|
-
rebindReservationSlot(req, "local", UNKNOWN_PRICING_ADMISSION_ESTIMATE_USD, settings);
|
|
4441
|
+
rebindReservationSlot(req, "local", null, UNKNOWN_PRICING_ADMISSION_ESTIMATE_USD, settings);
|
|
4266
4442
|
routeObservation = observeShadowRoute(req, undefined, settings);
|
|
4267
4443
|
return attachRouteObservation({
|
|
4268
4444
|
...(await dispatchAcpDelegation(req, settings, timing, routeObservation.decision, observer)),
|
|
@@ -4296,10 +4472,12 @@ export function createDispatchBundle(
|
|
|
4296
4472
|
model: lifecycle.target.wireModelId,
|
|
4297
4473
|
node: placement?.node?.id ?? "local",
|
|
4298
4474
|
};
|
|
4475
|
+
const endpoint = endpointCapacityForTarget(lifecycle.target.target.id);
|
|
4299
4476
|
assertRouteWithinApprovedEnvelope(req, effectiveRoute);
|
|
4300
4477
|
rebindReservationSlot(
|
|
4301
4478
|
req,
|
|
4302
4479
|
effectiveRoute.node,
|
|
4480
|
+
endpoint,
|
|
4303
4481
|
conservativeRouteAdmissionEstimateUsd(lifecycle.target.effectivePricing, admissionMaxOutputTokens(settings)),
|
|
4304
4482
|
settings,
|
|
4305
4483
|
);
|
|
@@ -4318,7 +4496,41 @@ export function createDispatchBundle(
|
|
|
4318
4496
|
shadow: () => observeShadowRoute(req, placed, settings),
|
|
4319
4497
|
});
|
|
4320
4498
|
|
|
4321
|
-
const
|
|
4499
|
+
const queuedIdentity =
|
|
4500
|
+
req.lineage === undefined && req.runIdHint !== undefined
|
|
4501
|
+
? {
|
|
4502
|
+
runId: req.runIdHint,
|
|
4503
|
+
agentId: req.agentId,
|
|
4504
|
+
task: req.task,
|
|
4505
|
+
agentAudience: lifecycle.agentAudience,
|
|
4506
|
+
requestOrigin: lifecycle.requestOrigin,
|
|
4507
|
+
targetId: lifecycle.target.target.id,
|
|
4508
|
+
wireModelId: lifecycle.target.wireModelId,
|
|
4509
|
+
runtimeId: lifecycle.target.runtime.id,
|
|
4510
|
+
runtimeKind: lifecycle.runtimeKind,
|
|
4511
|
+
budget: lifecycle.budgetEnvelope,
|
|
4512
|
+
...(endpoint !== null ? { endpoint: { key: endpoint.key, label: endpoint.label, limit: endpoint.limit } } : {}),
|
|
4513
|
+
...(placement !== null ? { node: placement.node.id } : {}),
|
|
4514
|
+
...(req.gate !== undefined ? { gate: { role: req.gate.role, cycle: req.gate.cycle } } : {}),
|
|
4515
|
+
...(req.council !== undefined ? { council: req.council } : {}),
|
|
4516
|
+
...(req.reroutes !== undefined && req.reroutes.length > 0 ? { rerouteCount: req.reroutes.length } : {}),
|
|
4517
|
+
...(lifecycle.target.modelCapabilities !== undefined &&
|
|
4518
|
+
lifecycle.target.modelCapabilities !== null &&
|
|
4519
|
+
lifecycle.target.modelCapabilities.contextWindow > 0
|
|
4520
|
+
? { contextWindow: lifecycle.target.modelCapabilities.contextWindow }
|
|
4521
|
+
: {}),
|
|
4522
|
+
}
|
|
4523
|
+
: null;
|
|
4524
|
+
if (queuedIdentity !== null) publishCapacityQueued(queuedIdentity, timing, placement?.node ?? null);
|
|
4525
|
+
let capacityLease: Awaited<ReturnType<typeof admitAssignmentCapacity>>;
|
|
4526
|
+
try {
|
|
4527
|
+
capacityLease = await admitAssignmentCapacity(req, placement?.node.id ?? "local", timing, endpoint);
|
|
4528
|
+
} catch (error) {
|
|
4529
|
+
if (queuedIdentity !== null) publishCapacityAdmissionFailure(queuedIdentity, error);
|
|
4530
|
+
throw error;
|
|
4531
|
+
} finally {
|
|
4532
|
+
if (queuedIdentity !== null) pendingCapacity.delete(queuedIdentity.runId);
|
|
4533
|
+
}
|
|
4322
4534
|
const leaseSlot = createLeaseSlotGuard(capacityAdmission, capacityLease.leaseId, req.lineage !== undefined);
|
|
4323
4535
|
|
|
4324
4536
|
const ledgerRef = (() => {
|
|
@@ -4387,6 +4599,8 @@ export function createDispatchBundle(
|
|
|
4387
4599
|
try {
|
|
4388
4600
|
worker = (placement?.spawn ?? spawnWorker)(spec, {
|
|
4389
4601
|
cwd: lifecycle.cwd,
|
|
4602
|
+
now,
|
|
4603
|
+
monotonicNow,
|
|
4390
4604
|
...(agentLedgerId !== null ? { onLedgerPost } : {}),
|
|
4391
4605
|
});
|
|
4392
4606
|
} catch (error) {
|
|
@@ -4443,10 +4657,21 @@ export function createDispatchBundle(
|
|
|
4443
4657
|
const upstreamResponses: RunReceiptUpstreamResponse[] = [];
|
|
4444
4658
|
const skillActivations: SkillActivation[] = [];
|
|
4445
4659
|
const finishContractEntries: unknown[] = [];
|
|
4660
|
+
let runIdForPermissionAudit: string | null = null;
|
|
4446
4661
|
// The worker's own tool calls, folded into what this run changed and what
|
|
4447
4662
|
// it validated. The sealed mutation-report contract is measured against
|
|
4448
4663
|
// this, so a reported path the run never touched cannot seal as fact.
|
|
4449
|
-
const runEffects = createRunEffectsRecorder(lifecycle.cwd
|
|
4664
|
+
const runEffects = createRunEffectsRecorder(lifecycle.cwd, {
|
|
4665
|
+
onWriteRecordDowngraded(downgrade) {
|
|
4666
|
+
const runId = runIdForPermissionAudit;
|
|
4667
|
+
if (runId === null) return;
|
|
4668
|
+
context.bus.emit(BusChannels.DispatchProgress, {
|
|
4669
|
+
runId,
|
|
4670
|
+
agentId: req.agentId,
|
|
4671
|
+
event: { type: "clio_write_record_downgraded", payload: downgrade },
|
|
4672
|
+
});
|
|
4673
|
+
},
|
|
4674
|
+
});
|
|
4450
4675
|
let finishContractAssistantText = "";
|
|
4451
4676
|
let finishContractAssistantTurnId: string | null = null;
|
|
4452
4677
|
let failureMessage: string | undefined;
|
|
@@ -4456,7 +4681,6 @@ export function createDispatchBundle(
|
|
|
4456
4681
|
const acceptsOutcomeCodeEvents =
|
|
4457
4682
|
lifecycle.runtimeKind === "http" ||
|
|
4458
4683
|
(lifecycle.runtimeKind === "sdk" && lifecycle.target.runtime.id === "claude-sdk");
|
|
4459
|
-
let runIdForPermissionAudit: string | null = null;
|
|
4460
4684
|
let workerPolicyPermissionCounter = 0;
|
|
4461
4685
|
const outputCapture = createWorkerOutputCapture();
|
|
4462
4686
|
const markObservedPhase = (field: "firstModelTokenAt" | "firstToolAt"): void => {
|
|
@@ -4575,6 +4799,7 @@ export function createDispatchBundle(
|
|
|
4575
4799
|
...(ruleId !== null ? { ruleId } : {}),
|
|
4576
4800
|
...(policySource !== null ? { policySource } : {}),
|
|
4577
4801
|
...(typeof event.payload.timeoutMs === "number" ? { timeoutMs: event.payload.timeoutMs } : {}),
|
|
4802
|
+
fallback: spec.escalation?.fallback ?? "deny",
|
|
4578
4803
|
escalation: true,
|
|
4579
4804
|
});
|
|
4580
4805
|
}
|
|
@@ -4649,6 +4874,7 @@ export function createDispatchBundle(
|
|
|
4649
4874
|
decidedBy,
|
|
4650
4875
|
actionClass,
|
|
4651
4876
|
reason,
|
|
4877
|
+
...(source === "timeout" ? { fallback: spec.escalation?.fallback ?? "deny" } : {}),
|
|
4652
4878
|
...(runIdForPermissionAudit !== null ? { requestedBy: runIdForPermissionAudit } : {}),
|
|
4653
4879
|
});
|
|
4654
4880
|
}
|
|
@@ -4704,8 +4930,10 @@ export function createDispatchBundle(
|
|
|
4704
4930
|
runIdForPermissionAudit = envelope.id;
|
|
4705
4931
|
lineage = lineageFor(req, envelope.id);
|
|
4706
4932
|
if (req.lineage === undefined) {
|
|
4707
|
-
|
|
4708
|
-
|
|
4933
|
+
if (capacityLease.assignmentId !== lineage.rootRunId) {
|
|
4934
|
+
capacityAdmission.rename(capacityLease.leaseId, lineage.rootRunId);
|
|
4935
|
+
await renameStoredAssignment(capacityLease.assignmentId, lineage.rootRunId);
|
|
4936
|
+
}
|
|
4709
4937
|
leaseSlot.transferToAssignment();
|
|
4710
4938
|
}
|
|
4711
4939
|
if (agentLedgerId !== null) {
|
|
@@ -4739,7 +4967,7 @@ export function createDispatchBundle(
|
|
|
4739
4967
|
...(req.council !== undefined ? { council: req.council } : {}),
|
|
4740
4968
|
...(req.plan !== undefined ? { plan: req.plan } : {}),
|
|
4741
4969
|
...(lifecycle.personaOverride ? { personaOverride: lifecycle.personaOverride } : {}),
|
|
4742
|
-
...(heartbeatAt ? { heartbeatAt: heartbeatIso(heartbeatAt
|
|
4970
|
+
...(heartbeatAt ? { heartbeatAt: heartbeatIso(heartbeatAt) } : {}),
|
|
4743
4971
|
});
|
|
4744
4972
|
observer?.onAdmitted({
|
|
4745
4973
|
runId: envelope.id,
|
|
@@ -4755,6 +4983,7 @@ export function createDispatchBundle(
|
|
|
4755
4983
|
// per-worker meter. All optional so consumers degrade to local/plain.
|
|
4756
4984
|
const fleetIdentity = {
|
|
4757
4985
|
budget: lifecycle.budgetEnvelope,
|
|
4986
|
+
...(endpoint !== null ? { endpoint: { key: endpoint.key, label: endpoint.label, limit: endpoint.limit } } : {}),
|
|
4758
4987
|
...(placement !== undefined && placement !== null ? { node: placement.node.id } : {}),
|
|
4759
4988
|
...(req.gate !== undefined ? { gate: { role: req.gate.role, cycle: req.gate.cycle } } : {}),
|
|
4760
4989
|
...(req.council !== undefined ? { council: req.council } : {}),
|
|
@@ -4765,18 +4994,20 @@ export function createDispatchBundle(
|
|
|
4765
4994
|
? { contextWindow: lifecycle.target.modelCapabilities.contextWindow }
|
|
4766
4995
|
: {}),
|
|
4767
4996
|
};
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4997
|
+
if (req.lineage !== undefined) {
|
|
4998
|
+
context.bus.emit(BusChannels.DispatchEnqueued, {
|
|
4999
|
+
runId: envelope.id,
|
|
5000
|
+
agentId: req.agentId,
|
|
5001
|
+
task: req.task,
|
|
5002
|
+
agentAudience: lifecycle.agentAudience,
|
|
5003
|
+
requestOrigin: lifecycle.requestOrigin,
|
|
5004
|
+
targetId: lifecycle.target.target.id,
|
|
5005
|
+
wireModelId: lifecycle.target.wireModelId,
|
|
5006
|
+
runtimeId: lifecycle.target.runtime.id,
|
|
5007
|
+
runtimeKind: lifecycle.runtimeKind,
|
|
5008
|
+
...fleetIdentity,
|
|
5009
|
+
});
|
|
5010
|
+
}
|
|
4780
5011
|
context.bus.emit(BusChannels.DispatchStarted, {
|
|
4781
5012
|
runId: envelope.id,
|
|
4782
5013
|
agentId: req.agentId,
|
|
@@ -5205,18 +5436,7 @@ export function createDispatchBundle(
|
|
|
5205
5436
|
cwd: lifecycle.cwd,
|
|
5206
5437
|
networkAllowed: lifecycle.admission.allowedTools.includes(ToolNames.WebFetch),
|
|
5207
5438
|
observedRunEffects,
|
|
5208
|
-
filesystem:
|
|
5209
|
-
readFile(filePath) {
|
|
5210
|
-
try {
|
|
5211
|
-
return readFileSync(filePath, "utf8");
|
|
5212
|
-
} catch {
|
|
5213
|
-
return null;
|
|
5214
|
-
}
|
|
5215
|
-
},
|
|
5216
|
-
pathExists(filePath) {
|
|
5217
|
-
return existsSync(filePath);
|
|
5218
|
-
},
|
|
5219
|
-
},
|
|
5439
|
+
filesystem: nodeResultContractFilesystem(),
|
|
5220
5440
|
});
|
|
5221
5441
|
const resultValidation = resultContract?.applicable === true ? resultContract.validation : null;
|
|
5222
5442
|
if (finalOutcome === "succeeded" && resultValidation?.conformance === "fail") {
|
|
@@ -5331,7 +5551,7 @@ export function createDispatchBundle(
|
|
|
5331
5551
|
...(receiptDraft.cacheWriteTokenCount !== undefined
|
|
5332
5552
|
? { cacheWriteTokenCount: receiptDraft.cacheWriteTokenCount }
|
|
5333
5553
|
: {}),
|
|
5334
|
-
...(activeRun.heartbeatAt ? { heartbeatAt: heartbeatIso(activeRun.heartbeatAt
|
|
5554
|
+
...(activeRun.heartbeatAt ? { heartbeatAt: heartbeatIso(activeRun.heartbeatAt) } : {}),
|
|
5335
5555
|
};
|
|
5336
5556
|
if (receiptDraft.reasoningTokenCount !== undefined) {
|
|
5337
5557
|
ledgerPatch.reasoningTokenCount = receiptDraft.reasoningTokenCount;
|
|
@@ -5354,9 +5574,28 @@ export function createDispatchBundle(
|
|
|
5354
5574
|
// the set. That run's window keeps today's blame-the-whole-diff
|
|
5355
5575
|
// behaviour; a run that never touched such a tool keeps the
|
|
5356
5576
|
// protection.
|
|
5357
|
-
const
|
|
5358
|
-
|
|
5359
|
-
|
|
5577
|
+
const toolTelemetryComplete = receipt.safety?.toolTelemetry?.coverage === "complete";
|
|
5578
|
+
const downgrades: WriteBoundaryAttributionDowngrade[] = observedRunEffects.writeRecordDowngrades.map((entry) => ({
|
|
5579
|
+
reason: entry.reason,
|
|
5580
|
+
tool: entry.tool,
|
|
5581
|
+
toolCallId: entry.toolCallId,
|
|
5582
|
+
runId: envelope.id,
|
|
5583
|
+
stepId: null,
|
|
5584
|
+
}));
|
|
5585
|
+
if (!toolTelemetryComplete) {
|
|
5586
|
+
downgrades.push({
|
|
5587
|
+
reason: "incomplete_tool_telemetry",
|
|
5588
|
+
tool: null,
|
|
5589
|
+
toolCallId: null,
|
|
5590
|
+
runId: envelope.id,
|
|
5591
|
+
stepId: null,
|
|
5592
|
+
});
|
|
5593
|
+
}
|
|
5594
|
+
recordRunWriteAttribution(envelope.id, {
|
|
5595
|
+
recorded: [...observedRunEffects.mutatedPaths],
|
|
5596
|
+
complete: toolTelemetryComplete && observedRunEffects.writeRecordComplete,
|
|
5597
|
+
downgrades,
|
|
5598
|
+
});
|
|
5360
5599
|
await ledgerRef.persist();
|
|
5361
5600
|
if (worktreeReceipt?.applied === true && req.taskWorktree !== undefined) {
|
|
5362
5601
|
try {
|
|
@@ -5628,12 +5867,14 @@ export function createDispatchBundle(
|
|
|
5628
5867
|
allowedTools: effectiveTools,
|
|
5629
5868
|
settings,
|
|
5630
5869
|
});
|
|
5870
|
+
const endpoint = endpointCapacityForTarget(target.target.id);
|
|
5631
5871
|
return {
|
|
5632
5872
|
agentId: req.agentId,
|
|
5633
5873
|
specFingerprint: agentSpecFingerprint(agentSpec),
|
|
5634
5874
|
targetId: target.target.id,
|
|
5635
5875
|
wireModelId: target.wireModelId,
|
|
5636
5876
|
runtimeId: target.runtime.id,
|
|
5877
|
+
...(endpoint !== null ? { endpoint: { key: endpoint.key, label: endpoint.label, limit: endpoint.limit } } : {}),
|
|
5637
5878
|
node: previewNode(req).node,
|
|
5638
5879
|
thinkingLevel: target.thinkingLevel,
|
|
5639
5880
|
toolSignature: toolSignature(effectiveTools),
|
|
@@ -6043,8 +6284,15 @@ export function createDispatchBundle(
|
|
|
6043
6284
|
return receipt;
|
|
6044
6285
|
}
|
|
6045
6286
|
|
|
6287
|
+
let journalBridge: RunEventJournalBridge | null = null;
|
|
6288
|
+
|
|
6046
6289
|
const extension: DomainExtension = {
|
|
6047
6290
|
async start() {
|
|
6291
|
+
// The journal subscribes before anything can dispatch. It rides the
|
|
6292
|
+
// domain's own progress and terminal channels, so it covers a run
|
|
6293
|
+
// whose caller iterates the handle itself (every operator path) as
|
|
6294
|
+
// well as one drained by the dispatch tool's event registry.
|
|
6295
|
+
if (options?.journalRunEvents === true) journalBridge = attachRunEventJournalBridge(context.bus);
|
|
6048
6296
|
// No in-memory executor survives a process restart, so every active
|
|
6049
6297
|
// side-store lease from an earlier bundle is orphaned and must expire.
|
|
6050
6298
|
cleanupDispatchReservations({ startup: true, nowMs: now() });
|
|
@@ -6110,6 +6358,10 @@ export function createDispatchBundle(
|
|
|
6110
6358
|
for (const ownerId of ownedReservations) rollbackDispatchReservation(ownerId, now());
|
|
6111
6359
|
ownedReservations.clear();
|
|
6112
6360
|
await Promise.allSettled([...assignmentWrites]);
|
|
6361
|
+
// After drain(), so the last run's terminal line is written before the
|
|
6362
|
+
// bridge stops listening.
|
|
6363
|
+
journalBridge?.stop();
|
|
6364
|
+
journalBridge = null;
|
|
6113
6365
|
},
|
|
6114
6366
|
};
|
|
6115
6367
|
|
|
@@ -6133,19 +6385,41 @@ export function createDispatchBundle(
|
|
|
6133
6385
|
*/
|
|
6134
6386
|
function snapshot(): DispatchSnapshot {
|
|
6135
6387
|
const tickNow = now();
|
|
6388
|
+
const tickMonotonic = monotonicNow();
|
|
6136
6389
|
const running: DispatchSnapshot["running"] = [];
|
|
6137
6390
|
const totals = { ...finalizedTotals };
|
|
6138
6391
|
const costAmounts = [...finalizedCosts];
|
|
6392
|
+
for (const pending of pendingCapacity.values()) {
|
|
6393
|
+
const startedAt = pending.timing.queuedAt ?? pending.timing.requestedAt ?? new Date(tickNow).toISOString();
|
|
6394
|
+
running.push({
|
|
6395
|
+
runId: pending.identity.runId,
|
|
6396
|
+
agentId: pending.identity.agentId,
|
|
6397
|
+
...(pending.identity.task !== undefined ? { task: pending.identity.task } : {}),
|
|
6398
|
+
...(pending.identity.budget !== undefined ? { budget: pending.identity.budget } : {}),
|
|
6399
|
+
runtimeKind: pending.identity.runtimeKind,
|
|
6400
|
+
outcomePhase: "queued",
|
|
6401
|
+
heartbeat: "n/a",
|
|
6402
|
+
lineage: { parentRunId: null, rootRunId: pending.identity.runId, attempt: 0, depth: 0 },
|
|
6403
|
+
startedAt,
|
|
6404
|
+
elapsedMs: 0,
|
|
6405
|
+
timing: deriveRunPhaseDurations(pending.timing, startedAt, new Date(tickNow).toISOString()),
|
|
6406
|
+
tokens: { input: 0, output: 0, total: 0 },
|
|
6407
|
+
costUsd: 0,
|
|
6408
|
+
costProvenance: "unknown",
|
|
6409
|
+
node: pending.node === null ? null : { ...pending.node },
|
|
6410
|
+
});
|
|
6411
|
+
}
|
|
6139
6412
|
for (const run of active.values()) {
|
|
6140
6413
|
let heartbeat: "alive" | "stale" | "dead" | "n/a" = "n/a";
|
|
6141
|
-
if (run.heartbeatAt && Number.isFinite(run.heartbeatAt
|
|
6414
|
+
if (run.heartbeatAt && Number.isFinite(heartbeatMonotonicAt(run.heartbeatAt))) {
|
|
6415
|
+
const heartbeatMonotonic = heartbeatMonotonicAt(run.heartbeatAt);
|
|
6142
6416
|
if (run.runtimeKind === "acp-delegation") {
|
|
6143
6417
|
const stallMs = run.stallTimeoutMs;
|
|
6144
6418
|
if (stallMs !== null && stallMs > 0) {
|
|
6145
|
-
heartbeat =
|
|
6419
|
+
heartbeat = tickMonotonic - heartbeatMonotonic > stallMs ? "dead" : "alive";
|
|
6146
6420
|
}
|
|
6147
6421
|
} else {
|
|
6148
|
-
heartbeat = classifyHeartbeat(
|
|
6422
|
+
heartbeat = classifyHeartbeat(heartbeatMonotonic, tickMonotonic, heartbeatSpec);
|
|
6149
6423
|
}
|
|
6150
6424
|
}
|
|
6151
6425
|
const meter = run.meter;
|
|
@@ -6271,6 +6545,7 @@ export function createDispatchBundle(
|
|
|
6271
6545
|
routeCandidates,
|
|
6272
6546
|
reservations: {
|
|
6273
6547
|
prepare: prepareReservation,
|
|
6548
|
+
release: (ownerId) => releaseDispatchReservation(ownerId, now()),
|
|
6274
6549
|
rollback: (ownerId) => rollbackDispatchReservation(ownerId, now()),
|
|
6275
6550
|
rollbackUnconsumed: (ownerId) => rollbackUnconsumedDispatchReservation(ownerId, now()),
|
|
6276
6551
|
get: getDispatchReservation,
|
|
@@ -6291,7 +6566,17 @@ export function createDispatchBundle(
|
|
|
6291
6566
|
observedRunWrites(runId) {
|
|
6292
6567
|
// A run this process never finalized, or finalized long enough ago to
|
|
6293
6568
|
// have been evicted, is unknown rather than silent, so both answer null.
|
|
6294
|
-
|
|
6569
|
+
const attribution = runWriteAttributions.get(runId);
|
|
6570
|
+
return attribution?.complete === true ? [...attribution.recorded] : null;
|
|
6571
|
+
},
|
|
6572
|
+
observedRunWriteAttribution(runId) {
|
|
6573
|
+
const attribution = runWriteAttributions.get(runId);
|
|
6574
|
+
if (attribution === undefined) return null;
|
|
6575
|
+
return {
|
|
6576
|
+
recorded: [...attribution.recorded],
|
|
6577
|
+
complete: attribution.complete,
|
|
6578
|
+
downgrades: attribution.downgrades?.map((entry) => ({ ...entry })) ?? [],
|
|
6579
|
+
};
|
|
6295
6580
|
},
|
|
6296
6581
|
assignments: {
|
|
6297
6582
|
get: (id) => assignments.get(id),
|
|
@@ -6302,6 +6587,17 @@ export function createDispatchBundle(
|
|
|
6302
6587
|
},
|
|
6303
6588
|
abort(runId, reason) {
|
|
6304
6589
|
const rootRunId = assignmentRootFor(runId);
|
|
6590
|
+
const queued = pendingCapacity.get(rootRunId);
|
|
6591
|
+
if (queued !== undefined && capacityAdmission.cancel(rootRunId)) {
|
|
6592
|
+
persistAssignment(cancelStoredAssignment(rootRunId), `${rootRunId}:cancel-queued`);
|
|
6593
|
+
context.bus.emit(BusChannels.RunAborted, {
|
|
6594
|
+
source: "dispatch_abort",
|
|
6595
|
+
runId: rootRunId,
|
|
6596
|
+
startedAt: null,
|
|
6597
|
+
elapsedMs: null,
|
|
6598
|
+
reason: reason?.detail ?? "operator abort while waiting for an endpoint slot",
|
|
6599
|
+
});
|
|
6600
|
+
}
|
|
6305
6601
|
const assignment = assignments.get(rootRunId);
|
|
6306
6602
|
if (assignment?.status === "running") {
|
|
6307
6603
|
assignments.cancel(assignment.id);
|