@iowarp/clio-coder 0.4.2 → 0.4.4
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 +98 -0
- package/CONTRIBUTING.md +86 -19
- package/README.md +35 -6
- package/dist/{acp-TMDQZDIG.js → acp-WNAYYF4F.js} +12 -13
- package/dist/{agents-5N5NG3XG.js → agents-3OKXHLOI.js} +60 -57
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-Z5CCBXKQ.js → auth-VKNNMGPU.js} +21 -19
- package/dist/{builtins-K6TNDT24.js → builtins-WGALA46I.js} +9 -4
- package/dist/{chunk-XE3PCIXH.js → chunk-23L32XTI.js} +12 -9
- package/dist/{chunk-I64IFBLB.js → chunk-25QBEXRS.js} +18 -11
- package/dist/{chunk-CDNVLKUX.js → chunk-26QSH3EJ.js} +13 -7
- package/dist/{chunk-QQLGQY2A.js → chunk-2ASED4PZ.js} +22 -22
- package/dist/{chunk-MCEPRMZW.js → chunk-2CU2H6KE.js} +2 -2
- package/dist/chunk-2DSOYNFC.js +108 -0
- package/dist/{chunk-72GZI5EV.js → chunk-2JH2WHGE.js} +2 -2
- package/dist/{chunk-I66EAJFY.js → chunk-2WZ546HR.js} +267 -232
- package/dist/{chunk-O3YUNJZ2.js → chunk-2ZSONWVL.js} +82 -25
- package/dist/{chunk-2NHR3NAY.js → chunk-36CT5VVL.js} +331 -42
- package/dist/{chunk-2X4RYJTJ.js → chunk-3GY4F45V.js} +3 -3
- package/dist/{chunk-ZW55JB7N.js → chunk-3ODX73FK.js} +4 -6
- package/dist/{chunk-PBP4B7XR.js → chunk-3UNOLWNZ.js} +3 -3
- package/dist/{chunk-4JDLP6ZS.js → chunk-3UUXNFEX.js} +14 -10
- package/dist/{chunk-RKSR6VSF.js → chunk-4IUZQIJ3.js} +29 -1
- package/dist/{chunk-ZW4HH5JJ.js → chunk-4M6Z5QVF.js} +6 -6
- package/dist/{chunk-K6BSR66V.js → chunk-4NSRCOYP.js} +4 -1
- package/dist/{chunk-M2DAX4F6.js → chunk-4WR7VSYB.js} +2 -2
- package/dist/{chunk-FSP7CMNU.js → chunk-54X7T7DK.js} +61 -6
- package/dist/{chunk-54ODD65L.js → chunk-5636DCO5.js} +4 -4
- package/dist/chunk-57XXR6DR.js +3763 -0
- package/dist/{chunk-3KIPBMUA.js → chunk-5ICU3EUH.js} +2 -2
- package/dist/{chunk-77QIVUZB.js → chunk-5MEZN6CB.js} +4 -4
- package/dist/{chunk-O42A54GG.js → chunk-5OIVVPHF.js} +2 -2
- package/dist/{chunk-YJISEZKC.js → chunk-5TUB6SLS.js} +6 -6
- package/dist/{chunk-IMXMHHMQ.js → chunk-6OSVSQL5.js} +341 -57
- package/dist/{chunk-Q4XWMHX6.js → chunk-6PAZTBPA.js} +14 -2
- package/dist/{chunk-FVDGR2ZL.js → chunk-6Q3CYFD3.js} +112 -39
- package/dist/{chunk-IDNA72AH.js → chunk-6QOTUPRG.js} +155 -36
- package/dist/{chunk-X7IARSHT.js → chunk-6UINWWS6.js} +16 -10
- package/dist/{chunk-CYZW7JHJ.js → chunk-72YIHOZQ.js} +9 -9
- package/dist/{chunk-IKSLQ4XV.js → chunk-75W7L2E2.js} +752 -861
- package/dist/{chunk-CRFOIAX3.js → chunk-7UGL4MB5.js} +6 -6
- package/dist/{chunk-HIICAHCJ.js → chunk-AUPNRN7C.js} +2 -2
- package/dist/{chunk-7BHIY2MW.js → chunk-BJVFZO5U.js} +8 -50
- package/dist/{chunk-B74PXLU7.js → chunk-CUSRQKPU.js} +65 -3
- package/dist/chunk-DQOVN6KV.js +386 -0
- package/dist/{chunk-E7GT7O5N.js → chunk-DT3LWJOB.js} +7 -4
- package/dist/chunk-DXKJURES.js +671 -0
- package/dist/{chunk-JBCS7CRR.js → chunk-EL24TAU4.js} +10 -10
- package/dist/{chunk-TPEQIQIE.js → chunk-ELWDPP3Y.js} +8 -8
- package/dist/{chunk-NDINPTJ4.js → chunk-ELZVTCGV.js} +5 -4
- package/dist/chunk-EXLD33WO.js +381 -0
- package/dist/chunk-FEAXX7B6.js +101 -0
- package/dist/{chunk-RLYRBIYQ.js → chunk-FFUPXJC4.js} +90 -331
- package/dist/{chunk-5PFYMY2V.js → chunk-FTMGRKEF.js} +2 -2
- package/dist/{chunk-34BHNEE3.js → chunk-GHS5EBTQ.js} +58 -7
- package/dist/{chunk-DYHAXKHD.js → chunk-GWZNEVM2.js} +12 -8
- package/dist/chunk-GX5WYQO4.js +59 -0
- package/dist/chunk-GYV6VZOC.js +26 -0
- package/dist/{chunk-MQXIVJ35.js → chunk-HAXOFFRH.js} +5 -5
- package/dist/chunk-I2DWJ4GM.js +390 -0
- package/dist/{chunk-TXOTCRLG.js → chunk-I5FWO7L5.js} +5 -5
- package/dist/{chunk-WNP7O5WZ.js → chunk-ID64D7PE.js} +4 -4
- package/dist/{chunk-XQRY4DTA.js → chunk-IGLP3ODT.js} +10 -10
- package/dist/chunk-IRXAATOX.js +539 -0
- package/dist/chunk-IXIY2H4R.js +44 -0
- package/dist/{chunk-SSEYRH53.js → chunk-IZXGRF7P.js} +92 -147
- package/dist/{chunk-5TSRNF4G.js → chunk-JCI2ROMZ.js} +164 -6
- package/dist/{chunk-JWJGP5DQ.js → chunk-JEIYHLOR.js} +7 -7
- package/dist/{chunk-F2I26BDK.js → chunk-JQLNNIKT.js} +4 -4
- package/dist/{chunk-BYMNWQ7O.js → chunk-JSD46VO2.js} +315 -63
- package/dist/{chunk-AK5XEFVZ.js → chunk-JT2RFCC5.js} +64 -14
- package/dist/{chunk-MCMZMDAC.js → chunk-K6T2ZAMZ.js} +168 -6
- package/dist/{chunk-PGF63K6I.js → chunk-KFV5L5SK.js} +73 -4
- package/dist/{chunk-IHXBNWMM.js → chunk-KXDSS5WJ.js} +7 -3
- package/dist/{chunk-PJX3WQUQ.js → chunk-LLXSDWXS.js} +3 -3
- package/dist/{chunk-DZAW46HP.js → chunk-LTIKRKFL.js} +3 -3
- package/dist/{chunk-DZEK6CJN.js → chunk-N56KALIC.js} +21 -21
- package/dist/{chunk-B7HM5Z7T.js → chunk-NAI6ZFCY.js} +9 -5
- package/dist/{chunk-I66ZTYNP.js → chunk-NRO2BJRH.js} +2656 -2213
- package/dist/{chunk-ZGNYYXQ6.js → chunk-NXIMQY5W.js} +3 -3
- package/dist/{chunk-IKOZFYBN.js → chunk-NXYCB2VD.js} +149 -106
- package/dist/{chunk-CWVRRIEI.js → chunk-NZMNUPZZ.js} +2 -2
- package/dist/{chunk-462T4EGZ.js → chunk-O5CVSAG5.js} +2 -2
- package/dist/chunk-ODGTEFFI.js +50 -0
- package/dist/{chunk-3F7VUY77.js → chunk-OEJSLEPW.js} +2 -2
- package/dist/{chunk-KKOJXO6R.js → chunk-OMQNJVKW.js} +4 -2
- package/dist/{chunk-5KW52TEP.js → chunk-Q4WO54TA.js} +132 -77
- package/dist/{chunk-W6NIE6OW.js → chunk-QUFRYSWI.js} +13 -7
- package/dist/{chunk-42FMPA75.js → chunk-QZWQA4DE.js} +2 -2
- package/dist/chunk-R6Q67RJH.js +134 -0
- package/dist/{chunk-W4YEMFBX.js → chunk-RAY4OVGZ.js} +3 -3
- package/dist/{chunk-ZNT2M6TG.js → chunk-RQCKCSRL.js} +17 -17
- package/dist/{chunk-LJID3DYZ.js → chunk-RXTN6AKH.js} +3 -3
- package/dist/{chunk-P75RZCJW.js → chunk-RZDWV63N.js} +3 -3
- package/dist/{chunk-UH632ZYL.js → chunk-S6PYF2XF.js} +2 -2
- package/dist/{chunk-HJWWJ6IL.js → chunk-TOIVGRUX.js} +17 -5
- package/dist/{chunk-HLAFFSEK.js → chunk-TQAHXW6Y.js} +2 -2
- package/dist/{chunk-JIEGK6UF.js → chunk-U6TMQNSI.js} +48 -4
- package/dist/{chunk-2HFQNRV3.js → chunk-UEPWCCTY.js} +12 -12
- package/dist/chunk-UOIZ7DA4.js +41 -0
- package/dist/{chunk-UH347SHR.js → chunk-USR47QNF.js} +11 -11
- package/dist/{chunk-AZ4WMN4W.js → chunk-V6HJFQZE.js} +2 -2
- package/dist/chunk-V76WTFTW.js +318 -0
- package/dist/{chunk-NMJXSHBJ.js → chunk-W54I7H25.js} +2 -2
- package/dist/{chunk-KPXDY6QF.js → chunk-XRZT5WY5.js} +2 -2
- package/dist/{chunk-UBRFI4HS.js → chunk-XULDXHTN.js} +142 -50
- package/dist/chunk-XXYSBZIQ.js +283 -0
- package/dist/{chunk-HKMD33FO.js → chunk-Y55JBDO5.js} +405 -122
- package/dist/{chunk-XOXV5GKE.js → chunk-YD5GIKET.js} +17 -8
- package/dist/{chunk-XGDPUNND.js → chunk-YECAMM3D.js} +2 -2
- package/dist/{chunk-BO7Y52RY.js → chunk-YNFKXPEC.js} +7 -7
- package/dist/{chunk-VXMFAE2W.js → chunk-YPC6ZR5L.js} +19 -6
- package/dist/{chunk-M2WXEHER.js → chunk-ZA4VCIGV.js} +2 -2
- package/dist/cli/index.js +42 -40
- package/dist/{clio-7VB377CC.js → clio-QLICPCF5.js} +7 -7
- package/dist/{code-nav-YVLCYA7V.js → code-nav-IJR2DBPR.js} +9 -9
- package/dist/{components-UBWCQSRW.js → components-2TGAI2RC.js} +5 -6
- package/dist/{config-4HVOS65E.js → config-IUA6OYNS.js} +88 -81
- package/dist/{configure-PIWO7B24.js → configure-VEPX4NMX.js} +26 -25
- package/dist/{context-KQYIWPWT.js → context-2DKHWH2T.js} +60 -45
- package/dist/{context-IYEHL3WQ.js → context-4MPR7WKB.js} +78 -69
- package/dist/{context-N6ZE3LGJ.js → context-BOYF5EJM.js} +15 -11
- package/dist/{context-clear-G4OGZJDS.js → context-clear-S4ZJCQUX.js} +73 -65
- package/dist/context-map-COB37XXN.js +505 -0
- package/dist/{context-working-set-BWLF6LJP.js → context-working-set-3I3FYX6Y.js} +18 -17
- package/dist/detail-A7JAVSIG.js +98 -0
- package/dist/{dispatch-runner-2QQAITS3.js → dispatch-runner-RJ5I2F2O.js} +99 -75
- package/dist/{docs-PD3EXDKU.js → docs-SPOV3BAN.js} +3 -5
- package/dist/{doctor-LHBD36VU.js → doctor-DKICC2SN.js} +71 -48
- package/dist/{eval-C45FYRJ6.js → eval-OQOQUDHK.js} +308 -146
- package/dist/{eval-inventory-6DEJPLBF.js → eval-inventory-Y6QRFOH5.js} +4 -4
- package/dist/{evidence-6SHONYAF.js → evidence-4DQ25GUQ.js} +79 -175
- package/dist/evidence-4F5USFKH.js +208 -0
- package/dist/{evolve-KRKMV72X.js → evolve-GSS52E5J.js} +71 -67
- package/dist/{extensions-KPZ2UHBB.js → extensions-G7MFLYHT.js} +8 -9
- package/dist/{fleet-IVTCKDHT.js → fleet-Q37YHHAQ.js} +126 -118
- package/dist/{fleet-commands-EDWL3IT7.js → fleet-commands-G7E4N7SM.js} +16 -13
- package/dist/{fleet-decisions-YP3YEFGK.js → fleet-decisions-O7M6QBA2.js} +9 -8
- package/dist/{fleet-graph-ZFWKHY2M.js → fleet-graph-TOUBW6OW.js} +21 -20
- package/dist/{fleet-inspect-FVUNCBML.js → fleet-inspect-SW33JJNI.js} +65 -60
- package/dist/{fleet-preflight-UN5XED4R.js → fleet-preflight-CV2655TW.js} +4 -5
- package/dist/{fleet-validate-XOWC4HSX.js → fleet-validate-KESZX2YH.js} +25 -24
- package/dist/{fleet-verify-UN3SODEL.js → fleet-verify-UQPMTVE3.js} +66 -61
- package/dist/{fleet-view-TWHJKCN6.js → fleet-view-MN2VG4MR.js} +65 -60
- package/dist/{init-T2QORQ3Y.js → init-PXEXQSBF.js} +90 -82
- package/dist/{interop-IN5I2A66.js → interop-ZG5T62U3.js} +12 -13
- package/dist/inventory-C26CFDRR.js +101 -0
- package/dist/{library-LSCATDLZ.js → library-B2W4N74O.js} +29 -29
- package/dist/{memory-HYOKAGGJ.js → memory-YCANYS5A.js} +73 -69
- package/dist/{models-2GPMFYCM.js → models-GERTU3YI.js} +51 -47
- package/dist/{monitor-E4ASVUJH.js → monitor-CPNIUULB.js} +74 -67
- package/dist/{orchestrator-DDMPR3PY.js → orchestrator-J4BSH4WQ.js} +1288 -1606
- package/dist/{panes-E3RUXOW5.js → panes-BOHAEGYC.js} +4 -4
- package/dist/{panes-IXKLOKA2.js → panes-NXSLDQZ2.js} +10 -11
- package/dist/{paths-L7LGY6RN.js → paths-VSUWNC22.js} +6 -7
- package/dist/reset-TNWTB5LU.js +343 -0
- package/dist/{resources-OTRSN34L.js → resources-4PXNMD5G.js} +29 -22
- package/dist/{run-5DEYH5QK.js → run-D6XJ34CN.js} +132 -132
- package/dist/{share-IHWTLO3M.js → share-2NWMJJEE.js} +27 -27
- package/dist/{skills-IYMXMKW4.js → skills-KR7WON5G.js} +40 -33
- package/dist/{skills-eval-DROHSJAR.js → skills-eval-O2ZNOLDS.js} +81 -77
- package/dist/{skills-inventory-D7X4L4ZX.js → skills-inventory-ZZOUBK7O.js} +23 -22
- package/dist/{slash-commands-QBM7UZ3B.js → slash-commands-ZXPJD64J.js} +47 -37
- package/dist/{steer-Z5DO23FJ.js → steer-XA25PSCS.js} +4 -4
- package/dist/{support-U7QOWY26.js → support-7EMVWYG2.js} +6 -6
- package/dist/{targets-P2FUC4IL.js → targets-OMH2XCSN.js} +50 -49
- package/dist/tasks-IPAGMEIX.js +36 -0
- package/dist/{terminal-lease-YREJ3JX2.js → terminal-lease-C2J3JYRE.js} +4 -4
- package/dist/{tools-5B7RO6MV.js → tools-EFFEAIDP.js} +8 -9
- package/dist/{trace-YMGMUM6A.js → trace-FXMXUZUF.js} +7 -7
- package/dist/uninstall-HALS6BLF.js +407 -0
- package/dist/upgrade-MS72RJEP.js +306 -0
- package/dist/{usage-ME5MPXGX.js → usage-NHG6MCJM.js} +162 -108
- package/dist/{verifiers-BVZ7IWOO.js → verifiers-7AUNVXDY.js} +155 -22
- package/dist/{verify-5K7ZKQFC.js → verify-FWYGPKMR.js} +14 -12
- package/dist/{web-fetch-MPARV2K7.js → web-fetch-V4FKSDAV.js} +4 -4
- package/dist/{wiki-generate-F5W5QTYY.js → wiki-generate-743CIGJW.js} +99 -90
- package/dist/{with-panes-BYOJCLAM.js → with-panes-BDQEWBRT.js} +10 -10
- package/dist/worker/entry.js +72 -68
- package/docs/README.md +3 -2
- package/docs/architecture/acp.md +17 -0
- package/docs/architecture/artifact-placement.md +1 -0
- package/docs/architecture/artifact-versions.md +2 -2
- package/docs/architecture/context-engine.md +4 -0
- package/docs/architecture/dispatch-typed-intent.md +1 -1
- package/docs/architecture/evidence-and-memory.md +1 -1
- package/docs/architecture/middleware-and-components.md +1 -1
- package/docs/architecture/model-catalog.md +21 -10
- package/docs/architecture/observability.md +19 -2
- package/docs/architecture/prompt-envelope-and-tools.md +17 -5
- package/docs/architecture/provider-adapter-cookbook.md +63 -0
- package/docs/architecture/safety-model.md +25 -22
- package/docs/architecture/tui-design.md +1 -1
- package/docs/guide/built-in-agents.md +25 -11
- package/docs/guide/commands-and-modes.md +18 -3
- package/docs/guide/configuration-and-targets.md +100 -10
- package/docs/guide/configuration-reference.md +17 -7
- package/docs/guide/environment-variables.md +4 -2
- package/docs/guide/installation-and-lifecycle.md +37 -4
- package/docs/guide/proactive-memory.md +66 -55
- package/docs/guide/skills-marketplace.md +18 -0
- package/docs/guide/tool-usage.md +78 -3
- package/docs/history/config-knobs-audit.md +2 -2
- package/docs/process/development-pipeline.md +40 -2
- package/docs/process/eval-runner.md +67 -3
- package/docs/process/git-commit-provenance.md +15 -0
- package/docs/process/release-cut-checklist.md +207 -0
- package/docs/process/scientific-validation.md +18 -17
- package/evals/behavioral-machinery-support.ts +1 -0
- package/evals/behavioral-machinery.yaml +1 -1
- package/evals/behavioral-model.yaml +3 -2
- package/package.json +2 -2
- package/skills/README.md +7 -5
- package/skills/coding/ast-grep/SKILL.md +101 -30
- package/skills/coding/ast-grep/evals.md +26 -0
- package/skills/coding/coding-standards/SKILL.md +47 -2
- package/skills/coding/coding-standards/evals.md +23 -0
- package/skills/coding/prototype/SKILL.md +87 -28
- package/skills/coding/prototype/evals.md +19 -0
- package/skills/coding/tdd/SKILL.md +80 -53
- package/skills/coding/tdd/evals.md +20 -0
- package/skills/context/context-handoff/SKILL.md +43 -2
- package/skills/context/context-handoff/evals.md +44 -0
- package/skills/context/context-prime/SKILL.md +45 -15
- package/skills/context/context-prime/evals.md +45 -0
- package/skills/git/branch-closeout/SKILL.md +132 -0
- package/skills/git/branch-closeout/evals.md +133 -0
- package/skills/git/branch-closeout/references/closeout-checklist.md +81 -0
- package/skills/git/file-ticket/SKILL.md +77 -63
- package/skills/git/file-ticket/assets/issue-template.md +22 -0
- package/skills/git/file-ticket/evals.md +31 -26
- package/skills/git/file-ticket/references/issue-discovery.md +49 -0
- package/skills/git/fix-issue/SKILL.md +87 -64
- package/skills/git/fix-issue/evals.md +35 -31
- package/skills/git/fix-issue/references/diagnosis-and-rca.md +46 -0
- package/skills/git/resolve-merge-conflicts/SKILL.md +100 -51
- package/skills/git/resolve-merge-conflicts/evals.md +52 -25
- package/skills/git/resolve-merge-conflicts/references/conflict-matrix.md +126 -0
- package/skills/git/ship/SKILL.md +103 -67
- package/skills/git/ship/assets/pr-template.md +21 -0
- package/skills/git/ship/evals.md +44 -28
- package/skills/git/ship/references/remote-and-branch-policy.md +62 -0
- package/skills/git/worktree-create/SKILL.md +80 -50
- package/skills/git/worktree-create/evals.md +40 -33
- package/skills/git/worktree-create/references/worktree-setup.md +62 -66
- package/skills/git/worktree-merge/SKILL.md +112 -65
- package/skills/git/worktree-merge/evals.md +42 -34
- package/skills/git/worktree-merge/references/merge-strategies.md +52 -0
- package/skills/planning/archify/SKILL.md +196 -0
- package/skills/planning/archify/evals.md +65 -0
- package/skills/planning/architecture/SKILL.md +61 -12
- package/skills/planning/architecture/evals.md +65 -0
- package/skills/planning/backlog/SKILL.md +130 -14
- package/skills/planning/backlog/evals.md +142 -0
- package/skills/planning/prd/SKILL.md +47 -6
- package/skills/planning/prd/evals.md +54 -0
- package/skills/planning/product-intent/SKILL.md +57 -2
- package/skills/planning/product-intent/evals.md +70 -0
- package/skills/planning/tech-spec/SKILL.md +53 -2
- package/skills/planning/tech-spec/evals.md +73 -0
- package/skills/registry.yaml +58 -50
- package/skills/remote.yaml +13 -0
- package/skills/research/arxiv-literature/SKILL.md +76 -18
- package/skills/research/arxiv-literature/evals.md +50 -0
- package/skills/research/experiment-protocol/SKILL.md +20 -1
- package/skills/research/experiment-protocol/evals.md +23 -0
- package/skills/research/scientific-debugging/SKILL.md +24 -1
- package/skills/research/scientific-debugging/evals.md +18 -0
- package/skills/research/scientific-modernization/SKILL.md +26 -1
- package/skills/research/scientific-modernization/evals.md +27 -0
- package/skills/skill-marketplace.json +63 -28
- package/skills/workflow/cut-it/SKILL.md +64 -5
- package/skills/workflow/cut-it/evals.md +101 -0
- package/skills/workflow/design-council/SKILL.md +112 -27
- package/skills/workflow/design-council/evals.md +161 -0
- package/skills/workflow/grill-me/SKILL.md +85 -10
- package/skills/workflow/grill-me/evals.md +153 -0
- package/skills/workflow/workflow-distiller/SKILL.md +76 -17
- package/skills/workflow/workflow-distiller/evals.md +118 -0
- package/src/cli/args.ts +0 -8
- package/src/cli/configure-interop.ts +105 -13
- package/src/cli/configure-oauth.ts +57 -0
- package/src/cli/configure-onboarding.ts +980 -0
- package/src/cli/configure-target.ts +594 -0
- package/src/cli/configure.ts +1084 -529
- package/src/cli/context-map.ts +114 -0
- package/src/cli/context.ts +4 -0
- package/src/cli/doctor-state-size.ts +1 -12
- package/src/cli/doctor-validation-contract.ts +28 -0
- package/src/cli/doctor.ts +5 -0
- package/src/cli/evidence-detail.ts +1 -75
- package/src/cli/evidence-inventory.ts +1 -167
- package/src/cli/index.ts +3 -0
- package/src/cli/lifecycle-presenter.ts +436 -0
- package/src/cli/models.ts +10 -2
- package/src/cli/modes/print.ts +5 -1
- package/src/cli/reset.ts +228 -106
- package/src/cli/run.ts +7 -4
- package/src/cli/select.ts +664 -0
- package/src/cli/skills.ts +9 -2
- package/src/cli/targets.ts +3 -0
- package/src/cli/tasks.ts +84 -0
- package/src/cli/uninstall.ts +233 -165
- package/src/cli/upgrade.ts +210 -150
- package/src/cli/usage.ts +92 -27
- package/src/cli/validate-model.ts +3 -3
- package/src/cli/verifiers.ts +147 -1
- package/src/cli/wiki-generate.ts +1 -0
- package/src/core/commit-attribution.ts +41 -1
- package/src/core/config.ts +56 -0
- package/src/core/external-diagnostic.ts +44 -0
- package/src/core/gateway-routing.ts +157 -0
- package/src/core/git-commit-attribution.ts +46 -3
- package/src/core/run-overrides.ts +0 -5
- package/src/core/safe-exec.ts +17 -2
- package/src/core/skill-activation.ts +92 -2
- package/src/core/tool-names.ts +5 -2
- package/src/domains/agents/builtins/architect.md +1 -1
- package/src/domains/agents/builtins/coder.md +1 -1
- package/src/domains/agents/builtins/documenter.md +1 -1
- package/src/domains/agents/builtins/git-master.md +1 -1
- package/src/domains/agents/builtins/provenance.md +7 -7
- package/src/domains/agents/builtins/tester.md +1 -1
- package/src/domains/agents/builtins/verifier.md +2 -2
- package/src/domains/agents/builtins/wiki-writer.md +4 -3
- package/src/domains/agents/builtins/world-knowledge.md +31 -0
- package/src/domains/agents/catalog.ts +1 -1
- package/src/domains/agents/result-contract.ts +70 -0
- package/src/domains/context/extension.ts +31 -7
- package/src/domains/context/refresh.ts +3 -0
- package/src/domains/context/wiki/frontmatter.ts +5 -2
- package/src/domains/context/wiki/generate.ts +6 -0
- package/src/domains/context/wiki/map-seed.ts +589 -0
- package/src/domains/context/wiki/plan.ts +2 -2
- package/src/domains/context/wiki/prompts.ts +43 -0
- package/src/domains/dispatch/active-route-planner.ts +4 -0
- package/src/domains/dispatch/admission.ts +29 -0
- package/src/domains/dispatch/agent-candidates.ts +10 -0
- package/src/domains/dispatch/budget-envelope.ts +86 -1
- package/src/domains/dispatch/capability-match.ts +1 -0
- package/src/domains/dispatch/capacity-lease.ts +17 -0
- package/src/domains/dispatch/code-step.ts +11 -4
- package/src/domains/dispatch/contract.ts +42 -8
- package/src/domains/dispatch/execution-scheduler.ts +2 -0
- package/src/domains/dispatch/extension.ts +184 -56
- package/src/domains/dispatch/fleet-commit-attribution.ts +5 -0
- package/src/domains/dispatch/fleet-run.ts +1 -0
- package/src/domains/dispatch/host-verification.ts +114 -13
- package/src/domains/dispatch/intent.ts +28 -18
- package/src/domains/dispatch/orphan-recovery.ts +2 -0
- package/src/domains/dispatch/receipt-integrity.ts +4 -0
- package/src/domains/dispatch/reservation-store.ts +5 -3
- package/src/domains/dispatch/state.ts +15 -2
- package/src/domains/dispatch/types.ts +20 -2
- package/src/domains/dispatch/worker-model-metadata.ts +38 -0
- package/src/domains/eval/metrics/call-ledger-stream.ts +34 -11
- package/src/domains/eval/metrics/token-stream.ts +201 -31
- package/src/domains/eval/metrics/tracked.ts +40 -4
- package/src/domains/eval/runners/clio-run.ts +17 -11
- package/src/domains/eval/runners/context-index.ts +2 -7
- package/src/domains/eval/runners/context-init.ts +3 -6
- package/src/domains/eval/runners/external-command.ts +29 -11
- package/src/domains/eval/schema/suite.ts +28 -0
- package/src/domains/eval/schema/verdict.ts +2 -2
- package/src/domains/eval/suites/resolve.ts +13 -1
- package/src/domains/eval/suites/run.ts +24 -3
- package/src/domains/evidence/build.ts +102 -15
- package/src/domains/evidence/detail.ts +69 -0
- package/src/domains/evidence/eval.ts +13 -1
- package/src/domains/evidence/finish-contract-map.ts +5 -1
- package/src/domains/evidence/inventory.ts +167 -0
- package/src/domains/evidence/store.ts +16 -0
- package/src/domains/evidence/types.ts +12 -0
- package/src/domains/extensions/resources.ts +7 -0
- package/src/domains/interop/registry.ts +6 -2
- package/src/domains/interop/types.ts +4 -0
- package/src/domains/lifecycle/migrations/index.ts +4 -0
- package/src/domains/memory/task-memory-policy.ts +70 -26
- package/src/domains/memory/task-memory-telemetry.ts +1 -0
- package/src/domains/middleware/index.ts +0 -1
- package/src/domains/middleware/marketplace-offer.ts +22 -35
- package/src/domains/middleware/memory-intervention.ts +127 -32
- package/src/domains/middleware/memory-step-endpoint.ts +3 -2
- package/src/domains/middleware/runtime.ts +7 -3
- package/src/domains/middleware/skills-reminder.ts +31 -2
- package/src/domains/mux/detect.ts +3 -6
- package/src/domains/observability/accountability.ts +15 -1
- package/src/domains/observability/compaction-usage.ts +118 -0
- package/src/domains/observability/contract.ts +52 -7
- package/src/domains/observability/cost.ts +1 -1
- package/src/domains/observability/evidence-index.ts +10 -0
- package/src/domains/observability/extension.ts +15 -6
- package/src/domains/observability/out-of-turn-usage.ts +52 -21
- package/src/domains/observability/projection.ts +394 -45
- package/src/{interactive → domains/observability}/worker-progress.ts +3 -3
- package/src/domains/prompts/fragments/operating/contract.md +2 -0
- package/src/domains/prompts/fragments/wiki/page.md +8 -0
- package/src/domains/providers/contract.ts +4 -1
- package/src/domains/providers/extension.ts +40 -9
- package/src/domains/providers/model-capabilities.ts +9 -0
- package/src/domains/providers/model-discovery.ts +3 -4
- package/src/domains/providers/model-runtime-capabilities.ts +15 -5
- package/src/domains/providers/models/local-models/clio-coder-local-coding-targets.yaml +48 -26
- package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +225 -45
- package/src/domains/providers/runtimes/claude/claude-code.ts +9 -0
- package/src/domains/providers/runtimes/common/lmstudio-http.ts +6 -2
- package/src/domains/providers/runtimes/common/local-synth.ts +2 -0
- package/src/domains/providers/runtimes/protocol/litellm.ts +119 -29
- package/src/domains/providers/support.ts +11 -5
- package/src/domains/providers/target-model-cache.ts +25 -2
- package/src/domains/providers/types/capability-flags.ts +2 -0
- package/src/domains/providers/types/runtime-descriptor.ts +20 -1
- package/src/domains/providers/types/target-descriptor.ts +19 -0
- package/src/domains/resources/index.ts +3 -0
- package/src/domains/resources/skills/install.ts +72 -7
- package/src/domains/resources/skills/loader.ts +7 -0
- package/src/domains/resources/skills/marketplace.ts +63 -11
- package/src/domains/safety/action-classifier.ts +7 -0
- package/src/domains/safety/autonomy.ts +15 -0
- package/src/domains/safety/default-path-policy.ts +2 -0
- package/src/domains/safety/finish-contract-registration.ts +29 -14
- package/src/domains/safety/finish-contract.ts +252 -40
- package/src/domains/safety/index.ts +21 -1
- package/src/domains/safety/path-policy.ts +1 -1
- package/src/domains/safety/policy-engine.ts +60 -17
- package/src/domains/safety/protected-artifacts.ts +191 -88
- package/src/domains/safety/rigor.ts +53 -39
- package/src/domains/safety/run-effects.ts +2 -22
- package/src/domains/safety/skill-authority.ts +55 -0
- package/src/domains/safety/validation-contract.ts +388 -0
- package/src/domains/session/archive-readers.ts +10 -1
- package/src/domains/session/compaction/compact.ts +72 -22
- package/src/domains/session/decision-board.ts +101 -2
- package/src/domains/session/entries.ts +50 -7
- package/src/domains/session/extension.ts +4 -4
- package/src/domains/session/handoff.ts +2 -1
- package/src/domains/session/manager.ts +2 -3
- package/src/domains/session/task-board.ts +14 -1
- package/src/domains/session/tree/fork.ts +1 -2
- package/src/domains/session/tree/navigator.ts +1 -1
- package/src/domains/session/usage.ts +3 -3
- package/src/domains/user-tasks/acceptance.ts +56 -0
- package/src/domains/user-tasks/active-acceptance.ts +40 -0
- package/src/domains/user-tasks/store.ts +34 -3
- package/src/engine/acp/adapter.ts +24 -6
- package/src/engine/acp/server.ts +21 -4
- package/src/engine/acp/transport.ts +53 -8
- package/src/engine/acp/types.ts +4 -0
- package/src/engine/agent.ts +13 -3
- package/src/engine/ai.ts +26 -8
- package/src/engine/antigravity/subprocess-runtime.ts +386 -120
- package/src/engine/api-registry.ts +3 -0
- package/src/engine/apis/ollama-native.ts +15 -0
- package/src/engine/apis/openai-completions.ts +117 -14
- package/src/engine/claude/subprocess-runtime.ts +107 -60
- package/src/engine/external-subprocess.ts +122 -6
- package/src/entry/background-model-metadata.ts +18 -0
- package/src/entry/compaction-prompt.ts +57 -0
- package/src/entry/orchestrator.ts +416 -218
- package/src/entry/task-memory-lifecycle.ts +35 -0
- package/src/interactive/chat-loop-messages.ts +13 -4
- package/src/interactive/chat-loop.ts +65 -2
- package/src/interactive/chat-renderer.ts +1 -0
- package/src/interactive/cost-overlay.ts +26 -2
- package/src/interactive/dispatch-board.ts +46 -717
- package/src/interactive/fleet-run-preview.ts +2 -1
- package/src/interactive/interactive-application.ts +3 -2
- package/src/interactive/interactive-presentation.ts +55 -12
- package/src/interactive/interactive-slash-runtime.ts +4 -2
- package/src/interactive/oracle.ts +5 -2
- package/src/interactive/overlays/fleet-run-approval.ts +3 -2
- package/src/interactive/overlays/message-picker.ts +2 -2
- package/src/interactive/overlays/settings.ts +2 -2
- package/src/interactive/overlays/tree-selector.ts +2 -2
- package/src/interactive/renderers/branch-summary.ts +1 -1
- package/src/interactive/renderers/worker-entry.ts +32 -0
- package/src/interactive/slash-autocomplete.ts +4 -6
- package/src/interactive/slash-commands.ts +49 -45
- package/src/interactive/slash-spec.ts +28 -0
- package/src/interactive/theme/labels.ts +19 -13
- package/src/interactive/turn-context.ts +9 -5
- package/src/interactive/turn-recovery.ts +8 -0
- package/src/interactive/turn-runtime.ts +27 -11
- package/src/interactive/turn-state.ts +7 -0
- package/src/interactive/view/artifacts.ts +2 -0
- package/src/interactive/worker-receipts.ts +1 -0
- package/src/interactive/worker-stream.ts +13 -4
- package/src/tools/bootstrap.ts +4 -0
- package/src/tools/builtin-tool-catalog.ts +31 -0
- package/src/tools/compete-worktrees.ts +7 -1
- package/src/tools/context/index.ts +30 -9
- package/src/tools/core-bootstrap.ts +16 -0
- package/src/tools/decide.ts +136 -0
- package/src/tools/dispatch-admission.ts +21 -0
- package/src/tools/dispatch-arguments.ts +1 -0
- package/src/tools/dispatch-event-text.ts +10 -0
- package/src/tools/dispatch-plan.ts +6 -2
- package/src/tools/dispatch-runner.ts +27 -1
- package/src/tools/dispatch-types.ts +6 -0
- package/src/tools/evidence.ts +96 -0
- package/src/tools/limitation.ts +76 -0
- package/src/tools/policy.ts +9 -0
- package/src/tools/presentation.ts +3 -0
- package/src/tools/registry.ts +11 -5
- package/src/tools/result-shaping.ts +17 -5
- package/src/tools/task-worktree.ts +13 -3
- package/src/tools/tasks.ts +10 -1
- package/src/tools/verify/authoring.ts +170 -83
- package/src/tools/verify/catalog.ts +122 -5
- package/src/tools/verify/index.ts +2 -1
- package/src/tools/verify/numeric.ts +298 -0
- package/src/tools/verify/perf.ts +143 -0
- package/src/tools/verify/scripts.ts +229 -2
- package/src/tools/worker-evidence.ts +3 -1
- package/src/worker/spec-contract.ts +4 -0
- package/dist/chunk-2Z2IKEXI.js +0 -1554
- package/dist/chunk-RVG5JXAL.js +0 -41
- package/dist/chunk-T56WDKA5.js +0 -183
- package/dist/chunk-VN3SHNBN.js +0 -313
- package/dist/chunk-VPKWYKEY.js +0 -169
- package/dist/reset-OAQP3W4O.js +0 -230
- package/dist/uninstall-N34PCTGJ.js +0 -331
- package/dist/upgrade-PXK3S2YM.js +0 -325
|
@@ -17,6 +17,11 @@ import {
|
|
|
17
17
|
} from "@earendil-works/pi-ai";
|
|
18
18
|
import { openAICompletionsApi } from "@earendil-works/pi-ai/api/openai-completions.lazy";
|
|
19
19
|
import type { BackendCompletionTimings, BackendTimingsSource } from "../../core/cache-telemetry.js";
|
|
20
|
+
import {
|
|
21
|
+
type GatewayRoutingObservation,
|
|
22
|
+
liteLLMGatewayRoutingFromHeaders,
|
|
23
|
+
liteLLMRouteFailureMessage,
|
|
24
|
+
} from "../../core/gateway-routing.js";
|
|
20
25
|
import type { ResponseModelIdObservation } from "../../core/response-model-id.js";
|
|
21
26
|
import {
|
|
22
27
|
type AppliedThinking,
|
|
@@ -27,7 +32,7 @@ import {
|
|
|
27
32
|
import { lmStudioReasoningEffort } from "../../domains/providers/runtimes/common/lmstudio-http.js";
|
|
28
33
|
import type { ThinkingLevel } from "../../domains/providers/types/capability-flags.js";
|
|
29
34
|
import type { LocalModelQuirks, SamplingProfile } from "../../domains/providers/types/local-model-quirks.js";
|
|
30
|
-
import type { LmStudioTargetSettings } from "../../domains/providers/types/target-descriptor.js";
|
|
35
|
+
import type { LiteLLMTargetSettings, LmStudioTargetSettings } from "../../domains/providers/types/target-descriptor.js";
|
|
31
36
|
import { filterGemmaChannelStream, usesGemmaChannelMarkers } from "../gemma-channel-filter.js";
|
|
32
37
|
import { HarmonyResponseParser } from "../harmony-response.js";
|
|
33
38
|
import { createSentinelStripper, stripTokenizerSentinels } from "../strip-tokenizer-sentinels.js";
|
|
@@ -42,6 +47,8 @@ declare module "@earendil-works/pi-ai" {
|
|
|
42
47
|
interface AssistantMessage {
|
|
43
48
|
/** Direct observation of model-id presence in an OpenAI-compatible response. */
|
|
44
49
|
responseModelIdObservation?: ResponseModelIdObservation;
|
|
50
|
+
/** Route, fallback, retry, and proxy timing facts reported by LiteLLM. */
|
|
51
|
+
gatewayRouting?: GatewayRoutingObservation;
|
|
45
52
|
/** Backend-reported prefill and prediction timings when available. */
|
|
46
53
|
backendTimings?: BackendCompletionTimings;
|
|
47
54
|
}
|
|
@@ -69,6 +76,7 @@ interface ClioRuntimeMetadata {
|
|
|
69
76
|
quirks?: LocalModelQuirks;
|
|
70
77
|
chatTemplateKwargsUnsupported?: boolean;
|
|
71
78
|
lmstudio?: LmStudioTargetSettings;
|
|
79
|
+
litellm?: LiteLLMTargetSettings;
|
|
72
80
|
lmstudioReasoningOptions?: ReadonlyArray<string>;
|
|
73
81
|
lmstudioDefaultModel?: string;
|
|
74
82
|
};
|
|
@@ -101,6 +109,7 @@ interface ResponseModelIdCapture {
|
|
|
101
109
|
modelIdDone: boolean;
|
|
102
110
|
backendTimings: BackendCompletionTimings | null;
|
|
103
111
|
backendTimingsSource: BackendTimingsSource | null;
|
|
112
|
+
gatewayRouting: GatewayRoutingObservation | null;
|
|
104
113
|
buffer: string;
|
|
105
114
|
decoder: TextDecoder | null;
|
|
106
115
|
}
|
|
@@ -199,7 +208,10 @@ function observeResponseModelIdBytes(
|
|
|
199
208
|
if (captureCanStopEarly(capture) || flush) capture.decoder = null;
|
|
200
209
|
}
|
|
201
210
|
|
|
202
|
-
function captureResponseModelId(response: Response, capture: ResponseModelIdCapture): Response {
|
|
211
|
+
function captureResponseModelId(response: Response, capture: ResponseModelIdCapture, model: Model<Api>): Response {
|
|
212
|
+
if (runtimeMetadata(model)?.runtimeId === "litellm") {
|
|
213
|
+
capture.gatewayRouting = liteLLMGatewayRoutingFromHeaders(response.headers);
|
|
214
|
+
}
|
|
203
215
|
if (!response.body || !response.headers.get("content-type")?.toLowerCase().includes("text/event-stream")) {
|
|
204
216
|
return response;
|
|
205
217
|
}
|
|
@@ -234,6 +246,7 @@ function withResponseModelIdCapture<TOptions extends StreamOptions>(
|
|
|
234
246
|
modelIdDone: false,
|
|
235
247
|
backendTimings: null,
|
|
236
248
|
backendTimingsSource: backendTimingsSourceForModel(model),
|
|
249
|
+
gatewayRouting: null,
|
|
237
250
|
buffer: "",
|
|
238
251
|
decoder: new TextDecoder(),
|
|
239
252
|
};
|
|
@@ -241,7 +254,7 @@ function withResponseModelIdCapture<TOptions extends StreamOptions>(
|
|
|
241
254
|
options.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
242
255
|
const capturedOptions = {
|
|
243
256
|
...options,
|
|
244
|
-
fetch: async (input, init) => captureResponseModelId(await fetchImpl(input, init), capture),
|
|
257
|
+
fetch: async (input, init) => captureResponseModelId(await fetchImpl(input, init), capture, model),
|
|
245
258
|
} as TOptions;
|
|
246
259
|
const source = sourceFactory(capturedOptions);
|
|
247
260
|
const annotated = createAssistantMessageEventStream();
|
|
@@ -255,9 +268,11 @@ function withResponseModelIdCapture<TOptions extends StreamOptions>(
|
|
|
255
268
|
: { state: "not-observed" };
|
|
256
269
|
if (event.type === "done") {
|
|
257
270
|
event.message.responseModelIdObservation = observation;
|
|
271
|
+
if (capture.gatewayRouting !== null) event.message.gatewayRouting = capture.gatewayRouting;
|
|
258
272
|
if (capture.backendTimings !== null) event.message.backendTimings = capture.backendTimings;
|
|
259
273
|
} else if (event.type === "error") {
|
|
260
274
|
event.error.responseModelIdObservation = observation;
|
|
275
|
+
if (capture.gatewayRouting !== null) event.error.gatewayRouting = capture.gatewayRouting;
|
|
261
276
|
if (capture.backendTimings !== null) event.error.backendTimings = capture.backendTimings;
|
|
262
277
|
}
|
|
263
278
|
annotated.push(event as AssistantMessageEvent);
|
|
@@ -271,6 +286,31 @@ function withResponseModelIdCapture<TOptions extends StreamOptions>(
|
|
|
271
286
|
return annotated;
|
|
272
287
|
}
|
|
273
288
|
|
|
289
|
+
/** Make a failed physical gateway route final and useful to an operator. */
|
|
290
|
+
function withLiteLLMRouteFailureAdvice(
|
|
291
|
+
model: Model<"openai-completions">,
|
|
292
|
+
source: AssistantMessageEventStream,
|
|
293
|
+
): AssistantMessageEventStream {
|
|
294
|
+
const metadata = runtimeMetadata(model);
|
|
295
|
+
if (metadata?.runtimeId !== "litellm") return source;
|
|
296
|
+
const advised = createAssistantMessageEventStream();
|
|
297
|
+
(async () => {
|
|
298
|
+
try {
|
|
299
|
+
for await (const event of source) {
|
|
300
|
+
if (event.type === "error") {
|
|
301
|
+
event.error.errorMessage = liteLLMRouteFailureMessage(event.error.errorMessage, metadata.targetId, model.id);
|
|
302
|
+
}
|
|
303
|
+
advised.push(event as AssistantMessageEvent);
|
|
304
|
+
}
|
|
305
|
+
advised.end();
|
|
306
|
+
} catch (err) {
|
|
307
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
308
|
+
throw new Error(liteLLMRouteFailureMessage(message, metadata.targetId, model.id));
|
|
309
|
+
}
|
|
310
|
+
})();
|
|
311
|
+
return advised;
|
|
312
|
+
}
|
|
313
|
+
|
|
274
314
|
function samplingParamsFromProfile(profile: SamplingProfile): Record<string, unknown> {
|
|
275
315
|
return {
|
|
276
316
|
...(profile.topP !== undefined ? { top_p: profile.topP } : {}),
|
|
@@ -395,6 +435,17 @@ function applyThinkingPayload(
|
|
|
395
435
|
) {
|
|
396
436
|
next.reasoning_effort = resolved.request.reasoningEffort;
|
|
397
437
|
}
|
|
438
|
+
// LiteLLM generic openai/<local model> routes otherwise drop this standard
|
|
439
|
+
// parameter. Allow only the effort this model/runtime actually resolved;
|
|
440
|
+
// unknown off controls and unrelated caller parameters gain no allowance.
|
|
441
|
+
if (
|
|
442
|
+
resolved.runtimeId === "litellm" &&
|
|
443
|
+
resolved.request.reasoningEffort &&
|
|
444
|
+
next.reasoning_effort === resolved.request.reasoningEffort
|
|
445
|
+
) {
|
|
446
|
+
const allowed = Array.isArray(next.allowed_openai_params) ? next.allowed_openai_params : [];
|
|
447
|
+
next.allowed_openai_params = [...new Set([...allowed, "reasoning_effort"])];
|
|
448
|
+
}
|
|
398
449
|
if (resolved.request.chatTemplateKwargs && !chatTemplateKwargsUnsupported(model)) {
|
|
399
450
|
const existing = isPlainRecord(next.chat_template_kwargs) ? next.chat_template_kwargs : {};
|
|
400
451
|
next.chat_template_kwargs = { ...existing, ...resolved.request.chatTemplateKwargs };
|
|
@@ -433,15 +484,15 @@ function applyLmStudioPayload(
|
|
|
433
484
|
if (request?.ttlSeconds !== undefined) next.ttl = request.ttlSeconds;
|
|
434
485
|
if (request?.draftModel !== undefined) next.draft_model = request.draftModel;
|
|
435
486
|
if (resolved.thinking.mechanism === "none" || resolved.thinking.mechanism === "always-on") return next;
|
|
436
|
-
const resolvedEffort =
|
|
437
|
-
resolved.
|
|
438
|
-
lmStudioReasoningEffort(resolved.thinking.effectiveLevel
|
|
487
|
+
const resolvedEffort = runtimeMetadata(model)?.lmstudioReasoningOptions
|
|
488
|
+
? lmStudioReasoningEffort(resolved.thinking.effectiveLevel, runtimeMetadata(model)?.lmstudioReasoningOptions)
|
|
489
|
+
: (resolved.request.reasoningEffort ?? lmStudioReasoningEffort(resolved.thinking.effectiveLevel));
|
|
439
490
|
switch (request?.reasoning) {
|
|
440
491
|
case "off":
|
|
441
|
-
next.reasoning_effort = "
|
|
492
|
+
next.reasoning_effort = lmStudioReasoningEffort("off", runtimeMetadata(model)?.lmstudioReasoningOptions);
|
|
442
493
|
break;
|
|
443
494
|
case "on":
|
|
444
|
-
next.reasoning_effort = "low";
|
|
495
|
+
next.reasoning_effort = lmStudioReasoningEffort("low", runtimeMetadata(model)?.lmstudioReasoningOptions);
|
|
445
496
|
break;
|
|
446
497
|
case "low":
|
|
447
498
|
case "medium":
|
|
@@ -584,6 +635,50 @@ function withRemainingContextBudget<TOptions extends StreamOptions>(
|
|
|
584
635
|
} as TOptions;
|
|
585
636
|
}
|
|
586
637
|
|
|
638
|
+
function hasHeader(headers: Readonly<Record<string, unknown>> | undefined, name: string): boolean {
|
|
639
|
+
if (!headers) return false;
|
|
640
|
+
const wanted = name.toLowerCase();
|
|
641
|
+
return Object.keys(headers).some((key) => key.toLowerCase() === wanted);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Apply LiteLLM's request-control headers at the final transport boundary.
|
|
646
|
+
*
|
|
647
|
+
* The OpenAI SDK otherwise retries twice below Clio's visible recovery loop and
|
|
648
|
+
* below LiteLLM's own router, multiplying a single failure into several hidden
|
|
649
|
+
* attempts. Gateway requests use zero client retries by default; optional
|
|
650
|
+
* `numRetries` controls the proxy router itself, where any configured attempts
|
|
651
|
+
* remain observable. A physical-routing gateway should leave it at zero.
|
|
652
|
+
*/
|
|
653
|
+
function withLiteLLMRequestOptions<TOptions extends StreamOptions>(
|
|
654
|
+
model: Model<"openai-completions">,
|
|
655
|
+
options: TOptions,
|
|
656
|
+
): TOptions {
|
|
657
|
+
const metadata = runtimeMetadata(model);
|
|
658
|
+
if (metadata?.runtimeId !== "litellm") return options;
|
|
659
|
+
const request = metadata.litellm?.request;
|
|
660
|
+
const modelHeaders = model.headers as Readonly<Record<string, unknown>> | undefined;
|
|
661
|
+
const optionHeaders = options.headers as Readonly<Record<string, unknown>> | undefined;
|
|
662
|
+
const headers: Record<string, string | null> = { ...(options.headers ?? {}) };
|
|
663
|
+
const setDefault = (name: string, value: string | undefined): void => {
|
|
664
|
+
if (value === undefined || hasHeader(modelHeaders, name) || hasHeader(optionHeaders, name)) return;
|
|
665
|
+
headers[name] = value;
|
|
666
|
+
};
|
|
667
|
+
setDefault("x-litellm-tags", ["clio-coder", ...(request?.tags ?? [])].join(","));
|
|
668
|
+
if (request?.sendSessionId !== false) setDefault("x-litellm-session-id", options.sessionId);
|
|
669
|
+
setDefault("x-litellm-timeout", request?.timeoutSeconds?.toString());
|
|
670
|
+
setDefault("x-litellm-stream-timeout", request?.streamTimeoutSeconds?.toString());
|
|
671
|
+
setDefault("x-litellm-num-retries", request?.numRetries?.toString());
|
|
672
|
+
return {
|
|
673
|
+
...options,
|
|
674
|
+
headers,
|
|
675
|
+
// Never hide duplicate attempts inside the OpenAI SDK beneath Clio's
|
|
676
|
+
// operator-visible failure. The gateway may still be configured to retry,
|
|
677
|
+
// but physical-routing deployments should keep that policy at zero too.
|
|
678
|
+
maxRetries: options.maxRetries ?? 0,
|
|
679
|
+
} as TOptions;
|
|
680
|
+
}
|
|
681
|
+
|
|
587
682
|
function requiredToolArguments(tool: Tool): ReadonlyArray<string> {
|
|
588
683
|
const schema = tool.parameters as unknown;
|
|
589
684
|
if (schema === null || typeof schema !== "object" || Array.isArray(schema)) return [];
|
|
@@ -921,15 +1016,18 @@ export const openAICompletionsApiProvider: EngineApiProvider<"openai-completions
|
|
|
921
1016
|
const resolved = resolvedCapabilitiesForModel(model, defaultLevel);
|
|
922
1017
|
const effectiveContext = stripsThinking(resolved) ? stripThinkingFromContext(context) : context;
|
|
923
1018
|
const withSamplers = withSamplingOverrides(model, options, resolved);
|
|
1019
|
+
const withGatewayOptions = withLiteLLMRequestOptions(
|
|
1020
|
+
model,
|
|
1021
|
+
withRemainingContextBudget(model, effectiveContext, withSamplers),
|
|
1022
|
+
);
|
|
924
1023
|
return guardMalformedToolCalls(
|
|
925
1024
|
withReasoningTokenEstimate(
|
|
926
1025
|
stripSentinelsFromStream(
|
|
927
1026
|
stripNeverReasoningFromStream(
|
|
928
1027
|
filterGemmaChannelStream(
|
|
929
|
-
|
|
1028
|
+
withLiteLLMRouteFailureAdvice(
|
|
930
1029
|
model,
|
|
931
|
-
|
|
932
|
-
(capturedOptions) =>
|
|
1030
|
+
withResponseModelIdCapture(model, withGatewayOptions, (capturedOptions) =>
|
|
933
1031
|
withLocalResidency(
|
|
934
1032
|
model,
|
|
935
1033
|
{
|
|
@@ -938,6 +1036,7 @@ export const openAICompletionsApiProvider: EngineApiProvider<"openai-completions
|
|
|
938
1036
|
},
|
|
939
1037
|
(requestModel) => piOpenAICompletions.stream(requestModel, effectiveContext, capturedOptions),
|
|
940
1038
|
),
|
|
1039
|
+
),
|
|
941
1040
|
),
|
|
942
1041
|
usesGemmaChannelMarkers(resolved.modelId),
|
|
943
1042
|
),
|
|
@@ -954,15 +1053,18 @@ export const openAICompletionsApiProvider: EngineApiProvider<"openai-completions
|
|
|
954
1053
|
const resolved = resolvedCapabilitiesForModel(model, thinkingLevelFromSimple(options));
|
|
955
1054
|
const effectiveContext = stripsThinking(resolved) ? stripThinkingFromContext(context) : context;
|
|
956
1055
|
const withSamplers = withSamplingOverrides(model, options, resolved);
|
|
1056
|
+
const withGatewayOptions = withLiteLLMRequestOptions(
|
|
1057
|
+
model,
|
|
1058
|
+
withRemainingContextBudget(model, effectiveContext, withSamplers),
|
|
1059
|
+
);
|
|
957
1060
|
return guardMalformedToolCalls(
|
|
958
1061
|
withReasoningTokenEstimate(
|
|
959
1062
|
stripSentinelsFromStream(
|
|
960
1063
|
stripNeverReasoningFromStream(
|
|
961
1064
|
filterGemmaChannelStream(
|
|
962
|
-
|
|
1065
|
+
withLiteLLMRouteFailureAdvice(
|
|
963
1066
|
model,
|
|
964
|
-
|
|
965
|
-
(capturedOptions) =>
|
|
1067
|
+
withResponseModelIdCapture(model, withGatewayOptions, (capturedOptions) =>
|
|
966
1068
|
withLocalResidency(
|
|
967
1069
|
model,
|
|
968
1070
|
{
|
|
@@ -971,6 +1073,7 @@ export const openAICompletionsApiProvider: EngineApiProvider<"openai-completions
|
|
|
971
1073
|
},
|
|
972
1074
|
(requestModel) => piOpenAICompletions.streamSimple(requestModel, effectiveContext, capturedOptions),
|
|
973
1075
|
),
|
|
1076
|
+
),
|
|
974
1077
|
),
|
|
975
1078
|
usesGemmaChannelMarkers(resolved.modelId),
|
|
976
1079
|
),
|
|
@@ -1,17 +1,30 @@
|
|
|
1
1
|
import { type ChildProcessByStdio, spawn } from "node:child_process";
|
|
2
|
-
import {
|
|
3
|
-
import type { Readable } from "node:stream";
|
|
2
|
+
import type { Readable, Writable } from "node:stream";
|
|
4
3
|
|
|
4
|
+
import { boundedExternalDiagnostic } from "../../core/external-diagnostic.js";
|
|
5
|
+
import { buildSafeToolEnv, resolveSafeCwd } from "../../core/safe-exec.js";
|
|
5
6
|
import type { AutonomyLevel } from "../../domains/safety/autonomy.js";
|
|
6
7
|
import { assertToolProfileEnforceable } from "../../tools/profiles.js";
|
|
7
|
-
import { readStderr, waitForClose } from "../external-subprocess.js";
|
|
8
|
+
import { createProcessTreeTerminator, readBoundedLines, readStderr, waitForClose } from "../external-subprocess.js";
|
|
8
9
|
import type { AgentEvent, AgentMessage, Usage } from "../types.js";
|
|
9
10
|
import type { WorkerEventEmit, WorkerRunHandle, WorkerRunInput, WorkerRunResult } from "../worker-runtime.js";
|
|
10
11
|
import { isClaudeCodeSessionId } from "./session-id.js";
|
|
11
12
|
|
|
12
13
|
const READ_ONLY_CLAUDE_TOOLS = ["Read", "Grep", "Glob", "LS", "WebFetch", "WebSearch"] as const;
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
/** Official CLI binary, resolved from the operator's PATH. */
|
|
16
|
+
const CLAUDE_BINARY = "claude";
|
|
17
|
+
export const CLAUDE_MAX_STREAM_LINE_BYTES = 1024 * 1024;
|
|
18
|
+
export const CLAUDE_MAX_STREAM_BYTES = 8 * 1024 * 1024;
|
|
19
|
+
|
|
20
|
+
type ClaudeChildProcess = ChildProcessByStdio<Writable, Readable, Readable>;
|
|
21
|
+
|
|
22
|
+
export interface ClaudeRuntimeDependencies {
|
|
23
|
+
binary?: string;
|
|
24
|
+
workspaceRoot?: string;
|
|
25
|
+
environment?: NodeJS.ProcessEnv;
|
|
26
|
+
killGraceMs?: number;
|
|
27
|
+
}
|
|
15
28
|
|
|
16
29
|
export interface ClaudeSubprocessPermissionConfig {
|
|
17
30
|
permissionMode: "plan" | "dontAsk" | "acceptEdits" | "default" | "bypassPermissions";
|
|
@@ -48,15 +61,20 @@ export function claudeSubprocessPermissionConfigForAutonomy(
|
|
|
48
61
|
return { permissionMode: "default", extraArgs: [], dangerousBypass: false };
|
|
49
62
|
}
|
|
50
63
|
|
|
51
|
-
function buildClaudeCodePrompt(input: WorkerRunInput): string {
|
|
64
|
+
export function buildClaudeCodePrompt(input: WorkerRunInput): string {
|
|
52
65
|
const parts = (input.dynamicPromptMessages ?? []).map((message) => message.body.trim()).filter(Boolean);
|
|
53
66
|
parts.push(input.task);
|
|
54
67
|
return parts.join("\n\n");
|
|
55
68
|
}
|
|
56
69
|
|
|
57
|
-
|
|
70
|
+
/**
|
|
71
|
+
* `claude -p` reads the user prompt from stdin when no positional prompt is
|
|
72
|
+
* given, so the prompt never appears in argv. The system prompt stays on
|
|
73
|
+
* `--append-system-prompt`: stdin carries only the user turn.
|
|
74
|
+
*/
|
|
75
|
+
export function buildClaudeCodeArgs(input: WorkerRunInput, gateEnv: NodeJS.ProcessEnv = process.env): string[] {
|
|
58
76
|
assertToolProfileEnforceable(input.toolProfile, "claude-code");
|
|
59
|
-
const permission = claudeSubprocessPermissionConfigForAutonomy(input.autonomy);
|
|
77
|
+
const permission = claudeSubprocessPermissionConfigForAutonomy(input.autonomy, gateEnv);
|
|
60
78
|
const args = [
|
|
61
79
|
"-p",
|
|
62
80
|
"--output-format",
|
|
@@ -71,7 +89,6 @@ function buildClaudeCodeArgs(input: WorkerRunInput): string[] {
|
|
|
71
89
|
const systemPrompt = input.systemPrompt.trim();
|
|
72
90
|
if (systemPrompt.length > 0) args.push("--append-system-prompt", systemPrompt);
|
|
73
91
|
if (isClaudeCodeSessionId(input.sessionId)) args.push("--session-id", input.sessionId.trim());
|
|
74
|
-
args.push(buildClaudeCodePrompt(input));
|
|
75
92
|
return args;
|
|
76
93
|
}
|
|
77
94
|
|
|
@@ -170,8 +187,11 @@ function buildAssistantMessage(input: {
|
|
|
170
187
|
exitCode: number;
|
|
171
188
|
aborted: boolean;
|
|
172
189
|
stderr: string;
|
|
190
|
+
transportError?: string;
|
|
173
191
|
}): AgentMessage & { role: "assistant" } {
|
|
174
|
-
const
|
|
192
|
+
const transportError = input.transportError ?? "";
|
|
193
|
+
const failed = input.exitCode !== 0 || transportError.length > 0;
|
|
194
|
+
const errorMessage = !failed ? "" : transportError || resultError(input.result, input.stderr);
|
|
175
195
|
const message: AgentMessage & { role: "assistant" } = {
|
|
176
196
|
role: "assistant",
|
|
177
197
|
content: [{ type: "text", text: input.text }],
|
|
@@ -179,12 +199,12 @@ function buildAssistantMessage(input: {
|
|
|
179
199
|
provider: "anthropic",
|
|
180
200
|
model: input.model,
|
|
181
201
|
usage: normalizeUsage(input.result?.usage, finite(input.result?.total_cost_usd)),
|
|
182
|
-
stopReason: input.aborted ? "aborted" :
|
|
202
|
+
stopReason: input.aborted ? "aborted" : failed ? "error" : "stop",
|
|
183
203
|
timestamp: Date.now(),
|
|
184
204
|
} as AgentMessage & { role: "assistant" };
|
|
185
205
|
if (typeof input.result?.request_id === "string") message.responseId = input.result.request_id;
|
|
186
206
|
if (typeof input.result?.model === "string") message.responseModel = input.result.model;
|
|
187
|
-
if (errorMessage.length > 0) message.errorMessage = errorMessage;
|
|
207
|
+
if (errorMessage.length > 0) message.errorMessage = boundedExternalDiagnostic(errorMessage);
|
|
188
208
|
return message;
|
|
189
209
|
}
|
|
190
210
|
|
|
@@ -224,9 +244,14 @@ async function readJsonLines(
|
|
|
224
244
|
emit: WorkerEventEmit,
|
|
225
245
|
state: { started: boolean; text: string; model: string; result: Record<string, unknown> | null },
|
|
226
246
|
): Promise<void> {
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
247
|
+
for await (const bounded of readBoundedLines(child.stdout, {
|
|
248
|
+
maxLineBytes: CLAUDE_MAX_STREAM_LINE_BYTES,
|
|
249
|
+
maxTotalBytes: CLAUDE_MAX_STREAM_BYTES,
|
|
250
|
+
})) {
|
|
251
|
+
if (bounded.kind === "oversized") {
|
|
252
|
+
throw new Error(`claude stream-json line exceeded ${CLAUDE_MAX_STREAM_LINE_BYTES} bytes`);
|
|
253
|
+
}
|
|
254
|
+
const trimmed = bounded.line.trim();
|
|
230
255
|
if (trimmed.length === 0) continue;
|
|
231
256
|
let parsed: unknown;
|
|
232
257
|
try {
|
|
@@ -250,12 +275,21 @@ async function readJsonLines(
|
|
|
250
275
|
}
|
|
251
276
|
}
|
|
252
277
|
|
|
253
|
-
export function startClaudeCodeWorkerRun(
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
278
|
+
export function startClaudeCodeWorkerRun(
|
|
279
|
+
input: WorkerRunInput,
|
|
280
|
+
emit: WorkerEventEmit,
|
|
281
|
+
dependencies: ClaudeRuntimeDependencies = {},
|
|
282
|
+
): WorkerRunHandle {
|
|
283
|
+
const sourceEnv = dependencies.environment ?? process.env;
|
|
284
|
+
const args = buildClaudeCodeArgs(input, sourceEnv);
|
|
285
|
+
const prompt = buildClaudeCodePrompt(input);
|
|
286
|
+
const workspaceRoot = dependencies.workspaceRoot ?? process.cwd();
|
|
287
|
+
const cwd = resolveSafeCwd(input.cwd, workspaceRoot);
|
|
288
|
+
const child: ClaudeChildProcess = spawn(dependencies.binary ?? CLAUDE_BINARY, args, {
|
|
289
|
+
cwd,
|
|
290
|
+
env: buildSafeToolEnv({}, sourceEnv),
|
|
291
|
+
detached: process.platform !== "win32",
|
|
292
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
259
293
|
});
|
|
260
294
|
const streamState = {
|
|
261
295
|
started: false,
|
|
@@ -264,53 +298,66 @@ export function startClaudeCodeWorkerRun(input: WorkerRunInput, emit: WorkerEven
|
|
|
264
298
|
result: null as Record<string, unknown> | null,
|
|
265
299
|
};
|
|
266
300
|
let aborted = false;
|
|
267
|
-
let
|
|
268
|
-
|
|
301
|
+
let settled = false;
|
|
302
|
+
let transportError = "";
|
|
303
|
+
const terminator = createProcessTreeTerminator(child, dependencies.killGraceMs ?? 1500);
|
|
269
304
|
const abort = (): void => {
|
|
305
|
+
if (settled) return;
|
|
270
306
|
aborted = true;
|
|
271
|
-
|
|
272
|
-
child.kill("SIGTERM");
|
|
273
|
-
killTimer = setTimeout(() => {
|
|
274
|
-
if (!child.killed) child.kill("SIGKILL");
|
|
275
|
-
}, 1500);
|
|
307
|
+
terminator.terminate();
|
|
276
308
|
};
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
309
|
+
const onAbort = (): void => abort();
|
|
310
|
+
if (input.signal?.aborted) abort();
|
|
311
|
+
else input.signal?.addEventListener("abort", onAbort, { once: true });
|
|
312
|
+
child.once("error", (cause) => {
|
|
313
|
+
transportError ||=
|
|
314
|
+
(cause as NodeJS.ErrnoException).code === "ENOENT"
|
|
315
|
+
? "Claude Code CLI (`claude`) is not installed or not on PATH."
|
|
316
|
+
: cause.message;
|
|
317
|
+
});
|
|
318
|
+
child.stdin.on("error", (cause) => {
|
|
319
|
+
if (!aborted) transportError ||= `could not send prompt to Claude Code CLI: ${cause.message}`;
|
|
320
|
+
});
|
|
321
|
+
child.stdin.end(prompt);
|
|
281
322
|
|
|
282
323
|
const promise = (async (): Promise<WorkerRunResult> => {
|
|
283
324
|
emit({ type: "agent_start" } as AgentEvent);
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
325
|
+
try {
|
|
326
|
+
const stderrPromise = readStderr(child);
|
|
327
|
+
const stdoutPromise = readJsonLines(child, emit, streamState).catch((cause) => {
|
|
328
|
+
transportError ||= cause instanceof Error ? cause.message : String(cause);
|
|
329
|
+
terminator.terminate();
|
|
330
|
+
});
|
|
331
|
+
const exitCode = await waitForClose(child);
|
|
332
|
+
await stdoutPromise;
|
|
333
|
+
const stderr = await stderrPromise.catch(() => "");
|
|
334
|
+
const finalText =
|
|
335
|
+
streamState.text ||
|
|
336
|
+
resultText(streamState.result) ||
|
|
337
|
+
(exitCode === 0 ? "" : resultError(streamState.result, stderr));
|
|
338
|
+
const finalMessage = buildAssistantMessage({
|
|
339
|
+
model: streamState.model,
|
|
340
|
+
text: finalText,
|
|
341
|
+
result: streamState.result,
|
|
342
|
+
exitCode,
|
|
343
|
+
aborted,
|
|
344
|
+
stderr,
|
|
345
|
+
transportError,
|
|
346
|
+
});
|
|
347
|
+
if (!streamState.started) emit({ type: "message_start", message: finalMessage } as AgentEvent);
|
|
348
|
+
emit({ type: "message_end", message: finalMessage } as AgentEvent);
|
|
349
|
+
const messages: AgentMessage[] = [finalMessage];
|
|
350
|
+
emit({ type: "agent_end", messages } as AgentEvent);
|
|
351
|
+
if (finalMessage.stopReason === "error" && finalMessage.errorMessage && !aborted) {
|
|
352
|
+
process.stderr.write(`[worker:claude-code] ${finalMessage.errorMessage}\n`);
|
|
353
|
+
}
|
|
354
|
+
return { messages, exitCode: finalMessage.stopReason === "stop" ? 0 : 1 };
|
|
355
|
+
} finally {
|
|
356
|
+
settled = true;
|
|
357
|
+
terminator.cleanup();
|
|
358
|
+
input.signal?.removeEventListener("abort", onAbort);
|
|
308
359
|
}
|
|
309
|
-
return { messages, exitCode: exitCode === 0 ? 0 : 1 };
|
|
310
360
|
})();
|
|
311
361
|
|
|
312
|
-
return {
|
|
313
|
-
promise,
|
|
314
|
-
abort,
|
|
315
|
-
};
|
|
362
|
+
return { promise, abort };
|
|
316
363
|
}
|
|
@@ -1,15 +1,125 @@
|
|
|
1
1
|
import type { ChildProcessByStdio } from "node:child_process";
|
|
2
2
|
import type { Readable } from "node:stream";
|
|
3
3
|
|
|
4
|
+
import { boundedExternalDiagnostic } from "../core/external-diagnostic.js";
|
|
5
|
+
|
|
4
6
|
export type SubprocessWithStdio = ChildProcessByStdio<null, Readable, Readable>;
|
|
5
7
|
|
|
8
|
+
export type BoundedLine = { kind: "line"; line: string } | { kind: "oversized" };
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Split a byte stream without ever retaining more than one bounded line.
|
|
12
|
+
* Node has already allocated each incoming chunk, but an unterminated provider
|
|
13
|
+
* line cannot make this decoder accumulate without limit.
|
|
14
|
+
*/
|
|
15
|
+
export async function* readBoundedLines(
|
|
16
|
+
readable: Readable,
|
|
17
|
+
options: { maxLineBytes: number; maxTotalBytes: number },
|
|
18
|
+
): AsyncGenerator<BoundedLine> {
|
|
19
|
+
let segments: Buffer[] = [];
|
|
20
|
+
let lineBytes = 0;
|
|
21
|
+
let totalBytes = 0;
|
|
22
|
+
let discarding = false;
|
|
23
|
+
const finishLine = (): BoundedLine | null => {
|
|
24
|
+
if (discarding) {
|
|
25
|
+
segments = [];
|
|
26
|
+
lineBytes = 0;
|
|
27
|
+
discarding = false;
|
|
28
|
+
return { kind: "oversized" };
|
|
29
|
+
}
|
|
30
|
+
if (lineBytes === 0) return { kind: "line", line: "" };
|
|
31
|
+
const joined = Buffer.concat(segments, lineBytes);
|
|
32
|
+
segments = [];
|
|
33
|
+
lineBytes = 0;
|
|
34
|
+
const end = joined.at(-1) === 0x0d ? joined.length - 1 : joined.length;
|
|
35
|
+
return { kind: "line", line: joined.subarray(0, end).toString("utf8") };
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
for await (const raw of readable) {
|
|
39
|
+
const chunk = Buffer.isBuffer(raw) ? raw : Buffer.from(String(raw));
|
|
40
|
+
totalBytes += chunk.byteLength;
|
|
41
|
+
if (totalBytes > options.maxTotalBytes) throw new Error("external stdout exceeded the cumulative output limit");
|
|
42
|
+
let offset = 0;
|
|
43
|
+
while (offset < chunk.length) {
|
|
44
|
+
const newline = chunk.indexOf(0x0a, offset);
|
|
45
|
+
const end = newline === -1 ? chunk.length : newline;
|
|
46
|
+
const piece = chunk.subarray(offset, end);
|
|
47
|
+
if (!discarding && piece.length > 0) {
|
|
48
|
+
if (lineBytes + piece.length > options.maxLineBytes) {
|
|
49
|
+
segments = [];
|
|
50
|
+
lineBytes = 0;
|
|
51
|
+
discarding = true;
|
|
52
|
+
} else {
|
|
53
|
+
segments.push(piece);
|
|
54
|
+
lineBytes += piece.length;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (newline === -1) break;
|
|
58
|
+
const line = finishLine();
|
|
59
|
+
if (line) yield line;
|
|
60
|
+
offset = newline + 1;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (discarding || lineBytes > 0) {
|
|
64
|
+
const line = finishLine();
|
|
65
|
+
if (line) yield line;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
6
69
|
export async function readStderr(child: { stderr: Readable }): Promise<string> {
|
|
7
|
-
let
|
|
70
|
+
let tail = Buffer.alloc(0);
|
|
8
71
|
for await (const chunk of child.stderr) {
|
|
9
|
-
|
|
10
|
-
|
|
72
|
+
const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));
|
|
73
|
+
tail = Buffer.concat([tail, bytes]);
|
|
74
|
+
if (tail.byteLength > 8192) tail = tail.subarray(tail.byteLength - 8192);
|
|
11
75
|
}
|
|
12
|
-
return
|
|
76
|
+
return boundedExternalDiagnostic(tail.toString("utf8"));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface ProcessTreeTerminator {
|
|
80
|
+
terminate(): void;
|
|
81
|
+
cleanup(): void;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** POSIX process-group termination with a direct-child fallback; Windows is direct-child only. */
|
|
85
|
+
export function createProcessTreeTerminator(
|
|
86
|
+
child: { pid?: number | undefined; exitCode: number | null; kill(signal?: NodeJS.Signals): boolean },
|
|
87
|
+
graceMs = 1500,
|
|
88
|
+
): ProcessTreeTerminator {
|
|
89
|
+
let sent = false;
|
|
90
|
+
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
91
|
+
const signal = (name: NodeJS.Signals): void => {
|
|
92
|
+
if (child.pid && process.platform !== "win32") {
|
|
93
|
+
try {
|
|
94
|
+
process.kill(-child.pid, name);
|
|
95
|
+
return;
|
|
96
|
+
} catch {
|
|
97
|
+
// The child may not have established its group yet.
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (child.exitCode !== null) return;
|
|
101
|
+
child.kill(name);
|
|
102
|
+
};
|
|
103
|
+
return {
|
|
104
|
+
terminate() {
|
|
105
|
+
if (sent) return;
|
|
106
|
+
sent = true;
|
|
107
|
+
signal("SIGTERM");
|
|
108
|
+
timer = setTimeout(() => {
|
|
109
|
+
timer = null;
|
|
110
|
+
signal("SIGKILL");
|
|
111
|
+
}, graceMs);
|
|
112
|
+
},
|
|
113
|
+
cleanup() {
|
|
114
|
+
if (timer) {
|
|
115
|
+
clearTimeout(timer);
|
|
116
|
+
timer = null;
|
|
117
|
+
// A closed leader can leave descendants with independent stdio.
|
|
118
|
+
// Finish the requested cancellation before releasing its escalation.
|
|
119
|
+
signal("SIGKILL");
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
};
|
|
13
123
|
}
|
|
14
124
|
|
|
15
125
|
export function waitForClose(child: {
|
|
@@ -17,7 +127,13 @@ export function waitForClose(child: {
|
|
|
17
127
|
once(event: "close", listener: (code: number | null) => void): unknown;
|
|
18
128
|
}): Promise<number> {
|
|
19
129
|
return new Promise((resolve) => {
|
|
20
|
-
|
|
21
|
-
|
|
130
|
+
let settled = false;
|
|
131
|
+
const finish = (code: number): void => {
|
|
132
|
+
if (settled) return;
|
|
133
|
+
settled = true;
|
|
134
|
+
resolve(code);
|
|
135
|
+
};
|
|
136
|
+
child.once("error", () => finish(1));
|
|
137
|
+
child.once("close", (code: number | null) => finish(code ?? 1));
|
|
22
138
|
});
|
|
23
139
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ProvidersContract } from "../domains/providers/contract.js";
|
|
2
|
+
|
|
3
|
+
/** Cold gateway roles need their own declared model controls before synthesis.
|
|
4
|
+
* Read metadata only; an unknown/mixed successful probe remains authoritative.
|
|
5
|
+
* Memory supplies its existing deadline/generation signal, including auth.
|
|
6
|
+
*/
|
|
7
|
+
export async function prepareBackgroundModelMetadata(
|
|
8
|
+
providers: ProvidersContract,
|
|
9
|
+
targetId: string,
|
|
10
|
+
signal?: AbortSignal,
|
|
11
|
+
): Promise<void> {
|
|
12
|
+
signal?.throwIfAborted();
|
|
13
|
+
const status = providers.list().find((entry) => entry.target.id === targetId);
|
|
14
|
+
if (status?.target.runtime === "litellm" && status.health.lastCheckAt === null) {
|
|
15
|
+
await providers.probeTarget(targetId, { reasoning: false, ...(signal ? { signal } : {}) });
|
|
16
|
+
}
|
|
17
|
+
signal?.throwIfAborted();
|
|
18
|
+
}
|