@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
package/src/cli/trace.ts
CHANGED
|
@@ -4,12 +4,15 @@ import { resolve } from "node:path";
|
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
5
|
import { clioStatePath } from "../core/xdg.js";
|
|
6
6
|
import {
|
|
7
|
+
DEFAULT_TRACE_RETENTION_POLICY,
|
|
8
|
+
resolveTraceRetentionPolicy,
|
|
7
9
|
TRACE_EVENT_POLL_LIMIT,
|
|
8
10
|
type TraceEventRow,
|
|
9
11
|
type TracePhaseRow,
|
|
10
12
|
type TraceProcessRow,
|
|
11
13
|
TraceReader,
|
|
12
14
|
type TraceRunRow,
|
|
15
|
+
TraceStore,
|
|
13
16
|
traceDatabasePath,
|
|
14
17
|
} from "../domains/observability/trace-store.js";
|
|
15
18
|
|
|
@@ -18,11 +21,15 @@ const HELP = `Usage:
|
|
|
18
21
|
clio-coder trace phases <runId> [--db PATH]
|
|
19
22
|
clio-coder trace tail <runId> [--follow] [--db PATH]
|
|
20
23
|
clio-coder trace procs <runId> [--db PATH]
|
|
24
|
+
clio-coder trace prune [--max-age-days N] [--max-bytes N] [--db PATH] [--json]
|
|
21
25
|
clio-coder trace sql <SELECT query> [--db PATH]
|
|
22
26
|
clio-coder trace ui [--db PATH] [--port N] source checkout only
|
|
23
27
|
|
|
24
28
|
The viewer ships with the repository, not the npm package, so from an installed
|
|
25
29
|
Clio the subcommands above are the way in. They read the same database.
|
|
30
|
+
Pruning keeps ${DEFAULT_TRACE_RETENTION_POLICY.maxAgeDays} days and at most ${DEFAULT_TRACE_RETENTION_POLICY.maxBytes} bytes by default. Set
|
|
31
|
+
CLIO_CODER_TRACE_RETENTION_DAYS or CLIO_CODER_TRACE_MAX_BYTES to change the automatic
|
|
32
|
+
policy; prune flags override those values for one command.
|
|
26
33
|
`;
|
|
27
34
|
|
|
28
35
|
interface ParsedTraceArgs {
|
|
@@ -34,6 +41,8 @@ interface ParsedTraceArgs {
|
|
|
34
41
|
limit: number;
|
|
35
42
|
port: number;
|
|
36
43
|
json: boolean;
|
|
44
|
+
maxAgeDays: number | undefined;
|
|
45
|
+
maxBytes: number | undefined;
|
|
37
46
|
}
|
|
38
47
|
|
|
39
48
|
function parseTraceArgs(args: string[]): ParsedTraceArgs {
|
|
@@ -44,11 +53,19 @@ function parseTraceArgs(args: string[]): ParsedTraceArgs {
|
|
|
44
53
|
let limit = 50;
|
|
45
54
|
let port = 0;
|
|
46
55
|
let json = false;
|
|
56
|
+
let maxAgeDays: number | undefined;
|
|
57
|
+
let maxBytes: number | undefined;
|
|
47
58
|
for (let index = 0; index < args.length; index += 1) {
|
|
48
59
|
const arg = args[index];
|
|
49
60
|
if (arg === "--follow") follow = true;
|
|
50
61
|
else if (arg === "--json") json = true;
|
|
51
|
-
else if (
|
|
62
|
+
else if (
|
|
63
|
+
arg === "--db" ||
|
|
64
|
+
arg === "--limit" ||
|
|
65
|
+
arg === "--port" ||
|
|
66
|
+
arg === "--max-age-days" ||
|
|
67
|
+
arg === "--max-bytes"
|
|
68
|
+
) {
|
|
52
69
|
const value = args[index + 1];
|
|
53
70
|
if (value === undefined) throw new Error(`${arg} requires a value`);
|
|
54
71
|
index += 1;
|
|
@@ -56,20 +73,25 @@ function parseTraceArgs(args: string[]): ParsedTraceArgs {
|
|
|
56
73
|
db = resolve(value);
|
|
57
74
|
dbExplicit = true;
|
|
58
75
|
} else if (arg === "--limit") limit = parseInteger(value, "--limit", 1, 500);
|
|
59
|
-
else port = parseInteger(value, "--port", 0, 65_535);
|
|
76
|
+
else if (arg === "--port") port = parseInteger(value, "--port", 0, 65_535);
|
|
77
|
+
else if (arg === "--max-age-days") maxAgeDays = parseInteger(value, arg, 1, 36_500);
|
|
78
|
+
else maxBytes = parseInteger(value, arg, 1024 * 1024, Number.MAX_SAFE_INTEGER);
|
|
60
79
|
} else if (arg?.startsWith("--db=")) {
|
|
61
80
|
db = resolve(arg.slice(5));
|
|
62
81
|
dbExplicit = true;
|
|
63
82
|
} else if (arg?.startsWith("--limit=")) limit = parseInteger(arg.slice(8), "--limit", 1, 500);
|
|
64
83
|
else if (arg?.startsWith("--port=")) port = parseInteger(arg.slice(7), "--port", 0, 65_535);
|
|
84
|
+
else if (arg?.startsWith("--max-age-days=")) maxAgeDays = parseInteger(arg.slice(15), "--max-age-days", 1, 36_500);
|
|
85
|
+
else if (arg?.startsWith("--max-bytes="))
|
|
86
|
+
maxBytes = parseInteger(arg.slice(12), "--max-bytes", 1024 * 1024, Number.MAX_SAFE_INTEGER);
|
|
65
87
|
else if (arg?.startsWith("-")) throw new Error(`unknown trace flag: ${arg}`);
|
|
66
88
|
else if (arg !== undefined) positional.push(arg);
|
|
67
89
|
}
|
|
68
|
-
return { positional, db, dbExplicit, follow, limit, port, json };
|
|
90
|
+
return { positional, db, dbExplicit, follow, limit, port, json, maxAgeDays, maxBytes };
|
|
69
91
|
}
|
|
70
92
|
|
|
71
93
|
/** Every subcommand `trace` answers to. Anything else is a usage error. */
|
|
72
|
-
const TRACE_COMMANDS = new Set(["runs", "phases", "tail", "procs", "sql", "ui"]);
|
|
94
|
+
const TRACE_COMMANDS = new Set(["runs", "phases", "tail", "procs", "prune", "sql", "ui"]);
|
|
73
95
|
|
|
74
96
|
/** The subcommands whose first positional is a run id. */
|
|
75
97
|
const TRACE_COMMANDS_NEEDING_RUN_ID = new Set(["phases", "tail", "procs"]);
|
|
@@ -132,6 +154,7 @@ export async function runTraceCommand(args: string[]): Promise<number> {
|
|
|
132
154
|
// the operator typed is a different claim, so a --db that is not there stays
|
|
133
155
|
// an error and says which path it means.
|
|
134
156
|
if (!existsSync(parsed.db)) return missingDatabase(parsed);
|
|
157
|
+
if (command === "prune") return runTracePrune(parsed);
|
|
135
158
|
|
|
136
159
|
let reader: TraceReader;
|
|
137
160
|
try {
|
|
@@ -189,6 +212,42 @@ export async function runTraceCommand(args: string[]): Promise<number> {
|
|
|
189
212
|
}
|
|
190
213
|
}
|
|
191
214
|
|
|
215
|
+
function runTracePrune(parsed: ParsedTraceArgs): number {
|
|
216
|
+
let policy: ReturnType<typeof resolveTraceRetentionPolicy>;
|
|
217
|
+
try {
|
|
218
|
+
policy = resolveTraceRetentionPolicy({
|
|
219
|
+
...(parsed.maxAgeDays === undefined ? {} : { maxAgeDays: parsed.maxAgeDays }),
|
|
220
|
+
...(parsed.maxBytes === undefined ? {} : { maxBytes: parsed.maxBytes }),
|
|
221
|
+
});
|
|
222
|
+
} catch (error) {
|
|
223
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
224
|
+
return 1;
|
|
225
|
+
}
|
|
226
|
+
let store: TraceStore;
|
|
227
|
+
try {
|
|
228
|
+
store = new TraceStore(parsed.db, { retention: policy });
|
|
229
|
+
} catch (error) {
|
|
230
|
+
process.stderr.write(`trace database: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
231
|
+
return 1;
|
|
232
|
+
}
|
|
233
|
+
try {
|
|
234
|
+
const result = store.prune(policy);
|
|
235
|
+
if (parsed.json) {
|
|
236
|
+
process.stdout.write(`${JSON.stringify({ policy, ...result }, null, 2)}\n`);
|
|
237
|
+
} else {
|
|
238
|
+
process.stdout.write(
|
|
239
|
+
`trace prune: removed ${result.runsRemoved.toLocaleString("en-US")} runs and ${result.rowsRemoved.toLocaleString("en-US")} rows; reclaimed ${result.bytesRemoved.toLocaleString("en-US")} bytes; VACUUM ${result.vacuumed ? "ran" : "not needed"}; protected ${result.protectedRuns.toLocaleString("en-US")} live runs\n`,
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
return 0;
|
|
243
|
+
} catch (error) {
|
|
244
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
245
|
+
return 1;
|
|
246
|
+
} finally {
|
|
247
|
+
store.close();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
192
251
|
async function tail(reader: TraceReader, runId: string, follow: boolean): Promise<void> {
|
|
193
252
|
let cursor = 0;
|
|
194
253
|
let idleTerminalPolls = 0;
|
package/src/cli/usage.ts
CHANGED
|
@@ -12,9 +12,12 @@ import { readEvidenceIndex } from "../domains/observability/evidence-index.js";
|
|
|
12
12
|
import { type OutOfTurnUsageRow, readOutOfTurnUsageRows } from "../domains/observability/out-of-turn-usage.js";
|
|
13
13
|
import { loadSkills } from "../domains/resources/index.js";
|
|
14
14
|
import {
|
|
15
|
+
foldPromptCacheTelemetry,
|
|
16
|
+
hasPromptCacheTelemetry,
|
|
15
17
|
type LedgerUsageCall,
|
|
16
18
|
ledgerUsageCalls,
|
|
17
19
|
listSessionLedgerRefs,
|
|
20
|
+
type PromptCacheTelemetry,
|
|
18
21
|
parseSessionEntries,
|
|
19
22
|
readAuditRows,
|
|
20
23
|
} from "../domains/session/index.js";
|
|
@@ -69,6 +72,8 @@ interface SessionUsage {
|
|
|
69
72
|
entriesInWindow: number;
|
|
70
73
|
/** Completed API calls this session recorded in the window, one per call. */
|
|
71
74
|
usageCalls: LedgerUsageCall[];
|
|
75
|
+
/** Backend prompt-cache facts persisted on assistant calls in the window. */
|
|
76
|
+
promptCache: PromptCacheTelemetry;
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
/** Per-call usage folded over one grouping (a model, or the whole window). */
|
|
@@ -102,32 +107,37 @@ function addResponseModelIdObservation(counts: ResponseModelIdObservationCounts,
|
|
|
102
107
|
|
|
103
108
|
/**
|
|
104
109
|
* How the folded calls split between the session's own turns and the rounds
|
|
105
|
-
* that were billed beside it. A `/btw` side question
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
110
|
+
* that were billed beside it. A `/btw` side question, a `/handoff` round, a
|
|
111
|
+
* session pre-warm, and a proactive-memory step are real spend and belong in
|
|
112
|
+
* the token and cost totals, but none of them is a turn: they never entered
|
|
113
|
+
* the session. `turns` therefore subtracts them from the folded row count,
|
|
114
|
+
* which is exactly what the `/cost` overlay does.
|
|
109
115
|
*/
|
|
110
116
|
interface CallOrigins {
|
|
111
117
|
rows: number;
|
|
112
118
|
sideQuestions: number;
|
|
113
119
|
handoffs: number;
|
|
120
|
+
prewarms: number;
|
|
121
|
+
backgroundMemory: number;
|
|
114
122
|
}
|
|
115
123
|
|
|
116
124
|
function emptyCallOrigins(): CallOrigins {
|
|
117
|
-
return { rows: 0, sideQuestions: 0, handoffs: 0 };
|
|
125
|
+
return { rows: 0, sideQuestions: 0, handoffs: 0, prewarms: 0, backgroundMemory: 0 };
|
|
118
126
|
}
|
|
119
127
|
|
|
120
128
|
function turnsOf(origins: CallOrigins): number {
|
|
121
|
-
return origins.rows - origins.sideQuestions - origins.handoffs;
|
|
129
|
+
return origins.rows - origins.sideQuestions - origins.handoffs - origins.prewarms - origins.backgroundMemory;
|
|
122
130
|
}
|
|
123
131
|
|
|
124
132
|
function hasLabelledCall(origins: CallOrigins): boolean {
|
|
125
|
-
return origins.sideQuestions > 0 || origins.handoffs > 0;
|
|
133
|
+
return origins.sideQuestions > 0 || origins.handoffs > 0 || origins.prewarms > 0 || origins.backgroundMemory > 0;
|
|
126
134
|
}
|
|
127
135
|
|
|
128
136
|
function addOutOfTurnRow(origins: CallOrigins, row: OutOfTurnUsageRow): void {
|
|
129
137
|
origins.rows += 1;
|
|
130
138
|
if (row.label === "side-question") origins.sideQuestions += 1;
|
|
139
|
+
else if (row.label === "prewarm") origins.prewarms += 1;
|
|
140
|
+
else if (row.label === "background-memory") origins.backgroundMemory += 1;
|
|
131
141
|
else origins.handoffs += 1;
|
|
132
142
|
}
|
|
133
143
|
|
|
@@ -435,6 +445,9 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
435
445
|
const usageRows = [...usageByModel.values()].sort(
|
|
436
446
|
(a, b) => b.totals.totalTokens - a.totals.totalTokens || a.providerId.localeCompare(b.providerId),
|
|
437
447
|
);
|
|
448
|
+
const cacheSessions = sessions
|
|
449
|
+
.filter((session) => hasPromptCacheTelemetry(session.promptCache))
|
|
450
|
+
.sort((a, b) => a.sessionId.localeCompare(b.sessionId));
|
|
438
451
|
|
|
439
452
|
const approvedMemory = memoryRecords.filter((record) => record.approved && record.rejectedAt === undefined);
|
|
440
453
|
const pendingMemory = memoryRecords.filter((record) => !record.approved && record.rejectedAt === undefined);
|
|
@@ -515,8 +528,8 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
515
528
|
emit({ kind: "fact", fact: "audit-tool-calls", value: auditToolCalls.length, blocked: auditBlocked.length });
|
|
516
529
|
if (usageMeasurable) {
|
|
517
530
|
// The origin split is emitted only when something out of turn was
|
|
518
|
-
// recorded, so a report over an archive with no `/btw
|
|
519
|
-
// round in it stays byte-identical to what it printed before.
|
|
531
|
+
// recorded, so a report over an archive with no `/btw`, `/handoff`, or
|
|
532
|
+
// pre-warm round in it stays byte-identical to what it printed before.
|
|
520
533
|
emit({
|
|
521
534
|
kind: "fact",
|
|
522
535
|
fact: "tokens",
|
|
@@ -526,6 +539,8 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
526
539
|
turns: turnsOf(callOrigins),
|
|
527
540
|
sideQuestions: callOrigins.sideQuestions,
|
|
528
541
|
handoffs: callOrigins.handoffs,
|
|
542
|
+
prewarms: callOrigins.prewarms,
|
|
543
|
+
backgroundMemorySteps: callOrigins.backgroundMemory,
|
|
529
544
|
}
|
|
530
545
|
: {}),
|
|
531
546
|
});
|
|
@@ -540,6 +555,15 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
540
555
|
...row.totals,
|
|
541
556
|
});
|
|
542
557
|
}
|
|
558
|
+
for (const session of cacheSessions) {
|
|
559
|
+
emit({
|
|
560
|
+
kind: "fact",
|
|
561
|
+
fact: "session-cache",
|
|
562
|
+
sessionId: session.sessionId,
|
|
563
|
+
uncachedPrefillTokens: session.promptCache.uncachedPrefillTokens,
|
|
564
|
+
verdictCounts: session.promptCache.verdictCounts,
|
|
565
|
+
});
|
|
566
|
+
}
|
|
543
567
|
}
|
|
544
568
|
for (const [tool, totals] of topTools) emit({ kind: "fact", fact: "top-tool", tool, ...totals });
|
|
545
569
|
for (const [shape, count] of topShapes) {
|
|
@@ -600,6 +624,10 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
600
624
|
out(` turns in window: ${turnsOf(callOrigins)}`);
|
|
601
625
|
if (callOrigins.sideQuestions > 0) out(` side questions in window: ${callOrigins.sideQuestions}`);
|
|
602
626
|
if (callOrigins.handoffs > 0) out(` handoffs in window: ${callOrigins.handoffs}`);
|
|
627
|
+
if (callOrigins.prewarms > 0) out(` pre-warms in window: ${callOrigins.prewarms}`);
|
|
628
|
+
if (callOrigins.backgroundMemory > 0) {
|
|
629
|
+
out(` background memory steps in window: ${callOrigins.backgroundMemory}`);
|
|
630
|
+
}
|
|
603
631
|
}
|
|
604
632
|
out(` provider-reported cost in window: $${usageTotals.costUsd.toFixed(4)}`);
|
|
605
633
|
}
|
|
@@ -639,6 +667,27 @@ export async function runUsageCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
639
667
|
),
|
|
640
668
|
);
|
|
641
669
|
}
|
|
670
|
+
if (cacheSessions.length > 0) {
|
|
671
|
+
out("");
|
|
672
|
+
out(" prompt cache by session (from backend timings and persisted verdicts)");
|
|
673
|
+
process.stdout.write(
|
|
674
|
+
indent(
|
|
675
|
+
formatColumns([
|
|
676
|
+
["session", "uncached prefill", "hot/partial/cold/small"],
|
|
677
|
+
...cacheSessions.map((session) => [
|
|
678
|
+
session.sessionId,
|
|
679
|
+
session.promptCache.uncachedPrefillTokens === null ? "n/a" : String(session.promptCache.uncachedPrefillTokens),
|
|
680
|
+
[
|
|
681
|
+
session.promptCache.verdictCounts.hot,
|
|
682
|
+
session.promptCache.verdictCounts.partial,
|
|
683
|
+
session.promptCache.verdictCounts.cold,
|
|
684
|
+
session.promptCache.verdictCounts.small,
|
|
685
|
+
].join("/"),
|
|
686
|
+
]),
|
|
687
|
+
]),
|
|
688
|
+
),
|
|
689
|
+
);
|
|
690
|
+
}
|
|
642
691
|
if (topTools.length > 0) {
|
|
643
692
|
out("");
|
|
644
693
|
out(" top tools (from receipt toolStats)");
|
|
@@ -865,6 +914,9 @@ async function readSessions(
|
|
|
865
914
|
}
|
|
866
915
|
const parsedEntries = parseSessionEntries(raw, ref.path);
|
|
867
916
|
diagnostics.malformedSessionLines += parsedEntries.errors.length;
|
|
917
|
+
const accountingEntries = parsedEntries.entries.filter(
|
|
918
|
+
(entry) => entry.kind === "modelChange" || inWindow(entry.timestamp, windowStart, windowEnd),
|
|
919
|
+
);
|
|
868
920
|
const usage: SessionUsage = {
|
|
869
921
|
sessionId: ref.sessionId,
|
|
870
922
|
cwdHash: ref.cwdHash,
|
|
@@ -874,11 +926,8 @@ async function readSessions(
|
|
|
874
926
|
// modelChange rows are kept regardless of the window: they carry no
|
|
875
927
|
// usage of their own, and dropping the ones that predate the window
|
|
876
928
|
// would attribute in-window calls to the wrong target.
|
|
877
|
-
usageCalls: ledgerUsageCalls(
|
|
878
|
-
|
|
879
|
-
(entry) => entry.kind === "modelChange" || inWindow(entry.timestamp, windowStart, windowEnd),
|
|
880
|
-
),
|
|
881
|
-
),
|
|
929
|
+
usageCalls: ledgerUsageCalls(accountingEntries),
|
|
930
|
+
promptCache: foldPromptCacheTelemetry(accountingEntries),
|
|
882
931
|
};
|
|
883
932
|
for (const entry of parsedEntries.entries) {
|
|
884
933
|
if (!inWindow(entry.timestamp, windowStart, windowEnd)) continue;
|
package/src/core/bus-events.ts
CHANGED
|
@@ -51,6 +51,7 @@ export const BusChannels = {
|
|
|
51
51
|
ToolBudgetExceeded: "safety.toolBudgetExceeded",
|
|
52
52
|
ProviderHealth: "provider.health",
|
|
53
53
|
RuntimeNotice: "runtime.notice",
|
|
54
|
+
ResidencyMutation: "residency.mutation",
|
|
54
55
|
DispatchScopeNotice: "dispatch.scopeNotice",
|
|
55
56
|
DispatchEnqueued: "dispatch.enqueued",
|
|
56
57
|
DispatchStarted: "dispatch.started",
|
|
@@ -64,6 +65,7 @@ export const BusChannels = {
|
|
|
64
65
|
ContextWarning: "context.warning",
|
|
65
66
|
ContextPruned: "context.pruned",
|
|
66
67
|
ContextRecalled: "context.recalled",
|
|
68
|
+
MemoryStepCompleted: "memory.stepCompleted",
|
|
67
69
|
AgentStatusChanged: "agent.status.changed",
|
|
68
70
|
RunAborted: "run.aborted",
|
|
69
71
|
BudgetAlert: "budget.alert",
|
|
@@ -100,6 +102,28 @@ export interface RuntimeNoticePayload {
|
|
|
100
102
|
detail?: Record<string, number | string | boolean>;
|
|
101
103
|
}
|
|
102
104
|
|
|
105
|
+
/**
|
|
106
|
+
* One completed proactive-memory model step, published on
|
|
107
|
+
* {@link BusChannels.MemoryStepCompleted}. It carries the endpoint the step
|
|
108
|
+
* called and nothing about what the step decided: the only consumer is the
|
|
109
|
+
* turn context, which stamps an expected-cold reason when a step ran between
|
|
110
|
+
* turns on the endpoint the chat target streams against.
|
|
111
|
+
*/
|
|
112
|
+
export interface MemoryStepCompletedPayload {
|
|
113
|
+
endpointKey: string;
|
|
114
|
+
targetId: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** A successful model load or eviction on one residency-managed endpoint. */
|
|
118
|
+
export interface ResidencyMutationPayload {
|
|
119
|
+
targetKey: string;
|
|
120
|
+
targetId: string;
|
|
121
|
+
runtimeId: string;
|
|
122
|
+
model: string;
|
|
123
|
+
operation: "load" | "evict";
|
|
124
|
+
at: number;
|
|
125
|
+
}
|
|
126
|
+
|
|
103
127
|
/**
|
|
104
128
|
* Window-resolution warning published on {@link BusChannels.ContextWarning}.
|
|
105
129
|
* Emitted on transitions only: `warning` carries the text when a warning
|
|
@@ -133,7 +157,7 @@ export type DispatchScopeNoticePayload =
|
|
|
133
157
|
};
|
|
134
158
|
|
|
135
159
|
export type ContextActivityKind = "context-init" | "context-clear" | "context-refresh" | "context-wiki" | "compaction";
|
|
136
|
-
export type ContextActivityPhase = "scan" | "codewiki" | "generate" | "clio-md" | "state" | "done";
|
|
160
|
+
export type ContextActivityPhase = "scan" | "codewiki" | "generate" | "clio-md" | "state" | "compact" | "done";
|
|
137
161
|
export type ContextActivityStatus = "started" | "running" | "completed" | "failed";
|
|
138
162
|
|
|
139
163
|
/** Structured progress for context operations. Interactive renders this as a live context island. */
|
|
@@ -505,6 +529,8 @@ export interface DispatchRunIdentity {
|
|
|
505
529
|
wireModelId: string;
|
|
506
530
|
runtimeId: string;
|
|
507
531
|
runtimeKind: RunKind;
|
|
532
|
+
/** Canonical inference scheduler and its resolved request-slot bound. */
|
|
533
|
+
endpoint?: { key: string; label: string; limit: number } | undefined;
|
|
508
534
|
/** Admitted invocation budget provenance for native workers. */
|
|
509
535
|
budget?: RunToolBudgetEnvelope | undefined;
|
|
510
536
|
/** Fleet node id the run was placed on; absent renders as the local node. */
|
|
@@ -761,6 +787,7 @@ export type BusPayloadMap = {
|
|
|
761
787
|
[BusChannels.ToolBudgetExceeded]: ToolBudgetExceededPayload;
|
|
762
788
|
[BusChannels.ProviderHealth]: ProviderHealthPayload;
|
|
763
789
|
[BusChannels.RuntimeNotice]: RuntimeNoticePayload;
|
|
790
|
+
[BusChannels.ResidencyMutation]: ResidencyMutationPayload;
|
|
764
791
|
[BusChannels.DispatchScopeNotice]: DispatchScopeNoticePayload;
|
|
765
792
|
[BusChannels.DispatchEnqueued]: DispatchEnqueuedPayload;
|
|
766
793
|
[BusChannels.DispatchStarted]: DispatchStartedPayload;
|
|
@@ -774,6 +801,7 @@ export type BusPayloadMap = {
|
|
|
774
801
|
[BusChannels.ContextWarning]: ContextWarningPayload;
|
|
775
802
|
[BusChannels.ContextPruned]: ContextPrunedPayload;
|
|
776
803
|
[BusChannels.ContextRecalled]: ContextRecalledPayload;
|
|
804
|
+
[BusChannels.MemoryStepCompleted]: MemoryStepCompletedPayload;
|
|
777
805
|
[BusChannels.AgentStatusChanged]: AgentStatusChangedPayload;
|
|
778
806
|
[BusChannels.RunAborted]: RunAbortedPayload;
|
|
779
807
|
[BusChannels.BudgetAlert]: BudgetAlertPayload;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** Cache classification for one backend completion call. */
|
|
2
|
+
export type BackendCacheVerdict = "hot" | "partial" | "cold" | "small";
|
|
3
|
+
|
|
4
|
+
/** Backend timing source that directly reports local prefill work. */
|
|
5
|
+
export type BackendTimingsSource = "llamacpp-timings" | "lmstudio-timings";
|
|
6
|
+
|
|
7
|
+
/** Normalized prefill and prediction timings reported by the serving backend. */
|
|
8
|
+
export interface BackendCompletionTimings {
|
|
9
|
+
promptTokens: number;
|
|
10
|
+
cachedTokens: number | null;
|
|
11
|
+
predictedTokens: number;
|
|
12
|
+
promptMs: number;
|
|
13
|
+
predictedMs: number;
|
|
14
|
+
source: BackendTimingsSource;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Per-session call counts grouped by backend cache verdict. */
|
|
18
|
+
export interface CacheVerdictCounts {
|
|
19
|
+
hot: number;
|
|
20
|
+
partial: number;
|
|
21
|
+
cold: number;
|
|
22
|
+
small: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function emptyCacheVerdictCounts(): CacheVerdictCounts {
|
|
26
|
+
return { hot: 0, partial: 0, cold: 0, small: 0 };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Return newly evaluated prefill tokens when the backend reports cache reads. */
|
|
30
|
+
export function uncachedPrefillTokens(backend: BackendCompletionTimings | null | undefined): number | null {
|
|
31
|
+
if (backend === null || backend === undefined || backend.cachedTokens === null) return null;
|
|
32
|
+
if (
|
|
33
|
+
!Number.isFinite(backend.promptTokens) ||
|
|
34
|
+
backend.promptTokens < 0 ||
|
|
35
|
+
!Number.isFinite(backend.cachedTokens) ||
|
|
36
|
+
backend.cachedTokens < 0 ||
|
|
37
|
+
backend.cachedTokens > backend.promptTokens
|
|
38
|
+
) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return backend.promptTokens - backend.cachedTokens;
|
|
42
|
+
}
|
package/src/core/config.ts
CHANGED
|
@@ -521,6 +521,7 @@ function validateTarget(issues: Issues, path: string, value: unknown): ClioSetti
|
|
|
521
521
|
"gateway",
|
|
522
522
|
"pricing",
|
|
523
523
|
"lmstudio",
|
|
524
|
+
"maxConcurrentRequests",
|
|
524
525
|
]);
|
|
525
526
|
const id = "id" in value ? expectString(issues, `${path}.id`, value.id) : undefined;
|
|
526
527
|
const runtime = "runtime" in value ? expectString(issues, `${path}.runtime`, value.runtime) : undefined;
|
|
@@ -566,6 +567,10 @@ function validateTarget(issues: Issues, path: string, value: unknown): ClioSetti
|
|
|
566
567
|
const v = validateLmStudioSettings(issues, `${path}.lmstudio`, value.lmstudio);
|
|
567
568
|
if (v !== undefined) target.lmstudio = v;
|
|
568
569
|
}
|
|
570
|
+
if ("maxConcurrentRequests" in value) {
|
|
571
|
+
const v = expectInteger(issues, `${path}.maxConcurrentRequests`, value.maxConcurrentRequests, { min: 1 });
|
|
572
|
+
if (v !== undefined) target.maxConcurrentRequests = v;
|
|
573
|
+
}
|
|
569
574
|
return target;
|
|
570
575
|
}
|
|
571
576
|
|
|
@@ -1004,6 +1009,7 @@ const TOP_LEVEL_KEYS = [
|
|
|
1004
1009
|
"keybindings",
|
|
1005
1010
|
"compaction",
|
|
1006
1011
|
"context",
|
|
1012
|
+
"prewarm",
|
|
1007
1013
|
"retry",
|
|
1008
1014
|
"guardrails",
|
|
1009
1015
|
] as const;
|
|
@@ -1589,6 +1595,18 @@ export function validateSettings(raw: unknown): SettingsValidationResult {
|
|
|
1589
1595
|
}
|
|
1590
1596
|
}
|
|
1591
1597
|
|
|
1598
|
+
if ("prewarm" in raw) {
|
|
1599
|
+
if (!isPlainObject(raw.prewarm)) {
|
|
1600
|
+
issues.add("prewarm", `expected a map, got ${describe(raw.prewarm)}`);
|
|
1601
|
+
} else {
|
|
1602
|
+
issues.unknownKeys("prewarm", raw.prewarm, ["enabled"]);
|
|
1603
|
+
if ("enabled" in raw.prewarm) {
|
|
1604
|
+
const v = expectBoolean(issues, "prewarm.enabled", raw.prewarm.enabled);
|
|
1605
|
+
if (v !== undefined) settings.prewarm.enabled = v;
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1592
1610
|
if ("retry" in raw) {
|
|
1593
1611
|
if (!isPlainObject(raw.retry)) {
|
|
1594
1612
|
issues.add("retry", `expected a map, got ${describe(raw.retry)}`);
|
package/src/core/defaults.ts
CHANGED
|
@@ -151,6 +151,21 @@ export interface WorkingSetSettings {
|
|
|
151
151
|
minEvictableTokens: number;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Prompt pre-warm settings (`prewarm`). On a local server prefill is the cost,
|
|
156
|
+
* and the prefix the next turn will send is fully known before the operator
|
|
157
|
+
* types anything: at session start, after a resume rebuilds the message array,
|
|
158
|
+
* and after a compaction settles. Clio sends that prefix to the backend right
|
|
159
|
+
* then so the slot's prefix cache already holds it when the real turn arrives.
|
|
160
|
+
*
|
|
161
|
+
* - enabled: master switch. The feature is off on every tier but
|
|
162
|
+
* `local-native` whatever this says, and off for workers and headless runs,
|
|
163
|
+
* because it buys latency for an operator watching a local server.
|
|
164
|
+
*/
|
|
165
|
+
export interface PrewarmSettings {
|
|
166
|
+
enabled: boolean;
|
|
167
|
+
}
|
|
168
|
+
|
|
154
169
|
/**
|
|
155
170
|
* Transient provider retry controls for the interactive chat loop. These are
|
|
156
171
|
* intentionally small and mirror the session retry helper defaults. Dispatched
|
|
@@ -354,11 +369,15 @@ export const DEFAULT_SETTINGS = {
|
|
|
354
369
|
everyNTools: 10,
|
|
355
370
|
windowSteps: 8,
|
|
356
371
|
maxTokens: 400,
|
|
357
|
-
// A memory step runs detached from the turn that triggered it,
|
|
358
|
-
//
|
|
359
|
-
//
|
|
360
|
-
//
|
|
361
|
-
|
|
372
|
+
// A memory step runs detached from the turn that triggered it, but it
|
|
373
|
+
// runs on a real inference endpoint that the operator's own turns and
|
|
374
|
+
// dispatched workers also queue against. The operator's ledger over 14
|
|
375
|
+
// days recorded 60 llm-tier steps spending 1,666 seconds of model time
|
|
376
|
+
// for 6 injections, with one step holding a local server for 102.5
|
|
377
|
+
// seconds to answer nothing. The deadline is what a turn boundary can
|
|
378
|
+
// actually wait for; a step that runs past it is recorded as timed out
|
|
379
|
+
// rather than spending the remaining minutes unobserved.
|
|
380
|
+
timeoutMs: 30_000,
|
|
362
381
|
},
|
|
363
382
|
},
|
|
364
383
|
watchdog: { enabled: false } as WatchdogSettings,
|
|
@@ -444,6 +463,9 @@ export const DEFAULT_SETTINGS = {
|
|
|
444
463
|
context: {
|
|
445
464
|
workingSet: DEFAULT_WORKING_SET_SETTINGS,
|
|
446
465
|
},
|
|
466
|
+
prewarm: {
|
|
467
|
+
enabled: true,
|
|
468
|
+
} as PrewarmSettings,
|
|
447
469
|
retry: {
|
|
448
470
|
enabled: true,
|
|
449
471
|
maxRetries: 3,
|
|
@@ -539,7 +561,7 @@ memory:
|
|
|
539
561
|
everyNTools: 10
|
|
540
562
|
windowSteps: 8
|
|
541
563
|
maxTokens: 400
|
|
542
|
-
timeoutMs:
|
|
564
|
+
timeoutMs: 30000
|
|
543
565
|
|
|
544
566
|
# Opt-in turn-end watchdog. When enabled, a turn that changed the tree is
|
|
545
567
|
# reviewed by one read-only verifier run briefed with the turn's coalesced diff
|
|
@@ -751,6 +773,14 @@ context:
|
|
|
751
773
|
protectLastTurns: 6
|
|
752
774
|
minEvictableTokens: 200
|
|
753
775
|
|
|
776
|
+
# Prompt pre-warm. At session start, after a resume rebuilds the message array,
|
|
777
|
+
# and after a compaction settles, Clio sends the prefix the next turn would send
|
|
778
|
+
# (minus your text) so a local server has already prefilled it when you press
|
|
779
|
+
# Enter. Local-native targets only, interactive sessions only, and never while a
|
|
780
|
+
# turn or a dispatch is running.
|
|
781
|
+
prewarm:
|
|
782
|
+
enabled: true
|
|
783
|
+
|
|
754
784
|
# Transient provider/stream retry controls for interactive chat.
|
|
755
785
|
# Retryable errors include overloads, rate limits, 5xx responses, network
|
|
756
786
|
# resets, and timeouts. Context overflow uses compaction recovery instead.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical identity of an OpenAI-compatible inference endpoint: normalized
|
|
3
|
+
* HTTP scheme, lower-cased host, normalized port, and normalized base path with
|
|
4
|
+
* a conventional terminal `/v1` mount stripped. Credentials, query, and
|
|
5
|
+
* fragment do not participate. Host aliases are not resolved, so
|
|
6
|
+
* `localhost` and `127.0.0.1` stay distinct. Shared by dispatch capacity and
|
|
7
|
+
* residency locking so both speak the same key for one server.
|
|
8
|
+
*/
|
|
9
|
+
export function canonicalEndpointUrl(raw: string | null | undefined): string | null {
|
|
10
|
+
if (!raw?.trim()) return null;
|
|
11
|
+
try {
|
|
12
|
+
const url = new URL(raw.trim().replace(/^ws:/u, "http:").replace(/^wss:/u, "https:"));
|
|
13
|
+
url.protocol = url.protocol.toLowerCase();
|
|
14
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
15
|
+
url.hostname = url.hostname.toLowerCase();
|
|
16
|
+
url.username = "";
|
|
17
|
+
url.password = "";
|
|
18
|
+
url.hash = "";
|
|
19
|
+
url.search = "";
|
|
20
|
+
let path = url.pathname.replace(/\/{2,}/gu, "/").replace(/\/$/u, "");
|
|
21
|
+
if (path.endsWith("/v1")) path = path.slice(0, -3);
|
|
22
|
+
url.pathname = path || "/";
|
|
23
|
+
return url.toString().replace(/\/$/u, "");
|
|
24
|
+
} catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { canonicalEndpointUrl } from "./endpoint-key.js";
|
|
2
|
+
|
|
3
|
+
/** Runtime families whose model residency Clio can actively mutate. */
|
|
4
|
+
export type ResidencyRuntimeId = "llamacpp" | "lmstudio" | "ollama-native";
|
|
5
|
+
|
|
6
|
+
const RESIDENCY_RUNTIME_IDS: ReadonlySet<string> = new Set<ResidencyRuntimeId>([
|
|
7
|
+
"llamacpp",
|
|
8
|
+
"lmstudio",
|
|
9
|
+
"ollama-native",
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
export function residencyTargetKey(runtimeId: ResidencyRuntimeId, baseUrl: string): string;
|
|
13
|
+
export function residencyTargetKey(runtimeId: string, baseUrl: string | null | undefined): string | null;
|
|
14
|
+
/** Stable key for one residency-managed server endpoint: its canonical URL. */
|
|
15
|
+
export function residencyTargetKey(runtimeId: string, baseUrl: string | null | undefined): string | null {
|
|
16
|
+
if (!RESIDENCY_RUNTIME_IDS.has(runtimeId) || typeof baseUrl !== "string") return null;
|
|
17
|
+
// The key is the canonical endpoint itself, without a runtime prefix, so the
|
|
18
|
+
// residency lock and dispatch capacity name one server the same way (#250).
|
|
19
|
+
// A base url the canonical form refuses, such as one written without a
|
|
20
|
+
// scheme, still gets a key: callers store this in `ResidencyAdapter.targetKey`,
|
|
21
|
+
// which is a `string`, and dispatch capacity has no key for that target
|
|
22
|
+
// either, so there is nothing to agree with and nothing to gain by dropping
|
|
23
|
+
// the lock the reconciler serializes on.
|
|
24
|
+
return canonicalEndpointUrl(baseUrl) ?? baseUrl;
|
|
25
|
+
}
|
|
@@ -11,11 +11,45 @@ export const RESPONSE_SCHEMA_MAX_SERIALIZED_BYTES = 64 * 1024;
|
|
|
11
11
|
* `schema` key, and returns HTTP 200 with unconstrained JSON, so widening this
|
|
12
12
|
* to the api family would convert a clean refusal into a silent
|
|
13
13
|
* non-enforcement. lmstudio declares `structuredOutputs: "json-schema"`
|
|
14
|
-
* truthfully and is still excluded here, because
|
|
15
|
-
* transport. Widen this only together with a dialect for the
|
|
14
|
+
* truthfully and is still excluded here, because the worker seam has no
|
|
15
|
+
* dialect for its transport. Widen this only together with a dialect for the
|
|
16
|
+
* runtime added; {@link responseSchemaDialectFor} is where the out-of-turn
|
|
17
|
+
* seam did exactly that (issue #223).
|
|
16
18
|
*/
|
|
17
19
|
export const RESPONSE_SCHEMA_RUNTIME_ID = "llamacpp";
|
|
18
20
|
|
|
21
|
+
/** The runtime that takes the standard OpenAI `json_schema` response format. */
|
|
22
|
+
export const OPENAI_SCHEMA_RUNTIME_ID = "lmstudio";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* How a runtime spells a JSON-schema response constraint on the wire.
|
|
26
|
+
*
|
|
27
|
+
* `llamacpp-json-object` is llama-server's own `response_format: { type:
|
|
28
|
+
* "json_object", schema }`, which it compiles into a sampler grammar.
|
|
29
|
+
* `openai-json-schema` is the standard `response_format: { type:
|
|
30
|
+
* "json_schema", json_schema: { name, strict, schema } }` that LM Studio
|
|
31
|
+
* implements.
|
|
32
|
+
*/
|
|
33
|
+
export type ResponseSchemaDialect = "llamacpp-json-object" | "openai-json-schema";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The dialect this runtime takes, or null when Clio has none for it and the
|
|
37
|
+
* request has to go unconstrained.
|
|
38
|
+
*
|
|
39
|
+
* Deliberately a name check, for the reason {@link RESPONSE_SCHEMA_RUNTIME_ID}
|
|
40
|
+
* gives: a generic OpenAI-compatible gateway answers HTTP 200 to a spelling it
|
|
41
|
+
* does not implement and returns unconstrained JSON, so a capability flag would
|
|
42
|
+
* turn a known non-enforcement into a silent one. This is the out-of-turn
|
|
43
|
+
* seam's table; the worker seam keeps the narrower
|
|
44
|
+
* {@link runtimeSpeaksResponseSchemaDialect} check, because a worker that
|
|
45
|
+
* cannot enforce a contract must refuse admission rather than degrade.
|
|
46
|
+
*/
|
|
47
|
+
export function responseSchemaDialectFor(runtimeId: string): ResponseSchemaDialect | null {
|
|
48
|
+
if (runtimeId === RESPONSE_SCHEMA_RUNTIME_ID) return "llamacpp-json-object";
|
|
49
|
+
if (runtimeId === OPENAI_SCHEMA_RUNTIME_ID) return "openai-json-schema";
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
19
53
|
/** Whether this runtime speaks the dialect above. Transport shape, not capability. */
|
|
20
54
|
export function runtimeSpeaksResponseSchemaDialect(runtime: { id: string; kind: string; apiFamily: string }): boolean {
|
|
21
55
|
return (
|
|
@@ -61,6 +61,9 @@ const NEXT_TURN_FIELDS = new Set<string>([
|
|
|
61
61
|
"delegation",
|
|
62
62
|
"compaction",
|
|
63
63
|
"context",
|
|
64
|
+
// The pre-warm reads its setting when a trigger fires, and every trigger sits
|
|
65
|
+
// on a turn boundary, so a change takes effect before the next turn runs.
|
|
66
|
+
"prewarm",
|
|
64
67
|
"retry",
|
|
65
68
|
]);
|
|
66
69
|
|