@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
|
@@ -2,7 +2,7 @@ import { performance } from "node:perf_hooks";
|
|
|
2
2
|
import type { OutputVerbosity } from "../core/defaults.js";
|
|
3
3
|
import { SKILL_SUGGESTION_PREFIX } from "../core/skill-activation.js";
|
|
4
4
|
import { rawDurationMs } from "../core/timers.js";
|
|
5
|
-
import { type Component, Markdown, truncateToWidth, wrapTextWithAnsi } from "../engine/tui.js";
|
|
5
|
+
import { type Component, Markdown, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "../engine/tui.js";
|
|
6
6
|
import type { AgentMessage } from "../engine/types.js";
|
|
7
7
|
import { toolPresentationPolicy } from "../tools/presentation.js";
|
|
8
8
|
import { toolResultPresentationPolicy } from "../tools/result-disposition.js";
|
|
@@ -252,7 +252,7 @@ type ReplayBlockRenderer = (width: number, detail: TranscriptDetailPolicy) => st
|
|
|
252
252
|
type AssistantStatusLine = { phase: StatusPhase; verb: string; toneHint: VerbRender["toneHint"] };
|
|
253
253
|
|
|
254
254
|
type TranscriptEntry =
|
|
255
|
-
| { role: "user"; text: string }
|
|
255
|
+
| { role: "user"; text: string; status?: () => UserTurnStatus }
|
|
256
256
|
| { role: "retryStatus"; status: RetryStatusPayload }
|
|
257
257
|
| {
|
|
258
258
|
role: "assistant";
|
|
@@ -308,8 +308,20 @@ export interface ReplayBlockFoldControl {
|
|
|
308
308
|
setFold(fold: FoldOverride): void;
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
+
/**
|
|
312
|
+
* Whether a painted operator turn exists in the ledger yet. `pending` is the
|
|
313
|
+
* window between the editor being consumed and admission; `refused` is a
|
|
314
|
+
* submit that never reached the durable append.
|
|
315
|
+
*/
|
|
316
|
+
export type UserTurnStatus = "pending" | "committed" | "refused";
|
|
317
|
+
|
|
311
318
|
export interface ChatPanel extends Component {
|
|
312
|
-
|
|
319
|
+
/**
|
|
320
|
+
* Paint an operator turn. `status`, when given, is read every frame while it
|
|
321
|
+
* reports anything but `committed`, so the row the transcript shows before
|
|
322
|
+
* admission is visibly not the durable turn it will become.
|
|
323
|
+
*/
|
|
324
|
+
appendUser(text: string, status?: () => UserTurnStatus): void;
|
|
313
325
|
/**
|
|
314
326
|
* Append a caller-rendered block. Pass `isLive` when the closure reads state
|
|
315
327
|
* that keeps changing after the append, so the panel keeps re-rendering it
|
|
@@ -675,6 +687,20 @@ function renderErrorSegmentLines(seg: ErrorSegment, width: number): string[] {
|
|
|
675
687
|
const CLIO_PREFIX = `${TEAL}${AGENT_GLYPH}${RESET} `;
|
|
676
688
|
const CLIO_PREFIX_ERROR = `${RED_CRIT}${AGENT_GLYPH}${RESET} `;
|
|
677
689
|
const USER_PREFIX = `${TEAL}${USER_GLYPH}${RESET} `;
|
|
690
|
+
/**
|
|
691
|
+
* A prompt Clio has taken but not yet committed. The glyph is dim rather than
|
|
692
|
+
* teal and the row says so, because the transcript used to paint an
|
|
693
|
+
* uncommitted prompt exactly like a durable user turn while the ledger still
|
|
694
|
+
* had no entry for it (issue #251).
|
|
695
|
+
*/
|
|
696
|
+
const USER_PREFIX_PENDING = `${DIM}${USER_GLYPH}${RESET} `;
|
|
697
|
+
/**
|
|
698
|
+
* The uncommitted-row tails, stored as plain text so their width can be spent
|
|
699
|
+
* against the row's budget before the dim codes go on. Both begin with the
|
|
700
|
+
* separating space they carry when they ride on the end of a body line.
|
|
701
|
+
*/
|
|
702
|
+
const USER_PENDING_TAIL = " · preparing";
|
|
703
|
+
const USER_REFUSED_TAIL = " · not sent";
|
|
678
704
|
const PROSE_GUTTER = " ";
|
|
679
705
|
const PROSE_GUTTER_WIDTH = 2;
|
|
680
706
|
|
|
@@ -688,6 +714,30 @@ function hangProseLines(lines: string[], firstPrefix?: string): string[] {
|
|
|
688
714
|
return lines.map((line, index) => `${index === 0 && firstPrefix !== undefined ? firstPrefix : PROSE_GUTTER}${line}`);
|
|
689
715
|
}
|
|
690
716
|
|
|
717
|
+
/**
|
|
718
|
+
* Put an uncommitted row's status tail on the row without letting it push a
|
|
719
|
+
* line past the terminal. The tail used to be concatenated onto the last
|
|
720
|
+
* rendered line unconditionally, so a body that had already folded near the
|
|
721
|
+
* content width came out up to 12 cells past the terminal, and pi-tui's
|
|
722
|
+
* `doRender` throws on an overlong line and kills the process. A `/share` of
|
|
723
|
+
* a worker answer is the ordinary way to hit that: a `research-report` body is
|
|
724
|
+
* JSON with no space to fold at, so an 80-column pane died on any shared body
|
|
725
|
+
* over 58 columns (#257).
|
|
726
|
+
*
|
|
727
|
+
* The tail rides on the last body line when that line has room for it, and
|
|
728
|
+
* drops to its own hanging row when it does not, so it stays whole either way
|
|
729
|
+
* rather than breaking between `·` and the word.
|
|
730
|
+
*/
|
|
731
|
+
function appendUserRowTail(rendered: string[], tail: string, width: number): void {
|
|
732
|
+
const last = rendered.length - 1;
|
|
733
|
+
const lastLine = rendered[last];
|
|
734
|
+
if (lastLine !== undefined && visibleWidth(lastLine) + tail.length <= width) {
|
|
735
|
+
rendered[last] = `${lastLine}${DIM}${tail}${RESET}`;
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
rendered.push(`${PROSE_GUTTER}${dimLine(tail.trimStart(), Math.max(1, width - PROSE_GUTTER_WIDTH))}`);
|
|
739
|
+
}
|
|
740
|
+
|
|
691
741
|
/**
|
|
692
742
|
* Static marker used when thinking is folded. This matches pi-coding-agent's
|
|
693
743
|
* hidden-thinking presentation and avoids previewing reasoning content.
|
|
@@ -964,8 +1014,11 @@ function renderEntryLines(
|
|
|
964
1014
|
const contentWidth = Math.max(1, width - PROSE_GUTTER_WIDTH);
|
|
965
1015
|
const lines: string[] = [];
|
|
966
1016
|
for (const sourceLine of entry.text.split("\n")) lines.push(...wrapTextWithAnsi(sourceLine, contentWidth));
|
|
967
|
-
const
|
|
1017
|
+
const status = entry.status?.() ?? "committed";
|
|
1018
|
+
const rendered = hangProseLines(lines, status === "committed" ? USER_PREFIX : USER_PREFIX_PENDING);
|
|
968
1019
|
if (rendered[0] !== undefined) rendered[0] = `${OSC133_PROMPT_START}${rendered[0]}`;
|
|
1020
|
+
if (status !== "committed")
|
|
1021
|
+
appendUserRowTail(rendered, status === "pending" ? USER_PENDING_TAIL : USER_REFUSED_TAIL, width);
|
|
969
1022
|
return rendered;
|
|
970
1023
|
}
|
|
971
1024
|
if (entry.role === "retryStatus") {
|
|
@@ -1450,7 +1503,8 @@ export function createChatPanel(options: ChatPanelOptions = {}): ChatPanel {
|
|
|
1450
1503
|
// only thinking still needs the time-keyed render key.
|
|
1451
1504
|
) ||
|
|
1452
1505
|
(entry.pending && openThinkingSegment(entry)?.startedAtMs !== undefined))) ||
|
|
1453
|
-
(entry.role === "replayBlock" && entry.isLive?.() === true)
|
|
1506
|
+
(entry.role === "replayBlock" && entry.isLive?.() === true) ||
|
|
1507
|
+
(entry.role === "user" && (entry.status?.() ?? "committed") !== "committed");
|
|
1454
1508
|
|
|
1455
1509
|
/**
|
|
1456
1510
|
* Settled entries whose render is a pure function of the base key. A live
|
|
@@ -1460,7 +1514,7 @@ export function createChatPanel(options: ChatPanelOptions = {}): ChatPanel {
|
|
|
1460
1514
|
* declares itself live is excluded on the same grounds.
|
|
1461
1515
|
*/
|
|
1462
1516
|
const entryIsStable = (entry: TranscriptEntry): boolean =>
|
|
1463
|
-
entry.role === "user" ||
|
|
1517
|
+
(entry.role === "user" && (entry.status?.() ?? "committed") === "committed") ||
|
|
1464
1518
|
(entry.role === "replayBlock" && entry.isLive?.() !== true) ||
|
|
1465
1519
|
(entry.role === "worker" && !entry.state.pending) ||
|
|
1466
1520
|
(entry.role === "assistant" &&
|
|
@@ -1593,8 +1647,8 @@ export function createChatPanel(options: ChatPanelOptions = {}): ChatPanel {
|
|
|
1593
1647
|
};
|
|
1594
1648
|
|
|
1595
1649
|
return {
|
|
1596
|
-
appendUser(text: string): void {
|
|
1597
|
-
transcript.push({ role: "user", text });
|
|
1650
|
+
appendUser(text: string, status?: () => UserTurnStatus): void {
|
|
1651
|
+
transcript.push({ role: "user", text, ...(status ? { status } : {}) });
|
|
1598
1652
|
markDirty();
|
|
1599
1653
|
},
|
|
1600
1654
|
appendReplayBlock(renderBlock: ReplayBlockRenderer, isLive?: () => boolean, fold?: ReplayBlockFoldControl): void {
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { Editor, stripTerminalSequences, type TUI, truncateToWidth, visibleWidth } from "../engine/tui.js";
|
|
2
2
|
import { fitHintEntries } from "./overlay-frame.js";
|
|
3
|
-
import { permissionHintEntries } from "./permission-hint.js";
|
|
3
|
+
import { type PermissionInspectionHint, permissionHintEntries } from "./permission-hint.js";
|
|
4
4
|
import type { ClioTheme } from "./theme/index.js";
|
|
5
5
|
import { clioTheme, editorTheme, GLYPH, rule } from "./theme/index.js";
|
|
6
|
+
import type { TurnPreparationPhase } from "./turn-state.js";
|
|
6
7
|
|
|
7
8
|
const REVERSE_VIDEO_BLANK = `${String.fromCharCode(27)}[7m ${String.fromCharCode(27)}[0m`;
|
|
8
9
|
const EMPTY_PROMPT = "Ask Clio… / for commands";
|
|
9
10
|
const CONFIRM_PROMPT = "A parked call is waiting for your decision";
|
|
11
|
+
const PREPARING_PROMPT = "Clio has your prompt and is preparing the turn";
|
|
12
|
+
const COMPACTING_PROMPT = "Clio has your prompt and is compacting the context first";
|
|
10
13
|
const MIN_HINT_WIDTH = 60;
|
|
11
14
|
|
|
12
15
|
function hasScrollIndicator(line: string): boolean {
|
|
@@ -28,6 +31,19 @@ export interface EditorChrome {
|
|
|
28
31
|
* dialog's keys whenever the prompt owns input (issues #186 and #194).
|
|
29
32
|
*/
|
|
30
33
|
isAwaitingApproval?: () => boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Whether that prompt is a mutation the operator can read locally, and
|
|
36
|
+
* whether it is open. The rail carries the dialog's keys, so it names the
|
|
37
|
+
* inspect key on exactly the cards that have one (issue #254).
|
|
38
|
+
*/
|
|
39
|
+
getPermissionInspection?: () => PermissionInspectionHint;
|
|
40
|
+
/**
|
|
41
|
+
* Where a consumed prompt is between the editor and the stream. The editor
|
|
42
|
+
* is cleared before admission, so without this the composer went straight
|
|
43
|
+
* back to `MESSAGE` and a 77-second pre-submit compaction was
|
|
44
|
+
* indistinguishable from a dropped Enter (issue #251).
|
|
45
|
+
*/
|
|
46
|
+
getTurnPreparation?: () => TurnPreparationPhase;
|
|
31
47
|
/** Whether the current draft will actually steer Clio or live dispatch work on Enter. */
|
|
32
48
|
willEnterSteer?: (text: string) => boolean;
|
|
33
49
|
/** Resolved submit binding, formatted for display. */
|
|
@@ -36,7 +52,7 @@ export interface EditorChrome {
|
|
|
36
52
|
getNewlineKeyLabel?: () => string;
|
|
37
53
|
}
|
|
38
54
|
|
|
39
|
-
type ComposerMode = "MESSAGE" | "FOLLOW-UP" | "STEER" | "CONFIRM";
|
|
55
|
+
type ComposerMode = "MESSAGE" | "FOLLOW-UP" | "STEER" | "CONFIRM" | "PREPARING" | "COMPACTING";
|
|
40
56
|
|
|
41
57
|
function normalizeThinkingHint(value: string): string {
|
|
42
58
|
return value
|
|
@@ -72,7 +88,15 @@ function styledRailLabel(theme: ClioTheme, chrome: EditorChrome): string {
|
|
|
72
88
|
|
|
73
89
|
function composerMode(chrome: EditorChrome, text: string): ComposerMode {
|
|
74
90
|
if (chrome.isAwaitingApproval?.() ?? false) return "CONFIRM";
|
|
75
|
-
if (!(chrome.isStreaming?.() ?? false))
|
|
91
|
+
if (!(chrome.isStreaming?.() ?? false)) {
|
|
92
|
+
// A prompt Clio is holding is not an idle composer. Streaming outranks it
|
|
93
|
+
// because a steer typed during a live run is what the rail is for, and a
|
|
94
|
+
// steer's own submit passes through this window on its way to the queue.
|
|
95
|
+
const preparation = chrome.getTurnPreparation?.() ?? "idle";
|
|
96
|
+
if (preparation === "compacting") return "COMPACTING";
|
|
97
|
+
if (preparation === "preparing") return "PREPARING";
|
|
98
|
+
return "MESSAGE";
|
|
99
|
+
}
|
|
76
100
|
const willSteer = chrome.willEnterSteer?.(text) ?? text.trim().length > 0;
|
|
77
101
|
return willSteer ? "STEER" : "FOLLOW-UP";
|
|
78
102
|
}
|
|
@@ -89,16 +113,29 @@ function lowerRailHint(theme: ClioTheme, chrome: EditorChrome): string {
|
|
|
89
113
|
* both surfaces narrow in the same order and never drop allow or stop first.
|
|
90
114
|
* The rule spends three columns around a right label, hence the subtraction.
|
|
91
115
|
*/
|
|
92
|
-
function confirmRailHint(
|
|
93
|
-
|
|
116
|
+
function confirmRailHint(
|
|
117
|
+
theme: ClioTheme,
|
|
118
|
+
width: number,
|
|
119
|
+
hasDraft: boolean,
|
|
120
|
+
inspection: PermissionInspectionHint,
|
|
121
|
+
): string {
|
|
122
|
+
return theme.fg("warning", fitHintEntries(permissionHintEntries(hasDraft, inspection), Math.max(1, width - 3)));
|
|
94
123
|
}
|
|
95
124
|
|
|
96
125
|
function modeToken(mode: ComposerMode): "action" | "accentDeep" | "warning" {
|
|
97
|
-
if (mode === "STEER") return "action";
|
|
126
|
+
if (mode === "STEER" || mode === "PREPARING" || mode === "COMPACTING") return "action";
|
|
98
127
|
if (mode === "CONFIRM") return "warning";
|
|
99
128
|
return "accentDeep";
|
|
100
129
|
}
|
|
101
130
|
|
|
131
|
+
/** The line the empty composer shows for the mode it is in. */
|
|
132
|
+
function emptyPromptFor(mode: ComposerMode): string {
|
|
133
|
+
if (mode === "CONFIRM") return CONFIRM_PROMPT;
|
|
134
|
+
if (mode === "PREPARING") return PREPARING_PROMPT;
|
|
135
|
+
if (mode === "COMPACTING") return COMPACTING_PROMPT;
|
|
136
|
+
return EMPTY_PROMPT;
|
|
137
|
+
}
|
|
138
|
+
|
|
102
139
|
function renderEmptyPrompt(line: string, width: number, theme: ClioTheme, text = EMPTY_PROMPT): string {
|
|
103
140
|
const cursorAt = line.indexOf(REVERSE_VIDEO_BLANK);
|
|
104
141
|
if (cursorAt < 0) return line;
|
|
@@ -151,7 +188,7 @@ export class ClioEditor extends Editor {
|
|
|
151
188
|
}
|
|
152
189
|
|
|
153
190
|
if (text.length === 0 && lines[1]) {
|
|
154
|
-
lines[1] = renderEmptyPrompt(lines[1], safeWidth, theme, mode
|
|
191
|
+
lines[1] = renderEmptyPrompt(lines[1], safeWidth, theme, emptyPromptFor(mode));
|
|
155
192
|
}
|
|
156
193
|
|
|
157
194
|
const bottomRail = findBottomRail(lines, safeWidth);
|
|
@@ -159,7 +196,7 @@ export class ClioEditor extends Editor {
|
|
|
159
196
|
// that a narrow composer can drop, the allow and deny keys are not.
|
|
160
197
|
if (bottomRail >= 0 && mode === "CONFIRM") {
|
|
161
198
|
lines[bottomRail] = rule(theme, safeWidth, {
|
|
162
|
-
right: confirmRailHint(theme, safeWidth, text.length > 0),
|
|
199
|
+
right: confirmRailHint(theme, safeWidth, text.length > 0, this.chrome.getPermissionInspection?.() ?? "none"),
|
|
163
200
|
fillToken: "frameStrong",
|
|
164
201
|
rightRaw: true,
|
|
165
202
|
rightTail: theme.style("frameStrong", "─", { bold: true }),
|
|
@@ -32,6 +32,8 @@ const PHASES: ReadonlyArray<ContextActivityPhase> = ["scan", "codewiki", "genera
|
|
|
32
32
|
* happen.
|
|
33
33
|
*/
|
|
34
34
|
const WIKI_PHASES: ReadonlyArray<ContextActivityPhase> = ["codewiki", "generate", "state", "done"];
|
|
35
|
+
/** Compaction is one bounded operation, not the five-stage context-init pipeline. */
|
|
36
|
+
const COMPACTION_PHASES: ReadonlyArray<ContextActivityPhase> = ["compact", "done"];
|
|
35
37
|
const PHASE_LABELS: Record<ContextActivityPhase, string> = {
|
|
36
38
|
scan: "scan",
|
|
37
39
|
// "index" rather than "wiki": this phase is the codewiki index build, and
|
|
@@ -40,6 +42,7 @@ const PHASE_LABELS: Record<ContextActivityPhase, string> = {
|
|
|
40
42
|
generate: "draft",
|
|
41
43
|
"clio-md": "CLIO-CODER.md",
|
|
42
44
|
state: "state",
|
|
45
|
+
compact: "compact",
|
|
43
46
|
done: "done",
|
|
44
47
|
};
|
|
45
48
|
const WIKI_PHASE_LABELS: Partial<Record<ContextActivityPhase, string>> = {
|
|
@@ -55,9 +58,10 @@ const KINDS: ReadonlySet<string> = new Set<ContextActivityKind>([
|
|
|
55
58
|
"context-wiki",
|
|
56
59
|
"compaction",
|
|
57
60
|
]);
|
|
58
|
-
const PHASE_SET: ReadonlySet<string> = new Set<ContextActivityPhase>(PHASES);
|
|
61
|
+
const PHASE_SET: ReadonlySet<string> = new Set<ContextActivityPhase>([...PHASES, ...COMPACTION_PHASES]);
|
|
59
62
|
|
|
60
63
|
function phasesFor(kind: ContextActivityKind): ReadonlyArray<ContextActivityPhase> {
|
|
64
|
+
if (kind === "compaction") return COMPACTION_PHASES;
|
|
61
65
|
return kind === "context-wiki" ? WIKI_PHASES : PHASES;
|
|
62
66
|
}
|
|
63
67
|
|
|
@@ -77,7 +77,7 @@ function legendRow(group: ContextLedgerGroup, contentWidth: number): string {
|
|
|
77
77
|
const tokens = formatTokens(group.tokens);
|
|
78
78
|
const percent = formatContextPercent(group.percent);
|
|
79
79
|
const right = `${tokens.padStart(9)} ${percent.padStart(6)}`;
|
|
80
|
-
const labelToken: ClioToken = group.category === "
|
|
80
|
+
const labelToken: ClioToken = group.category === "reserve" ? "frame" : group.category === "free" ? "dim" : "muted";
|
|
81
81
|
const leftWidth = Math.max(0, contentWidth - visibleWidth(right) - 2);
|
|
82
82
|
const labelText = group.label.length > leftWidth ? group.label.slice(0, leftWidth) : group.label.padEnd(leftWidth);
|
|
83
83
|
return `${swatch} ${theme.fg(labelToken, labelText)} ${theme.fg("muted", right)}`;
|
|
@@ -108,6 +108,16 @@ function coldReasonLabel(reason: string): string {
|
|
|
108
108
|
return "compaction";
|
|
109
109
|
case "dispatch":
|
|
110
110
|
return "dispatch traffic";
|
|
111
|
+
case "residency":
|
|
112
|
+
return "residency change";
|
|
113
|
+
case "thinking_change":
|
|
114
|
+
return "thinking-level change";
|
|
115
|
+
case "tool_surface_change":
|
|
116
|
+
return "tool-surface change";
|
|
117
|
+
case "prompt_recompiled":
|
|
118
|
+
return "prompt recompile";
|
|
119
|
+
case "background_memory":
|
|
120
|
+
return "background memory step";
|
|
111
121
|
default:
|
|
112
122
|
return reason;
|
|
113
123
|
}
|
|
@@ -221,8 +231,10 @@ export function renderContextLedgerLines(
|
|
|
221
231
|
if (ledger.promptCache) {
|
|
222
232
|
const cache = ledger.promptCache;
|
|
223
233
|
const shell = cache.shellReused ? "shell reused" : "shell recompiled";
|
|
224
|
-
const backend
|
|
225
|
-
|
|
234
|
+
const backendCacheReadsUnknown = cache.backend?.cachedTokens === null;
|
|
235
|
+
const backend = backendCacheReadsUnknown
|
|
236
|
+
? "server does not report cache reads"
|
|
237
|
+
: cache.backendVerdict === "hot" || cache.backendVerdict === "partial"
|
|
226
238
|
? "backend reused"
|
|
227
239
|
: cache.backendVerdict === "cold"
|
|
228
240
|
? "backend cold"
|
|
@@ -232,24 +244,42 @@ export function renderContextLedgerLines(
|
|
|
232
244
|
const read = cache.cacheReadTokens !== null ? `cache read ${formatTokens(cache.cacheReadTokens)}` : "cache read n/a";
|
|
233
245
|
const uncached =
|
|
234
246
|
cache.uncachedInputTokens !== null ? `uncached input ${formatTokens(cache.uncachedInputTokens)}` : null;
|
|
235
|
-
const line =
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
//
|
|
239
|
-
//
|
|
240
|
-
|
|
247
|
+
const line = backendCacheReadsUnknown
|
|
248
|
+
? ["prompt cache:", shell, "·", backend].join(" ")
|
|
249
|
+
: ["prompt cache:", shell, "·", backend, "·", read, ...(uncached ? ["·", uncached] : [])].join(" ");
|
|
250
|
+
// Reasons Clio recorded before the run describe either prefix-byte changes
|
|
251
|
+
// or local-server activity that displaced the cached prefix. A cold turn
|
|
252
|
+
// after one of them is expected rather than a provider surprise.
|
|
253
|
+
const coldReasons =
|
|
254
|
+
cache.backendVerdict === "cold" && !backendCacheReadsUnknown ? (cache.expectedColdReasons ?? []) : [];
|
|
241
255
|
// A reused shell with a cold backend means Clio kept the bytes stable
|
|
242
256
|
// but the provider re-prefilled anyway; surface that disagreement
|
|
243
257
|
// instead of hiding it. An expected reason explains the same numbers, so
|
|
244
258
|
// it is reported on its own line and not as a warning.
|
|
245
|
-
const misleading =
|
|
259
|
+
const misleading =
|
|
260
|
+
cache.shellReused && cache.backendVerdict === "cold" && !backendCacheReadsUnknown && coldReasons.length === 0;
|
|
246
261
|
lines.push(theme.fg(misleading ? "warning" : "dim", line));
|
|
262
|
+
if (cache.backend) {
|
|
263
|
+
const prefill =
|
|
264
|
+
cache.backend.cachedTokens !== null && cache.uncachedPrefillTokens !== null
|
|
265
|
+
? `prefill: ${formatTokens(cache.uncachedPrefillTokens)} uncached · ${formatTokens(cache.backend.cachedTokens)} cached · ${formatTokens(cache.backend.promptMs)} ms`
|
|
266
|
+
: `prefill: ${formatTokens(cache.backend.promptTokens)} prompt · ${formatTokens(cache.backend.promptMs)} ms`;
|
|
267
|
+
lines.push(theme.fg("dim", prefill));
|
|
268
|
+
}
|
|
247
269
|
if (coldReasons.length > 0) {
|
|
248
270
|
const reasons = coldReasons.map(coldReasonLabel).join(", ");
|
|
249
271
|
lines.push(theme.fg("dim", `last cold turn: ${reasons} (expected)`));
|
|
250
272
|
}
|
|
251
273
|
}
|
|
252
274
|
|
|
275
|
+
if (ledger.prewarm) {
|
|
276
|
+
// What the backend has already prefilled for the turn the operator has not
|
|
277
|
+
// typed yet. It survives until the next settled run answers the question.
|
|
278
|
+
const tokens = ledger.prewarm.tokens !== null ? `${formatTokens(ledger.prewarm.tokens)} tokens` : "prefix";
|
|
279
|
+
const aborted = ledger.prewarm.aborted ? " (aborted on submit; prefix stays in the slot)" : "";
|
|
280
|
+
lines.push(theme.fg("dim", `prewarmed: ${tokens} in ${formatTokens(ledger.prewarm.ms)} ms${aborted}`));
|
|
281
|
+
}
|
|
282
|
+
|
|
253
283
|
if (ledger.lastCompaction) {
|
|
254
284
|
const pruneInfo = `last compaction: reclaimed ${formatTokens(ledger.lastCompaction.tokensBefore)} -> ${formatTokens(ledger.lastCompaction.tokensAfter)} tokens (${ledger.lastCompaction.stage})`;
|
|
255
285
|
lines.push(theme.fg("dim", pruneInfo));
|
|
@@ -11,6 +11,12 @@ import {
|
|
|
11
11
|
type ObservabilityContract,
|
|
12
12
|
type ObservabilitySnapshot,
|
|
13
13
|
} from "../domains/observability/index.js";
|
|
14
|
+
import {
|
|
15
|
+
foldPromptCacheTelemetry,
|
|
16
|
+
hasPromptCacheTelemetry,
|
|
17
|
+
type PromptCacheTelemetry,
|
|
18
|
+
type SessionEntry,
|
|
19
|
+
} from "../domains/session/index.js";
|
|
14
20
|
import type { Component, OverlayHandle, TUI } from "../engine/tui.js";
|
|
15
21
|
import { buildHint, showClioOverlayFrame } from "./overlay-frame.js";
|
|
16
22
|
import { clioTheme, rule } from "./theme/index.js";
|
|
@@ -36,6 +42,10 @@ export interface CostRow {
|
|
|
36
42
|
sideQuestions: number;
|
|
37
43
|
/** Calls in this row that were `/handoff` extraction rounds rather than turns. */
|
|
38
44
|
handoffs: number;
|
|
45
|
+
/** Calls in this row that were session pre-warms rather than turns. */
|
|
46
|
+
prewarms: number;
|
|
47
|
+
/** Calls in this row that were proactive-memory steps on the background target. */
|
|
48
|
+
backgroundMemory: number;
|
|
39
49
|
cost: CostAggregate;
|
|
40
50
|
}
|
|
41
51
|
|
|
@@ -67,6 +77,8 @@ export function aggregateCostEntries(entries: ReadonlyArray<CostEntry>): CostRow
|
|
|
67
77
|
existing.row.apiCalls += entry.apiCalls ?? 1;
|
|
68
78
|
if (entry.label === "side-question") existing.row.sideQuestions += 1;
|
|
69
79
|
if (entry.label === "handoff") existing.row.handoffs += 1;
|
|
80
|
+
if (entry.label === "prewarm") existing.row.prewarms += 1;
|
|
81
|
+
if (entry.label === "background-memory") existing.row.backgroundMemory += 1;
|
|
70
82
|
for (const requestedModelId of entry.requestedModelIds) existing.requestedModelIds.add(requestedModelId);
|
|
71
83
|
addResponseModelIdObservationCounts(
|
|
72
84
|
existing.responseModelIdObservationCounts,
|
|
@@ -89,6 +101,8 @@ export function aggregateCostEntries(entries: ReadonlyArray<CostEntry>): CostRow
|
|
|
89
101
|
apiCalls: entry.apiCalls ?? 1,
|
|
90
102
|
sideQuestions: entry.label === "side-question" ? 1 : 0,
|
|
91
103
|
handoffs: entry.label === "handoff" ? 1 : 0,
|
|
104
|
+
prewarms: entry.label === "prewarm" ? 1 : 0,
|
|
105
|
+
backgroundMemory: entry.label === "background-memory" ? 1 : 0,
|
|
92
106
|
},
|
|
93
107
|
requestedModelIds: new Set(entry.requestedModelIds),
|
|
94
108
|
responseModelIdObservationCounts: { ...entry.responseModelIdObservationCounts },
|
|
@@ -127,6 +141,8 @@ function sumRows(
|
|
|
127
141
|
apiCalls: acc.apiCalls + row.apiCalls,
|
|
128
142
|
sideQuestions: acc.sideQuestions + row.sideQuestions,
|
|
129
143
|
handoffs: acc.handoffs + row.handoffs,
|
|
144
|
+
prewarms: acc.prewarms + row.prewarms,
|
|
145
|
+
backgroundMemory: acc.backgroundMemory + row.backgroundMemory,
|
|
130
146
|
}),
|
|
131
147
|
{
|
|
132
148
|
runs: 0,
|
|
@@ -139,6 +155,8 @@ function sumRows(
|
|
|
139
155
|
apiCalls: 0,
|
|
140
156
|
sideQuestions: 0,
|
|
141
157
|
handoffs: 0,
|
|
158
|
+
prewarms: 0,
|
|
159
|
+
backgroundMemory: 0,
|
|
142
160
|
},
|
|
143
161
|
);
|
|
144
162
|
}
|
|
@@ -179,7 +197,12 @@ function kvBlock(entries: ReadonlyArray<readonly [string, string, string?]>): st
|
|
|
179
197
|
});
|
|
180
198
|
}
|
|
181
199
|
|
|
182
|
-
function summaryBlock(
|
|
200
|
+
function summaryBlock(
|
|
201
|
+
totalCost: CostAggregate,
|
|
202
|
+
totalTokens: number,
|
|
203
|
+
rows: ReadonlyArray<CostRow>,
|
|
204
|
+
promptCache: PromptCacheTelemetry | null,
|
|
205
|
+
): string[] {
|
|
183
206
|
const totals = sumRows(rows);
|
|
184
207
|
const resolvedTotal = totalTokens > 0 ? totalTokens : totals.tokens;
|
|
185
208
|
// No priced call, no cost row: neither the `cost $0.00` the overlay used to
|
|
@@ -190,17 +213,36 @@ function summaryBlock(totalCost: CostAggregate, totalTokens: number, rows: Reado
|
|
|
190
213
|
// A side question is billed like anything else and is counted here, but it is
|
|
191
214
|
// deliberately not a turn: it never entered the session, so `turns` above
|
|
192
215
|
// excludes it and this row says how much of the spend sat beside the session.
|
|
216
|
+
const cacheRows =
|
|
217
|
+
promptCache !== null && hasPromptCacheTelemetry(promptCache)
|
|
218
|
+
? [
|
|
219
|
+
[
|
|
220
|
+
"uncached prefill",
|
|
221
|
+
promptCache.uncachedPrefillTokens === null ? "not reported" : formatTokens(promptCache.uncachedPrefillTokens),
|
|
222
|
+
] as const,
|
|
223
|
+
[
|
|
224
|
+
"cache verdicts",
|
|
225
|
+
`hot ${promptCache.verdictCounts.hot} · partial ${promptCache.verdictCounts.partial} · cold ${promptCache.verdictCounts.cold} · small ${promptCache.verdictCounts.small}`,
|
|
226
|
+
] as const,
|
|
227
|
+
]
|
|
228
|
+
: [];
|
|
193
229
|
return kvBlock([
|
|
194
|
-
[
|
|
230
|
+
[
|
|
231
|
+
"turns",
|
|
232
|
+
formatTokens(totals.runs - totals.sideQuestions - totals.handoffs - totals.prewarms - totals.backgroundMemory),
|
|
233
|
+
],
|
|
195
234
|
["model calls", formatTokens(totals.apiCalls)],
|
|
196
235
|
...(totals.sideQuestions > 0 ? [["side questions", formatTokens(totals.sideQuestions)] as const] : []),
|
|
197
236
|
...(totals.handoffs > 0 ? [["handoffs", formatTokens(totals.handoffs)] as const] : []),
|
|
237
|
+
...(totals.prewarms > 0 ? [["pre-warms", formatTokens(totals.prewarms)] as const] : []),
|
|
238
|
+
...(totals.backgroundMemory > 0 ? [["memory steps", formatTokens(totals.backgroundMemory)] as const] : []),
|
|
198
239
|
...(cost === null ? [] : [["cost", cost] as const]),
|
|
199
240
|
["input", formatTokens(totals.input)],
|
|
200
241
|
["output", formatTokens(totals.output)],
|
|
201
242
|
["reasoning", ...reasoningValue(totals.reasoningTokens)],
|
|
202
243
|
["cache read", ...cacheReadValue(totals.cacheRead, totals.apiCalls)],
|
|
203
244
|
["cache write", formatTokens(totals.cacheWrite)],
|
|
245
|
+
...cacheRows,
|
|
204
246
|
["processed", `${formatTokens(resolvedTotal)} tokens`],
|
|
205
247
|
]);
|
|
206
248
|
}
|
|
@@ -213,10 +255,12 @@ function modelBlock(row: CostRow): string[] {
|
|
|
213
255
|
return kvBlock([
|
|
214
256
|
["requested model ids", row.requestedModelIds.join(", ")],
|
|
215
257
|
["response model id observation", responseModelIdObservationCountsLabel(row.responseModelIdObservationCounts)],
|
|
216
|
-
["turns", formatTokens(row.runs - row.sideQuestions - row.handoffs)],
|
|
258
|
+
["turns", formatTokens(row.runs - row.sideQuestions - row.handoffs - row.prewarms - row.backgroundMemory)],
|
|
217
259
|
["model calls", formatTokens(row.apiCalls)],
|
|
218
260
|
...(row.sideQuestions > 0 ? [["side questions", formatTokens(row.sideQuestions)] as const] : []),
|
|
219
261
|
...(row.handoffs > 0 ? [["handoffs", formatTokens(row.handoffs)] as const] : []),
|
|
262
|
+
...(row.prewarms > 0 ? [["pre-warms", formatTokens(row.prewarms)] as const] : []),
|
|
263
|
+
...(row.backgroundMemory > 0 ? [["memory steps", formatTokens(row.backgroundMemory)] as const] : []),
|
|
220
264
|
...(cost === null ? [] : [["cost", cost] as const]),
|
|
221
265
|
["input", formatTokens(row.input)],
|
|
222
266
|
["output", formatTokens(row.output)],
|
|
@@ -232,10 +276,11 @@ export function formatCostOverlayBodyLines(
|
|
|
232
276
|
totalTokens: number,
|
|
233
277
|
rows: ReadonlyArray<CostRow>,
|
|
234
278
|
contentWidth: number,
|
|
279
|
+
promptCache: PromptCacheTelemetry | null = null,
|
|
235
280
|
): string[] {
|
|
236
281
|
const theme = clioTheme();
|
|
237
282
|
const lines: string[] = [];
|
|
238
|
-
for (const line of summaryBlock(totalCost, totalTokens, rows)) {
|
|
283
|
+
for (const line of summaryBlock(totalCost, totalTokens, rows, promptCache)) {
|
|
239
284
|
lines.push(line);
|
|
240
285
|
}
|
|
241
286
|
lines.push(rule(theme, contentWidth));
|
|
@@ -258,6 +303,7 @@ export interface CostSnapshot {
|
|
|
258
303
|
totalCost: CostAggregate;
|
|
259
304
|
totalTokens: number;
|
|
260
305
|
rows: CostRow[];
|
|
306
|
+
promptCache: PromptCacheTelemetry | null;
|
|
261
307
|
}
|
|
262
308
|
|
|
263
309
|
// Session totals come from the observability projection: when a snapshot is
|
|
@@ -268,6 +314,7 @@ function buildCostSnapshot(
|
|
|
268
314
|
observability: ObservabilityContract,
|
|
269
315
|
sessionId: string | null,
|
|
270
316
|
snapshot?: ObservabilitySnapshot,
|
|
317
|
+
getSessionEntries?: () => ReadonlyArray<SessionEntry>,
|
|
271
318
|
): CostSnapshot {
|
|
272
319
|
const entries = observability.costEntries();
|
|
273
320
|
const rows = aggregateCostEntries(entries);
|
|
@@ -277,11 +324,14 @@ function buildCostSnapshot(
|
|
|
277
324
|
totalCost: snapshot?.session.cost ?? observability.sessionCostSummary(),
|
|
278
325
|
totalTokens,
|
|
279
326
|
rows,
|
|
327
|
+
promptCache: getSessionEntries ? foldPromptCacheTelemetry(getSessionEntries()) : null,
|
|
280
328
|
};
|
|
281
329
|
}
|
|
282
330
|
|
|
283
331
|
export interface OpenCostOverlayOptions {
|
|
284
332
|
sessionId?: string | null;
|
|
333
|
+
/** Session ledger, read on every render so newly settled and branched calls appear. */
|
|
334
|
+
getSessionEntries?: () => ReadonlyArray<SessionEntry>;
|
|
285
335
|
}
|
|
286
336
|
|
|
287
337
|
class CostOverlayBody implements Component {
|
|
@@ -290,7 +340,13 @@ class CostOverlayBody implements Component {
|
|
|
290
340
|
render(width: number): string[] {
|
|
291
341
|
const contentWidth = Math.max(1, Math.floor(width));
|
|
292
342
|
const snapshot = this.getSnapshot();
|
|
293
|
-
return formatCostOverlayBodyLines(
|
|
343
|
+
return formatCostOverlayBodyLines(
|
|
344
|
+
snapshot.totalCost,
|
|
345
|
+
snapshot.totalTokens,
|
|
346
|
+
snapshot.rows,
|
|
347
|
+
contentWidth,
|
|
348
|
+
snapshot.promptCache,
|
|
349
|
+
);
|
|
294
350
|
}
|
|
295
351
|
|
|
296
352
|
invalidate(): void {}
|
|
@@ -312,7 +368,9 @@ export function openCostOverlay(
|
|
|
312
368
|
): OverlayHandle {
|
|
313
369
|
const sessionId = options?.sessionId ?? null;
|
|
314
370
|
let latest: ObservabilitySnapshot = observability.snapshot();
|
|
315
|
-
const body = new CostOverlayBody(() =>
|
|
371
|
+
const body = new CostOverlayBody(() =>
|
|
372
|
+
buildCostSnapshot(observability, sessionId, latest, options?.getSessionEntries),
|
|
373
|
+
);
|
|
316
374
|
const handle = showClioOverlayFrame(tui, body, {
|
|
317
375
|
anchor: "center",
|
|
318
376
|
width: COST_OVERLAY_WIDTH,
|