@iowarp/clio-coder 0.5.0 → 0.5.2
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/.claude-plugin/marketplace.json +4 -4
- package/CHANGELOG.md +35 -0
- package/CONTRIBUTING.md +9 -0
- package/README.md +12 -9
- package/ROADMAP.md +30 -5
- package/dist/{acp-KS7ARGV6.js → acp-F6PGOFZ4.js} +2 -2
- package/dist/{agents-YOGJ2YEJ.js → agents-ZHP4R6EX.js} +22 -21
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-CEDCO6O6.js → auth-N75U2H3Z.js} +4 -4
- package/dist/{chunk-D3KWFOUT.js → chunk-23UIXH6Z.js} +3 -3
- package/dist/{chunk-ZR5YA6ZF.js → chunk-36XVK5P5.js} +5 -5
- package/dist/{chunk-AVSR2HKI.js → chunk-3DZ4LPLS.js} +6 -6
- package/dist/{chunk-LYJJ6546.js → chunk-3GSPCWFX.js} +12 -12
- package/dist/{chunk-CRHPCPZP.js → chunk-4KC4CHKJ.js} +2 -2
- package/dist/{chunk-4VDHLCF5.js → chunk-4WJBWKMI.js} +2 -2
- package/dist/{chunk-KBUTSJSR.js → chunk-4XBYHXGK.js} +2 -2
- package/dist/{chunk-6W75D37F.js → chunk-53P775GE.js} +6 -3
- package/dist/{chunk-XZWSP67B.js → chunk-5APYAXCB.js} +2 -2
- package/dist/{chunk-D65E25JG.js → chunk-67HPYNTJ.js} +2 -2
- package/dist/{chunk-5JQR5B4D.js → chunk-6KV4KCQZ.js} +4 -4
- package/dist/{chunk-V4XJWDHR.js → chunk-6UKFRTXI.js} +2 -1
- package/dist/{chunk-NDPF2N2L.js → chunk-7DW7CJW2.js} +2 -2
- package/dist/{chunk-5KQEUIWM.js → chunk-7LUEQODV.js} +4 -4
- package/dist/{chunk-LNOXCGN2.js → chunk-7UFDIOBT.js} +3 -3
- package/dist/{chunk-DXSETN72.js → chunk-7WUGNN43.js} +2 -2
- package/dist/{chunk-V35KZDUZ.js → chunk-AA3GRZWS.js} +2 -2
- package/dist/{chunk-X4CEFOSG.js → chunk-ADO3OQIC.js} +4 -4
- package/dist/{chunk-UX2L5CUD.js → chunk-AI36V3ON.js} +3 -3
- package/dist/{chunk-B7GY6QER.js → chunk-B26OUMJW.js} +2 -2
- package/dist/{chunk-LAR7DX5E.js → chunk-B5TASTCK.js} +153 -62
- package/dist/{chunk-TGWZXJ7L.js → chunk-BEMQK5Q7.js} +92 -84
- package/dist/{chunk-RNDCROSG.js → chunk-CNXU7TR2.js} +3 -3
- package/dist/{chunk-3JLTRPN7.js → chunk-CVMUXT64.js} +35 -66
- package/dist/{chunk-733ZBT5P.js → chunk-E74MJF6G.js} +4 -4
- package/dist/{chunk-T2MDZES3.js → chunk-EBMTBE76.js} +3 -3
- package/dist/{chunk-OZ76TLGU.js → chunk-EEITU7S6.js} +2 -2
- package/dist/{chunk-GRHOXDKB.js → chunk-ELDJWJKM.js} +97 -14
- package/dist/{chunk-GCQFN7YI.js → chunk-EMYEQLWO.js} +2 -2
- package/dist/{chunk-LTWH2ACR.js → chunk-EQPFEDFV.js} +222 -127
- package/dist/{chunk-TDGYTWM6.js → chunk-F4I3H56H.js} +2 -2
- package/dist/chunk-F6KCJO3U.js +523 -0
- package/dist/{chunk-FGSQHUCK.js → chunk-F6VKWTTY.js} +5 -5
- package/dist/{chunk-UJD5MPP6.js → chunk-FLNXQQ5B.js} +2 -2
- package/dist/{chunk-EX57VVWW.js → chunk-FOSRJ2VZ.js} +4 -4
- package/dist/{chunk-ZARZ4POR.js → chunk-G5ZDQQE3.js} +3 -3
- package/dist/{chunk-HQVN7G4F.js → chunk-G62JBPXN.js} +7 -7
- package/dist/{chunk-ZJPORZTC.js → chunk-GIAI7A2K.js} +2 -2
- package/dist/chunk-GPTR6OTU.js +2551 -0
- package/dist/{chunk-EZD2BXGP.js → chunk-GUFQPTQK.js} +2 -2
- package/dist/{chunk-OPD7GL6F.js → chunk-H6FQVNZC.js} +8 -7
- package/dist/chunk-H7REJ7L5.js +80 -0
- package/dist/{chunk-EYTLV3W3.js → chunk-HTWTORF7.js} +2 -2
- package/dist/{chunk-DF6PI6GN.js → chunk-I6UKQPGS.js} +3 -3
- package/dist/{chunk-ISHUS7HC.js → chunk-JRW236JT.js} +3 -3
- package/dist/{chunk-DE2LU267.js → chunk-KKAJGT3B.js} +3 -2
- package/dist/{chunk-OV62D6KO.js → chunk-KQMYL5GR.js} +3 -3
- package/dist/{chunk-QDUUOZ3S.js → chunk-KWMFC7FN.js} +3 -3
- package/dist/{chunk-R7FGRZNF.js → chunk-LXYHCCIZ.js} +9 -9
- package/dist/{chunk-NFSK2VNU.js → chunk-LZMTVVN4.js} +2 -2
- package/dist/{chunk-62UK7AGW.js → chunk-M5PMRZSR.js} +397 -44
- package/dist/chunk-MMZMM6SW.js +131 -0
- package/dist/{chunk-FFYTC2KQ.js → chunk-MNABNEBX.js} +2 -2
- package/dist/{chunk-XMDBTYCH.js → chunk-N3CWOGVF.js} +3 -3
- package/dist/{chunk-VYRQHORQ.js → chunk-NMQSO6Z6.js} +4 -3
- package/dist/{chunk-R2UUNSNQ.js → chunk-O3ZAF7UY.js} +18 -5
- package/dist/{chunk-4SYHGVDE.js → chunk-OQNCLZI4.js} +4 -4
- package/dist/{chunk-EG4ARXPC.js → chunk-OX6QTA4N.js} +3 -3
- package/dist/{chunk-P4GNZPXO.js → chunk-OYUS3UZP.js} +2 -2
- package/dist/{chunk-OQ2EOAHA.js → chunk-PF36KOGI.js} +291 -112
- package/dist/{chunk-55RMDDFM.js → chunk-PGQG7ZMW.js} +2 -2
- package/dist/{chunk-CBAQPTDU.js → chunk-PIU6BXXW.js} +2 -2
- package/dist/{chunk-EKV4UBCM.js → chunk-PZBQUJ2F.js} +2 -2
- package/dist/{chunk-7RET77VB.js → chunk-Q2HKY32Y.js} +2 -2
- package/dist/{chunk-U6YTUVOX.js → chunk-Q4RMNWMZ.js} +4 -4
- package/dist/chunk-Q6FRR3AQ.js +48 -0
- package/dist/{chunk-6RJMYYIE.js → chunk-QJSIAJBY.js} +3 -3
- package/dist/{chunk-DOUISWEE.js → chunk-QOJ4ERMU.js} +5 -5
- package/dist/{chunk-IFPDAD7R.js → chunk-RWSRKXLT.js} +3 -3
- package/dist/{chunk-T33IYTZM.js → chunk-SAASVMIY.js} +3 -3
- package/dist/{chunk-2DTIWSAW.js → chunk-SEQDH6JC.js} +3 -3
- package/dist/{chunk-BRCOSE7O.js → chunk-SZUO5BSE.js} +2 -2
- package/dist/{chunk-HOEDA42N.js → chunk-T7HZ7KJF.js} +2 -2
- package/dist/{chunk-OJXOA6YU.js → chunk-TL6LNERH.js} +2 -2
- package/dist/{chunk-UCINIRHW.js → chunk-TPCZXWLT.js} +3 -3
- package/dist/{chunk-ZUKUCZYZ.js → chunk-TQ2KTH4A.js} +2 -2
- package/dist/{chunk-4WOOTKFD.js → chunk-U3FETNQB.js} +341 -20
- package/dist/{chunk-5B3RTYAK.js → chunk-UGDSB4AN.js} +2 -2
- package/dist/{chunk-VKHLUZNO.js → chunk-UZ7YBL43.js} +3 -3
- package/dist/{chunk-QNUQ7K7D.js → chunk-VKMSEO7Y.js} +4 -4
- package/dist/{chunk-IN7DGBVS.js → chunk-VLX5VZ35.js} +5 -5
- package/dist/{chunk-SJGS3GDI.js → chunk-WAGBMMNX.js} +5 -5
- package/dist/{chunk-BFOSV5EZ.js → chunk-WX2YCH7F.js} +2 -2
- package/dist/{chunk-3LT34CAM.js → chunk-XBIGUILU.js} +32 -17
- package/dist/{chunk-XDHUDE5K.js → chunk-XKYBFRWR.js} +5 -5
- package/dist/{chunk-U5QU5ZOD.js → chunk-XYPWFSU5.js} +3 -3
- package/dist/{chunk-YBUECLAF.js → chunk-YEJQDODA.js} +2 -2
- package/dist/{chunk-YQ6XEFVK.js → chunk-Z74OGONW.js} +39 -7
- package/dist/{chunk-I4ELN5BX.js → chunk-ZTNOEJRI.js} +2 -2
- package/dist/cli/index.js +26 -26
- package/dist/{clio-K2PBVCEM.js → clio-4IKFE25F.js} +2 -2
- package/dist/{clio-context-tools-GR4OHFSO.js → clio-context-tools-OHJXYX4R.js} +25 -23
- package/dist/{code-nav-4X3OI6DK.js → code-nav-XPM3MY5I.js} +7 -7
- package/dist/{config-Q5J7UBAB.js → config-343YS25T.js} +43 -41
- package/dist/{config-graph-P3555574.js → config-graph-WI263KDX.js} +43 -41
- package/dist/{configure-KIJ32ZO6.js → configure-GZDG4HER.js} +21 -21
- package/dist/{context-LFBQOSXT.js → context-4OFO7N7Y.js} +12 -12
- package/dist/{context-WBH3KSVR.js → context-JLK2RLOG.js} +42 -40
- package/dist/{context-NNLBES2Y.js → context-O6DIWCF6.js} +23 -21
- package/dist/{context-clear-YOHMQ6SQ.js → context-clear-MR7KOGQI.js} +42 -40
- package/dist/{context-working-set-MRAEVDNV.js → context-working-set-YZAD3KWO.js} +14 -13
- package/dist/{data-tool-JJPBGMQJ.js → data-tool-EKD7DFHG.js} +7 -7
- package/dist/{detail-RHJOTGN4.js → detail-YZPHFEVJ.js} +43 -41
- package/dist/{dispatch-runner-NC7PYNIO.js → dispatch-runner-VKVXVTWJ.js} +44 -42
- package/dist/{doctor-S5KZ2GTN.js → doctor-53AVQXAO.js} +17 -16
- package/dist/{doctor-deep-2EJQSHIZ.js → doctor-deep-BLRB2NCG.js} +5 -5
- package/dist/{eval-3D6M36N7.js → eval-P3BQSLQE.js} +21 -20
- package/dist/{evidence-XNVPPLVK.js → evidence-6LLI6SZH.js} +44 -42
- package/dist/{evidence-6IYN52ET.js → evidence-HTN3JLUO.js} +42 -40
- package/dist/{evidence-JVECPI3F.js → evidence-NJRE3R5H.js} +42 -40
- package/dist/{evolve-TLPUDJDM.js → evolve-WWZHJVJP.js} +42 -40
- package/dist/{fleet-WKVBF5SZ.js → fleet-GGZ4BVJE.js} +64 -62
- package/dist/{fleet-6RJWIOEO.js → fleet-QG3IIWWM.js} +44 -42
- package/dist/{fleet-commands-L6WFT7KZ.js → fleet-commands-J2ZIKISQ.js} +7 -7
- package/dist/{fleet-decisions-BTQMWU5A.js → fleet-decisions-Y2Q7375Q.js} +8 -8
- package/dist/{fleet-graph-553DZ67Q.js → fleet-graph-TCBCCCBP.js} +11 -11
- package/dist/{fleet-inspect-236FZPRB.js → fleet-inspect-KOLKBC56.js} +44 -42
- package/dist/{fleet-preflight-NZQHABWO.js → fleet-preflight-44UNCC4Y.js} +27 -25
- package/dist/{fleet-validate-7NLAE26R.js → fleet-validate-K2FXRZVA.js} +13 -13
- package/dist/{fleet-verify-E3RO6A5W.js → fleet-verify-AS444WDW.js} +42 -40
- package/dist/{fleet-view-KMZQY7YJ.js → fleet-view-X4JU4J6O.js} +43 -41
- package/dist/gui/ops-worker.js +9 -9
- package/dist/gui/reads-worker.js +9 -8
- package/dist/{init-DV5B6HQG.js → init-VSOWFHVL.js} +54 -52
- package/dist/{interactive-OXGYZYAS.js → interactive-JRCBENLZ.js} +1733 -577
- package/dist/{interop-J7UOBOSF.js → interop-JR6BCY7R.js} +10 -10
- package/dist/{inventory-OEGIL6PY.js → inventory-3JUGLVJI.js} +43 -41
- package/dist/{library-ROZAMUIL.js → library-7BOH3Y7N.js} +15 -15
- package/dist/{library-B3UPGY4V.js → library-7PFONXUI.js} +9 -9
- package/dist/{library-MXQA5DLT.js → library-TUYZMFIA.js} +7 -7
- package/dist/{library-import-2LTWOVBD.js → library-import-TJVXKLDK.js} +10 -10
- package/dist/{library-inventory-LJ3XHLWO.js → library-inventory-MD3AYTP4.js} +9 -9
- package/dist/{library-validation-DARHHUNW.js → library-validation-ZDLITEA3.js} +7 -7
- package/dist/{mcp-2GSPYQ54.js → mcp-EFCWUPUR.js} +3 -3
- package/dist/{memory-J3STUUIK.js → memory-Q2YVOKK5.js} +42 -40
- package/dist/{models-Y3GMFJ2V.js → models-M7BOCW7F.js} +17 -16
- package/dist/{monitor-LHNH577J.js → monitor-2HD3MC67.js} +47 -45
- package/dist/{orchestrator-DTAPXULA.js → orchestrator-OUW3ZN6Y.js} +1894 -226
- package/dist/{panes-A743ONZ5.js → panes-TTPPSYCL.js} +3 -3
- package/dist/{preload-OJBMAIXF.js → preload-A47C2NUF.js} +42 -40
- package/dist/{providers-CMETPZNS.js → providers-T43W7EL4.js} +4 -4
- package/dist/{resources-FY6XYFN2.js → resources-TP6X2V6W.js} +20 -11
- package/dist/{run-H64MEVTA.js → run-LDSBPMCS.js} +61 -59
- package/dist/{share-CAFMMQLM.js → share-URHKKMHR.js} +9 -9
- package/dist/{skills-ERKQUC7L.js → skills-E477MOOO.js} +13 -11
- package/dist/{skills-eval-CQ23MYQK.js → skills-eval-AIBR2L7H.js} +583 -93
- package/dist/{skills-inventory-TVUYJDVN.js → skills-inventory-HLMKY3R5.js} +13 -11
- package/dist/{slash-commands-ROG3KIFJ.js → slash-commands-LIIZKA5Y.js} +28 -26
- package/dist/{startup-background-KDWCQMWT.js → startup-background-JR2KDK6R.js} +43 -41
- package/dist/{steer-KKYXJSH4.js → steer-D7RTAPCM.js} +3 -3
- package/dist/{system-ZDW44ZGX.js → system-X2P5N4IY.js} +14 -13
- package/dist/{targets-AJWA6E7Z.js → targets-VFFAKUFM.js} +25 -24
- package/dist/{tasks-6L2JJRC5.js → tasks-ERAWZA22.js} +6 -6
- package/dist/{terminal-lease-YFUSDPAD.js → terminal-lease-V2N2BIKQ.js} +2 -2
- package/dist/{trace-LA5MVR4Y.js → trace-MA5BT7XY.js} +3 -3
- package/dist/{usage-XSILDHKF.js → usage-WYFY2L6M.js} +50 -48
- package/dist/{verifiers-ECA5GIHL.js → verifiers-TYIW2XKF.js} +7 -7
- package/dist/{verify-R6QQCCEB.js → verify-242UFYTP.js} +6 -6
- package/dist/{web-fetch-PVZNMBOB.js → web-fetch-LRAGYU6Y.js} +3 -3
- package/dist/{wiki-generate-RP22WP5K.js → wiki-generate-OFKOX2T6.js} +53 -51
- package/dist/worker/entry.js +31 -29
- package/docs/architecture/architecture.md +1 -0
- package/docs/architecture/context-engine.md +4 -2
- package/docs/architecture/observability.md +6 -4
- package/docs/architecture/prompt-envelope-and-tools.md +1 -1
- package/docs/architecture/session-lifecycle.md +1 -1
- package/docs/architecture/tui-design.md +12 -9
- package/docs/gui/parity/02-slash-and-surfaces.md +1 -1
- package/docs/guide/commands-and-modes.md +91 -5
- package/docs/guide/configuration-and-targets.md +2 -2
- package/docs/guide/context-continuity.md +49 -0
- package/docs/guide/proactive-memory.md +6 -3
- package/library/registry.yaml +292 -32
- package/library/skills/README.md +27 -2
- package/library/skills/context/context-handoff/SKILL.md +10 -4
- package/library/skills/meta/clio-coder-dev/SKILL.md +92 -88
- package/library/skills/meta/clio-coder-dev/evals.md +51 -46
- package/library/skills/meta/clio-coder-dev/plugin.json +2 -2
- package/library/skills/meta/clio-coder-dev/references/change-map.md +49 -0
- package/library/skills/meta/clio-coder-test/SKILL.md +89 -142
- package/library/skills/meta/clio-coder-test/evals.md +58 -62
- package/library/skills/meta/clio-coder-test/plugin.json +2 -2
- package/library/skills/meta/clio-coder-test/references/harness.md +3 -3
- package/library/skills/meta/clio-coder-test/references/lifecycle-validation.md +30 -0
- package/library/skills/meta/clio-coder-test/references/test-map.md +60 -89
- package/library/skills/registry.yaml +5 -5
- package/library/skills/skill-marketplace.json +12 -14
- package/package.json +1 -1
- package/src/cli/skills-eval.ts +1064 -54
- package/src/cli/usage.ts +2 -2
- package/src/core/clio-repo.ts +3 -0
- package/src/core/tool-names.ts +1 -0
- package/src/domains/context/budget/inspection.ts +9 -0
- package/src/domains/context/budget/live-view.ts +418 -0
- package/src/domains/context/budget/pressure.ts +393 -0
- package/src/domains/context/budget/request-fit.ts +15 -0
- package/src/domains/evidence/build.ts +24 -0
- package/src/domains/gateway/mcp/client.ts +1 -1
- package/src/domains/memory/commit-state.ts +160 -0
- package/src/domains/memory/operations.ts +18 -10
- package/src/domains/memory/prompt-cache.ts +95 -0
- package/src/domains/memory/prompt-section.ts +50 -7
- package/src/domains/memory/relevance.ts +93 -0
- package/src/domains/memory/restoration.ts +78 -0
- package/src/domains/memory/store.ts +39 -1
- package/src/domains/middleware/memory-intervention.ts +116 -24
- package/src/domains/observability/background-memory-usage.ts +1 -1
- package/src/domains/observability/cost.ts +3 -3
- package/src/domains/observability/extension.ts +1 -1
- package/src/domains/observability/metrics.ts +1 -1
- package/src/domains/prompts/compiler.ts +1 -1
- package/src/domains/prompts/extension.ts +38 -1
- package/src/domains/quota/anthropic-max-provider.ts +134 -0
- package/src/domains/quota/anthropic-usage.ts +220 -0
- package/src/domains/quota/antigravity-provider.ts +339 -0
- package/src/domains/quota/cache.ts +87 -0
- package/src/domains/quota/claude-code-provider.ts +169 -0
- package/src/domains/quota/codex-provider.ts +237 -0
- package/src/domains/quota/presentation.ts +240 -0
- package/src/domains/quota/registry.ts +23 -0
- package/src/domains/quota/service.ts +93 -0
- package/src/domains/quota/summary-feed.ts +86 -0
- package/src/domains/quota/types.ts +84 -0
- package/src/domains/resources/index.ts +11 -0
- package/src/domains/resources/skills/catalog-view.ts +571 -0
- package/src/domains/resources/skills/lexical-match.ts +136 -0
- package/src/domains/resources/skills/loader.ts +38 -0
- package/src/domains/resources/skills/promotion.ts +1 -55
- package/src/domains/resources/skills/provenance-pin.ts +50 -20
- package/src/domains/safety/action-classifier.ts +1 -0
- package/src/domains/session/compaction/branch-summary.ts +4 -1
- package/src/domains/session/compaction/compact.ts +18 -2
- package/src/domains/session/compaction/cut-point.ts +20 -1
- package/src/domains/session/compaction/tokens.ts +48 -3
- package/src/domains/session/context-accounting.ts +8 -1
- package/src/domains/session/continuity/carry.ts +59 -0
- package/src/domains/session/continuity/contract.ts +592 -0
- package/src/domains/session/continuity/evidence.ts +290 -0
- package/src/domains/session/continuity/fold.ts +1075 -0
- package/src/domains/session/continuity/note.ts +79 -0
- package/src/domains/session/continuity/operator-request.ts +104 -0
- package/src/domains/session/continuity/persistence.ts +408 -0
- package/src/domains/session/continuity/ports.ts +231 -0
- package/src/domains/session/continuity/projection.ts +538 -0
- package/src/domains/session/continuity/validate.ts +352 -0
- package/src/domains/session/entries.ts +50 -3
- package/src/domains/session/index.ts +48 -0
- package/src/domains/session/migrations/index.ts +7 -3
- package/src/domains/session/tree/fork.ts +15 -1
- package/src/domains/session/usage.ts +2 -2
- package/src/engine/acp/commands.ts +1 -1
- package/src/engine/agent.ts +133 -9
- package/src/engine/session.ts +13 -6
- package/src/entry/orchestrator.ts +116 -33
- package/src/interactive/chat-loop-messages.ts +2 -2
- package/src/interactive/chat-loop.ts +219 -63
- package/src/interactive/chat-renderer.ts +99 -8
- package/src/interactive/context-overlay.ts +24 -3
- package/src/interactive/continuity-controller.ts +526 -0
- package/src/interactive/dispatch-board.ts +21 -3
- package/src/interactive/footer/dashboard.ts +25 -1
- package/src/interactive/footer/key-hints.ts +2 -2
- package/src/interactive/footer/pages.ts +70 -27
- package/src/interactive/footer/widgets.ts +32 -7
- package/src/interactive/footer-panel.ts +1 -1
- package/src/interactive/interactive-application.ts +7 -2
- package/src/interactive/interactive-input-runtime.ts +2 -2
- package/src/interactive/interactive-presentation.ts +15 -0
- package/src/interactive/interactive-slash-runtime.ts +45 -8
- package/src/interactive/interactive-tickers.ts +7 -1
- package/src/interactive/model-session-replay.ts +130 -3
- package/src/interactive/output-reserve.ts +35 -0
- package/src/interactive/overlay-general-openers.ts +12 -8
- package/src/interactive/overlay-key-routing.ts +6 -9
- package/src/interactive/overlay-lifecycle.ts +10 -6
- package/src/interactive/overlay-session-lifecycle.ts +21 -14
- package/src/interactive/quota-view.ts +229 -0
- package/src/interactive/session-last-turn.ts +1 -1
- package/src/interactive/session-transcript.ts +2 -1
- package/src/interactive/session-usage-reseed.ts +2 -2
- package/src/interactive/side-question.ts +2 -2
- package/src/interactive/slash-commands.ts +28 -9
- package/src/interactive/turn-context.ts +686 -63
- package/src/interactive/turn-middleware.ts +39 -6
- package/src/interactive/turn-persistence.ts +15 -2
- package/src/interactive/turn-prewarm.ts +1 -1
- package/src/interactive/turn-runtime.ts +48 -5
- package/src/interactive/{cost-overlay.ts → usage-overlay.ts} +121 -33
- package/src/interactive/welcome-dashboard.ts +26 -3
- package/src/tools/agent-tools.ts +3 -1
- package/src/tools/bootstrap.ts +6 -0
- package/src/tools/builtin-tool-catalog.ts +9 -0
- package/src/tools/context/index.ts +148 -113
- package/src/tools/context/surface.ts +11 -7
- package/src/tools/core-bootstrap.ts +4 -0
- package/src/tools/observation.ts +8 -2
- package/src/tools/policy.ts +3 -0
- package/src/tools/self-compact.ts +31 -0
- package/src/tools/surface.ts +1 -0
- package/src/tools/tasks.ts +1 -1
- package/dist/chunk-CTFPFW3H.js +0 -44
- package/dist/chunk-EOJPDNUP.js +0 -1325
- package/dist/chunk-I4Y4WKZR.js +0 -386
package/src/engine/agent.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type AssistantMessage,
|
|
3
|
+
createAssistantMessageEventStream,
|
|
4
|
+
createInitialSystemMessage,
|
|
5
|
+
toToolDeclaration,
|
|
6
|
+
} from "@earendil-works/pi-ai";
|
|
2
7
|
import { resolvedRequestContext } from "./context.js";
|
|
3
8
|
/**
|
|
4
9
|
* Thin wrapper over Clio's engine Agent class.
|
|
@@ -13,12 +18,33 @@ import { resolvedRequestContext } from "./context.js";
|
|
|
13
18
|
* Pi's resolved prompt/tool request view through streamFn.
|
|
14
19
|
*/
|
|
15
20
|
|
|
16
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
Agent,
|
|
23
|
+
type AgentMessage,
|
|
24
|
+
type AgentOptions,
|
|
25
|
+
type BeforeToolCallContext,
|
|
26
|
+
type StreamFn,
|
|
27
|
+
} from "@earendil-works/pi-agent-core";
|
|
17
28
|
import { isDispositionedToolResultError } from "../tools/result-disposition.js";
|
|
18
29
|
import { engineStreamSimple } from "./api-registry.js";
|
|
19
30
|
|
|
20
31
|
export type EngineStreamFn = (...args: Parameters<typeof engineStreamSimple>) => ReturnType<StreamFn>;
|
|
21
32
|
|
|
33
|
+
/** Pi's settled-turn port, after all awaited result listeners. Replace context, not operator messages. */
|
|
34
|
+
export type EnginePrepareNextTurnContext = Parameters<NonNullable<AgentOptions["prepareNextTurnWithContext"]>>[0];
|
|
35
|
+
export type EnginePrepareNextTurnUpdate = Awaited<ReturnType<NonNullable<AgentOptions["prepareNextTurnWithContext"]>>>;
|
|
36
|
+
export type EngineToolBatchContext = Pick<BeforeToolCallContext, "assistantMessage" | "context">;
|
|
37
|
+
export interface EngineToolBatchRejection {
|
|
38
|
+
reason: string;
|
|
39
|
+
}
|
|
40
|
+
export interface EngineStreamRequest {
|
|
41
|
+
model: Parameters<StreamFn>[0];
|
|
42
|
+
/** Actual normalized transcript, after conversion and the final steering drain. Inspect only. */
|
|
43
|
+
context: Parameters<StreamFn>[1];
|
|
44
|
+
options: Parameters<StreamFn>[2];
|
|
45
|
+
}
|
|
46
|
+
export type EngineStreamAdmission = { block: true; reason: string } | { block: false; correlationId?: string };
|
|
47
|
+
|
|
22
48
|
export type EngineAgentOptions = Omit<AgentOptions, "streamFn"> & {
|
|
23
49
|
/** Legacy/custom request view. Explicit overrides also replace the native hook in tests. */
|
|
24
50
|
streamFn?: EngineStreamFn;
|
|
@@ -26,11 +52,63 @@ export type EngineAgentOptions = Omit<AgentOptions, "streamFn"> & {
|
|
|
26
52
|
transcriptStreamFn?: StreamFn;
|
|
27
53
|
/** Called immediately before each native stream delegate invocation. */
|
|
28
54
|
onStreamInvocation?: () => void;
|
|
55
|
+
/** One fail-closed decision per assistant batch, before any valid sibling's per-call guard. */
|
|
56
|
+
beforeToolBatch?: (
|
|
57
|
+
context: EngineToolBatchContext,
|
|
58
|
+
signal?: AbortSignal,
|
|
59
|
+
) => EngineToolBatchRejection | undefined | Promise<EngineToolBatchRejection | undefined>;
|
|
60
|
+
/** Synchronous final admission: no suspension, reduction, request mutation, or model invocation. */
|
|
61
|
+
beforeStreamRequest?: (request: EngineStreamRequest) => EngineStreamAdmission;
|
|
29
62
|
};
|
|
30
63
|
|
|
31
64
|
export interface EngineAgentHandle {
|
|
32
65
|
agent: Agent;
|
|
33
66
|
state(): Agent["state"];
|
|
67
|
+
/** Exact emitted assistant object only. In-memory attribution, never proof of success or durability. */
|
|
68
|
+
requestCorrelationId(message: AgentMessage): string | undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function batchAwareBeforeToolCall(
|
|
72
|
+
batch: NonNullable<EngineAgentOptions["beforeToolBatch"]>,
|
|
73
|
+
delegate: AgentOptions["beforeToolCall"],
|
|
74
|
+
): NonNullable<AgentOptions["beforeToolCall"]> {
|
|
75
|
+
const decisions = new WeakMap<AssistantMessage, Promise<EngineToolBatchRejection | undefined>>();
|
|
76
|
+
return async (context, signal) => {
|
|
77
|
+
let decision = decisions.get(context.assistantMessage);
|
|
78
|
+
if (!decision) {
|
|
79
|
+
decision = Promise.resolve()
|
|
80
|
+
.then(() => batch({ assistantMessage: context.assistantMessage, context: context.context }, signal))
|
|
81
|
+
.catch(() => ({ reason: "Tool batch admission failed" }));
|
|
82
|
+
decisions.set(context.assistantMessage, decision);
|
|
83
|
+
}
|
|
84
|
+
const rejection = await decision;
|
|
85
|
+
if (rejection) return { block: true, reason: rejection.reason.slice(0, 1024) || "Tool batch rejected" };
|
|
86
|
+
return delegate?.(context, signal);
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function refusedStream(request: EngineStreamRequest, reason: string, aborted = false): ReturnType<StreamFn> {
|
|
91
|
+
const stream = createAssistantMessageEventStream();
|
|
92
|
+
const message: AssistantMessage = {
|
|
93
|
+
role: "assistant",
|
|
94
|
+
content: [],
|
|
95
|
+
api: request.model.api,
|
|
96
|
+
provider: request.model.provider,
|
|
97
|
+
model: request.model.id,
|
|
98
|
+
usage: {
|
|
99
|
+
input: 0,
|
|
100
|
+
output: 0,
|
|
101
|
+
cacheRead: 0,
|
|
102
|
+
cacheWrite: 0,
|
|
103
|
+
totalTokens: 0,
|
|
104
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
105
|
+
},
|
|
106
|
+
stopReason: aborted ? "aborted" : "error",
|
|
107
|
+
errorMessage: reason.slice(0, 1024) || "Request admission refused",
|
|
108
|
+
timestamp: Date.now(),
|
|
109
|
+
};
|
|
110
|
+
stream.push({ type: "error", reason: aborted ? "aborted" : "error", error: message });
|
|
111
|
+
return stream;
|
|
34
112
|
}
|
|
35
113
|
|
|
36
114
|
function dispositionAwareAfterToolCall(
|
|
@@ -46,17 +124,53 @@ function dispositionAwareAfterToolCall(
|
|
|
46
124
|
}
|
|
47
125
|
|
|
48
126
|
export function createEngineAgent(options: EngineAgentOptions = {}): EngineAgentHandle {
|
|
49
|
-
const {
|
|
127
|
+
const {
|
|
128
|
+
streamFn,
|
|
129
|
+
transcriptStreamFn = engineStreamSimple,
|
|
130
|
+
onStreamInvocation,
|
|
131
|
+
beforeToolBatch,
|
|
132
|
+
beforeStreamRequest,
|
|
133
|
+
...agentOptions
|
|
134
|
+
} = options;
|
|
135
|
+
const correlations = new WeakMap<AgentMessage, string>();
|
|
136
|
+
let activeCorrelationId: string | undefined;
|
|
137
|
+
const invoke: StreamFn = (model, context, streamOptions) => {
|
|
138
|
+
onStreamInvocation?.();
|
|
139
|
+
return streamFn
|
|
140
|
+
? streamFn(model, resolvedRequestContext(context), streamOptions)
|
|
141
|
+
: transcriptStreamFn(model, context, streamOptions);
|
|
142
|
+
};
|
|
143
|
+
const admit: StreamFn = (model, context, streamOptions) => {
|
|
144
|
+
if (!beforeStreamRequest) return invoke(model, context, streamOptions);
|
|
145
|
+
activeCorrelationId = undefined;
|
|
146
|
+
const request: EngineStreamRequest = { model, context, options: streamOptions };
|
|
147
|
+
let admission: EngineStreamAdmission;
|
|
148
|
+
try {
|
|
149
|
+
admission = beforeStreamRequest(request);
|
|
150
|
+
} catch {
|
|
151
|
+
return refusedStream(request, "Request admission failed", streamOptions?.signal?.aborted);
|
|
152
|
+
}
|
|
153
|
+
if (streamOptions?.signal?.aborted) return refusedStream(request, "Request aborted before invocation", true);
|
|
154
|
+
if (admission.block) return refusedStream(request, admission.reason);
|
|
155
|
+
activeCorrelationId = admission.correlationId;
|
|
156
|
+
return invoke(model, context, streamOptions);
|
|
157
|
+
};
|
|
50
158
|
const agent = new Agent({
|
|
51
159
|
...agentOptions,
|
|
52
|
-
streamFn:
|
|
53
|
-
|
|
54
|
-
return streamFn
|
|
55
|
-
? streamFn(model, resolvedRequestContext(context), streamOptions)
|
|
56
|
-
: transcriptStreamFn(model, context, streamOptions);
|
|
57
|
-
},
|
|
160
|
+
streamFn: beforeStreamRequest ? admit : invoke,
|
|
161
|
+
...(beforeToolBatch ? { beforeToolCall: batchAwareBeforeToolCall(beforeToolBatch, options.beforeToolCall) } : {}),
|
|
58
162
|
afterToolCall: dispositionAwareAfterToolCall(options.afterToolCall),
|
|
59
163
|
});
|
|
164
|
+
if (beforeStreamRequest) {
|
|
165
|
+
agent.subscribe((event) => {
|
|
166
|
+
if (event.type === "message_end" && event.message.role === "assistant" && activeCorrelationId !== undefined) {
|
|
167
|
+
correlations.set(event.message, activeCorrelationId);
|
|
168
|
+
}
|
|
169
|
+
if (event.type === "agent_start" || event.type === "turn_end" || event.type === "agent_end") {
|
|
170
|
+
activeCorrelationId = undefined;
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}
|
|
60
174
|
// Pi correctly drops aborted assistants at the provider boundary: partial
|
|
61
175
|
// reasoning and tool calls are not valid provider history. Preserve the
|
|
62
176
|
// lifecycle fact and visible text as a host record instead, including on
|
|
@@ -83,6 +197,7 @@ export function createEngineAgent(options: EngineAgentOptions = {}): EngineAgent
|
|
|
83
197
|
return {
|
|
84
198
|
agent,
|
|
85
199
|
state: () => agent.state,
|
|
200
|
+
requestCorrelationId: (message) => correlations.get(message),
|
|
86
201
|
};
|
|
87
202
|
}
|
|
88
203
|
|
|
@@ -99,3 +214,12 @@ export function replaceEngineMessages(
|
|
|
99
214
|
export function setEngineSystemPrompt(agent: Agent, systemPrompt: string): void {
|
|
100
215
|
replaceEngineMessages(agent, agent.state.messages, systemPrompt);
|
|
101
216
|
}
|
|
217
|
+
|
|
218
|
+
/** Explicit host recovery can follow a terminal assistant. Empty input starts
|
|
219
|
+
* the native loop on the installed transcript without emitting a user message.
|
|
220
|
+
* Agent.continue() rejects that tail even when durable operator control already
|
|
221
|
+
* authorized another invocation. Normal tool continuation stays inside Pi.
|
|
222
|
+
*/
|
|
223
|
+
export function continueEngineWithoutInput(agent: Agent): Promise<void> {
|
|
224
|
+
return agent.prompt([]);
|
|
225
|
+
}
|
package/src/engine/session.ts
CHANGED
|
@@ -62,19 +62,26 @@ export interface ClioSessionMeta {
|
|
|
62
62
|
platform: string;
|
|
63
63
|
nodeVersion: string;
|
|
64
64
|
/**
|
|
65
|
-
* Version
|
|
65
|
+
* Version 5 on every new session. Readers reject earlier versions, sessions
|
|
66
66
|
* that omit this field, and versions from the future.
|
|
67
67
|
*/
|
|
68
68
|
sessionFormatVersion?: number;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
|
-
* Version 4
|
|
73
|
-
* `contextRecall`).
|
|
74
|
-
*
|
|
75
|
-
*
|
|
72
|
+
* Version 4 added the working-set ledger kinds (`contextEviction`,
|
|
73
|
+
* `contextRecall`). Version 5 adds the durable continuity kinds
|
|
74
|
+
* (`handoffTransaction`, `continuityCommit`) and the optional continuity
|
|
75
|
+
* payload a compaction summary carries.
|
|
76
|
+
*
|
|
77
|
+
* Each bump exists for the same reason: an older reader would parse the new
|
|
78
|
+
* records as unknown kinds and replay the session as if the state they record
|
|
79
|
+
* had never happened. A v4 build reading a v5 ledger would show no accepted
|
|
80
|
+
* handoff note and no paused transaction, so it refuses the file instead of
|
|
81
|
+
* misreading it. Both steps are additive to the ledger, so no historical entry
|
|
82
|
+
* is rewritten; only the metadata stamp moves.
|
|
76
83
|
*/
|
|
77
|
-
export const CURRENT_SESSION_FORMAT_VERSION =
|
|
84
|
+
export const CURRENT_SESSION_FORMAT_VERSION = 5;
|
|
78
85
|
|
|
79
86
|
export interface ClioSessionJsonlHeader {
|
|
80
87
|
type: "session";
|
|
@@ -65,11 +65,8 @@ import {
|
|
|
65
65
|
} from "../domains/lifecycle/index.js";
|
|
66
66
|
import { getVersionInfo } from "../domains/lifecycle/version.js";
|
|
67
67
|
import {
|
|
68
|
-
buildMemoryPromptSection,
|
|
69
|
-
canonicalMemoryRepositoryIdentity,
|
|
70
68
|
createTaskMemoryTelemetrySink,
|
|
71
69
|
createTaskMemoryTrace,
|
|
72
|
-
loadMemoryRecordsSync,
|
|
73
70
|
proposeInjectedTaskMemory,
|
|
74
71
|
readTaskMemorySpendSummary,
|
|
75
72
|
renderTaskMemoryHandoffSource,
|
|
@@ -81,6 +78,7 @@ import {
|
|
|
81
78
|
taskMemoryHandoffSeedOffer,
|
|
82
79
|
taskMemoryTracePath,
|
|
83
80
|
} from "../domains/memory/index.js";
|
|
81
|
+
import { createMemoryPromptReader } from "../domains/memory/prompt-cache.js";
|
|
84
82
|
import { TaskMemoryBank } from "../domains/memory/task-bank.js";
|
|
85
83
|
import { TaskMemoryEndpointBusyError } from "../domains/memory/task-memory-policy.js";
|
|
86
84
|
import { createDemoGuidanceRegistration } from "../domains/middleware/demo-guidance.js";
|
|
@@ -166,6 +164,8 @@ import type { CompactionCallObservation } from "../domains/session/compaction/co
|
|
|
166
164
|
import { type CompactInput, type CompactResult, compact } from "../domains/session/compaction/compact.js";
|
|
167
165
|
import { collectSessionEntries } from "../domains/session/compaction/session-entries.js";
|
|
168
166
|
import { estimateTokens } from "../domains/session/compaction/tokens.js";
|
|
167
|
+
import { continuityPayloadFromFold } from "../domains/session/continuity/carry.js";
|
|
168
|
+
import { continuityProjectionTokens, resolveContinuityProjection } from "../domains/session/continuity/projection.js";
|
|
169
169
|
import type { SessionContract, SessionMeta } from "../domains/session/contract.js";
|
|
170
170
|
import { activeDecisionRefs, createDecisionBoardStore } from "../domains/session/decision-board.js";
|
|
171
171
|
import type { CompactionSummaryEntry, CompactionTrigger, SessionEntry } from "../domains/session/entries.js";
|
|
@@ -205,7 +205,10 @@ import { cwdHash, openSession, readSessionTailTurns, sessionCurrentPath, session
|
|
|
205
205
|
import type { EngineModel } from "../engine/types.js";
|
|
206
206
|
import { createChatLoop } from "../interactive/chat-loop.js";
|
|
207
207
|
import type { RunIo } from "../interactive/index.js";
|
|
208
|
-
import {
|
|
208
|
+
import {
|
|
209
|
+
buildModelReplayAgentMessagesFromTurns,
|
|
210
|
+
continuityContextFromSession,
|
|
211
|
+
} from "../interactive/model-session-replay.js";
|
|
209
212
|
import { prepareBackgroundModelMetadata } from "./background-model-metadata.js";
|
|
210
213
|
import type { BootOptions } from "./boot-options.js";
|
|
211
214
|
import { readCompactionSystemPrompt } from "./compaction-prompt.js";
|
|
@@ -824,7 +827,15 @@ async function runCompactionFlow(
|
|
|
824
827
|
instructions?: string,
|
|
825
828
|
trigger?: CompactionTrigger,
|
|
826
829
|
observability?: BackgroundMemoryUsageSink,
|
|
827
|
-
budget?: Pick<
|
|
830
|
+
budget?: Pick<
|
|
831
|
+
CompactInput,
|
|
832
|
+
| "keepRecentTokens"
|
|
833
|
+
| "preserveUserTurnId"
|
|
834
|
+
| "skillContextState"
|
|
835
|
+
| "signal"
|
|
836
|
+
| "beforeSummaryCall"
|
|
837
|
+
| "checkpointForSummary"
|
|
838
|
+
>,
|
|
828
839
|
summarize?: CompactInput["summarize"],
|
|
829
840
|
): Promise<CompactResult | null> {
|
|
830
841
|
const meta = session.current();
|
|
@@ -837,6 +848,26 @@ async function runCompactionFlow(
|
|
|
837
848
|
session.current()?.id === meta.id && (session.tree(meta.id).leafId ?? undefined) === activeLeafTurnId;
|
|
838
849
|
const entries = filterEntriesToActivePath(readSessionEntriesForCompact(meta.id), activeLeafTurnId);
|
|
839
850
|
if (entries.length === 0) return null;
|
|
851
|
+
// Folded over the full applicable ledger before this compaction cuts it, so
|
|
852
|
+
// the carry written below reflects every durable transition, including ones
|
|
853
|
+
// older than the cut. Resolved once and used for three things: the payload
|
|
854
|
+
// the summary carries, the note's one-time price on both sides of the
|
|
855
|
+
// before/after comparison, and nothing else. Inspection never executes the
|
|
856
|
+
// action it proposes.
|
|
857
|
+
const continuity = resolveContinuityProjection({
|
|
858
|
+
entries,
|
|
859
|
+
sessionId: meta.id,
|
|
860
|
+
...(meta.parentSessionId && meta.parentTurnId
|
|
861
|
+
? { fork: { parentSessionId: meta.parentSessionId, parentTurnId: meta.parentTurnId } }
|
|
862
|
+
: {}),
|
|
863
|
+
});
|
|
864
|
+
// Only this session's own validated fold is carried forward. An inherited
|
|
865
|
+
// note is recall: writing it into this session's summary would republish
|
|
866
|
+
// another branch's transaction under this one's compaction.
|
|
867
|
+
const continuityNote = {
|
|
868
|
+
tokens: continuityProjectionTokens(continuity),
|
|
869
|
+
anchorTurnId: continuity.noteAnchorTurnId,
|
|
870
|
+
};
|
|
840
871
|
budget?.signal?.throwIfAborted();
|
|
841
872
|
const systemPrompt = await readCompactionSystemPrompt(settings.context.compaction.systemPrompt, meta.cwd);
|
|
842
873
|
budget?.signal?.throwIfAborted();
|
|
@@ -876,6 +907,7 @@ async function runCompactionFlow(
|
|
|
876
907
|
try {
|
|
877
908
|
result = await compact({
|
|
878
909
|
entries,
|
|
910
|
+
continuityNote,
|
|
879
911
|
...budget,
|
|
880
912
|
...(summarize ? { summarize } : {}),
|
|
881
913
|
onCall: (call) => calls.push(call),
|
|
@@ -912,6 +944,26 @@ async function runCompactionFlow(
|
|
|
912
944
|
result.usage = { ...result.usage, targetId: resolved.targetId, modelId: resolved.wireModelId };
|
|
913
945
|
}
|
|
914
946
|
|
|
947
|
+
// Refold before publishing the carry. The projection above was resolved
|
|
948
|
+
// before prompt loading, route resolution and the summary stream, and a
|
|
949
|
+
// transition appended during any of those awaits leaves the message leaf
|
|
950
|
+
// untouched, so the origin check just above passes while the carry in hand
|
|
951
|
+
// still says `ready`. §3 requires the summary to embed the *current*
|
|
952
|
+
// validated fold, so the ledger is re-read and refolded here. Only the carry
|
|
953
|
+
// is re-derived: `result` indexes the entry array the cut was computed
|
|
954
|
+
// against, which must not move under it.
|
|
955
|
+
const settledContinuity = resolveContinuityProjection({
|
|
956
|
+
entries: filterEntriesToActivePath(readSessionEntriesForCompact(meta.id), activeLeafTurnId),
|
|
957
|
+
sessionId: meta.id,
|
|
958
|
+
...(meta.parentSessionId && meta.parentTurnId
|
|
959
|
+
? { fork: { parentSessionId: meta.parentSessionId, parentTurnId: meta.parentTurnId } }
|
|
960
|
+
: {}),
|
|
961
|
+
});
|
|
962
|
+
// A suppressed projection publishes no authoritative carry: the adapter marks
|
|
963
|
+
// its own fold unvalidated, and `continuityPayloadFromFold` refuses one.
|
|
964
|
+
const continuityCarry =
|
|
965
|
+
settledContinuity.current === null ? null : continuityPayloadFromFold(settledContinuity.current);
|
|
966
|
+
|
|
915
967
|
const entry: Omit<CompactionSummaryEntry, "timestamp"> = {
|
|
916
968
|
kind: "compactionSummary",
|
|
917
969
|
turnId: randomUUID(),
|
|
@@ -923,12 +975,23 @@ async function runCompactionFlow(
|
|
|
923
975
|
firstKeptTurnId: result.firstKeptTurnId ?? "",
|
|
924
976
|
messagesSummarized: result.messagesSummarized,
|
|
925
977
|
isSplitTurn: result.isSplitTurn,
|
|
926
|
-
tokensAfter: estimateTokensAfterCompaction(entries, result),
|
|
978
|
+
tokensAfter: estimateTokensAfterCompaction(entries, result, continuityNote.tokens),
|
|
979
|
+
// The latest validated fold, carried so the transaction survives the cut
|
|
980
|
+
// that is about to remove its earlier records from replay. It preserves
|
|
981
|
+
// the immutable identity, accepted note, original policy and commit; it
|
|
982
|
+
// never manufactures a commit and never turns an eviction-only outcome
|
|
983
|
+
// into a summarized one. A later ordinary compaction with no handoff of
|
|
984
|
+
// its own still carries the newest validated payload forward, which is
|
|
985
|
+
// what keeps an eviction-only commit's state alive across summary cycles.
|
|
986
|
+
...(continuityCarry === null ? {} : { continuity: continuityCarry }),
|
|
927
987
|
// The summarization call is a real model call. Persisting its provider
|
|
928
|
-
// usage on the entry is what puts it in front of `/
|
|
988
|
+
// usage on the entry is what puts it in front of `/usage` and `clio-coder usage
|
|
929
989
|
// report`, which folded the ledger and so counted every call but this one.
|
|
930
990
|
...(result.usage !== undefined ? { usage: result.usage } : {}),
|
|
931
991
|
};
|
|
992
|
+
if (budget?.checkpointForSummary) {
|
|
993
|
+
entry.continuity = budget.checkpointForSummary(entry.turnId, entry.tokensBefore, entry.tokensAfter ?? 0);
|
|
994
|
+
}
|
|
932
995
|
if (trigger !== undefined) entry.trigger = trigger;
|
|
933
996
|
try {
|
|
934
997
|
session.appendEntry(entry);
|
|
@@ -986,7 +1049,15 @@ export function createProductionAutoCompact(
|
|
|
986
1049
|
): (
|
|
987
1050
|
instructions?: string,
|
|
988
1051
|
trigger?: CompactionTrigger,
|
|
989
|
-
budget?: Pick<
|
|
1052
|
+
budget?: Pick<
|
|
1053
|
+
CompactInput,
|
|
1054
|
+
| "keepRecentTokens"
|
|
1055
|
+
| "preserveUserTurnId"
|
|
1056
|
+
| "skillContextState"
|
|
1057
|
+
| "signal"
|
|
1058
|
+
| "beforeSummaryCall"
|
|
1059
|
+
| "checkpointForSummary"
|
|
1060
|
+
>,
|
|
990
1061
|
) => Promise<CompactResult | null> {
|
|
991
1062
|
return (instructions, trigger, budget) =>
|
|
992
1063
|
runCompactionFlow(session, getSettings(), providers, instructions, trigger, observability, budget, summarize);
|
|
@@ -1023,13 +1094,24 @@ function estimateTokensFromSummary(result: CompactResult): number {
|
|
|
1023
1094
|
* still holds the assistant message whose usage describes the pre-compaction
|
|
1024
1095
|
* prompt. Anchoring on it reports precisely the number compaction removed.
|
|
1025
1096
|
*/
|
|
1026
|
-
function estimateTokensAfterCompaction(
|
|
1097
|
+
function estimateTokensAfterCompaction(
|
|
1098
|
+
entries: ReadonlyArray<SessionEntry>,
|
|
1099
|
+
result: CompactResult,
|
|
1100
|
+
/**
|
|
1101
|
+
* The projected continuity note, which survives the reduction and is
|
|
1102
|
+
* therefore on both sides. It is already inside `tokensBefore` and the
|
|
1103
|
+
* subtraction below never removes it, because continuity records estimate at
|
|
1104
|
+
* zero; it only has to be restored on the floor branch, which discards
|
|
1105
|
+
* `tokensBefore` entirely.
|
|
1106
|
+
*/
|
|
1107
|
+
continuityNoteTokens = 0,
|
|
1108
|
+
): number {
|
|
1027
1109
|
let droppedTokens = 0;
|
|
1028
1110
|
for (const entry of entries.slice(0, result.firstKeptEntryIndex)) droppedTokens += estimateTokens(entry);
|
|
1029
1111
|
const summaryTokens = estimateTokensFromSummary(result);
|
|
1030
1112
|
// The summary alone is the floor: a session whose dropped estimate exceeds
|
|
1031
1113
|
// the measured anchor must not report a negative or sub-summary context.
|
|
1032
|
-
return Math.max(summaryTokens, result.tokensBefore - droppedTokens + summaryTokens);
|
|
1114
|
+
return Math.max(summaryTokens + continuityNoteTokens, result.tokensBefore - droppedTokens + summaryTokens);
|
|
1033
1115
|
}
|
|
1034
1116
|
|
|
1035
1117
|
/**
|
|
@@ -1482,7 +1564,7 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
|
|
|
1482
1564
|
const memorySettings = (config?.get() ?? readSettings()).context.memory;
|
|
1483
1565
|
// Bound late: the registration is built here, but the buffer a deferred
|
|
1484
1566
|
// reminder lands in belongs to the chat loop that has not been composed yet.
|
|
1485
|
-
let deferredMemoryReminderSink: ((message: string) => void) | null = null;
|
|
1567
|
+
let deferredMemoryReminderSink: ((message: string, isCurrent?: () => boolean) => void) | null = null;
|
|
1486
1568
|
// The watchdog's findings are for the operator, not the model, so they take
|
|
1487
1569
|
// the transcript-notice path rather than the reminder buffer. Bound late for
|
|
1488
1570
|
// the same reason: the chat loop that owns the transcript is composed below.
|
|
@@ -1495,7 +1577,7 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
|
|
|
1495
1577
|
// check and the cost row read the same resolution the step itself used.
|
|
1496
1578
|
/**
|
|
1497
1579
|
* Account for one background memory step exactly as a `/btw` side question is
|
|
1498
|
-
* accounted for: the in-process cost tracker under its own label so `/
|
|
1580
|
+
* accounted for: the in-process cost tracker under its own label so `/usage`
|
|
1499
1581
|
* shows it while the session lives, and one durable out-of-turn row so
|
|
1500
1582
|
* `clio-coder usage report` can still see it afterwards.
|
|
1501
1583
|
*
|
|
@@ -1537,7 +1619,7 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
|
|
|
1537
1619
|
// A headless run submits no further turn, so a detached step could only
|
|
1538
1620
|
// finish after the process that would have read it has exited.
|
|
1539
1621
|
deliversDeferredReminders: options.headless === undefined,
|
|
1540
|
-
onDeferredReminder: (message) => deferredMemoryReminderSink?.(message),
|
|
1622
|
+
onDeferredReminder: (message, isCurrent) => deferredMemoryReminderSink?.(message, isCurrent),
|
|
1541
1623
|
getSettings: () => {
|
|
1542
1624
|
const memory = effectiveSettingsForDispatch?.().context.memory ?? memorySettings;
|
|
1543
1625
|
return {
|
|
@@ -1790,6 +1872,8 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
|
|
|
1790
1872
|
})
|
|
1791
1873
|
: null;
|
|
1792
1874
|
const toolBootstrap = registerAllTools(toolRegistry, {
|
|
1875
|
+
getContextBudget: () => chat.inspectLiveBudget(),
|
|
1876
|
+
requestSelfCompact: (note, toolCallId, signal) => chat.requestSelfCompact(note, toolCallId, signal),
|
|
1793
1877
|
getSettings: () => getCurrentSettings(),
|
|
1794
1878
|
termination,
|
|
1795
1879
|
captureWorkerContext: () => chat.captureWorkerContext?.() ?? null,
|
|
@@ -2177,21 +2261,7 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
|
|
|
2177
2261
|
bus,
|
|
2178
2262
|
...(prompts ? { prompts } : {}),
|
|
2179
2263
|
...(session ? { session } : {}),
|
|
2180
|
-
getMemorySection: (
|
|
2181
|
-
try {
|
|
2182
|
-
const records = loadMemoryRecordsSync(clioDataDir());
|
|
2183
|
-
const settings = getCurrentSettings();
|
|
2184
|
-
const targetId = session?.current()?.target ?? settings.chat?.target;
|
|
2185
|
-
const runtimeId = targetId ? providers.getTarget(targetId)?.runtime : undefined;
|
|
2186
|
-
return buildMemoryPromptSection(records, {
|
|
2187
|
-
scopes: ["global", "repo", "runtime"],
|
|
2188
|
-
activeRepository: canonicalMemoryRepositoryIdentity(process.cwd()),
|
|
2189
|
-
activeRuntime: runtimeId === undefined ? null : { kind: "runtime", key: runtimeId },
|
|
2190
|
-
}).section;
|
|
2191
|
-
} catch {
|
|
2192
|
-
return "";
|
|
2193
|
-
}
|
|
2194
|
-
},
|
|
2264
|
+
getMemorySection: createMemoryPromptReader({ getDataDir: clioDataDir }),
|
|
2195
2265
|
getTaskMemoryHandoffSource: () => {
|
|
2196
2266
|
const meta = session?.current();
|
|
2197
2267
|
if (!meta) throw new Error("task memory handoff requires an active session");
|
|
@@ -2205,6 +2275,7 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
|
|
|
2205
2275
|
agentIds: [],
|
|
2206
2276
|
});
|
|
2207
2277
|
},
|
|
2278
|
+
memoryCommitBridge: memoryIntervention,
|
|
2208
2279
|
registerDeferredReminderSink: (sink) => {
|
|
2209
2280
|
deferredMemoryReminderSink = sink;
|
|
2210
2281
|
},
|
|
@@ -2278,10 +2349,14 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
|
|
|
2278
2349
|
// parent onto.
|
|
2279
2350
|
chat.resetForSession(
|
|
2280
2351
|
leafTurnId,
|
|
2281
|
-
buildModelReplayAgentMessagesFromTurns(
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2352
|
+
buildModelReplayAgentMessagesFromTurns(readCurrentSessionEntries(), {
|
|
2353
|
+
...(leafTurnId ? { activeLeafTurnId: leafTurnId } : {}),
|
|
2354
|
+
// The same ownership the interactive /resume overlay supplies.
|
|
2355
|
+
// Without it this reader owns nothing, the fold finds no
|
|
2356
|
+
// current origin, and a resumed session boots with its accepted
|
|
2357
|
+
// note silently missing from the provider context.
|
|
2358
|
+
continuity: continuityContextFromSession(session),
|
|
2359
|
+
}),
|
|
2285
2360
|
);
|
|
2286
2361
|
} catch (err) {
|
|
2287
2362
|
chat.resetForSession(leafTurnId);
|
|
@@ -2332,8 +2407,15 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
|
|
|
2332
2407
|
...(session
|
|
2333
2408
|
? {
|
|
2334
2409
|
readSessionEntries: readSessionEntriesForCompact,
|
|
2410
|
+
// Ownership is read at call time, not captured: an ACP client
|
|
2411
|
+
// can switch sessions between turns, and a fork opened this way
|
|
2412
|
+
// must separate its own transactions from the ones it inherited
|
|
2413
|
+
// exactly as the interactive path does.
|
|
2335
2414
|
buildReplayMessages: (entries: ReadonlyArray<SessionEntry>, leafTurnId: string | null) =>
|
|
2336
|
-
buildModelReplayAgentMessagesFromTurns(entries,
|
|
2415
|
+
buildModelReplayAgentMessagesFromTurns(entries, {
|
|
2416
|
+
...(leafTurnId === null ? {} : { activeLeafTurnId: leafTurnId }),
|
|
2417
|
+
continuity: continuityContextFromSession(session),
|
|
2418
|
+
}),
|
|
2337
2419
|
}
|
|
2338
2420
|
: {}),
|
|
2339
2421
|
providers,
|
|
@@ -2788,6 +2870,7 @@ export async function bootOrchestrator(options: BootOptions = {}): Promise<BootR
|
|
|
2788
2870
|
);
|
|
2789
2871
|
}
|
|
2790
2872
|
},
|
|
2873
|
+
onRecoverHandoff: (handoffId, action) => chat.recoverHandoff(handoffId, action),
|
|
2791
2874
|
onCompact: async (instructions) => {
|
|
2792
2875
|
await chat.compact(instructions);
|
|
2793
2876
|
},
|
|
@@ -379,7 +379,7 @@ export interface RunUsageSummary {
|
|
|
379
379
|
* messages. Earlier versions of this function walked the list from the tail
|
|
380
380
|
* and returned the first match, which silently dropped every intermediate
|
|
381
381
|
* API call from the cost tally. Summing instead matches what the provider
|
|
382
|
-
* actually billed and keeps the `/
|
|
382
|
+
* actually billed and keeps the `/usage` overlay and footer counters
|
|
383
383
|
* aligned across tool-heavy runs.
|
|
384
384
|
*/
|
|
385
385
|
export function sumRunUsage(messages: ReadonlyArray<AgentMessage>): RunUsageSummary {
|
|
@@ -539,7 +539,7 @@ export function assistantSessionPayload(
|
|
|
539
539
|
*
|
|
540
540
|
* `estimated: true` is the provenance marker: no surface may report these as
|
|
541
541
|
* provider-reported numbers. The usage fold and the context estimator both skip
|
|
542
|
-
* aborted turns already, so this never reaches `/
|
|
542
|
+
* aborted turns already, so this never reaches `/usage` or the window math; it is
|
|
543
543
|
* the record's own honesty about what the cancelled call cost.
|
|
544
544
|
*
|
|
545
545
|
* Returns null when the provider did report usage (there is nothing to fill in)
|