@iowarp/clio-coder 0.3.8 → 0.3.9
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 +49 -0
- package/README.md +7 -3
- package/dist/{acp-U67UHUK2.js → acp-7LOELQFP.js} +6 -6
- package/dist/{agents-YU6SGALZ.js → agents-FIBG2SHA.js} +27 -25
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-5ZPJOIVG.js → auth-OI4LIH2I.js} +11 -12
- package/dist/{builtins-C6JMZVV6.js → builtins-AD25UL3C.js} +5 -5
- package/dist/{chunk-5FR74PWO.js → chunk-2JDWVJND.js} +2 -2
- package/dist/chunk-3DPEIQKN.js +113 -0
- package/dist/{chunk-4SPRNWDE.js → chunk-3DUR4WUA.js} +15 -15
- package/dist/{chunk-VHN4MY6O.js → chunk-3MRC2YSQ.js} +2 -2
- package/dist/{chunk-5DHKRSMQ.js → chunk-3UUY7R3Z.js} +11 -7
- package/dist/{chunk-IGWKHNIQ.js → chunk-3V5AYSEQ.js} +8 -8
- package/dist/{chunk-FHJEP5SW.js → chunk-465CC7FK.js} +8 -5
- package/dist/{chunk-5WIGXA4T.js → chunk-47CMYGET.js} +111 -4
- package/dist/{chunk-A3WNZD3P.js → chunk-4H6ULJ3H.js} +67 -21
- package/dist/{chunk-TB5666IT.js → chunk-4LJX2PUC.js} +3 -3
- package/dist/{chunk-XWSF374K.js → chunk-56KB5IJP.js} +2 -2
- package/dist/{chunk-SPULKLCF.js → chunk-5DQRIYDZ.js} +2 -2
- package/dist/{chunk-2HEJ2F35.js → chunk-5HFBWUMU.js} +20 -8
- package/dist/{chunk-WNIJTQQK.js → chunk-5PVQ4SRS.js} +78 -6
- package/dist/{chunk-DYIM5TJT.js → chunk-5QKCQQ3E.js} +262 -6
- package/dist/{chunk-TYPGUK6W.js → chunk-5T7RBWN2.js} +111 -5
- package/dist/{chunk-IIZWH4XA.js → chunk-774ILSRL.js} +2 -2
- package/dist/chunk-7C6RYZGQ.js +391 -0
- package/dist/{chunk-TANS5ZJS.js → chunk-AD7Y7STJ.js} +3 -3
- package/dist/{chunk-RWSI4YD7.js → chunk-AEYBF3TB.js} +33 -12
- package/dist/{chunk-DGSYXYMX.js → chunk-AMKHQW3C.js} +2 -2
- package/dist/{chunk-VWZOAB7K.js → chunk-B5XRQOLB.js} +7 -7
- package/dist/{chunk-WXY7KU3G.js → chunk-BVDVID7E.js} +2 -2
- package/dist/{chunk-PMDBGQSJ.js → chunk-CA42X6KT.js} +2 -2
- package/dist/{chunk-HLE42MG7.js → chunk-D73KXYPF.js} +3 -3
- package/dist/{chunk-5Q2VVUKB.js → chunk-DG4M6ZUE.js} +3 -3
- package/dist/{chunk-ME6CCNFO.js → chunk-EBOC7MT3.js} +6 -6
- package/dist/{chunk-MXKJU4JB.js → chunk-ECUO3KDP.js} +48 -7
- package/dist/{chunk-26LEYJZH.js → chunk-FALJGAWU.js} +2 -2
- package/dist/{chunk-GWS3VEIW.js → chunk-FWDFM5ZU.js} +24 -3
- package/dist/{chunk-7RGZWPB6.js → chunk-GAYUJ7LE.js} +67 -13
- package/dist/{chunk-VCBR6CU7.js → chunk-HAY4ZE2P.js} +2 -2
- package/dist/{chunk-FBVTI2TJ.js → chunk-HCBCAYZU.js} +11 -130
- package/dist/{chunk-WSB3FPX7.js → chunk-HJB5IUKP.js} +32 -136
- package/dist/{chunk-J3YUBZWY.js → chunk-HKO36JWF.js} +33 -5
- package/dist/{chunk-E77JEWSD.js → chunk-HPCTNZM2.js} +6 -36
- package/dist/{chunk-FJ3H4MN5.js → chunk-IHKBWSXF.js} +2 -2
- package/dist/{chunk-NMPKI6XL.js → chunk-JEQQR47K.js} +37 -18
- package/dist/{chunk-3BINW3FP.js → chunk-KV2AOLDF.js} +24 -4
- package/dist/{chunk-YS5VLNH5.js → chunk-LXPJXFM5.js} +7 -7
- package/dist/{chunk-7RFXX52T.js → chunk-MIX5N5AC.js} +271 -41
- package/dist/{chunk-K4XHGFR5.js → chunk-MLOK6ZOS.js} +1297 -218
- package/dist/{chunk-ZNLWCMVZ.js → chunk-MV2VUEJC.js} +2 -2
- package/dist/{chunk-MVVUPGPW.js → chunk-MXHC5QYU.js} +6 -6
- package/dist/{chunk-5H3GB5BO.js → chunk-N3PBVRTZ.js} +4 -382
- package/dist/{chunk-2HFZQUHL.js → chunk-N5XKWMDW.js} +17 -7
- package/dist/{chunk-5C3AQNDW.js → chunk-NNNWO6F2.js} +124 -36
- package/dist/{chunk-GU2UIAFZ.js → chunk-NQ6UCCOD.js} +3 -3
- package/dist/{chunk-N22QMJKY.js → chunk-NZU6YDNV.js} +4 -4
- package/dist/{chunk-ZVJ5BLO2.js → chunk-O6I4CIEU.js} +151 -13
- package/dist/{chunk-XN3L4EYL.js → chunk-OEDBCISO.js} +2 -2
- package/dist/{chunk-VAWNZU7Z.js → chunk-P3JGPQFL.js} +2 -2
- package/dist/{chunk-IJ7RPIYJ.js → chunk-PNY46YEY.js} +20 -3
- package/dist/{chunk-U6MBIEMB.js → chunk-PZ4I4JE2.js} +56 -35
- package/dist/{chunk-GPIEI3LY.js → chunk-QQ7EKM72.js} +2 -2
- package/dist/{chunk-WLFILSD5.js → chunk-R7LNVMCS.js} +66 -28
- package/dist/{chunk-GOXNB3AO.js → chunk-RAPCMZL4.js} +75 -4
- package/dist/chunk-RKKLTLYB.js +45 -0
- package/dist/{chunk-TT36MB5S.js → chunk-RKRLDWD3.js} +3 -1
- package/dist/{chunk-TTHACPOM.js → chunk-S4COXYBG.js} +456 -18
- package/dist/{chunk-WWCZ5F23.js → chunk-T3Z6VAAF.js} +69 -10
- package/dist/{chunk-GN57SG4G.js → chunk-TD7UE2L5.js} +9 -7
- package/dist/{chunk-TLQJPP24.js → chunk-TEO2TLVN.js} +523 -322
- package/dist/{chunk-FCSXB6T2.js → chunk-UOSL25KY.js} +14 -2
- package/dist/{chunk-KTYTFRMB.js → chunk-VKBMFOYV.js} +17 -15
- package/dist/{chunk-PT7HYKEM.js → chunk-VO2LKSTM.js} +2 -2
- package/dist/{chunk-P43ETTHK.js → chunk-VPTUJU4P.js} +2 -2
- package/dist/{chunk-WEH5XRJQ.js → chunk-WIE7ZOSW.js} +2 -2
- package/dist/{chunk-EMYUUSFG.js → chunk-WXCJ7VME.js} +5 -5
- package/dist/{chunk-4DGYLA73.js → chunk-XDOQXGFO.js} +22 -7
- package/dist/{chunk-JOZYP4GM.js → chunk-YKOFT37S.js} +5 -5
- package/dist/chunk-YSEHGPCT.js +127 -0
- package/dist/{chunk-HFSBBKSQ.js → chunk-YW7UVM5V.js} +138 -3
- package/dist/cli/index.js +27 -27
- package/dist/{clio-QVTYJ57A.js → clio-LT5V7SSZ.js} +6 -6
- package/dist/{code-nav-FGGFIE7L.js → code-nav-LMW275PA.js} +4 -4
- package/dist/{config-LW5IJFQN.js → config-RXS5T3JT.js} +71 -43
- package/dist/{configure-7XIZCOU4.js → configure-2WYWSCSD.js} +14 -15
- package/dist/{context-Y6Y7QPR6.js → context-I3BTOTCS.js} +12 -12
- package/dist/{context-L3WL3X7K.js → context-MVOORGMF.js} +34 -33
- package/dist/{context-N52ZA626.js → context-PALKKQYL.js} +20 -20
- package/dist/{context-clear-MBQRLSDQ.js → context-clear-N2WOYZ2K.js} +34 -33
- package/dist/{context-index-HVMFQHK3.js → context-index-HNG3MOME.js} +2 -2
- package/dist/{context-working-set-GS6DSO7F.js → context-working-set-MIEVECVZ.js} +10 -11
- package/dist/{dispatch-runner-22ZCNOM3.js → dispatch-runner-VVA4SRRH.js} +34 -33
- package/dist/doctor-TWBWFK5V.js +165 -0
- package/dist/{eval-BEC2WHDA.js → eval-IJ5VEZDJ.js} +2016 -142
- package/dist/{evidence-REJUMSKM.js → evidence-L5APPXNV.js} +29 -28
- package/dist/{evolve-PY5ZBA5K.js → evolve-RGNKFJ52.js} +29 -28
- package/dist/{extensions-HVKU65YU.js → extensions-7WYWUX5A.js} +9 -3
- package/dist/{fleet-7WZEWRFA.js → fleet-6CNVBZZP.js} +87 -55
- package/dist/{fleet-commands-UVHWM76J.js → fleet-commands-L2SXSYEI.js} +6 -6
- package/dist/{fleet-graph-6ULH7PES.js → fleet-graph-2J3OOIPO.js} +14 -12
- package/dist/{fleet-preflight-J53T6CCE.js → fleet-preflight-CZRJ4JP5.js} +3 -4
- package/dist/{fleet-validate-72PC4SLA.js → fleet-validate-C5RI6DP7.js} +16 -15
- package/dist/{init-OG3TPGQG.js → init-VBN2ACVA.js} +50 -48
- package/dist/{library-CNTMPLRF.js → library-JHGUMLY2.js} +13 -11
- package/dist/{memory-6IS7F275.js → memory-K4OQIYWG.js} +31 -30
- package/dist/{models-ENRJDA5W.js → models-2NCZUWDD.js} +23 -22
- package/dist/{monitor-XLDVO7TN.js → monitor-MMVTJABD.js} +35 -34
- package/dist/{orchestrator-6KSPYRHA.js → orchestrator-ZKBPCHW6.js} +1627 -294
- package/dist/{reset-RZ4ER727.js → reset-DD5JGOY3.js} +3 -3
- package/dist/{run-Y2CNK5RU.js → run-QEGNX7FL.js} +56 -55
- package/dist/{share-A55GYP6Z.js → share-JKD3BQMW.js} +13 -11
- package/dist/{skills-ALC5J6AT.js → skills-LMQIKDOZ.js} +14 -12
- package/dist/{skills-eval-JPBEBYQU.js → skills-eval-I7X2774U.js} +34 -32
- package/dist/{steer-GGWFUJUD.js → steer-CF5TDANS.js} +3 -3
- package/dist/{support-MIETYA5E.js → support-I7LOJLIF.js} +4 -4
- package/dist/{targets-VGNXIR3S.js → targets-RUSR6B5Z.js} +58 -32
- package/dist/{terminal-lease-WOBR64YA.js → terminal-lease-QYVORFR4.js} +6 -4
- package/dist/{trace-PNCASAXC.js → trace-ODOQIVIW.js} +61 -6
- package/dist/{upgrade-FUSUAGHR.js → upgrade-XANW3FXB.js} +17 -16
- package/dist/{usage-N4MKVHKD.js → usage-4H7ZRXQT.js} +88 -44
- package/dist/{verifiers-YAWOJ3H2.js → verifiers-UZXNBZEB.js} +6 -6
- package/dist/{verify-LTDHYBGY.js → verify-BVKWTNDL.js} +5 -5
- package/dist/{wiki-generate-6M7GHTBJ.js → wiki-generate-MY7WV2QI.js} +49 -47
- package/dist/worker/entry.js +29 -33
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +1 -1
- package/docs/artifact-versions.md +6 -1
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +23 -2
- package/docs/commands-and-modes.md +1 -1
- package/docs/configuration-and-targets.md +30 -3
- package/docs/context-engine.md +63 -4
- package/docs/documentation-coverage.md +3 -3
- package/docs/documentation-guide.md +1 -1
- package/docs/environment-variables.md +2 -0
- package/docs/eval-runner.md +262 -11
- package/docs/evals-internal.md +72 -2
- package/docs/evidence-and-memory.md +11 -10
- package/docs/evolution.md +1 -1
- package/docs/extensions-and-sharing.md +3 -1
- package/docs/fleet-dispatch.md +4 -4
- package/docs/installation-and-lifecycle.md +1 -1
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +1 -1
- package/docs/observability.md +53 -2
- 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 +1 -1
- package/docs/scientific-validation.md +1 -1
- package/docs/skills-marketplace.md +1 -1
- package/docs/tool-usage.md +1 -1
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +87 -0
- package/docs/tui-design.md +1 -1
- package/docs/worker-dispatch-mechanics.md +1 -1
- package/package.json +2 -1
- package/src/cli/agents.ts +1 -1
- package/src/cli/config-inspect.ts +33 -6
- package/src/cli/config.ts +1 -1
- package/src/cli/doctor-state-size.ts +82 -0
- package/src/cli/doctor.ts +3 -1
- package/src/cli/eval.ts +80 -16
- package/src/cli/extensions.ts +5 -1
- package/src/cli/fleet.ts +32 -3
- package/src/cli/targets.ts +44 -13
- package/src/cli/trace.ts +63 -4
- package/src/cli/usage.ts +63 -14
- package/src/core/bus-events.ts +29 -1
- package/src/core/cache-telemetry.ts +42 -0
- package/src/core/config.ts +18 -0
- package/src/core/defaults.ts +36 -6
- package/src/core/endpoint-key.ts +27 -0
- package/src/core/residency-target-key.ts +25 -0
- package/src/core/response-schema.ts +36 -2
- package/src/domains/config/classify.ts +3 -0
- package/src/domains/context/codewiki/coordinator.ts +12 -4
- package/src/domains/dispatch/admission.ts +40 -3
- package/src/domains/dispatch/capacity-lease.ts +98 -9
- package/src/domains/dispatch/contract.ts +11 -0
- package/src/domains/dispatch/execution-plan.ts +44 -4
- package/src/domains/dispatch/extension.ts +166 -42
- package/src/domains/dispatch/fleet-run.ts +23 -3
- package/src/domains/dispatch/heartbeat.ts +32 -8
- package/src/domains/dispatch/index.ts +3 -0
- package/src/domains/dispatch/orphan-recovery.ts +5 -0
- package/src/domains/dispatch/reservation-store.ts +116 -8
- package/src/domains/dispatch/state.ts +4 -0
- 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 +355 -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/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 +74 -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/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 -0
- package/src/domains/memory/task-bank-promotion.ts +64 -0
- package/src/domains/memory/task-memory-policy.ts +77 -8
- 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 +2 -0
- package/src/domains/middleware/index.ts +1 -0
- package/src/domains/middleware/memory-intervention.ts +69 -5
- package/src/domains/middleware/memory-step-endpoint.ts +71 -0
- package/src/domains/observability/background-memory-usage.ts +140 -0
- package/src/domains/observability/cost.ts +1 -1
- package/src/domains/observability/index.ts +7 -0
- package/src/domains/observability/out-of-turn-usage.ts +51 -2
- package/src/domains/observability/trace-store.ts +192 -2
- package/src/domains/prompts/compiler.ts +100 -13
- package/src/domains/providers/endpoint-capacity.ts +96 -0
- package/src/domains/providers/index.ts +10 -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/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/types/capability-flags.ts +2 -0
- package/src/domains/providers/types/target-descriptor.ts +2 -0
- package/src/domains/resources/prompts/loader.ts +95 -33
- 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/engine/acp/adapter.ts +18 -3
- 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/provider-payload.ts +29 -1
- package/src/entry/orchestrator.ts +176 -30
- 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 +40 -10
- package/src/interactive/cost-overlay.ts +64 -6
- package/src/interactive/dispatch-board.ts +84 -12
- package/src/interactive/fleet-run-preview.ts +41 -15
- package/src/interactive/handoff-round.ts +41 -2
- package/src/interactive/interactive-application.ts +24 -1
- package/src/interactive/interactive-input-runtime.ts +8 -0
- package/src/interactive/interactive-presentation.ts +4 -0
- package/src/interactive/interactive-shell.ts +20 -17
- package/src/interactive/interactive-slash-runtime.ts +27 -4
- package/src/interactive/memory-overlay.ts +8 -0
- package/src/interactive/mutation-preview.ts +295 -0
- package/src/interactive/overlay-general-openers.ts +16 -0
- package/src/interactive/overlay-key-routing.ts +38 -0
- package/src/interactive/overlay-lifecycle.ts +38 -5
- package/src/interactive/overlay-permission-lifecycle.ts +22 -2
- package/src/interactive/overlay-session-lifecycle.ts +73 -9
- package/src/interactive/overlays/ask-user.ts +91 -19
- package/src/interactive/overlays/help-reference.ts +4 -0
- package/src/interactive/overlays/prompts.ts +11 -1
- package/src/interactive/overlays/settings.ts +35 -1
- 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/tool-execution.ts +4 -0
- package/src/interactive/side-question.ts +58 -1
- 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/terminal-lease.ts +2 -0
- package/src/interactive/turn-context.ts +299 -31
- 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/view-overlay.ts +28 -3
- package/src/tools/ask-user.ts +43 -2
- package/src/tools/dispatch-plan.ts +17 -9
- package/src/tools/dispatch-scout.ts +1 -1
- package/src/tools/registry.ts +16 -0
- package/dist/chunk-AOCYTWAV.js +0 -449
- package/dist/chunk-HWUFFB6L.js +0 -83
- package/dist/chunk-R346GLFC.js +0 -31
- package/dist/doctor-M7YEDGAE.js +0 -91
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { createHash } from "node:crypto";
|
|
10
|
-
import { mkdirSync } from "node:fs";
|
|
10
|
+
import { mkdirSync, statSync } from "node:fs";
|
|
11
11
|
import { createRequire } from "node:module";
|
|
12
12
|
import { hostname } from "node:os";
|
|
13
13
|
import { dirname, join } from "node:path";
|
|
@@ -27,6 +27,32 @@ export const TRACE_DATABASE_FILE = "trace.sqlite";
|
|
|
27
27
|
export const TRACE_EVENT_POLL_LIMIT = 500;
|
|
28
28
|
export const TRACE_PAYLOAD_LIMIT_BYTES = 16 * 1024;
|
|
29
29
|
export const TRACE_WRITE_QUEUE_LIMIT = 2048;
|
|
30
|
+
export const TRACE_RETENTION_DAYS_ENV = "CLIO_CODER_TRACE_RETENTION_DAYS";
|
|
31
|
+
export const TRACE_MAX_BYTES_ENV = "CLIO_CODER_TRACE_MAX_BYTES";
|
|
32
|
+
|
|
33
|
+
export interface TraceRetentionPolicy {
|
|
34
|
+
maxAgeDays: number;
|
|
35
|
+
maxBytes: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface TracePruneResult {
|
|
39
|
+
runsRemoved: number;
|
|
40
|
+
rowsRemoved: number;
|
|
41
|
+
bytesBefore: number;
|
|
42
|
+
bytesAfter: number;
|
|
43
|
+
bytesRemoved: number;
|
|
44
|
+
vacuumed: boolean;
|
|
45
|
+
protectedRuns: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Thirty days or 128 MiB, whichever limit the mirror reaches first. */
|
|
49
|
+
export const DEFAULT_TRACE_RETENTION_POLICY: Readonly<TraceRetentionPolicy> = Object.freeze({
|
|
50
|
+
maxAgeDays: 30,
|
|
51
|
+
maxBytes: 128 * 1024 * 1024,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
55
|
+
const VACUUM_RECLAIMABLE_FRACTION = 0.2;
|
|
30
56
|
|
|
31
57
|
type DatabaseSyncConstructor = typeof import("node:sqlite").DatabaseSync;
|
|
32
58
|
let sqliteConstructor: DatabaseSyncConstructor | null = null;
|
|
@@ -110,6 +136,40 @@ export function traceDatabasePath(stateDir: string): string {
|
|
|
110
136
|
return join(stateDir, TRACE_DATABASE_FILE);
|
|
111
137
|
}
|
|
112
138
|
|
|
139
|
+
/** Resolve the two operator-configurable retention bounds. */
|
|
140
|
+
export function resolveTraceRetentionPolicy(
|
|
141
|
+
overrides: Partial<TraceRetentionPolicy> = {},
|
|
142
|
+
environment: NodeJS.ProcessEnv = process.env,
|
|
143
|
+
): TraceRetentionPolicy {
|
|
144
|
+
const maxAgeDays =
|
|
145
|
+
overrides.maxAgeDays ??
|
|
146
|
+
parsePositiveRetentionNumber(environment[TRACE_RETENTION_DAYS_ENV], TRACE_RETENTION_DAYS_ENV, 1);
|
|
147
|
+
const maxBytes =
|
|
148
|
+
overrides.maxBytes ??
|
|
149
|
+
parsePositiveRetentionNumber(environment[TRACE_MAX_BYTES_ENV], TRACE_MAX_BYTES_ENV, 1024 * 1024);
|
|
150
|
+
return {
|
|
151
|
+
maxAgeDays: requirePositiveRetentionNumber(maxAgeDays, TRACE_RETENTION_DAYS_ENV, 1),
|
|
152
|
+
maxBytes: requirePositiveRetentionNumber(maxBytes, TRACE_MAX_BYTES_ENV, 1024 * 1024),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function parsePositiveRetentionNumber(raw: string | undefined, name: string, fallback: number): number {
|
|
157
|
+
if (raw === undefined || raw.trim().length === 0) {
|
|
158
|
+
return name === TRACE_RETENTION_DAYS_ENV
|
|
159
|
+
? DEFAULT_TRACE_RETENTION_POLICY.maxAgeDays
|
|
160
|
+
: DEFAULT_TRACE_RETENTION_POLICY.maxBytes;
|
|
161
|
+
}
|
|
162
|
+
const value = Number(raw);
|
|
163
|
+
return requirePositiveRetentionNumber(value, name, fallback);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function requirePositiveRetentionNumber(value: number, name: string, minimum: number): number {
|
|
167
|
+
if (!Number.isSafeInteger(value) || value < minimum) {
|
|
168
|
+
throw new Error(`${name} must be an integer of at least ${minimum}`);
|
|
169
|
+
}
|
|
170
|
+
return value;
|
|
171
|
+
}
|
|
172
|
+
|
|
113
173
|
export class TraceSchemaVersionError extends Error {
|
|
114
174
|
constructor(readonly found: number | null) {
|
|
115
175
|
super(
|
|
@@ -494,8 +554,13 @@ function reconcileAbandonedRuns(db: DatabaseSync): void {
|
|
|
494
554
|
|
|
495
555
|
export class TraceStore {
|
|
496
556
|
readonly db: DatabaseSync;
|
|
557
|
+
private readonly retention: TraceRetentionPolicy;
|
|
497
558
|
|
|
498
|
-
constructor(
|
|
559
|
+
constructor(
|
|
560
|
+
readonly path: string,
|
|
561
|
+
options: { retention?: Partial<TraceRetentionPolicy> } = {},
|
|
562
|
+
) {
|
|
563
|
+
this.retention = resolveTraceRetentionPolicy(options.retention);
|
|
499
564
|
mkdirSync(dirname(path), { recursive: true });
|
|
500
565
|
this.db = new (databaseSyncConstructor())(path);
|
|
501
566
|
applyConnectionPragmas(this.db);
|
|
@@ -523,6 +588,86 @@ export class TraceStore {
|
|
|
523
588
|
}
|
|
524
589
|
}
|
|
525
590
|
|
|
591
|
+
/**
|
|
592
|
+
* Remove whole terminal runs, including all of their dependent rows.
|
|
593
|
+
*
|
|
594
|
+
* Age pruning runs first. If the allocated database is still above the byte
|
|
595
|
+
* limit, the oldest remaining terminal runs are removed until the live page
|
|
596
|
+
* set fits or only queued/running runs remain. A live run is never a candidate.
|
|
597
|
+
*/
|
|
598
|
+
prune(policy: Partial<TraceRetentionPolicy> = this.retention, now = new Date().toISOString()): TracePruneResult {
|
|
599
|
+
const resolved = resolveTraceRetentionPolicy(policy);
|
|
600
|
+
const nowMs = Date.parse(now);
|
|
601
|
+
if (!Number.isFinite(nowMs)) throw new Error(`trace prune time is invalid: ${now}`);
|
|
602
|
+
const bytesBefore = traceDatabaseFootprintBytes(this.path);
|
|
603
|
+
let rowsRemoved = 0;
|
|
604
|
+
let runsRemoved = 0;
|
|
605
|
+
const removed = new Set<string>();
|
|
606
|
+
const cutoff = new Date(Math.max(0, nowMs - resolved.maxAgeDays * MILLISECONDS_PER_DAY)).toISOString();
|
|
607
|
+
|
|
608
|
+
const ageCandidates = this.db
|
|
609
|
+
.prepare(
|
|
610
|
+
"SELECT run_id FROM runs WHERE status IN ('success','fail') AND ended_at IS NOT NULL AND ended_at < ? ORDER BY ended_at, started_at, run_id",
|
|
611
|
+
)
|
|
612
|
+
.all(cutoff) as { run_id: string }[];
|
|
613
|
+
if (ageCandidates.length > 0) {
|
|
614
|
+
this.transaction(() => {
|
|
615
|
+
for (const candidate of ageCandidates) {
|
|
616
|
+
rowsRemoved += deleteTraceRun(this.db, candidate.run_id);
|
|
617
|
+
runsRemoved += 1;
|
|
618
|
+
removed.add(candidate.run_id);
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
let pages = tracePageStats(this.db);
|
|
624
|
+
if (pages.usedBytes > resolved.maxBytes) {
|
|
625
|
+
const sizeCandidates = this.db
|
|
626
|
+
.prepare(
|
|
627
|
+
"SELECT run_id FROM runs WHERE status IN ('success','fail') AND ended_at IS NOT NULL ORDER BY ended_at, started_at, run_id",
|
|
628
|
+
)
|
|
629
|
+
.all() as { run_id: string }[];
|
|
630
|
+
this.transaction(() => {
|
|
631
|
+
for (const candidate of sizeCandidates) {
|
|
632
|
+
if (pages.usedBytes <= resolved.maxBytes) break;
|
|
633
|
+
if (removed.has(candidate.run_id)) continue;
|
|
634
|
+
rowsRemoved += deleteTraceRun(this.db, candidate.run_id);
|
|
635
|
+
runsRemoved += 1;
|
|
636
|
+
removed.add(candidate.run_id);
|
|
637
|
+
pages = tracePageStats(this.db);
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
pages = tracePageStats(this.db);
|
|
643
|
+
const reclaimableFraction = pages.pageCount === 0 ? 0 : pages.freePages / pages.pageCount;
|
|
644
|
+
const sizeNeedsReclaim = pages.allocatedBytes > resolved.maxBytes && pages.freePages > 0;
|
|
645
|
+
const vacuumed =
|
|
646
|
+
rowsRemoved > 0 && pages.freePages > 0 && (reclaimableFraction >= VACUUM_RECLAIMABLE_FRACTION || sizeNeedsReclaim);
|
|
647
|
+
if (vacuumed) {
|
|
648
|
+
this.db.exec("VACUUM");
|
|
649
|
+
this.db.prepare("PRAGMA wal_checkpoint(TRUNCATE)").get();
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
const protectedRuns = Number(
|
|
653
|
+
(
|
|
654
|
+
this.db.prepare("SELECT COUNT(*) AS count FROM runs WHERE status IN ('queued','running')").get() as {
|
|
655
|
+
count: number | bigint;
|
|
656
|
+
}
|
|
657
|
+
).count,
|
|
658
|
+
);
|
|
659
|
+
const bytesAfter = traceDatabaseFootprintBytes(this.path);
|
|
660
|
+
return {
|
|
661
|
+
runsRemoved,
|
|
662
|
+
rowsRemoved,
|
|
663
|
+
bytesBefore,
|
|
664
|
+
bytesAfter,
|
|
665
|
+
bytesRemoved: Math.max(0, bytesBefore - bytesAfter),
|
|
666
|
+
vacuumed,
|
|
667
|
+
protectedRuns,
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
|
|
526
671
|
upsertRun(input: DispatchEnqueuedPayload, at = new Date().toISOString()): void {
|
|
527
672
|
this.transaction(() => {
|
|
528
673
|
this.db
|
|
@@ -859,6 +1004,7 @@ export class TraceStore {
|
|
|
859
1004
|
startedAt: at,
|
|
860
1005
|
});
|
|
861
1006
|
});
|
|
1007
|
+
this.prune(this.retention, at);
|
|
862
1008
|
}
|
|
863
1009
|
|
|
864
1010
|
/**
|
|
@@ -971,7 +1117,51 @@ export class TraceStore {
|
|
|
971
1117
|
startedAt: input.at,
|
|
972
1118
|
});
|
|
973
1119
|
});
|
|
1120
|
+
this.prune(this.retention, input.at);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
interface TracePageStats {
|
|
1125
|
+
pageCount: number;
|
|
1126
|
+
freePages: number;
|
|
1127
|
+
allocatedBytes: number;
|
|
1128
|
+
usedBytes: number;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
function tracePageStats(db: DatabaseSync): TracePageStats {
|
|
1132
|
+
const pageSize = Number((db.prepare("PRAGMA page_size").get() as { page_size: number | bigint }).page_size);
|
|
1133
|
+
const pageCount = Number((db.prepare("PRAGMA page_count").get() as { page_count: number | bigint }).page_count);
|
|
1134
|
+
const freePages = Number(
|
|
1135
|
+
(db.prepare("PRAGMA freelist_count").get() as { freelist_count: number | bigint }).freelist_count,
|
|
1136
|
+
);
|
|
1137
|
+
return {
|
|
1138
|
+
pageCount,
|
|
1139
|
+
freePages,
|
|
1140
|
+
allocatedBytes: pageCount * pageSize,
|
|
1141
|
+
usedBytes: Math.max(0, pageCount - freePages) * pageSize,
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
function deleteTraceRun(db: DatabaseSync, runId: string): number {
|
|
1146
|
+
let rows = 0;
|
|
1147
|
+
for (const table of ["events", "envelopes", "gate_results", "agent_sessions", "processes", "phases", "runs"]) {
|
|
1148
|
+
const result = db.prepare(`DELETE FROM ${table} WHERE run_id=?`).run(runId);
|
|
1149
|
+
rows += Number(result.changes);
|
|
1150
|
+
}
|
|
1151
|
+
return rows;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
function traceDatabaseFootprintBytes(path: string): number {
|
|
1155
|
+
let total = 0;
|
|
1156
|
+
for (const candidate of [path, `${path}-wal`, `${path}-shm`]) {
|
|
1157
|
+
try {
|
|
1158
|
+
total += statSync(candidate).size;
|
|
1159
|
+
} catch (error) {
|
|
1160
|
+
const code = typeof error === "object" && error !== null && "code" in error ? String(error.code) : "";
|
|
1161
|
+
if (code !== "ENOENT") throw error;
|
|
1162
|
+
}
|
|
974
1163
|
}
|
|
1164
|
+
return total;
|
|
975
1165
|
}
|
|
976
1166
|
|
|
977
1167
|
export class TraceReader {
|
|
@@ -48,12 +48,22 @@ export interface SessionPromptInputs {
|
|
|
48
48
|
memorySection?: string;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Which section order `compile()` lays down. `volatility` is the product
|
|
53
|
+
* order; `legacy-0.3.8` reproduces the order shipped before issue #249 and
|
|
54
|
+
* exists so a test can prove the change is a pure permutation. Nothing in
|
|
55
|
+
* `src/` may pass `legacy-0.3.8`; the boundary is the test suite.
|
|
56
|
+
*/
|
|
57
|
+
export type SessionPromptSectionOrder = "volatility" | "legacy-0.3.8";
|
|
58
|
+
|
|
51
59
|
export interface CompileInputs {
|
|
52
60
|
identity: string;
|
|
53
61
|
operatingContract: string;
|
|
54
62
|
safety: string;
|
|
55
63
|
sessionInputs: SessionPromptInputs;
|
|
56
64
|
additionalFragments?: ReadonlyArray<RenderedPromptFragment>;
|
|
65
|
+
/** Test-only escape hatch; see `SessionPromptSectionOrder`. Defaults to `volatility`. */
|
|
66
|
+
sectionOrder?: SessionPromptSectionOrder;
|
|
57
67
|
}
|
|
58
68
|
|
|
59
69
|
/** Stable inputs for one mediated fleet worker's canonical system prompt. */
|
|
@@ -439,21 +449,93 @@ function renderProjectBlock(contextFiles: string | undefined): string {
|
|
|
439
449
|
return trimmedFiles.length === 0 ? "" : `# Project\n\n${trimmedFiles}`;
|
|
440
450
|
}
|
|
441
451
|
|
|
442
|
-
|
|
452
|
+
/**
|
|
453
|
+
* The rendered memory section already opens with its own `# Memory` heading
|
|
454
|
+
* (`domains/memory/prompt-section.ts`), so prepending one unconditionally put
|
|
455
|
+
* the header in the prompt twice. Callers that pass a bare body still get a
|
|
456
|
+
* header; callers that pass a rendered section keep the one they wrote.
|
|
457
|
+
*
|
|
458
|
+
* `legacyDuplicateHeader` reproduces the 0.3.8 behavior and is reachable only
|
|
459
|
+
* through `sectionOrder: "legacy-0.3.8"`, so the permutation test compares
|
|
460
|
+
* against the whole prompt 0.3.8 emitted rather than a half-corrected one.
|
|
461
|
+
*/
|
|
462
|
+
function renderMemoryBlock(memorySection: string | undefined, legacyDuplicateHeader = false): string {
|
|
443
463
|
const trimmed = memorySection?.trim() ?? "";
|
|
444
|
-
|
|
464
|
+
if (trimmed.length === 0) return "";
|
|
465
|
+
if (legacyDuplicateHeader) return `# Memory\n\n${trimmed}`;
|
|
466
|
+
return /^#\s+Memory\s*$/.test(trimmed.split("\n", 1)[0] ?? "") ? trimmed : `# Memory\n\n${trimmed}`;
|
|
445
467
|
}
|
|
446
468
|
|
|
447
469
|
function estimatePromptTokens(text: string): number {
|
|
448
470
|
return ceilChars(text.trim().length);
|
|
449
471
|
}
|
|
450
472
|
|
|
473
|
+
/**
|
|
474
|
+
* The session prompt's section order, stable prefix first (issue #249).
|
|
475
|
+
*
|
|
476
|
+
* The rule, and it is the only rule: a section goes as late as its
|
|
477
|
+
* volatility, and anything that reads a clock, a probe, or a mutable store
|
|
478
|
+
* goes after everything that does not. Every backend Clio targets caches by
|
|
479
|
+
* exact prefix and re-prefills from the earliest changed byte, so a section
|
|
480
|
+
* that can change between two turns must not sit ahead of sections that
|
|
481
|
+
* cannot. That is why `runtime` is last of the compiled sections: its
|
|
482
|
+
* `Context window: N` moves when the backend reloads a model or a
|
|
483
|
+
* co-residency clamp lands, and before this order a single changed digit
|
|
484
|
+
* re-prefilled the tool contract, the roster, the hints, memory, and the
|
|
485
|
+
* project context behind it. `memory` sits just ahead of it because an
|
|
486
|
+
* approved memory record rewrites that section mid-session, and
|
|
487
|
+
* `project-context` is stable for the session's lifetime.
|
|
488
|
+
*
|
|
489
|
+
* The tail fragments (`workspace-root`, `clio-repo-awareness`,
|
|
490
|
+
* `project-rules`, `operator-profile`) are appended after this list in their
|
|
491
|
+
* own order: path-scoped project rules grow mid-session by design, which is
|
|
492
|
+
* exactly why they belong at the very end.
|
|
493
|
+
*
|
|
494
|
+
* Moving an entry here is a deliberate cache decision. `tests/contracts/
|
|
495
|
+
* prompt-prefix-layout.test.ts` pins this list so the move has to be made on
|
|
496
|
+
* purpose.
|
|
497
|
+
*/
|
|
498
|
+
export const SESSION_PROMPT_SECTION_ORDER: ReadonlyArray<string> = [
|
|
499
|
+
"identity",
|
|
500
|
+
"operating-contract",
|
|
501
|
+
"delegation",
|
|
502
|
+
"skills",
|
|
503
|
+
"safety",
|
|
504
|
+
"tool-contract",
|
|
505
|
+
"fleet",
|
|
506
|
+
"retrieval-hints",
|
|
507
|
+
"project-context",
|
|
508
|
+
"memory",
|
|
509
|
+
"runtime",
|
|
510
|
+
];
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* The order shipped through 0.3.8, kept only so a test can prove the new order
|
|
514
|
+
* is a permutation of it rather than a rewrite. Never reachable from `src/`.
|
|
515
|
+
*/
|
|
516
|
+
export const LEGACY_SESSION_PROMPT_SECTION_ORDER: ReadonlyArray<string> = [
|
|
517
|
+
"identity",
|
|
518
|
+
"operating-contract",
|
|
519
|
+
"delegation",
|
|
520
|
+
"skills",
|
|
521
|
+
"safety",
|
|
522
|
+
"runtime",
|
|
523
|
+
"tool-contract",
|
|
524
|
+
"fleet",
|
|
525
|
+
"retrieval-hints",
|
|
526
|
+
"memory",
|
|
527
|
+
"project-context",
|
|
528
|
+
];
|
|
529
|
+
|
|
451
530
|
/**
|
|
452
531
|
* Compile the session system prompt. Identity and the operating contract
|
|
453
532
|
* render verbatim from disk fragments; safety renders a one-line directive
|
|
454
533
|
* plus the safety fragment body; everything else renders inline from typed
|
|
455
534
|
* SessionPromptInputs. Output is one string, one sha256, one token estimate,
|
|
456
535
|
* and a flat section breakdown for the /context overlay.
|
|
536
|
+
*
|
|
537
|
+
* Sections are laid down in `SESSION_PROMPT_SECTION_ORDER`, whose doc comment
|
|
538
|
+
* states the volatility rule that fixes it.
|
|
457
539
|
*/
|
|
458
540
|
export function compile(table: FragmentTable, inputs: CompileInputs): CompiledSessionPrompt {
|
|
459
541
|
const identity = lookupFragment(table, inputs.identity, "identity");
|
|
@@ -493,17 +575,22 @@ export function compile(table: FragmentTable, inputs: CompileInputs): CompiledSe
|
|
|
493
575
|
const delegation = sessionCanDispatch(session) ? table.byId.get("operating.delegation") : undefined;
|
|
494
576
|
const skills = sessionHasContext(session) ? table.byId.get("operating.skills") : undefined;
|
|
495
577
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
578
|
+
const legacy = inputs.sectionOrder === "legacy-0.3.8";
|
|
579
|
+
const rendered = new Map<string, string>([
|
|
580
|
+
["identity", identityBody],
|
|
581
|
+
["operating-contract", operatingContract.body],
|
|
582
|
+
["delegation", delegation?.body ?? ""],
|
|
583
|
+
["skills", skills?.body ?? ""],
|
|
584
|
+
["safety", renderSafetySection(safety, autonomyLevel)],
|
|
585
|
+
["runtime", renderRuntimeBlock(session)],
|
|
586
|
+
["tool-contract", renderToolContractBlock(session)],
|
|
587
|
+
["fleet", renderFleetBlock(session)],
|
|
588
|
+
["retrieval-hints", renderRetrievalHintsBlock(session)],
|
|
589
|
+
["memory", renderMemoryBlock(session.memorySection, legacy)],
|
|
590
|
+
["project-context", renderProjectBlock(session.contextFiles)],
|
|
591
|
+
]);
|
|
592
|
+
const order = legacy ? LEGACY_SESSION_PROMPT_SECTION_ORDER : SESSION_PROMPT_SECTION_ORDER;
|
|
593
|
+
for (const id of order) push(id, rendered.get(id) ?? "");
|
|
507
594
|
for (const fragment of inputs.additionalFragments ?? []) {
|
|
508
595
|
push(fragment.id, fragment.body);
|
|
509
596
|
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { canonicalEndpointUrl } from "../../core/endpoint-key.js";
|
|
2
|
+
import type { TargetStatus } from "./contract.js";
|
|
3
|
+
import type { TargetDescriptor } from "./types/target-descriptor.js";
|
|
4
|
+
|
|
5
|
+
export type EndpointCapacitySource = "override" | "discovered" | "local-native-default";
|
|
6
|
+
|
|
7
|
+
export interface EndpointCapacity {
|
|
8
|
+
key: string;
|
|
9
|
+
label: string;
|
|
10
|
+
limit: number;
|
|
11
|
+
source: EndpointCapacitySource;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Runtime ids whose request schedulers are intentionally not modeled as fixed local slots. */
|
|
15
|
+
const UNBOUNDED_LOCAL_NATIVE_RUNTIMES = new Set(["vllm", "sglang"]);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Canonical identity of the inference scheduler behind a configured target.
|
|
19
|
+
* Scheme, normalized host and port, and normalized base path participate. DNS
|
|
20
|
+
* aliases do not collapse because Clio cannot prove they reach the same server.
|
|
21
|
+
*/
|
|
22
|
+
export function canonicalEndpointKey(value: TargetDescriptor | string): string | null {
|
|
23
|
+
return canonicalEndpointUrl(typeof value === "string" ? value : value.url);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Compact operator-facing identity. A non-root base path remains visible. */
|
|
27
|
+
export function endpointLabel(endpointKey: string): string {
|
|
28
|
+
try {
|
|
29
|
+
const url = new URL(endpointKey);
|
|
30
|
+
return `${url.host}${url.pathname === "/" ? "" : url.pathname}`;
|
|
31
|
+
} catch {
|
|
32
|
+
return endpointKey;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function positiveInteger(value: unknown): number | undefined {
|
|
37
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Resolve the endpoint bound from configuration, cached discovery, or the local-native fallback. */
|
|
41
|
+
export function endpointCapacityForStatus(status: TargetStatus): EndpointCapacity | null {
|
|
42
|
+
const key = canonicalEndpointKey(status.target);
|
|
43
|
+
if (key === null) return null;
|
|
44
|
+
const override = positiveInteger(status.target.maxConcurrentRequests);
|
|
45
|
+
if (override !== undefined) return { key, label: endpointLabel(key), limit: override, source: "override" };
|
|
46
|
+
const discovered = positiveInteger(status.probeCapabilities?.parallelSlots);
|
|
47
|
+
if (discovered !== undefined) return { key, label: endpointLabel(key), limit: discovered, source: "discovered" };
|
|
48
|
+
if (status.runtime?.tier !== "local-native" || UNBOUNDED_LOCAL_NATIVE_RUNTIMES.has(status.runtime.id)) return null;
|
|
49
|
+
return { key, label: endpointLabel(key), limit: 1, source: "local-native-default" };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function sourceRank(source: EndpointCapacitySource): number {
|
|
53
|
+
return source === "override" ? 2 : source === "discovered" ? 1 : 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Resolve one conservative limit per scheduler, preferring an explicit override. */
|
|
57
|
+
export function endpointCapacitiesForStatuses(
|
|
58
|
+
statuses: ReadonlyArray<TargetStatus>,
|
|
59
|
+
): Readonly<Record<string, EndpointCapacity>> {
|
|
60
|
+
const capacities: Record<string, EndpointCapacity> = {};
|
|
61
|
+
for (const status of statuses) {
|
|
62
|
+
const candidate = endpointCapacityForStatus(status);
|
|
63
|
+
if (candidate === null) continue;
|
|
64
|
+
const current = capacities[candidate.key];
|
|
65
|
+
if (
|
|
66
|
+
current === undefined ||
|
|
67
|
+
sourceRank(candidate.source) > sourceRank(current.source) ||
|
|
68
|
+
(sourceRank(candidate.source) === sourceRank(current.source) && candidate.limit < current.limit)
|
|
69
|
+
) {
|
|
70
|
+
capacities[candidate.key] = candidate;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return capacities;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The orchestrator's own request lives only in this process. It deliberately
|
|
78
|
+
* never enters dispatch-admission.json because process exit releases it.
|
|
79
|
+
*/
|
|
80
|
+
const foregroundStreams = new Map<string, number>();
|
|
81
|
+
|
|
82
|
+
export function registerForegroundStream(endpointKey: string): () => void {
|
|
83
|
+
foregroundStreams.set(endpointKey, (foregroundStreams.get(endpointKey) ?? 0) + 1);
|
|
84
|
+
let held = true;
|
|
85
|
+
return () => {
|
|
86
|
+
if (!held) return;
|
|
87
|
+
held = false;
|
|
88
|
+
const next = (foregroundStreams.get(endpointKey) ?? 1) - 1;
|
|
89
|
+
if (next <= 0) foregroundStreams.delete(endpointKey);
|
|
90
|
+
else foregroundStreams.set(endpointKey, next);
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function foregroundStreamUsage(): Readonly<Record<string, number>> {
|
|
95
|
+
return Object.fromEntries(foregroundStreams);
|
|
96
|
+
}
|
|
@@ -27,6 +27,16 @@ export {
|
|
|
27
27
|
export { AGENT_ROLE_TOOLS_REQUIRED_REASON, mergeCapabilities, supportsAgentRoleTools } from "./capabilities.js";
|
|
28
28
|
export type { ProvidersContract, TargetHealth, TargetStatus } from "./contract.js";
|
|
29
29
|
export { isDispatchEligibleRuntime, isOrchestratorEligibleRuntime, isTargetEligibleRuntime } from "./eligibility.js";
|
|
30
|
+
export {
|
|
31
|
+
canonicalEndpointKey,
|
|
32
|
+
type EndpointCapacity,
|
|
33
|
+
type EndpointCapacitySource,
|
|
34
|
+
endpointCapacitiesForStatuses,
|
|
35
|
+
endpointCapacityForStatus,
|
|
36
|
+
endpointLabel,
|
|
37
|
+
foregroundStreamUsage,
|
|
38
|
+
registerForegroundStream,
|
|
39
|
+
} from "./endpoint-capacity.js";
|
|
30
40
|
export { ProvidersManifest } from "./manifest.js";
|
|
31
41
|
export type { ModelCapabilityPatchTarget } from "./model-capabilities.js";
|
|
32
42
|
export { applyModelCapabilityPatch, resolveModelCapabilities } from "./model-capabilities.js";
|