@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
|
@@ -3,30 +3,30 @@ import {
|
|
|
3
3
|
buildEvictionFields,
|
|
4
4
|
planEviction,
|
|
5
5
|
resolveWorkingSetPolicy
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-SEQDH6JC.js";
|
|
7
7
|
import {
|
|
8
8
|
projectHeadlessJsonEvent,
|
|
9
9
|
setupSteerChannel
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PIU6BXXW.js";
|
|
11
11
|
import {
|
|
12
12
|
ShareDomainModule
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-RWSRKXLT.js";
|
|
14
14
|
import {
|
|
15
15
|
modelBootstrapGenerate,
|
|
16
16
|
resolveBootstrapRoute
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-3GSPCWFX.js";
|
|
18
18
|
import {
|
|
19
19
|
SchedulingDomainModule,
|
|
20
20
|
createPromptsDomainModule,
|
|
21
21
|
renderAgentCatalogSectionsFromSpecs
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-CVMUXT64.js";
|
|
23
23
|
import {
|
|
24
24
|
recordFailedCompactionCalls
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-23UIXH6Z.js";
|
|
26
26
|
import {
|
|
27
27
|
LifecycleDomainModule,
|
|
28
28
|
describeUpgradeNotice
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-4WJBWKMI.js";
|
|
30
30
|
import "./chunk-HOYZUKG7.js";
|
|
31
31
|
import "./chunk-QHSBROEW.js";
|
|
32
32
|
import {
|
|
@@ -44,12 +44,12 @@ import {
|
|
|
44
44
|
} from "./chunk-DR3TAEUA.js";
|
|
45
45
|
import {
|
|
46
46
|
steerToolSurface
|
|
47
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-EMYEQLWO.js";
|
|
48
48
|
import {
|
|
49
49
|
panesToolSurface
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-TQ2KTH4A.js";
|
|
51
51
|
import "./chunk-NASYVWDB.js";
|
|
52
|
-
import "./chunk-
|
|
52
|
+
import "./chunk-VLX5VZ35.js";
|
|
53
53
|
import {
|
|
54
54
|
ensureClioState,
|
|
55
55
|
takeUpgradeNotice
|
|
@@ -61,11 +61,12 @@ import {
|
|
|
61
61
|
prewarmPromptTokens,
|
|
62
62
|
recordStartupDiagnostic,
|
|
63
63
|
runPrewarmRound
|
|
64
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-WX2YCH7F.js";
|
|
65
65
|
import {
|
|
66
66
|
HANDOFF_RESPONSE_SCHEMA,
|
|
67
67
|
buildModelReplayAgentMessagesFromTurns,
|
|
68
68
|
compact,
|
|
69
|
+
continuityContextFromSession,
|
|
69
70
|
createAssistantGenerationTiming,
|
|
70
71
|
hasAssistantGenerationDelta,
|
|
71
72
|
rememberRecentModel,
|
|
@@ -73,12 +74,12 @@ import {
|
|
|
73
74
|
renderEvictionSkipLine,
|
|
74
75
|
subscribeLoopGuardStop,
|
|
75
76
|
watchdogBlockersNotice
|
|
76
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-M5PMRZSR.js";
|
|
77
78
|
import {
|
|
78
79
|
DEFAULT_KEEP_RECENT_TOKENS,
|
|
79
80
|
calculateContextTokens,
|
|
80
81
|
estimateTokens
|
|
81
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-Z74OGONW.js";
|
|
82
83
|
import {
|
|
83
84
|
assistantSessionPayload,
|
|
84
85
|
attachedToolSchemasFromState,
|
|
@@ -110,12 +111,12 @@ import {
|
|
|
110
111
|
toolNamesFromAgentState,
|
|
111
112
|
toolResultSummary,
|
|
112
113
|
toolSignatureFromState
|
|
113
|
-
} from "./chunk-
|
|
114
|
+
} from "./chunk-36XVK5P5.js";
|
|
114
115
|
import {
|
|
115
116
|
PROMPT_MANIFEST_VERSION,
|
|
116
117
|
appendPromptCompileRecord,
|
|
117
118
|
readPromptCompileRecords
|
|
118
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-GIAI7A2K.js";
|
|
119
120
|
import {
|
|
120
121
|
detectPlatformKeybindingWarnings,
|
|
121
122
|
detectTerminalKeySupport,
|
|
@@ -125,7 +126,7 @@ import {
|
|
|
125
126
|
} from "./chunk-3O5JWP4L.js";
|
|
126
127
|
import {
|
|
127
128
|
InteropDomainModule
|
|
128
|
-
} from "./chunk-
|
|
129
|
+
} from "./chunk-EBMTBE76.js";
|
|
129
130
|
import "./chunk-4A6YRGV4.js";
|
|
130
131
|
import {
|
|
131
132
|
BUILTIN_SLASH_COMMANDS,
|
|
@@ -133,7 +134,7 @@ import {
|
|
|
133
134
|
dispatchSlashCommand,
|
|
134
135
|
isWorkerShareNote,
|
|
135
136
|
parseSlashCommand
|
|
136
|
-
} from "./chunk-
|
|
137
|
+
} from "./chunk-XBIGUILU.js";
|
|
137
138
|
import {
|
|
138
139
|
bootstrapInputFromInitOptions
|
|
139
140
|
} from "./chunk-DGC6X6XR.js";
|
|
@@ -141,32 +142,32 @@ import "./chunk-RFCKPS2V.js";
|
|
|
141
142
|
import "./chunk-QUIJZSDW.js";
|
|
142
143
|
import {
|
|
143
144
|
AgentsDomainModule
|
|
144
|
-
} from "./chunk-
|
|
145
|
-
import "./chunk-
|
|
145
|
+
} from "./chunk-TPCZXWLT.js";
|
|
146
|
+
import "./chunk-TL6LNERH.js";
|
|
146
147
|
import "./chunk-GGPF6LLE.js";
|
|
147
148
|
import {
|
|
148
149
|
createUserTasksStore
|
|
149
|
-
} from "./chunk-
|
|
150
|
+
} from "./chunk-JRW236JT.js";
|
|
150
151
|
import {
|
|
151
152
|
compileScoutTransition
|
|
152
|
-
} from "./chunk-
|
|
153
|
+
} from "./chunk-I6UKQPGS.js";
|
|
153
154
|
import {
|
|
154
155
|
monitorToolSurface
|
|
155
|
-
} from "./chunk-
|
|
156
|
+
} from "./chunk-B26OUMJW.js";
|
|
156
157
|
import {
|
|
157
158
|
ObservabilityDomainModule,
|
|
158
159
|
recordBackgroundMemoryStep
|
|
159
|
-
} from "./chunk-
|
|
160
|
+
} from "./chunk-G62JBPXN.js";
|
|
160
161
|
import {
|
|
161
162
|
appendOutOfTurnUsageRow
|
|
162
|
-
} from "./chunk-
|
|
163
|
-
import "./chunk-
|
|
164
|
-
import "./chunk-
|
|
163
|
+
} from "./chunk-AA3GRZWS.js";
|
|
164
|
+
import "./chunk-T7HZ7KJF.js";
|
|
165
|
+
import "./chunk-OX6QTA4N.js";
|
|
165
166
|
import {
|
|
166
167
|
foldWorkingSet,
|
|
167
168
|
isTurnStart,
|
|
168
169
|
selectVisibleEntries
|
|
169
|
-
} from "./chunk-
|
|
170
|
+
} from "./chunk-GUFQPTQK.js";
|
|
170
171
|
import {
|
|
171
172
|
applyOverrides,
|
|
172
173
|
applyRoutingPatch,
|
|
@@ -184,7 +185,7 @@ import {
|
|
|
184
185
|
import "./chunk-LJRBX7QR.js";
|
|
185
186
|
import {
|
|
186
187
|
createResourcesDomainModule
|
|
187
|
-
} from "./chunk-
|
|
188
|
+
} from "./chunk-U3FETNQB.js";
|
|
188
189
|
import "./chunk-Y3JU5RPK.js";
|
|
189
190
|
import "./chunk-6OWUM2NC.js";
|
|
190
191
|
import {
|
|
@@ -209,6 +210,7 @@ import {
|
|
|
209
210
|
ACP_SESSION_META_KEY,
|
|
210
211
|
ACP_TOOL_PROGRESS_META_KEY,
|
|
211
212
|
ACP_USAGE_META_KEY,
|
|
213
|
+
MEMORY_RELEVANCE_VERSION,
|
|
212
214
|
buildMemoryPromptSection,
|
|
213
215
|
canonicalMemoryRepositoryIdentity,
|
|
214
216
|
createContextDomainModule,
|
|
@@ -217,11 +219,11 @@ import {
|
|
|
217
219
|
createRunReceiptQuality,
|
|
218
220
|
createTaskMemoryTrace,
|
|
219
221
|
endpointCapacityUsage,
|
|
220
|
-
loadMemoryRecordsSync,
|
|
221
222
|
newRunId,
|
|
222
223
|
openLedger,
|
|
223
224
|
proposeInjectedTaskMemory,
|
|
224
225
|
protectedResidencyModels,
|
|
226
|
+
readMemoryStoreSnapshot,
|
|
225
227
|
readTaskMemorySpendSummary,
|
|
226
228
|
renderDispatchReviewerTask,
|
|
227
229
|
renderTaskMemoryHandoffSource,
|
|
@@ -231,36 +233,42 @@ import {
|
|
|
231
233
|
taskMemoryBankSize,
|
|
232
234
|
taskMemoryHandoffSeedOffer,
|
|
233
235
|
taskMemoryTracePath
|
|
234
|
-
} from "./chunk-
|
|
236
|
+
} from "./chunk-EQPFEDFV.js";
|
|
235
237
|
import "./chunk-PECBKCDK.js";
|
|
236
238
|
import {
|
|
237
239
|
readGateDecisionArtifacts,
|
|
238
240
|
readPendingGateDecisions
|
|
239
|
-
} from "./chunk-
|
|
240
|
-
import "./chunk-
|
|
241
|
+
} from "./chunk-KQMYL5GR.js";
|
|
242
|
+
import "./chunk-ZTNOEJRI.js";
|
|
241
243
|
import {
|
|
242
244
|
isGitRepository,
|
|
243
245
|
recoverCleanupReadyCompeteGroups
|
|
244
|
-
} from "./chunk-
|
|
246
|
+
} from "./chunk-7WUGNN43.js";
|
|
245
247
|
import {
|
|
246
248
|
requireAgentSteps
|
|
247
|
-
} from "./chunk-
|
|
248
|
-
import "./chunk-
|
|
249
|
+
} from "./chunk-LZMTVVN4.js";
|
|
250
|
+
import "./chunk-EEITU7S6.js";
|
|
249
251
|
import {
|
|
250
252
|
SessionDomainModule,
|
|
251
253
|
addResponseModelIdObservationCounts,
|
|
252
254
|
attributedModelId,
|
|
255
|
+
continuityProjectionTokens,
|
|
256
|
+
continuityReplayText,
|
|
257
|
+
createContinuityPersistencePorts,
|
|
253
258
|
emptyResponseModelIdObservationCounts,
|
|
254
259
|
protectedArtifactEntryFromArtifact,
|
|
255
|
-
protectedArtifactStateFromSessionEntries
|
|
256
|
-
|
|
260
|
+
protectedArtifactStateFromSessionEntries,
|
|
261
|
+
resolveContinuityEvidence,
|
|
262
|
+
resolveContinuityProjection,
|
|
263
|
+
validateContinuityNote
|
|
264
|
+
} from "./chunk-GPTR6OTU.js";
|
|
257
265
|
import "./chunk-BOBCCDJ6.js";
|
|
258
266
|
import "./chunk-E6IPKW2E.js";
|
|
259
267
|
import {
|
|
260
268
|
SafetyDomainModule,
|
|
261
269
|
parseRigorOverride,
|
|
262
270
|
resolveRigor
|
|
263
|
-
} from "./chunk-
|
|
271
|
+
} from "./chunk-N3CWOGVF.js";
|
|
264
272
|
import {
|
|
265
273
|
configureRunEventJournal
|
|
266
274
|
} from "./chunk-UQIVHSE4.js";
|
|
@@ -277,16 +285,16 @@ import "./chunk-ZU4JPCPR.js";
|
|
|
277
285
|
import {
|
|
278
286
|
activeDecisionRefs,
|
|
279
287
|
createDecisionBoardStore
|
|
280
|
-
} from "./chunk-
|
|
288
|
+
} from "./chunk-XYPWFSU5.js";
|
|
281
289
|
import "./chunk-DNHVRBH4.js";
|
|
282
290
|
import {
|
|
283
291
|
filterEntriesToActivePath
|
|
284
292
|
} from "./chunk-O5F25NIE.js";
|
|
285
|
-
import "./chunk-
|
|
293
|
+
import "./chunk-Q4RMNWMZ.js";
|
|
286
294
|
import "./chunk-SD7SHNDW.js";
|
|
287
295
|
import {
|
|
288
296
|
discoverDeclaredChecks
|
|
289
|
-
} from "./chunk-
|
|
297
|
+
} from "./chunk-Q2HKY32Y.js";
|
|
290
298
|
import "./chunk-YQ3GFEUY.js";
|
|
291
299
|
import "./chunk-WTQGRBHV.js";
|
|
292
300
|
import "./chunk-GLIQT7SU.js";
|
|
@@ -311,17 +319,17 @@ import "./chunk-GM4TY6VN.js";
|
|
|
311
319
|
import "./chunk-XISLDHEL.js";
|
|
312
320
|
import {
|
|
313
321
|
collectSessionEntries
|
|
314
|
-
} from "./chunk-
|
|
315
|
-
import "./chunk-
|
|
316
|
-
import "./chunk-
|
|
317
|
-
import "./chunk-
|
|
318
|
-
import "./chunk-
|
|
322
|
+
} from "./chunk-CNXU7TR2.js";
|
|
323
|
+
import "./chunk-7LUEQODV.js";
|
|
324
|
+
import "./chunk-6KV4KCQZ.js";
|
|
325
|
+
import "./chunk-G5ZDQQE3.js";
|
|
326
|
+
import "./chunk-AI36V3ON.js";
|
|
319
327
|
import {
|
|
320
328
|
discoverMarketplaceSkills,
|
|
321
329
|
installSkill,
|
|
322
330
|
installedSkillNames,
|
|
323
331
|
modelVisibleSkills
|
|
324
|
-
} from "./chunk-
|
|
332
|
+
} from "./chunk-B5TASTCK.js";
|
|
325
333
|
import "./chunk-DNCE23JJ.js";
|
|
326
334
|
import "./chunk-CDQ2UC6W.js";
|
|
327
335
|
import "./chunk-5LP5FNNR.js";
|
|
@@ -336,6 +344,7 @@ import {
|
|
|
336
344
|
import "./chunk-LAVUQX3B.js";
|
|
337
345
|
import {
|
|
338
346
|
INTERACTIVE_LOOP_BLOCK_BUDGET,
|
|
347
|
+
continueEngineWithoutInput,
|
|
339
348
|
createEngineAgent,
|
|
340
349
|
createLoopGuardRegistration,
|
|
341
350
|
createProtectedArtifactsRegistration,
|
|
@@ -350,19 +359,19 @@ import {
|
|
|
350
359
|
replaceEngineMessages,
|
|
351
360
|
sanitizeLockedSynthesisMessage,
|
|
352
361
|
setEngineSystemPrompt
|
|
353
|
-
} from "./chunk-
|
|
362
|
+
} from "./chunk-ELDJWJKM.js";
|
|
354
363
|
import "./chunk-ZNUZ3EXD.js";
|
|
355
364
|
import {
|
|
356
365
|
captureWorkerContext
|
|
357
|
-
} from "./chunk-
|
|
366
|
+
} from "./chunk-LXYHCCIZ.js";
|
|
358
367
|
import {
|
|
359
368
|
DEFAULT_RECENT_ENTRY_LIMIT,
|
|
360
369
|
assessFinishContract,
|
|
361
370
|
recentEntries
|
|
362
|
-
} from "./chunk-
|
|
371
|
+
} from "./chunk-QOJ4ERMU.js";
|
|
363
372
|
import {
|
|
364
373
|
verifyReceiptIntegrity
|
|
365
|
-
} from "./chunk-
|
|
374
|
+
} from "./chunk-UZ7YBL43.js";
|
|
366
375
|
import {
|
|
367
376
|
COUNCIL_JUDGE_PROMPT,
|
|
368
377
|
COUNCIL_MAX_MEMBERS,
|
|
@@ -428,14 +437,14 @@ import {
|
|
|
428
437
|
watchdogBriefing,
|
|
429
438
|
withResolvedDispatchPlan,
|
|
430
439
|
writeMiddlewareDiagnosticToStderr
|
|
431
|
-
} from "./chunk-
|
|
440
|
+
} from "./chunk-PF36KOGI.js";
|
|
432
441
|
import {
|
|
433
442
|
createTaskBoardStore
|
|
434
|
-
} from "./chunk-
|
|
443
|
+
} from "./chunk-7DW7CJW2.js";
|
|
435
444
|
import "./chunk-7QXCO3AF.js";
|
|
436
445
|
import {
|
|
437
446
|
defaultRoutingIntent
|
|
438
|
-
} from "./chunk-
|
|
447
|
+
} from "./chunk-SAASVMIY.js";
|
|
439
448
|
import "./chunk-OH3YYA3B.js";
|
|
440
449
|
import "./chunk-VESL6DQY.js";
|
|
441
450
|
import "./chunk-FD3IAHQM.js";
|
|
@@ -444,40 +453,41 @@ import {
|
|
|
444
453
|
} from "./chunk-XNIZBOFV.js";
|
|
445
454
|
import {
|
|
446
455
|
TOOL_PROFILE_NAMES
|
|
447
|
-
} from "./chunk-
|
|
456
|
+
} from "./chunk-5APYAXCB.js";
|
|
448
457
|
import {
|
|
449
458
|
agentRoleFactsResolver,
|
|
450
459
|
gateDeciderAgentId,
|
|
451
460
|
requestExecutionRole
|
|
452
|
-
} from "./chunk-
|
|
461
|
+
} from "./chunk-SZUO5BSE.js";
|
|
453
462
|
import {
|
|
454
463
|
DEFAULT_KILL_GRACE_MS,
|
|
455
464
|
DEFAULT_TEARDOWN_BOUND_MS
|
|
456
|
-
} from "./chunk-
|
|
465
|
+
} from "./chunk-PGQG7ZMW.js";
|
|
457
466
|
import {
|
|
458
467
|
narrowDispatchIntentToReadOnly,
|
|
459
468
|
normalizeDispatchIntent
|
|
460
469
|
} from "./chunk-L4N3DWNW.js";
|
|
461
|
-
import "./chunk-
|
|
462
|
-
import "./chunk-
|
|
463
|
-
import "./chunk-
|
|
470
|
+
import "./chunk-F4I3H56H.js";
|
|
471
|
+
import "./chunk-Q6FRR3AQ.js";
|
|
472
|
+
import "./chunk-KKAJGT3B.js";
|
|
473
|
+
import "./chunk-H7REJ7L5.js";
|
|
464
474
|
import "./chunk-YYLCPDCC.js";
|
|
465
475
|
import "./chunk-EFSEIZE6.js";
|
|
466
|
-
import "./chunk-
|
|
476
|
+
import "./chunk-4XBYHXGK.js";
|
|
467
477
|
import {
|
|
468
478
|
expandInlineFileReferencesAsync
|
|
469
|
-
} from "./chunk-
|
|
470
|
-
import "./chunk-
|
|
471
|
-
import "./chunk-
|
|
472
|
-
import "./chunk-
|
|
479
|
+
} from "./chunk-YEJQDODA.js";
|
|
480
|
+
import "./chunk-4KC4CHKJ.js";
|
|
481
|
+
import "./chunk-MNABNEBX.js";
|
|
482
|
+
import "./chunk-FLNXQQ5B.js";
|
|
473
483
|
import {
|
|
474
484
|
escapeRegExp
|
|
475
485
|
} from "./chunk-DZLR4UEH.js";
|
|
476
486
|
import {
|
|
477
487
|
sweepExpiredToolOffloads,
|
|
478
488
|
toolResultPresentationText
|
|
479
|
-
} from "./chunk-
|
|
480
|
-
import "./chunk-
|
|
489
|
+
} from "./chunk-H6FQVNZC.js";
|
|
490
|
+
import "./chunk-E74MJF6G.js";
|
|
481
491
|
import "./chunk-GHXGMFQ5.js";
|
|
482
492
|
import "./chunk-KECNXMDE.js";
|
|
483
493
|
import "./chunk-WXA2CFJO.js";
|
|
@@ -493,6 +503,7 @@ import {
|
|
|
493
503
|
ProvidersDomainModule,
|
|
494
504
|
applyModelCapabilityPatch,
|
|
495
505
|
declareRuntimeNoticeProducer,
|
|
506
|
+
estimateInputTokensFromContext,
|
|
496
507
|
firstRuntimeResolutionError,
|
|
497
508
|
gatewayRoutingObservationFromRecord,
|
|
498
509
|
gatewayRoutingObservationLabel,
|
|
@@ -516,7 +527,7 @@ import {
|
|
|
516
527
|
setGlobalDefaultMaxOutputTokens,
|
|
517
528
|
setProtectedModelsProvider,
|
|
518
529
|
withRunOverrides
|
|
519
|
-
} from "./chunk-
|
|
530
|
+
} from "./chunk-HTWTORF7.js";
|
|
520
531
|
import "./chunk-MCJKEGHO.js";
|
|
521
532
|
import "./chunk-DVTBERFY.js";
|
|
522
533
|
import {
|
|
@@ -544,7 +555,7 @@ import {
|
|
|
544
555
|
reconcileSnapshot,
|
|
545
556
|
shouldCompact,
|
|
546
557
|
snapshotInputTokens
|
|
547
|
-
} from "./chunk-
|
|
558
|
+
} from "./chunk-53P775GE.js";
|
|
548
559
|
import {
|
|
549
560
|
VALID_THINKING_LEVELS,
|
|
550
561
|
registerBuiltinRuntimes
|
|
@@ -577,21 +588,30 @@ import {
|
|
|
577
588
|
incompleteInstallationAdvice
|
|
578
589
|
} from "./chunk-HMN2C6YL.js";
|
|
579
590
|
import {
|
|
591
|
+
HANDOFF_MAX_FLUSH_RETRIES,
|
|
592
|
+
HANDOFF_MAX_WINDOW_MS,
|
|
593
|
+
HANDOFF_POLICY_LIMITS,
|
|
594
|
+
HANDOFF_RECOVERY_REQUEST_CUSTOM_TYPE,
|
|
595
|
+
HANDOFF_SCHEMA_VERSION,
|
|
580
596
|
SKILL_CONTEXT_STATE,
|
|
581
|
-
|
|
597
|
+
canonicalJson,
|
|
598
|
+
isContinuityCheckpointPayload,
|
|
582
599
|
isSessionEntry,
|
|
583
|
-
isSkillActivation,
|
|
584
600
|
latestSkillContextState,
|
|
585
|
-
mainSkillContextState
|
|
586
|
-
|
|
587
|
-
skillSurfaceLabels,
|
|
588
|
-
skillSurfaceNames,
|
|
589
|
-
withModelSkillActivation
|
|
590
|
-
} from "./chunk-I4Y4WKZR.js";
|
|
601
|
+
mainSkillContextState
|
|
602
|
+
} from "./chunk-F6KCJO3U.js";
|
|
591
603
|
import {
|
|
592
604
|
DEFAULT_AUTONOMY_LEVEL,
|
|
593
605
|
modelMayActivateSkills
|
|
594
606
|
} from "./chunk-UZVYEF57.js";
|
|
607
|
+
import {
|
|
608
|
+
armedSkillSurface,
|
|
609
|
+
isSkillActivation,
|
|
610
|
+
skillActivationFromToolDetails,
|
|
611
|
+
skillSurfaceLabels,
|
|
612
|
+
skillSurfaceNames,
|
|
613
|
+
withModelSkillActivation
|
|
614
|
+
} from "./chunk-MMZMM6SW.js";
|
|
595
615
|
import "./chunk-O3VV6IVK.js";
|
|
596
616
|
import {
|
|
597
617
|
atomicWrite,
|
|
@@ -600,20 +620,20 @@ import {
|
|
|
600
620
|
readSessionTailTurns,
|
|
601
621
|
sessionCurrentPath,
|
|
602
622
|
sessionPaths
|
|
603
|
-
} from "./chunk-
|
|
623
|
+
} from "./chunk-PZBQUJ2F.js";
|
|
604
624
|
import "./chunk-UHW5V7HC.js";
|
|
605
625
|
import {
|
|
606
626
|
RESULT_SUMMARY_MAX_BYTES_CEILING,
|
|
607
627
|
parseScoutResult,
|
|
608
628
|
parseVerifierResult,
|
|
609
629
|
resultContractSourceId
|
|
610
|
-
} from "./chunk-
|
|
630
|
+
} from "./chunk-7UFDIOBT.js";
|
|
611
631
|
import "./chunk-BJH6WFIB.js";
|
|
612
632
|
import "./chunk-5EQO5NWP.js";
|
|
613
|
-
import "./chunk-
|
|
633
|
+
import "./chunk-NMQSO6Z6.js";
|
|
614
634
|
import {
|
|
615
635
|
toolMutationPaths
|
|
616
|
-
} from "./chunk-
|
|
636
|
+
} from "./chunk-OYUS3UZP.js";
|
|
617
637
|
import "./chunk-R2P2U3ZS.js";
|
|
618
638
|
import "./chunk-NTTS3O53.js";
|
|
619
639
|
import "./chunk-C2CPOIH2.js";
|
|
@@ -625,7 +645,7 @@ import {
|
|
|
625
645
|
} from "./chunk-M4KFUXS7.js";
|
|
626
646
|
import {
|
|
627
647
|
ToolNames
|
|
628
|
-
} from "./chunk-
|
|
648
|
+
} from "./chunk-6UKFRTXI.js";
|
|
629
649
|
import {
|
|
630
650
|
readSettings,
|
|
631
651
|
updateSettings
|
|
@@ -700,7 +720,7 @@ import {
|
|
|
700
720
|
|
|
701
721
|
// src/entry/orchestrator.ts
|
|
702
722
|
init_esm_shims();
|
|
703
|
-
import { randomUUID as
|
|
723
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
704
724
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
705
725
|
import { join as join3 } from "node:path";
|
|
706
726
|
|
|
@@ -1386,6 +1406,65 @@ function stableJson(value) {
|
|
|
1386
1406
|
return JSON.stringify(value);
|
|
1387
1407
|
}
|
|
1388
1408
|
|
|
1409
|
+
// src/domains/memory/prompt-cache.ts
|
|
1410
|
+
init_esm_shims();
|
|
1411
|
+
import { createHash } from "node:crypto";
|
|
1412
|
+
function createMemoryPromptReader(options) {
|
|
1413
|
+
const selection = { ...options.selection, scopes: [...options.selection?.scopes ?? ["global", "repo", "runtime"]] };
|
|
1414
|
+
const experimentalRelevance = options.experimentalRelevance === true;
|
|
1415
|
+
const readStore = options.readStore ?? readMemoryStoreSnapshot;
|
|
1416
|
+
let frame = null;
|
|
1417
|
+
let selected = null;
|
|
1418
|
+
return (request) => {
|
|
1419
|
+
const dataDir = options.getDataDir();
|
|
1420
|
+
const activeRepository = canonicalMemoryRepositoryIdentity(request.cwd);
|
|
1421
|
+
const authority = JSON.stringify([
|
|
1422
|
+
dataDir,
|
|
1423
|
+
request.sessionAuthority,
|
|
1424
|
+
request.cwd,
|
|
1425
|
+
activeRepository,
|
|
1426
|
+
request.targetId,
|
|
1427
|
+
request.runtimeId,
|
|
1428
|
+
request.modelId
|
|
1429
|
+
]);
|
|
1430
|
+
const frameKey = JSON.stringify([request.turnId, authority]);
|
|
1431
|
+
if (request.turnId !== null && frame?.key === frameKey) return frame.section;
|
|
1432
|
+
let section = "";
|
|
1433
|
+
try {
|
|
1434
|
+
const snapshot = readStore(dataDir);
|
|
1435
|
+
const relevance = {
|
|
1436
|
+
taskText: request.taskText,
|
|
1437
|
+
activePaths: [...request.activePaths],
|
|
1438
|
+
activeSymbols: [...request.activeSymbols ?? []]
|
|
1439
|
+
};
|
|
1440
|
+
const key = createHash("sha256").update(
|
|
1441
|
+
JSON.stringify([
|
|
1442
|
+
snapshot.revision,
|
|
1443
|
+
authority,
|
|
1444
|
+
selection,
|
|
1445
|
+
relevance,
|
|
1446
|
+
experimentalRelevance,
|
|
1447
|
+
MEMORY_RELEVANCE_VERSION
|
|
1448
|
+
])
|
|
1449
|
+
).digest("hex");
|
|
1450
|
+
if (selected?.key === key) section = selected.section;
|
|
1451
|
+
else {
|
|
1452
|
+
section = buildMemoryPromptSection(snapshot.records, {
|
|
1453
|
+
...selection,
|
|
1454
|
+
activeRepository,
|
|
1455
|
+
activeRuntime: { kind: "runtime", key: request.runtimeId },
|
|
1456
|
+
...experimentalRelevance ? { relevance } : {}
|
|
1457
|
+
}).section;
|
|
1458
|
+
selected = Object.freeze({ key, section });
|
|
1459
|
+
}
|
|
1460
|
+
} catch {
|
|
1461
|
+
selected = null;
|
|
1462
|
+
}
|
|
1463
|
+
frame = request.turnId === null ? null : Object.freeze({ key: frameKey, section });
|
|
1464
|
+
return section;
|
|
1465
|
+
};
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1389
1468
|
// src/domains/middleware/demo-guidance.ts
|
|
1390
1469
|
init_esm_shims();
|
|
1391
1470
|
function createDemoGuidanceRegistration(enabled) {
|
|
@@ -1498,13 +1577,29 @@ function recordDecision(options, turnId, assessment, rigor) {
|
|
|
1498
1577
|
}
|
|
1499
1578
|
}
|
|
1500
1579
|
|
|
1580
|
+
// src/domains/session/continuity/carry.ts
|
|
1581
|
+
init_esm_shims();
|
|
1582
|
+
function continuityPayloadFromFold(fold) {
|
|
1583
|
+
if (!fold.validated) return null;
|
|
1584
|
+
if (!fold.identity || !fold.accepted || !fold.policy || !fold.commit || !fold.state) return null;
|
|
1585
|
+
const payload = {
|
|
1586
|
+
schemaVersion: HANDOFF_SCHEMA_VERSION,
|
|
1587
|
+
identity: fold.identity,
|
|
1588
|
+
accepted: fold.accepted,
|
|
1589
|
+
policy: fold.policy,
|
|
1590
|
+
commit: fold.commit,
|
|
1591
|
+
state: fold.state
|
|
1592
|
+
};
|
|
1593
|
+
return isContinuityCheckpointPayload(payload) ? payload : null;
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1501
1596
|
// src/domains/session/protected-artifact-journal.ts
|
|
1502
1597
|
init_esm_shims();
|
|
1503
|
-
import { createHash, randomBytes } from "node:crypto";
|
|
1598
|
+
import { createHash as createHash2, randomBytes } from "node:crypto";
|
|
1504
1599
|
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync } from "node:fs";
|
|
1505
1600
|
import { join } from "node:path";
|
|
1506
1601
|
function sessionKey(sessionId) {
|
|
1507
|
-
return
|
|
1602
|
+
return createHash2("sha256").update(sessionId, "utf8").digest("hex");
|
|
1508
1603
|
}
|
|
1509
1604
|
function journalDirectory(sessionId) {
|
|
1510
1605
|
return join(clioStateDir(), "protected-artifact-pending", sessionKey(sessionId));
|
|
@@ -1537,7 +1632,7 @@ function recordPayload(record2, legacyNaming = false) {
|
|
|
1537
1632
|
};
|
|
1538
1633
|
}
|
|
1539
1634
|
function digest(record2, legacyNaming = false) {
|
|
1540
|
-
return
|
|
1635
|
+
return createHash2("sha256").update(JSON.stringify(recordPayload(record2, legacyNaming)), "utf8").digest("hex");
|
|
1541
1636
|
}
|
|
1542
1637
|
function withoutIntegrity(record2) {
|
|
1543
1638
|
return {
|
|
@@ -2001,7 +2096,7 @@ function headlessContext(host, notice, push) {
|
|
|
2001
2096
|
listAgents: () => unreachable("listAgents"),
|
|
2002
2097
|
listDelegationAgents: () => unreachable("listDelegationAgents"),
|
|
2003
2098
|
shutdown: () => unreachable("shutdown"),
|
|
2004
|
-
|
|
2099
|
+
openUsage: () => unreachable("openUsage"),
|
|
2005
2100
|
openSideQuestion: () => unreachable("openSideQuestion"),
|
|
2006
2101
|
startHandoff: () => unreachable("startHandoff"),
|
|
2007
2102
|
openContextView: () => unreachable("openContextView"),
|
|
@@ -4216,8 +4311,689 @@ function promptResponse(stopReason, active) {
|
|
|
4216
4311
|
|
|
4217
4312
|
// src/interactive/chat-loop.ts
|
|
4218
4313
|
init_esm_shims();
|
|
4314
|
+
|
|
4315
|
+
// src/interactive/continuity-controller.ts
|
|
4316
|
+
init_esm_shims();
|
|
4317
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
4318
|
+
|
|
4319
|
+
// src/domains/session/continuity/persistence.ts
|
|
4320
|
+
init_esm_shims();
|
|
4321
|
+
function continuityRecordDigest(entry) {
|
|
4322
|
+
return canonicalJson(entry);
|
|
4323
|
+
}
|
|
4324
|
+
function blocked(reason, accepted, barrierAttempts, anomalies) {
|
|
4325
|
+
return { status: "uncertain", reason, accepted: [...accepted], barrierAttempts, anomalies };
|
|
4326
|
+
}
|
|
4327
|
+
function readback(entry, ports) {
|
|
4328
|
+
try {
|
|
4329
|
+
return ports.readExact(entry);
|
|
4330
|
+
} catch (error) {
|
|
4331
|
+
return { status: "unresolved", detail: error instanceof Error ? error.message : String(error) };
|
|
4332
|
+
}
|
|
4333
|
+
}
|
|
4334
|
+
function reconcileContinuityEntry(entry, ports) {
|
|
4335
|
+
const result = readback(entry, ports);
|
|
4336
|
+
if (result.status === "matching") return { status: "accepted" };
|
|
4337
|
+
if (result.status === "conflicting") {
|
|
4338
|
+
return { status: "conflicting", ...result.detail === void 0 ? {} : { detail: result.detail } };
|
|
4339
|
+
}
|
|
4340
|
+
if (result.status === "unresolved") {
|
|
4341
|
+
return { status: "unresolved", ...result.detail === void 0 ? {} : { detail: result.detail } };
|
|
4342
|
+
}
|
|
4343
|
+
return { status: "absent" };
|
|
4344
|
+
}
|
|
4345
|
+
function invalidSchedule(retry) {
|
|
4346
|
+
if (!Number.isSafeInteger(retry.limit) || retry.limit < 0 || retry.limit > HANDOFF_MAX_FLUSH_RETRIES) {
|
|
4347
|
+
return `retry limit ${retry.limit} is not an integer in 0..${HANDOFF_MAX_FLUSH_RETRIES}`;
|
|
4348
|
+
}
|
|
4349
|
+
if (!Number.isFinite(retry.deadlineAtMs)) return "retry deadline is not finite";
|
|
4350
|
+
const now = retry.now();
|
|
4351
|
+
if (!Number.isFinite(now)) return "retry clock is not finite";
|
|
4352
|
+
return null;
|
|
4353
|
+
}
|
|
4354
|
+
function createClockGuard(retry) {
|
|
4355
|
+
let observed = Number.NEGATIVE_INFINITY;
|
|
4356
|
+
let broken = false;
|
|
4357
|
+
return {
|
|
4358
|
+
read() {
|
|
4359
|
+
if (broken) return null;
|
|
4360
|
+
const now = retry.now();
|
|
4361
|
+
if (!Number.isFinite(now) || now < observed) {
|
|
4362
|
+
broken = true;
|
|
4363
|
+
return null;
|
|
4364
|
+
}
|
|
4365
|
+
observed = now;
|
|
4366
|
+
return now;
|
|
4367
|
+
}
|
|
4368
|
+
};
|
|
4369
|
+
}
|
|
4370
|
+
async function runBarrier(request, ports, retry, clock) {
|
|
4371
|
+
const flushing = request.barrier.kind === "flush";
|
|
4372
|
+
const port = flushing ? ports.flushAppends : ports.checkpoint;
|
|
4373
|
+
if (!port) {
|
|
4374
|
+
return {
|
|
4375
|
+
ok: false,
|
|
4376
|
+
attempts: 0,
|
|
4377
|
+
reason: "unsupported_barrier_port",
|
|
4378
|
+
detail: `${request.barrier.kind} port is not available`
|
|
4379
|
+
};
|
|
4380
|
+
}
|
|
4381
|
+
let attempts = 0;
|
|
4382
|
+
let detail = "";
|
|
4383
|
+
for (let round = 0; round <= retry.limit; round += 1) {
|
|
4384
|
+
let before = clock.read();
|
|
4385
|
+
if (round > 0) {
|
|
4386
|
+
if (before === null || before >= retry.deadlineAtMs) break;
|
|
4387
|
+
try {
|
|
4388
|
+
await retry.wait(round);
|
|
4389
|
+
} catch (error) {
|
|
4390
|
+
return {
|
|
4391
|
+
ok: false,
|
|
4392
|
+
attempts,
|
|
4393
|
+
reason: "barrier_failed",
|
|
4394
|
+
detail: `retry wait rejected: ${error instanceof Error ? error.message : String(error)}`
|
|
4395
|
+
};
|
|
4396
|
+
}
|
|
4397
|
+
before = clock.read();
|
|
4398
|
+
if (before === null) {
|
|
4399
|
+
return { ok: false, attempts, reason: "invalid_retry_schedule", detail: "retry clock became unusable" };
|
|
4400
|
+
}
|
|
4401
|
+
if (ports.isStateRemoved()) return { ok: false, attempts, reason: "state_removed", detail: "state removed" };
|
|
4402
|
+
if (!ports.isOriginCurrent()) return { ok: false, attempts, reason: "origin_changed", detail: "origin changed" };
|
|
4403
|
+
if (before >= retry.deadlineAtMs) break;
|
|
4404
|
+
}
|
|
4405
|
+
attempts += 1;
|
|
4406
|
+
try {
|
|
4407
|
+
if (request.barrier.kind === "flush") {
|
|
4408
|
+
port();
|
|
4409
|
+
} else {
|
|
4410
|
+
await port(request.barrier.reason);
|
|
4411
|
+
}
|
|
4412
|
+
const after = clock.read();
|
|
4413
|
+
return {
|
|
4414
|
+
ok: true,
|
|
4415
|
+
attempts,
|
|
4416
|
+
confirmedWithinDeadline: before !== null && after !== null && after < retry.deadlineAtMs
|
|
4417
|
+
};
|
|
4418
|
+
} catch (error) {
|
|
4419
|
+
detail = error instanceof Error ? error.message : String(error);
|
|
4420
|
+
}
|
|
4421
|
+
}
|
|
4422
|
+
return { ok: false, attempts, reason: "barrier_failed", detail: detail || "deadline reached before the barrier ran" };
|
|
4423
|
+
}
|
|
4424
|
+
async function persistContinuityGroup(request, ports, retry) {
|
|
4425
|
+
const anomalies = [];
|
|
4426
|
+
const accepted = [];
|
|
4427
|
+
const wanted = /* @__PURE__ */ new Map();
|
|
4428
|
+
for (const entry of request.entries) {
|
|
4429
|
+
const digest2 = continuityRecordDigest(entry);
|
|
4430
|
+
const previous = wanted.get(entry.turnId);
|
|
4431
|
+
if (previous !== void 0 && previous !== digest2) {
|
|
4432
|
+
anomalies.push({
|
|
4433
|
+
kind: "duplicate_conflict",
|
|
4434
|
+
entryId: entry.turnId,
|
|
4435
|
+
detail: "the group contains two different records under one entry id"
|
|
4436
|
+
});
|
|
4437
|
+
return blocked("duplicate_group_entry", accepted, 0, anomalies);
|
|
4438
|
+
}
|
|
4439
|
+
wanted.set(entry.turnId, digest2);
|
|
4440
|
+
}
|
|
4441
|
+
const acceptedIds = /* @__PURE__ */ new Set();
|
|
4442
|
+
for (const progress of request.alreadyAccepted ?? []) {
|
|
4443
|
+
const expected = wanted.get(progress.entryId);
|
|
4444
|
+
if (expected === void 0 || expected !== progress.payloadDigest) {
|
|
4445
|
+
anomalies.push({
|
|
4446
|
+
kind: "duplicate_conflict",
|
|
4447
|
+
entryId: progress.entryId,
|
|
4448
|
+
detail: "reported progress does not match this group's record for that id"
|
|
4449
|
+
});
|
|
4450
|
+
return blocked("progress_mismatch", [], 0, anomalies);
|
|
4451
|
+
}
|
|
4452
|
+
if (acceptedIds.has(progress.entryId)) continue;
|
|
4453
|
+
acceptedIds.add(progress.entryId);
|
|
4454
|
+
accepted.push({ entryId: progress.entryId, payloadDigest: progress.payloadDigest });
|
|
4455
|
+
}
|
|
4456
|
+
const scheduleProblem = invalidSchedule(retry);
|
|
4457
|
+
if (scheduleProblem) {
|
|
4458
|
+
anomalies.push({ kind: "malformed_record", entryId: null, detail: scheduleProblem });
|
|
4459
|
+
return blocked("invalid_retry_schedule", accepted, 0, anomalies);
|
|
4460
|
+
}
|
|
4461
|
+
const clock = createClockGuard(retry);
|
|
4462
|
+
const remaining = () => request.entries.filter((entry) => !acceptedIds.has(entry.turnId));
|
|
4463
|
+
const startedAt = clock.read();
|
|
4464
|
+
if (startedAt === null) {
|
|
4465
|
+
anomalies.push({ kind: "malformed_record", entryId: null, detail: "the retry clock is not usable" });
|
|
4466
|
+
return blocked("invalid_retry_schedule", accepted, 0, anomalies);
|
|
4467
|
+
}
|
|
4468
|
+
if (startedAt >= retry.deadlineAtMs && remaining().length > 0) {
|
|
4469
|
+
anomalies.push({
|
|
4470
|
+
kind: "malformed_record",
|
|
4471
|
+
entryId: null,
|
|
4472
|
+
detail: "the deadline passed before the group was written"
|
|
4473
|
+
});
|
|
4474
|
+
return blocked("deadline_expired", accepted, 0, anomalies);
|
|
4475
|
+
}
|
|
4476
|
+
if (ports.isStateRemoved()) return blocked("state_removed", accepted, 0, anomalies);
|
|
4477
|
+
if (!ports.isOriginCurrent()) return blocked("origin_changed", accepted, 0, anomalies);
|
|
4478
|
+
const writeBlocked = () => {
|
|
4479
|
+
const now = clock.read();
|
|
4480
|
+
if (now === null) return "invalid_retry_schedule";
|
|
4481
|
+
if (now >= retry.deadlineAtMs) return "deadline_expired";
|
|
4482
|
+
if (ports.isStateRemoved()) return "state_removed";
|
|
4483
|
+
if (!ports.isOriginCurrent()) return "origin_changed";
|
|
4484
|
+
return null;
|
|
4485
|
+
};
|
|
4486
|
+
for (const entry of request.entries) {
|
|
4487
|
+
if (acceptedIds.has(entry.turnId)) continue;
|
|
4488
|
+
const guard = writeBlocked();
|
|
4489
|
+
if (guard) {
|
|
4490
|
+
anomalies.push({ kind: "malformed_record", entryId: entry.turnId, detail: `write refused: ${guard}` });
|
|
4491
|
+
return blocked(guard, accepted, 0, anomalies);
|
|
4492
|
+
}
|
|
4493
|
+
const digest2 = continuityRecordDigest(entry);
|
|
4494
|
+
const accept = () => {
|
|
4495
|
+
accepted.push({ entryId: entry.turnId, payloadDigest: digest2 });
|
|
4496
|
+
acceptedIds.add(entry.turnId);
|
|
4497
|
+
};
|
|
4498
|
+
try {
|
|
4499
|
+
ports.append(entry);
|
|
4500
|
+
accept();
|
|
4501
|
+
continue;
|
|
4502
|
+
} catch (error) {
|
|
4503
|
+
anomalies.push({
|
|
4504
|
+
kind: "malformed_record",
|
|
4505
|
+
entryId: entry.turnId,
|
|
4506
|
+
detail: `append threw: ${error instanceof Error ? error.message : String(error)}`
|
|
4507
|
+
});
|
|
4508
|
+
}
|
|
4509
|
+
const reconciled = reconcileContinuityEntry(entry, ports);
|
|
4510
|
+
if (reconciled.status === "accepted") {
|
|
4511
|
+
accept();
|
|
4512
|
+
continue;
|
|
4513
|
+
}
|
|
4514
|
+
if (reconciled.status === "conflicting") {
|
|
4515
|
+
anomalies.push({
|
|
4516
|
+
kind: "duplicate_conflict",
|
|
4517
|
+
entryId: entry.turnId,
|
|
4518
|
+
detail: reconciled.detail ?? "stored record has this id and different payload"
|
|
4519
|
+
});
|
|
4520
|
+
return blocked("append_conflicting", accepted, 0, anomalies);
|
|
4521
|
+
}
|
|
4522
|
+
if (reconciled.status === "unresolved") {
|
|
4523
|
+
return blocked("append_unresolved", accepted, 0, anomalies);
|
|
4524
|
+
}
|
|
4525
|
+
const reguard = writeBlocked();
|
|
4526
|
+
if (reguard) {
|
|
4527
|
+
anomalies.push({ kind: "malformed_record", entryId: entry.turnId, detail: `reappend refused: ${reguard}` });
|
|
4528
|
+
return blocked(reguard, accepted, 0, anomalies);
|
|
4529
|
+
}
|
|
4530
|
+
try {
|
|
4531
|
+
ports.append(entry);
|
|
4532
|
+
accept();
|
|
4533
|
+
} catch (error) {
|
|
4534
|
+
const second = reconcileContinuityEntry(entry, ports);
|
|
4535
|
+
if (second.status === "accepted") {
|
|
4536
|
+
accept();
|
|
4537
|
+
continue;
|
|
4538
|
+
}
|
|
4539
|
+
anomalies.push({
|
|
4540
|
+
kind: "malformed_record",
|
|
4541
|
+
entryId: entry.turnId,
|
|
4542
|
+
detail: `reappend threw: ${error instanceof Error ? error.message : String(error)}`
|
|
4543
|
+
});
|
|
4544
|
+
return blocked(
|
|
4545
|
+
second.status === "absent" ? "append_absent_after_retry" : "append_unresolved",
|
|
4546
|
+
accepted,
|
|
4547
|
+
0,
|
|
4548
|
+
anomalies
|
|
4549
|
+
);
|
|
4550
|
+
}
|
|
4551
|
+
}
|
|
4552
|
+
if (ports.isStateRemoved()) return blocked("state_removed", accepted, 0, anomalies);
|
|
4553
|
+
if (!ports.isOriginCurrent()) return blocked("origin_changed", accepted, 0, anomalies);
|
|
4554
|
+
const barrier = await runBarrier(request, ports, retry, clock);
|
|
4555
|
+
if (!barrier.ok) {
|
|
4556
|
+
anomalies.push({
|
|
4557
|
+
kind: "malformed_record",
|
|
4558
|
+
entryId: null,
|
|
4559
|
+
detail: `${request.barrier.kind} barrier did not complete: ${barrier.detail}`
|
|
4560
|
+
});
|
|
4561
|
+
return blocked(barrier.reason, accepted, barrier.attempts, anomalies);
|
|
4562
|
+
}
|
|
4563
|
+
if (ports.isStateRemoved()) return blocked("state_removed", accepted, barrier.attempts, anomalies);
|
|
4564
|
+
if (!ports.isOriginCurrent()) return blocked("origin_changed", accepted, barrier.attempts, anomalies);
|
|
4565
|
+
return {
|
|
4566
|
+
status: "durable",
|
|
4567
|
+
accepted,
|
|
4568
|
+
barrierAttempts: barrier.attempts,
|
|
4569
|
+
confirmedWithinDeadline: barrier.confirmedWithinDeadline
|
|
4570
|
+
};
|
|
4571
|
+
}
|
|
4572
|
+
|
|
4573
|
+
// src/interactive/continuity-controller.ts
|
|
4574
|
+
var ContinuityController = class {
|
|
4575
|
+
constructor(deps) {
|
|
4576
|
+
this.deps = deps;
|
|
4577
|
+
this.now = deps.now ?? Date.now;
|
|
4578
|
+
this.id = deps.id ?? randomUUID2;
|
|
4579
|
+
}
|
|
4580
|
+
deps;
|
|
4581
|
+
live = null;
|
|
4582
|
+
busy = false;
|
|
4583
|
+
now;
|
|
4584
|
+
id;
|
|
4585
|
+
armDeadline(live) {
|
|
4586
|
+
live.deadlineTimer = setTimeout(
|
|
4587
|
+
() => live.abort.abort(new Error("Handoff automatic deadline expired.")),
|
|
4588
|
+
Math.max(1, live.deadline - this.now())
|
|
4589
|
+
);
|
|
4590
|
+
live.deadlineTimer.unref?.();
|
|
4591
|
+
}
|
|
4592
|
+
fold(live = this.live) {
|
|
4593
|
+
if (!live?.origin.ports.isOriginCurrent() || live.origin.ports.isStateRemoved()) return null;
|
|
4594
|
+
return resolveContinuityProjection({
|
|
4595
|
+
entries: this.deps.entries(),
|
|
4596
|
+
sessionId: live.origin.sessionId,
|
|
4597
|
+
nowMs: this.now()
|
|
4598
|
+
}).current;
|
|
4599
|
+
}
|
|
4600
|
+
check(live) {
|
|
4601
|
+
live.abort.signal.throwIfAborted();
|
|
4602
|
+
if (this.live !== live || !live.origin.ports.isOriginCurrent()) throw new Error("Handoff ownership changed.");
|
|
4603
|
+
if (live.uncertain) throw new Error("Handoff persistence is unresolved; inspect before recovery.");
|
|
4604
|
+
if (this.now() >= live.deadline) throw new Error("Handoff automatic deadline expired.");
|
|
4605
|
+
}
|
|
4606
|
+
async persist(live, entries, checkpoint = false, closing = false) {
|
|
4607
|
+
const result = await persistContinuityGroup(
|
|
4608
|
+
{
|
|
4609
|
+
entries: entries.map((entry) => ({ ...entry })),
|
|
4610
|
+
barrier: checkpoint ? { kind: "checkpoint", reason: "context-handoff" } : { kind: "flush" }
|
|
4611
|
+
},
|
|
4612
|
+
live.origin.ports,
|
|
4613
|
+
{
|
|
4614
|
+
limit: live.policy.flushRetryLimit,
|
|
4615
|
+
deadlineAtMs: closing ? this.now() + 5e3 : live.deadline,
|
|
4616
|
+
now: this.now,
|
|
4617
|
+
wait: async () => {
|
|
4618
|
+
}
|
|
4619
|
+
}
|
|
4620
|
+
);
|
|
4621
|
+
if (result.status !== "durable" || !result.confirmedWithinDeadline) {
|
|
4622
|
+
live.uncertain = true;
|
|
4623
|
+
throw new Error(
|
|
4624
|
+
`Handoff durability unresolved: ${result.status === "durable" ? "deadline expired" : result.reason}`
|
|
4625
|
+
);
|
|
4626
|
+
}
|
|
4627
|
+
}
|
|
4628
|
+
async transition(live, event, closing = false) {
|
|
4629
|
+
const fold = this.fold(live);
|
|
4630
|
+
if (!fold?.validated || fold.identity?.handoffId !== live.identity.handoffId || !fold.state)
|
|
4631
|
+
throw new Error("Handoff head cannot be validated.");
|
|
4632
|
+
const entryId = this.id();
|
|
4633
|
+
const entry = {
|
|
4634
|
+
kind: "handoffTransaction",
|
|
4635
|
+
schemaVersion: 1,
|
|
4636
|
+
turnId: entryId,
|
|
4637
|
+
parentTurnId: live.identity.branchAnchorTurnId,
|
|
4638
|
+
timestamp: new Date(this.now()).toISOString(),
|
|
4639
|
+
identity: live.identity,
|
|
4640
|
+
transition: {
|
|
4641
|
+
entryId,
|
|
4642
|
+
prevEntryId: fold.state.transition.entryId,
|
|
4643
|
+
sequence: fold.state.transition.sequence + 1,
|
|
4644
|
+
attempt: fold.attemptsSpent + (event.phase === "reducing" ? 1 : 0)
|
|
4645
|
+
},
|
|
4646
|
+
event
|
|
4647
|
+
};
|
|
4648
|
+
await this.persist(live, [entry], false, closing);
|
|
4649
|
+
if (!this.fold(live)?.validated) throw new Error("Persisted handoff transition failed validation.");
|
|
4650
|
+
}
|
|
4651
|
+
async request(note, toolCallId, signal) {
|
|
4652
|
+
const validation = validateContinuityNote(note);
|
|
4653
|
+
if (!validation.ok) throw new Error(`Invalid handoff note: ${validation.reason}`);
|
|
4654
|
+
if (!toolCallId || this.busy || this.live)
|
|
4655
|
+
throw new Error("A context handoff is already pending or no tool identity was supplied.");
|
|
4656
|
+
signal?.throwIfAborted();
|
|
4657
|
+
const origin = this.deps.captureOrigin();
|
|
4658
|
+
if (origin.ports.isStateRemoved() || !origin.ports.isOriginCurrent())
|
|
4659
|
+
throw new Error("The originating session is unavailable.");
|
|
4660
|
+
if (!this.deps.admitNote(validation.accepted))
|
|
4661
|
+
throw new Error("Exact handoff note and protected context exceed the replay budget.");
|
|
4662
|
+
const prior = resolveContinuityProjection({
|
|
4663
|
+
entries: this.deps.entries(),
|
|
4664
|
+
sessionId: origin.sessionId,
|
|
4665
|
+
nowMs: this.now()
|
|
4666
|
+
}).current;
|
|
4667
|
+
if (prior && prior.phase !== "absent" && prior.phase !== "acknowledged")
|
|
4668
|
+
throw new Error("An earlier handoff requires operator recovery.");
|
|
4669
|
+
const preparedAtMs = this.now();
|
|
4670
|
+
const policy = {
|
|
4671
|
+
...HANDOFF_POLICY_LIMITS,
|
|
4672
|
+
preparedAtMs,
|
|
4673
|
+
automaticDeadlineAtMs: preparedAtMs + HANDOFF_MAX_WINDOW_MS
|
|
4674
|
+
};
|
|
4675
|
+
const identity = {
|
|
4676
|
+
handoffId: this.id(),
|
|
4677
|
+
preparedEntryId: this.id(),
|
|
4678
|
+
commitId: this.id(),
|
|
4679
|
+
commitEntryId: this.id(),
|
|
4680
|
+
originSessionId: origin.sessionId,
|
|
4681
|
+
branchAnchorTurnId: origin.leafTurnId,
|
|
4682
|
+
initiatingTurnId: origin.initiatingTurnId,
|
|
4683
|
+
toolCallId,
|
|
4684
|
+
sourceRevision: origin.sourceRevision
|
|
4685
|
+
};
|
|
4686
|
+
const live = {
|
|
4687
|
+
origin,
|
|
4688
|
+
identity,
|
|
4689
|
+
accepted: validation.accepted,
|
|
4690
|
+
policy,
|
|
4691
|
+
deadline: policy.automaticDeadlineAtMs,
|
|
4692
|
+
abort: new AbortController(),
|
|
4693
|
+
uncertain: false
|
|
4694
|
+
};
|
|
4695
|
+
this.live = live;
|
|
4696
|
+
this.armDeadline(live);
|
|
4697
|
+
const entry = {
|
|
4698
|
+
kind: "handoffTransaction",
|
|
4699
|
+
schemaVersion: 1,
|
|
4700
|
+
turnId: identity.preparedEntryId,
|
|
4701
|
+
parentTurnId: identity.branchAnchorTurnId,
|
|
4702
|
+
timestamp: new Date(preparedAtMs).toISOString(),
|
|
4703
|
+
identity,
|
|
4704
|
+
transition: { entryId: identity.preparedEntryId, prevEntryId: null, sequence: 0, attempt: 0 },
|
|
4705
|
+
event: { phase: "prepared", accepted: live.accepted, policy }
|
|
4706
|
+
};
|
|
4707
|
+
try {
|
|
4708
|
+
await this.persist(live, [entry]);
|
|
4709
|
+
signal?.throwIfAborted();
|
|
4710
|
+
this.check(live);
|
|
4711
|
+
return `Context handoff ${identity.handoffId} prepared. The exact note is saved. Reduction and continuation follow after this tool receipt is persisted.`;
|
|
4712
|
+
} catch (error) {
|
|
4713
|
+
await this.pause();
|
|
4714
|
+
throw error;
|
|
4715
|
+
}
|
|
4716
|
+
}
|
|
4717
|
+
readyPayload(live, outcome, before, after, ref) {
|
|
4718
|
+
this.check(live);
|
|
4719
|
+
const fold = this.fold(live);
|
|
4720
|
+
if (!fold?.validated || fold.phase !== "reducing" || !fold.state)
|
|
4721
|
+
throw new Error("No durable reduction attempt owns this checkpoint.");
|
|
4722
|
+
const transition = {
|
|
4723
|
+
entryId: live.identity.commitEntryId,
|
|
4724
|
+
prevEntryId: fold.state.transition.entryId,
|
|
4725
|
+
sequence: fold.state.transition.sequence + 1,
|
|
4726
|
+
attempt: fold.attemptsSpent
|
|
4727
|
+
};
|
|
4728
|
+
return {
|
|
4729
|
+
schemaVersion: 1,
|
|
4730
|
+
identity: live.identity,
|
|
4731
|
+
accepted: live.accepted,
|
|
4732
|
+
policy: live.policy,
|
|
4733
|
+
commit: {
|
|
4734
|
+
outcome,
|
|
4735
|
+
entry: {
|
|
4736
|
+
turnId: live.identity.commitEntryId,
|
|
4737
|
+
parentTurnId: live.identity.branchAnchorTurnId,
|
|
4738
|
+
timestamp: new Date(this.now()).toISOString()
|
|
4739
|
+
},
|
|
4740
|
+
transition,
|
|
4741
|
+
tokensBefore: before,
|
|
4742
|
+
tokensAfter: after,
|
|
4743
|
+
...outcome === "summarized" ? { summaryRef: ref ?? "" } : outcome === "evicted" ? { evictionRef: ref ?? "" } : {}
|
|
4744
|
+
},
|
|
4745
|
+
state: { transition, event: { phase: "ready" }, activeResume: fold.state.activeResume, delivery: null }
|
|
4746
|
+
};
|
|
4747
|
+
}
|
|
4748
|
+
/** Called only at the settled engine boundary, after awaited result persistence. */
|
|
4749
|
+
async settle(signal, recovery = false) {
|
|
4750
|
+
const live = this.live;
|
|
4751
|
+
if (!live || this.busy || live.deliveryId) return false;
|
|
4752
|
+
this.busy = true;
|
|
4753
|
+
const onAbort = () => live.abort.abort(signal?.reason);
|
|
4754
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
4755
|
+
try {
|
|
4756
|
+
if (signal?.aborted) onAbort();
|
|
4757
|
+
this.check(live);
|
|
4758
|
+
const fold = this.fold(live);
|
|
4759
|
+
if (!fold?.validated) throw new Error("Handoff evidence is unresolved.");
|
|
4760
|
+
if (!recovery) {
|
|
4761
|
+
const entries = this.deps.entries();
|
|
4762
|
+
const preparedIndex = entries.findIndex((entry) => entry.turnId === live.identity.preparedEntryId);
|
|
4763
|
+
const receipt = preparedIndex >= 0 && entries.slice(preparedIndex + 1).some((entry) => {
|
|
4764
|
+
if (entry.kind !== "message" || entry.role !== "tool_result") return false;
|
|
4765
|
+
const payload = entry.payload;
|
|
4766
|
+
return entry.parentTurnId === live.origin.leafTurnId && payload.toolCallId === live.identity.toolCallId && payload.toolName === "self_compact" && payload.isError === false;
|
|
4767
|
+
});
|
|
4768
|
+
if (!receipt) throw new Error("Matching successful handoff receipt has not been persisted.");
|
|
4769
|
+
}
|
|
4770
|
+
await this.persist(live, []);
|
|
4771
|
+
this.check(live);
|
|
4772
|
+
if (!fold.commit) {
|
|
4773
|
+
if (fold.attemptsSpent >= live.policy.maxAttempts) throw new Error("Handoff reduction attempts exhausted.");
|
|
4774
|
+
const resumeRef2 = fold.state?.activeResume?.entryId;
|
|
4775
|
+
await this.transition(live, { phase: "reducing", ...resumeRef2 ? { resumeRef: resumeRef2 } : {} });
|
|
4776
|
+
const before = this.deps.inputTokens();
|
|
4777
|
+
const priorIds = new Set(this.deps.entries().map((entry) => entry.turnId));
|
|
4778
|
+
let payload;
|
|
4779
|
+
let calls = 0;
|
|
4780
|
+
await this.deps.reduce(
|
|
4781
|
+
{
|
|
4782
|
+
beforeSummaryCall: () => {
|
|
4783
|
+
this.check(live);
|
|
4784
|
+
if (++calls > live.policy.maxSummaryCallsPerAttempt)
|
|
4785
|
+
throw new Error("Handoff summary invocation limit reached.");
|
|
4786
|
+
},
|
|
4787
|
+
checkpointForSummary: (ref, tokensBefore, tokensAfter) => {
|
|
4788
|
+
payload = this.readyPayload(live, "summarized", tokensBefore, tokensAfter, ref);
|
|
4789
|
+
return payload;
|
|
4790
|
+
}
|
|
4791
|
+
},
|
|
4792
|
+
live.abort.signal
|
|
4793
|
+
);
|
|
4794
|
+
this.check(live);
|
|
4795
|
+
if (!payload) {
|
|
4796
|
+
this.deps.installReplay();
|
|
4797
|
+
if (!this.deps.fits()) throw new Error("Context remains unsafe after reduction; the exact note is retained.");
|
|
4798
|
+
const eviction = [...this.deps.entries()].reverse().find((entry) => entry.kind === "contextEviction" && !priorIds.has(entry.turnId));
|
|
4799
|
+
payload = this.readyPayload(
|
|
4800
|
+
live,
|
|
4801
|
+
eviction ? "evicted" : "continuity_only",
|
|
4802
|
+
before,
|
|
4803
|
+
this.deps.inputTokens(),
|
|
4804
|
+
eviction?.turnId
|
|
4805
|
+
);
|
|
4806
|
+
}
|
|
4807
|
+
await this.persist(
|
|
4808
|
+
live,
|
|
4809
|
+
[
|
|
4810
|
+
{
|
|
4811
|
+
kind: "continuityCommit",
|
|
4812
|
+
...payload.commit.entry,
|
|
4813
|
+
continuity: { ...payload, state: { ...payload.state, activeResume: null } }
|
|
4814
|
+
}
|
|
4815
|
+
],
|
|
4816
|
+
true
|
|
4817
|
+
);
|
|
4818
|
+
this.check(live);
|
|
4819
|
+
if (!this.fold(live)?.validated) throw new Error("Handoff checkpoint cannot be validated.");
|
|
4820
|
+
this.deps.onCommit?.(live.identity.commitId, payload.commit.outcome);
|
|
4821
|
+
}
|
|
4822
|
+
this.deps.installReplay();
|
|
4823
|
+
if (!this.deps.fits()) throw new Error("Compacted continuation exceeds the request budget.");
|
|
4824
|
+
this.check(live);
|
|
4825
|
+
const continuationTurnId = this.deps.leaf();
|
|
4826
|
+
if (!continuationTurnId) throw new Error("Continuation has no persisted message anchor.");
|
|
4827
|
+
const deliveryId = this.id();
|
|
4828
|
+
const deliveryFold = this.fold(live);
|
|
4829
|
+
const resumeRef = deliveryFold?.phase === "resumed" ? deliveryFold.state?.activeResume?.entryId : void 0;
|
|
4830
|
+
await this.transition(live, {
|
|
4831
|
+
phase: "delivered",
|
|
4832
|
+
deliveryId,
|
|
4833
|
+
continuationTurnId,
|
|
4834
|
+
...resumeRef ? { resumeRef } : {}
|
|
4835
|
+
});
|
|
4836
|
+
this.check(live);
|
|
4837
|
+
live.deliveryId = deliveryId;
|
|
4838
|
+
return true;
|
|
4839
|
+
} catch (error) {
|
|
4840
|
+
await this.pause();
|
|
4841
|
+
throw error;
|
|
4842
|
+
} finally {
|
|
4843
|
+
signal?.removeEventListener("abort", onAbort);
|
|
4844
|
+
this.busy = false;
|
|
4845
|
+
}
|
|
4846
|
+
}
|
|
4847
|
+
/** Synchronous final provider boundary, including steering drained after prepare. */
|
|
4848
|
+
admission() {
|
|
4849
|
+
const live = this.live;
|
|
4850
|
+
if (!live) return { block: false };
|
|
4851
|
+
try {
|
|
4852
|
+
this.check(live);
|
|
4853
|
+
if (!live.deliveryId) throw new Error("Context handoff has not durably reached delivery.");
|
|
4854
|
+
return { block: false, correlationId: live.deliveryId };
|
|
4855
|
+
} catch (error) {
|
|
4856
|
+
return { block: true, reason: error instanceof Error ? error.message : String(error) };
|
|
4857
|
+
}
|
|
4858
|
+
}
|
|
4859
|
+
async response(entryId, correlationId) {
|
|
4860
|
+
const live = this.live;
|
|
4861
|
+
if (!live || !entryId || !correlationId || correlationId !== live.deliveryId || live.abort.signal.aborted || !live.origin.ports.isOriginCurrent())
|
|
4862
|
+
return;
|
|
4863
|
+
this.check(live);
|
|
4864
|
+
const evidence = resolveContinuityEvidence({
|
|
4865
|
+
entries: this.deps.entries(),
|
|
4866
|
+
unreadableRecords: 0
|
|
4867
|
+
}).terminalResponses.find((row) => row.entryId === entryId);
|
|
4868
|
+
if (evidence?.status !== "success") return;
|
|
4869
|
+
await this.transition(live, { phase: "acknowledged", deliveryId: correlationId, terminalResponseEntryId: entryId });
|
|
4870
|
+
if (live.deadlineTimer) clearTimeout(live.deadlineTimer);
|
|
4871
|
+
this.live = null;
|
|
4872
|
+
}
|
|
4873
|
+
cancel() {
|
|
4874
|
+
this.live?.abort.abort(new Error("Operator cancelled the context handoff."));
|
|
4875
|
+
}
|
|
4876
|
+
async pause() {
|
|
4877
|
+
const live = this.live;
|
|
4878
|
+
if (!live) return;
|
|
4879
|
+
live.abort.abort();
|
|
4880
|
+
if (live.deadlineTimer) clearTimeout(live.deadlineTimer);
|
|
4881
|
+
try {
|
|
4882
|
+
const fold = this.fold(live);
|
|
4883
|
+
if (!live.uncertain && fold?.validated && ["prepared", "reducing", "ready", "delivered", "resumed"].includes(fold.phase)) {
|
|
4884
|
+
await this.transition(
|
|
4885
|
+
live,
|
|
4886
|
+
{ phase: "paused", reason: live.deliveryId ? "delivery_uncertain" : "operator_cancelled" },
|
|
4887
|
+
true
|
|
4888
|
+
);
|
|
4889
|
+
}
|
|
4890
|
+
} catch (error) {
|
|
4891
|
+
this.deps.notice(`Handoff ${live.identity.handoffId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
4892
|
+
} finally {
|
|
4893
|
+
if (this.live === live) this.live = null;
|
|
4894
|
+
}
|
|
4895
|
+
}
|
|
4896
|
+
/** Host-only operator action; never reachable through tool arguments. */
|
|
4897
|
+
async recover(handoffId, action) {
|
|
4898
|
+
if (this.live || this.busy) throw new Error("A handoff is already active.");
|
|
4899
|
+
const origin = this.deps.captureOrigin();
|
|
4900
|
+
let fold = resolveContinuityProjection({
|
|
4901
|
+
entries: this.deps.entries(),
|
|
4902
|
+
sessionId: origin.sessionId,
|
|
4903
|
+
nowMs: this.now()
|
|
4904
|
+
}).current;
|
|
4905
|
+
if (!fold?.validated || fold.identity?.handoffId !== handoffId || !fold.accepted || !fold.policy || !fold.state)
|
|
4906
|
+
throw new Error("No validated handoff matches that identity on this branch.");
|
|
4907
|
+
if (["prepared", "reducing", "ready", "delivered", "resumed"].includes(fold.phase)) {
|
|
4908
|
+
this.live = {
|
|
4909
|
+
origin,
|
|
4910
|
+
identity: fold.identity,
|
|
4911
|
+
accepted: fold.accepted,
|
|
4912
|
+
policy: fold.policy,
|
|
4913
|
+
deadline: this.now() + HANDOFF_MAX_WINDOW_MS,
|
|
4914
|
+
abort: new AbortController(),
|
|
4915
|
+
uncertain: false
|
|
4916
|
+
};
|
|
4917
|
+
if (fold.missingCommit) {
|
|
4918
|
+
const expected = { ...fold.missingCommit.entry };
|
|
4919
|
+
const readback2 = origin.ports.readExact(expected);
|
|
4920
|
+
if (readback2.status !== "absent" && readback2.status !== "matching") {
|
|
4921
|
+
this.live = null;
|
|
4922
|
+
throw new Error("Commit reconstruction is unresolved.");
|
|
4923
|
+
}
|
|
4924
|
+
await this.persist(this.live, readback2.status === "absent" ? [expected] : [], true);
|
|
4925
|
+
}
|
|
4926
|
+
await this.pause();
|
|
4927
|
+
fold = resolveContinuityProjection({
|
|
4928
|
+
entries: this.deps.entries(),
|
|
4929
|
+
sessionId: origin.sessionId,
|
|
4930
|
+
nowMs: this.now()
|
|
4931
|
+
}).current;
|
|
4932
|
+
if (!fold?.validated || !fold.identity || !fold.accepted || !fold.policy || !fold.state)
|
|
4933
|
+
throw new Error("Interrupted handoff could not be paused durably.");
|
|
4934
|
+
}
|
|
4935
|
+
if (!["paused", "failed"].includes(fold.phase))
|
|
4936
|
+
throw new Error("Only a paused or failed handoff accepts operator recovery.");
|
|
4937
|
+
if (action === "reduce" ? fold.commit !== null || fold.attemptsSpent >= fold.policy.maxAttempts : fold.commit === null)
|
|
4938
|
+
throw new Error("That recovery action is unavailable for this handoff.");
|
|
4939
|
+
const now = this.now();
|
|
4940
|
+
const live = {
|
|
4941
|
+
origin,
|
|
4942
|
+
identity: fold.identity,
|
|
4943
|
+
accepted: fold.accepted,
|
|
4944
|
+
policy: fold.policy,
|
|
4945
|
+
deadline: now + HANDOFF_MAX_WINDOW_MS,
|
|
4946
|
+
abort: new AbortController(),
|
|
4947
|
+
uncertain: false
|
|
4948
|
+
};
|
|
4949
|
+
this.live = live;
|
|
4950
|
+
this.armDeadline(live);
|
|
4951
|
+
const request = {
|
|
4952
|
+
kind: "custom",
|
|
4953
|
+
customType: HANDOFF_RECOVERY_REQUEST_CUSTOM_TYPE,
|
|
4954
|
+
turnId: this.id(),
|
|
4955
|
+
parentTurnId: origin.leafTurnId,
|
|
4956
|
+
timestamp: new Date(now).toISOString(),
|
|
4957
|
+
display: false,
|
|
4958
|
+
data: {
|
|
4959
|
+
version: 1,
|
|
4960
|
+
requestKind: "handoff_recovery",
|
|
4961
|
+
handoffId,
|
|
4962
|
+
action,
|
|
4963
|
+
sessionId: origin.sessionId,
|
|
4964
|
+
branchAnchorTurnId: fold.identity.branchAnchorTurnId,
|
|
4965
|
+
selectedLeafTurnId: origin.leafTurnId,
|
|
4966
|
+
pausedOrFailedEntryId: fold.state.transition.entryId
|
|
4967
|
+
}
|
|
4968
|
+
};
|
|
4969
|
+
try {
|
|
4970
|
+
await this.persist(live, [request]);
|
|
4971
|
+
await this.transition(live, {
|
|
4972
|
+
phase: "resumed",
|
|
4973
|
+
authority: {
|
|
4974
|
+
operatorRequestEntryId: request.turnId,
|
|
4975
|
+
pausedOrFailedEntryId: fold.state.transition.entryId,
|
|
4976
|
+
action,
|
|
4977
|
+
automaticDeadlineAtMs: live.deadline
|
|
4978
|
+
}
|
|
4979
|
+
});
|
|
4980
|
+
await this.settle(void 0, true);
|
|
4981
|
+
} catch (error) {
|
|
4982
|
+
await this.pause();
|
|
4983
|
+
throw error;
|
|
4984
|
+
}
|
|
4985
|
+
}
|
|
4986
|
+
};
|
|
4987
|
+
|
|
4988
|
+
// src/interactive/chat-loop.ts
|
|
4219
4989
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4220
4990
|
|
|
4991
|
+
// src/domains/context/budget/request-fit.ts
|
|
4992
|
+
init_esm_shims();
|
|
4993
|
+
function requestFits(input, output, window) {
|
|
4994
|
+
return input !== null && output !== null && window !== null && Number.isFinite(input) && input >= 0 && Number.isFinite(output) && output >= 0 && Number.isFinite(window) && window > 0 && input + output <= window;
|
|
4995
|
+
}
|
|
4996
|
+
|
|
4221
4997
|
// src/domains/session/retry.ts
|
|
4222
4998
|
init_esm_shims();
|
|
4223
4999
|
import { performance as performance2 } from "node:perf_hooks";
|
|
@@ -4467,7 +5243,323 @@ Extract the handoff record for that goal now.`
|
|
|
4467
5243
|
|
|
4468
5244
|
// src/interactive/turn-context.ts
|
|
4469
5245
|
init_esm_shims();
|
|
4470
|
-
import { createHash as
|
|
5246
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
5247
|
+
|
|
5248
|
+
// src/domains/context/budget/live-view.ts
|
|
5249
|
+
init_esm_shims();
|
|
5250
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
5251
|
+
|
|
5252
|
+
// src/domains/context/budget/pressure.ts
|
|
5253
|
+
init_esm_shims();
|
|
5254
|
+
var DEFAULT_REDUCE_THRESHOLD = 0.8;
|
|
5255
|
+
var DEFAULT_WORKING_SET_TARGET = 0.6;
|
|
5256
|
+
var NOTICE_PROPORTION = 0.65 / 0.8;
|
|
5257
|
+
var PREPARE_PROPORTION = 0.72 / 0.8;
|
|
5258
|
+
var ADVISORY_RESET_BAND = 0.05;
|
|
5259
|
+
var INITIAL_ADVISORY_MEMORY = Object.freeze({
|
|
5260
|
+
announcedPhase: "normal",
|
|
5261
|
+
advisoryKey: null,
|
|
5262
|
+
noCutKey: null
|
|
5263
|
+
});
|
|
5264
|
+
var ADVISORY_RANK = { normal: 0, notice: 1, prepare: 2 };
|
|
5265
|
+
function isPositiveFinite(value) {
|
|
5266
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
5267
|
+
}
|
|
5268
|
+
function isNonNegativeFinite(value) {
|
|
5269
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
5270
|
+
}
|
|
5271
|
+
function resolvePressurePolicy(input = {}) {
|
|
5272
|
+
const reduce = input.reduceThreshold ?? DEFAULT_REDUCE_THRESHOLD;
|
|
5273
|
+
const target = input.workingSetTarget ?? DEFAULT_WORKING_SET_TARGET;
|
|
5274
|
+
if (!Number.isFinite(reduce) || reduce <= 0 || reduce > 1) {
|
|
5275
|
+
return { ok: false, reason: "reduce-threshold-out-of-range" };
|
|
5276
|
+
}
|
|
5277
|
+
if (!Number.isFinite(target) || target <= 0 || target >= reduce) {
|
|
5278
|
+
return { ok: false, reason: "target-out-of-range" };
|
|
5279
|
+
}
|
|
5280
|
+
const hasNotice = input.noticeThreshold !== void 0;
|
|
5281
|
+
const hasPrepare = input.prepareThreshold !== void 0;
|
|
5282
|
+
if (hasNotice !== hasPrepare) return { ok: false, reason: "advisory-thresholds-incomplete" };
|
|
5283
|
+
const notice = hasNotice ? input.noticeThreshold : reduce * NOTICE_PROPORTION;
|
|
5284
|
+
const prepare = hasPrepare ? input.prepareThreshold : reduce * PREPARE_PROPORTION;
|
|
5285
|
+
if (!Number.isFinite(notice) || !Number.isFinite(prepare)) {
|
|
5286
|
+
return { ok: false, reason: "advisory-thresholds-out-of-order" };
|
|
5287
|
+
}
|
|
5288
|
+
if (!(notice > 0 && notice < prepare && prepare < reduce)) {
|
|
5289
|
+
return { ok: false, reason: "advisory-thresholds-out-of-order" };
|
|
5290
|
+
}
|
|
5291
|
+
return {
|
|
5292
|
+
ok: true,
|
|
5293
|
+
policy: Object.freeze({ notice, prepare, reduce, target, derived: !hasNotice })
|
|
5294
|
+
};
|
|
5295
|
+
}
|
|
5296
|
+
function advisoryIdentity(facts, policy) {
|
|
5297
|
+
const identity = facts.contextIdentity ?? {};
|
|
5298
|
+
return JSON.stringify([
|
|
5299
|
+
"advisory/1",
|
|
5300
|
+
facts.revision.sessionId,
|
|
5301
|
+
facts.revision.branchAnchorTurnId,
|
|
5302
|
+
Number.isFinite(facts.effectiveContextWindow) ? facts.effectiveContextWindow : null,
|
|
5303
|
+
policy.notice,
|
|
5304
|
+
policy.prepare,
|
|
5305
|
+
policy.reduce,
|
|
5306
|
+
policy.target,
|
|
5307
|
+
identity.epoch ?? null,
|
|
5308
|
+
identity.targetId ?? null,
|
|
5309
|
+
identity.modelId ?? null,
|
|
5310
|
+
identity.promptFingerprint ?? null,
|
|
5311
|
+
identity.toolSignature ?? null
|
|
5312
|
+
]);
|
|
5313
|
+
}
|
|
5314
|
+
function requestIdentity(advisoryKey, facts) {
|
|
5315
|
+
return JSON.stringify(["request/1", advisoryKey, facts.revision.revisionId]);
|
|
5316
|
+
}
|
|
5317
|
+
function unmeasuredDecision(facts, policy, prior, reason) {
|
|
5318
|
+
return Object.freeze({
|
|
5319
|
+
phase: "normal",
|
|
5320
|
+
pressure: null,
|
|
5321
|
+
headroomTokens: null,
|
|
5322
|
+
measured: false,
|
|
5323
|
+
inputSource: facts.inputSource,
|
|
5324
|
+
completeInputTokens: null,
|
|
5325
|
+
admission: Object.freeze({ result: "unknown", reason, requiredTokens: null }),
|
|
5326
|
+
advisory: Object.freeze({
|
|
5327
|
+
emit: false,
|
|
5328
|
+
phase: "normal",
|
|
5329
|
+
suppressedBy: "measurement-unknown"
|
|
5330
|
+
}),
|
|
5331
|
+
// An unmeasured turn carries prior memory through untouched. Advancing
|
|
5332
|
+
// the advisory key here would consume the re-arm owed to a target, model,
|
|
5333
|
+
// window, or policy change first seen without a usable reading.
|
|
5334
|
+
memory: Object.freeze({ ...prior }),
|
|
5335
|
+
policy
|
|
5336
|
+
});
|
|
5337
|
+
}
|
|
5338
|
+
function evaluatePressure(facts, policy, prior = INITIAL_ADVISORY_MEMORY) {
|
|
5339
|
+
if (!isPositiveFinite(facts.effectiveContextWindow)) {
|
|
5340
|
+
return unmeasuredDecision(facts, policy, prior, "window-unknown");
|
|
5341
|
+
}
|
|
5342
|
+
if (facts.inputTokens === null || !Number.isFinite(facts.inputTokens) || facts.inputTokens < 0) {
|
|
5343
|
+
return unmeasuredDecision(facts, policy, prior, "input-unknown");
|
|
5344
|
+
}
|
|
5345
|
+
const overhead = isNonNegativeFinite(facts.pendingRequestOverheadTokens) ? facts.pendingRequestOverheadTokens : null;
|
|
5346
|
+
const reserve = isNonNegativeFinite(facts.outputReserveTokens) ? facts.outputReserveTokens : null;
|
|
5347
|
+
if (overhead === null || reserve === null) {
|
|
5348
|
+
return unmeasuredDecision(facts, policy, prior, "input-unknown");
|
|
5349
|
+
}
|
|
5350
|
+
const window = facts.effectiveContextWindow;
|
|
5351
|
+
const completeInput = facts.inputTokens + overhead;
|
|
5352
|
+
const required = completeInput + reserve;
|
|
5353
|
+
const pressure = completeInput / window;
|
|
5354
|
+
const headroom = window - required;
|
|
5355
|
+
const advisoryKey = advisoryIdentity(facts, policy);
|
|
5356
|
+
const requestKey = requestIdentity(advisoryKey, facts);
|
|
5357
|
+
const noCutNow = facts.reduction === "no-useful-cut";
|
|
5358
|
+
const noCutCarried = prior.noCutKey !== null && prior.noCutKey === requestKey;
|
|
5359
|
+
const suppressedByNoCut = noCutNow || noCutCarried;
|
|
5360
|
+
let phase;
|
|
5361
|
+
let admission;
|
|
5362
|
+
if (required > window) {
|
|
5363
|
+
phase = "recover";
|
|
5364
|
+
admission = {
|
|
5365
|
+
result: "unsafe",
|
|
5366
|
+
reason: suppressedByNoCut ? "exceeds-window-no-material" : "exceeds-window",
|
|
5367
|
+
requiredTokens: required
|
|
5368
|
+
};
|
|
5369
|
+
} else if (pressure >= policy.reduce) {
|
|
5370
|
+
phase = "reduce";
|
|
5371
|
+
admission = {
|
|
5372
|
+
result: suppressedByNoCut ? "admit" : "reduce-first",
|
|
5373
|
+
reason: suppressedByNoCut ? "fits" : "pressure-at-reduce-threshold",
|
|
5374
|
+
requiredTokens: required
|
|
5375
|
+
};
|
|
5376
|
+
} else {
|
|
5377
|
+
phase = pressure >= policy.prepare ? "prepare" : pressure >= policy.notice ? "notice" : "normal";
|
|
5378
|
+
admission = { result: "admit", reason: "fits", requiredTokens: required };
|
|
5379
|
+
}
|
|
5380
|
+
const advisoryPhase = phase === "notice" || phase === "prepare" ? phase : "normal";
|
|
5381
|
+
const rearmed = prior.advisoryKey !== null && prior.advisoryKey !== advisoryKey;
|
|
5382
|
+
const resetLevel = policy.notice * (1 - ADVISORY_RESET_BAND);
|
|
5383
|
+
const fellBelowReset = pressure < resetLevel;
|
|
5384
|
+
const announcedBefore = rearmed || fellBelowReset ? "normal" : prior.announcedPhase;
|
|
5385
|
+
const actionWouldBeRequested = advisoryPhase !== "normal" || phase === "reduce" || phase === "recover";
|
|
5386
|
+
let emit = false;
|
|
5387
|
+
let suppressedBy = null;
|
|
5388
|
+
if (suppressedByNoCut && actionWouldBeRequested) {
|
|
5389
|
+
suppressedBy = "no-useful-cut-unchanged-revision";
|
|
5390
|
+
} else if (advisoryPhase === "normal") {
|
|
5391
|
+
suppressedBy = "not-crossed";
|
|
5392
|
+
} else if (ADVISORY_RANK[advisoryPhase] > ADVISORY_RANK[announcedBefore]) {
|
|
5393
|
+
emit = true;
|
|
5394
|
+
} else {
|
|
5395
|
+
suppressedBy = "already-announced";
|
|
5396
|
+
}
|
|
5397
|
+
const nextAnnounced = emit ? advisoryPhase : announcedBefore;
|
|
5398
|
+
const nextNoCutKey = noCutNow || noCutCarried ? requestKey : null;
|
|
5399
|
+
return Object.freeze({
|
|
5400
|
+
phase,
|
|
5401
|
+
pressure,
|
|
5402
|
+
headroomTokens: headroom,
|
|
5403
|
+
measured: true,
|
|
5404
|
+
inputSource: facts.inputSource,
|
|
5405
|
+
completeInputTokens: completeInput,
|
|
5406
|
+
admission: Object.freeze(admission),
|
|
5407
|
+
advisory: Object.freeze({ emit, phase: advisoryPhase, suppressedBy }),
|
|
5408
|
+
memory: Object.freeze({ announcedPhase: nextAnnounced, advisoryKey, noCutKey: nextNoCutKey }),
|
|
5409
|
+
policy
|
|
5410
|
+
});
|
|
5411
|
+
}
|
|
5412
|
+
|
|
5413
|
+
// src/domains/context/budget/live-view.ts
|
|
5414
|
+
function resolveLiveBudgetPolicy(reduceThreshold, workingSetTarget) {
|
|
5415
|
+
const configured = resolvePressurePolicy({
|
|
5416
|
+
...typeof reduceThreshold === "number" ? { reduceThreshold } : {},
|
|
5417
|
+
...typeof workingSetTarget === "number" ? { workingSetTarget } : {}
|
|
5418
|
+
});
|
|
5419
|
+
if (configured.ok) return { policy: configured.policy, rejection: null };
|
|
5420
|
+
const fallback = resolvePressurePolicy({
|
|
5421
|
+
reduceThreshold: DEFAULT_REDUCE_THRESHOLD,
|
|
5422
|
+
workingSetTarget: DEFAULT_WORKING_SET_TARGET
|
|
5423
|
+
});
|
|
5424
|
+
if (!fallback.ok) throw new Error(`default pressure policy is unresolvable: ${fallback.reason}`);
|
|
5425
|
+
return { policy: fallback.policy, rejection: configured.reason };
|
|
5426
|
+
}
|
|
5427
|
+
function materialFingerprint(input) {
|
|
5428
|
+
return createHash3("sha256").update(
|
|
5429
|
+
JSON.stringify([
|
|
5430
|
+
"live-budget/1",
|
|
5431
|
+
input.sessionId,
|
|
5432
|
+
input.branchAnchorTurnId,
|
|
5433
|
+
input.navigationEpoch,
|
|
5434
|
+
input.targetId,
|
|
5435
|
+
input.runtimeId,
|
|
5436
|
+
input.modelId,
|
|
5437
|
+
input.modelApi,
|
|
5438
|
+
input.effectiveWindow,
|
|
5439
|
+
input.windowSource,
|
|
5440
|
+
input.estimatedInputTokens,
|
|
5441
|
+
input.anchoredInputTokens,
|
|
5442
|
+
input.inputTokens,
|
|
5443
|
+
input.inputSource,
|
|
5444
|
+
input.historical,
|
|
5445
|
+
input.breakdown,
|
|
5446
|
+
input.breakdownSource,
|
|
5447
|
+
input.outputReserveTokens,
|
|
5448
|
+
input.thresholdReserveTokens,
|
|
5449
|
+
input.policy.notice,
|
|
5450
|
+
input.policy.prepare,
|
|
5451
|
+
input.policy.reduce,
|
|
5452
|
+
input.policy.target,
|
|
5453
|
+
input.policyRejection,
|
|
5454
|
+
input.reduction,
|
|
5455
|
+
input.reductionBasisKey,
|
|
5456
|
+
input.promptFingerprint,
|
|
5457
|
+
input.toolSignature,
|
|
5458
|
+
input.lastReduction,
|
|
5459
|
+
input.pendingHandoff,
|
|
5460
|
+
input.lastOutcome
|
|
5461
|
+
])
|
|
5462
|
+
).digest("hex");
|
|
5463
|
+
}
|
|
5464
|
+
function pressureFacts(input) {
|
|
5465
|
+
return {
|
|
5466
|
+
revision: {
|
|
5467
|
+
sessionId: input.sessionId ?? "",
|
|
5468
|
+
branchAnchorTurnId: input.branchAnchorTurnId,
|
|
5469
|
+
// The policy reuses a no-cut refusal only for this exact identity, so
|
|
5470
|
+
// it has to be the post-accounting one: a recalibrated anchor or a
|
|
5471
|
+
// different resolved output cap is a request the reducer never saw.
|
|
5472
|
+
revisionId: input.reductionBasisKey
|
|
5473
|
+
},
|
|
5474
|
+
inputTokens: input.inputTokens,
|
|
5475
|
+
inputSource: input.inputSource === "anchored-plus-estimated-tail" ? "trusted" : "estimated",
|
|
5476
|
+
effectiveContextWindow: input.effectiveWindow,
|
|
5477
|
+
outputReserveTokens: input.outputReserveTokens ?? Number.NaN,
|
|
5478
|
+
// The live estimate already prices pending text, tool schemas, and every
|
|
5479
|
+
// injected block, so there is nothing left for the caller to add once.
|
|
5480
|
+
pendingRequestOverheadTokens: 0,
|
|
5481
|
+
reduction: input.reduction,
|
|
5482
|
+
contextIdentity: {
|
|
5483
|
+
targetId: input.targetId,
|
|
5484
|
+
modelId: input.modelId,
|
|
5485
|
+
promptFingerprint: input.promptFingerprint,
|
|
5486
|
+
toolSignature: input.toolSignature,
|
|
5487
|
+
epoch: input.navigationEpoch
|
|
5488
|
+
}
|
|
5489
|
+
};
|
|
5490
|
+
}
|
|
5491
|
+
function frozenCopy(value) {
|
|
5492
|
+
return value === null ? null : Object.freeze({ ...value });
|
|
5493
|
+
}
|
|
5494
|
+
function createLiveBudgetProducer() {
|
|
5495
|
+
let view = null;
|
|
5496
|
+
let fingerprint = null;
|
|
5497
|
+
let sequence = 0;
|
|
5498
|
+
let memory = INITIAL_ADVISORY_MEMORY;
|
|
5499
|
+
let decision = null;
|
|
5500
|
+
return {
|
|
5501
|
+
publish(input) {
|
|
5502
|
+
const next = materialFingerprint(input);
|
|
5503
|
+
const transitioned = next !== fingerprint;
|
|
5504
|
+
if (transitioned) {
|
|
5505
|
+
fingerprint = next;
|
|
5506
|
+
sequence += 1;
|
|
5507
|
+
}
|
|
5508
|
+
const revision = `lb-${sequence}-${next.slice(0, 16)}`;
|
|
5509
|
+
if (transitioned || decision === null) {
|
|
5510
|
+
decision = evaluatePressure(pressureFacts(input), input.policy, memory);
|
|
5511
|
+
memory = decision.memory;
|
|
5512
|
+
}
|
|
5513
|
+
view = Object.freeze({
|
|
5514
|
+
revision,
|
|
5515
|
+
capturedSnapshotId: input.capturedSnapshotId,
|
|
5516
|
+
sessionId: input.sessionId,
|
|
5517
|
+
branchAnchorTurnId: input.branchAnchorTurnId,
|
|
5518
|
+
activeLeafTurnId: input.activeLeafTurnId,
|
|
5519
|
+
activeUserTurnId: input.activeUserTurnId,
|
|
5520
|
+
targetId: input.targetId,
|
|
5521
|
+
runtimeId: input.runtimeId,
|
|
5522
|
+
modelId: input.modelId,
|
|
5523
|
+
modelApi: input.modelApi,
|
|
5524
|
+
effectiveWindow: input.effectiveWindow,
|
|
5525
|
+
windowSource: input.windowSource,
|
|
5526
|
+
estimatedInputTokens: input.estimatedInputTokens,
|
|
5527
|
+
anchoredInputTokens: input.anchoredInputTokens,
|
|
5528
|
+
inputTokens: input.inputTokens,
|
|
5529
|
+
inputSource: input.inputSource,
|
|
5530
|
+
historical: input.historical,
|
|
5531
|
+
breakdown: frozenCopy(input.breakdown),
|
|
5532
|
+
breakdownSource: input.breakdownSource,
|
|
5533
|
+
outputReserveTokens: input.outputReserveTokens,
|
|
5534
|
+
thresholdReserveTokens: input.thresholdReserveTokens,
|
|
5535
|
+
headroomTokens: decision.headroomTokens,
|
|
5536
|
+
pressure: decision.pressure,
|
|
5537
|
+
phase: decision.phase,
|
|
5538
|
+
admission: decision.admission,
|
|
5539
|
+
advisory: decision.advisory,
|
|
5540
|
+
policy: Object.freeze({ ...input.policy }),
|
|
5541
|
+
policyRejection: input.policyRejection,
|
|
5542
|
+
reduction: input.reduction,
|
|
5543
|
+
// Copied and frozen at this boundary. An injected reader owns the
|
|
5544
|
+
// object it returns and may reuse or mutate it; a published view is
|
|
5545
|
+
// the thing a revision names, and it does not change underneath one.
|
|
5546
|
+
lastReduction: frozenCopy(input.lastReduction),
|
|
5547
|
+
pendingHandoff: frozenCopy(input.pendingHandoff),
|
|
5548
|
+
lastOutcome: frozenCopy(input.lastOutcome)
|
|
5549
|
+
});
|
|
5550
|
+
return view;
|
|
5551
|
+
},
|
|
5552
|
+
current() {
|
|
5553
|
+
return view;
|
|
5554
|
+
},
|
|
5555
|
+
reset() {
|
|
5556
|
+
view = null;
|
|
5557
|
+
fingerprint = null;
|
|
5558
|
+
decision = null;
|
|
5559
|
+
memory = INITIAL_ADVISORY_MEMORY;
|
|
5560
|
+
}
|
|
5561
|
+
};
|
|
5562
|
+
}
|
|
4471
5563
|
|
|
4472
5564
|
// src/domains/session/compaction/mask-observations.ts
|
|
4473
5565
|
init_esm_shims();
|
|
@@ -4663,6 +5755,16 @@ function maskStaleObservations(entries, excludeLastTurns) {
|
|
|
4663
5755
|
};
|
|
4664
5756
|
}
|
|
4665
5757
|
|
|
5758
|
+
// src/interactive/output-reserve.ts
|
|
5759
|
+
init_esm_shims();
|
|
5760
|
+
function resolveTurnOutputReserve(agentRuntime, inputTokens) {
|
|
5761
|
+
return resolveReservedOutputTokens(agentRuntime.runtimeResolution.capabilityDecisions?.maxTokens, {
|
|
5762
|
+
api: agentRuntime.agent.state.model?.api ?? "",
|
|
5763
|
+
contextWindow: agentRuntime.runtimeResolution.contextWindowDetails.effectiveContextWindow,
|
|
5764
|
+
inputTokens
|
|
5765
|
+
});
|
|
5766
|
+
}
|
|
5767
|
+
|
|
4666
5768
|
// src/interactive/turn-context.ts
|
|
4667
5769
|
function evictionSkipMessage(visibleEntries, workingSet, policyId) {
|
|
4668
5770
|
const turns = visibleEntries.filter(isTurnStart).length;
|
|
@@ -4673,6 +5775,9 @@ function evictionSkipMessage(visibleEntries, workingSet, policyId) {
|
|
|
4673
5775
|
policyId
|
|
4674
5776
|
});
|
|
4675
5777
|
}
|
|
5778
|
+
function messageListDigest(messages) {
|
|
5779
|
+
return createHash4("sha256").update(JSON.stringify(messages)).digest("hex");
|
|
5780
|
+
}
|
|
4676
5781
|
function createTurnContext(deps) {
|
|
4677
5782
|
const { state, middleware } = deps;
|
|
4678
5783
|
const compactionTrigger = new AutoCompactionTrigger();
|
|
@@ -4689,8 +5794,16 @@ function createTurnContext(deps) {
|
|
|
4689
5794
|
let resumedPromptHashRead = false;
|
|
4690
5795
|
let resumedPromptHash = null;
|
|
4691
5796
|
const sessionWorkingContextPaths = /* @__PURE__ */ new Set();
|
|
5797
|
+
let memoryTurnSequence = 0;
|
|
5798
|
+
let memoryAuthorityEpoch = 0;
|
|
5799
|
+
let memoryTurn = null;
|
|
5800
|
+
const memoryOrigin = (runtime) => JSON.stringify([process.cwd(), runtime.targetId, runtime.runtimeId, runtime.wireModelId]);
|
|
4692
5801
|
let pendingPromptLogEntry = null;
|
|
4693
5802
|
let emptyAutoCompactContextKey = null;
|
|
5803
|
+
const budgetProducer = createLiveBudgetProducer();
|
|
5804
|
+
let branchAnchorTurnId = null;
|
|
5805
|
+
let navigationEpoch = 0;
|
|
5806
|
+
let noUsefulCutBasisKey = null;
|
|
4694
5807
|
const pendingColdReasons = /* @__PURE__ */ new Set();
|
|
4695
5808
|
let runExpectedColdReasons = [];
|
|
4696
5809
|
let nextAssistantColdReasons = [];
|
|
@@ -4808,7 +5921,7 @@ function createTurnContext(deps) {
|
|
|
4808
5921
|
resumedPromptHash = records[records.length - 1]?.systemPromptHash ?? null;
|
|
4809
5922
|
return resumedPromptHash;
|
|
4810
5923
|
};
|
|
4811
|
-
const resolveWindowWithoutRuntime = () => {
|
|
5924
|
+
const resolveWindowWithoutRuntime = (allowLedgerRead = true) => {
|
|
4812
5925
|
const settings = deps.getSettings();
|
|
4813
5926
|
const targetId = settings.chat?.target?.trim();
|
|
4814
5927
|
const wireModelId = settings.chat?.model?.trim();
|
|
@@ -4820,7 +5933,7 @@ function createTurnContext(deps) {
|
|
|
4820
5933
|
use: "orchestrator",
|
|
4821
5934
|
requireTools: false,
|
|
4822
5935
|
requireOutputBudget: true,
|
|
4823
|
-
knownLoadedContextWindow: rememberedLoadedContextWindow(targetId, wireModelId)
|
|
5936
|
+
knownLoadedContextWindow: allowLedgerRead ? rememberedLoadedContextWindow(targetId, wireModelId) : currentContextSnapshot?.contextWindowSource === "loaded" && currentContextSnapshot.providerId === targetId && currentContextSnapshot.modelId === wireModelId ? currentContextSnapshot.effectiveContextWindow : null
|
|
4824
5937
|
});
|
|
4825
5938
|
return resolved.ok ? resolved.target.contextWindowDetails : null;
|
|
4826
5939
|
};
|
|
@@ -4834,8 +5947,8 @@ function createTurnContext(deps) {
|
|
|
4834
5947
|
"unknown"
|
|
4835
5948
|
]);
|
|
4836
5949
|
const snapshotWindowSource = (snapshot) => CONTEXT_WINDOW_SOURCES.has(snapshot.contextWindowSource) ? snapshot.contextWindowSource : null;
|
|
4837
|
-
const windowWithoutRuntime = () => {
|
|
4838
|
-
const details = resolveWindowWithoutRuntime();
|
|
5950
|
+
const windowWithoutRuntime = (allowLedgerRead = true) => {
|
|
5951
|
+
const details = resolveWindowWithoutRuntime(allowLedgerRead);
|
|
4839
5952
|
if (details) {
|
|
4840
5953
|
return {
|
|
4841
5954
|
contextWindow: details.effectiveContextWindow,
|
|
@@ -4861,7 +5974,7 @@ function createTurnContext(deps) {
|
|
|
4861
5974
|
const anchor = reconciledAnchor;
|
|
4862
5975
|
if (!anchor) return null;
|
|
4863
5976
|
const messages = agentRuntime.agent.state.messages.filter((message) => message.role !== "system");
|
|
4864
|
-
if (anchor.runtime !== agentRuntime || anchor.model !== agentRuntime.agent.state.model || anchor.modelKey !== anchorModelKey(agentRuntime) || anchor.targetId !== agentRuntime.targetId || anchor.runtimeId !== agentRuntime.runtimeId || anchor.wireModelId !== agentRuntime.wireModelId || anchor.anchoredMessages.length > messages.length || anchor.anchoredMessages.some((message, index) => message !== messages[index])) {
|
|
5977
|
+
if (anchor.runtime !== agentRuntime || anchor.model !== agentRuntime.agent.state.model || anchor.modelKey !== anchorModelKey(agentRuntime) || anchor.targetId !== agentRuntime.targetId || anchor.runtimeId !== agentRuntime.runtimeId || anchor.wireModelId !== agentRuntime.wireModelId || anchor.anchoredMessages.length > messages.length || anchor.anchoredMessages.some((message, index) => message !== messages[index]) || messageListDigest(messages.slice(0, anchor.anchoredMessages.length)) !== anchor.contentDigest) {
|
|
4865
5978
|
reconciledAnchor = null;
|
|
4866
5979
|
return null;
|
|
4867
5980
|
}
|
|
@@ -4873,13 +5986,14 @@ function createTurnContext(deps) {
|
|
|
4873
5986
|
}
|
|
4874
5987
|
return anchor.tokens + tail;
|
|
4875
5988
|
};
|
|
5989
|
+
let pendingUserImages = [];
|
|
4876
5990
|
const liveContextEstimate = (agentRuntime, pendingUserText) => {
|
|
4877
5991
|
const contextWindow = agentRuntime.runtimeResolution.contextWindowDetails.effectiveContextWindow;
|
|
4878
5992
|
const estimateInput = {
|
|
4879
5993
|
systemPrompt: agentRuntime.agent.state.systemPrompt,
|
|
4880
5994
|
messages: agentRuntime.agent.state.messages.filter((message) => message.role !== "system"),
|
|
4881
5995
|
tools: agentRuntime.agent.state.tools,
|
|
4882
|
-
...pendingUserText !== void 0 ? { pendingUserText } : {}
|
|
5996
|
+
...pendingUserText !== void 0 ? { pendingUserText, pendingUserImages } : {}
|
|
4883
5997
|
};
|
|
4884
5998
|
const breakdown = estimateAgentContextBreakdown(estimateInput);
|
|
4885
5999
|
const historyTokens = reconciledHistoryTokens(agentRuntime);
|
|
@@ -4897,12 +6011,177 @@ function createTurnContext(deps) {
|
|
|
4897
6011
|
breakdown
|
|
4898
6012
|
};
|
|
4899
6013
|
};
|
|
6014
|
+
const sha256Json = (value) => createHash4("sha256").update(JSON.stringify(value)).digest("hex");
|
|
6015
|
+
const liveBudgetContentFingerprint = (agentRuntime, pendingUserText, promptFingerprint, toolSignature) => {
|
|
6016
|
+
const settings = deps.getSettings();
|
|
6017
|
+
const eligibility = {
|
|
6018
|
+
compaction: settings.context.compaction ?? null,
|
|
6019
|
+
workingSet: settings.context.workingSet ?? null,
|
|
6020
|
+
maxOutputTokens: settings.chat?.maxOutputTokens ?? null
|
|
6021
|
+
};
|
|
6022
|
+
if (!agentRuntime) {
|
|
6023
|
+
const snapshot = currentContextSnapshot;
|
|
6024
|
+
return sha256Json([
|
|
6025
|
+
"historical/1",
|
|
6026
|
+
settings.chat?.target ?? null,
|
|
6027
|
+
settings.chat?.model ?? null,
|
|
6028
|
+
snapshot?.snapshotId ?? null,
|
|
6029
|
+
snapshot ? snapshotInputTokens(snapshot) : null,
|
|
6030
|
+
snapshot?.sources.total ?? null,
|
|
6031
|
+
windowWithoutRuntime(false).contextWindow,
|
|
6032
|
+
promptFingerprint,
|
|
6033
|
+
toolSignature,
|
|
6034
|
+
eligibility
|
|
6035
|
+
]);
|
|
6036
|
+
}
|
|
6037
|
+
const details = agentRuntime.runtimeResolution.contextWindowDetails;
|
|
6038
|
+
return sha256Json([
|
|
6039
|
+
"live/1",
|
|
6040
|
+
agentRuntime.targetId,
|
|
6041
|
+
agentRuntime.runtimeId,
|
|
6042
|
+
agentRuntime.wireModelId,
|
|
6043
|
+
agentRuntime.agent.state.model?.api ?? null,
|
|
6044
|
+
details.effectiveContextWindow,
|
|
6045
|
+
details.contextWindowSource,
|
|
6046
|
+
promptFingerprint,
|
|
6047
|
+
toolSignature,
|
|
6048
|
+
// Same serialization the anchor validates its attested prefix with, so
|
|
6049
|
+
// the two cannot disagree about whether the conversation changed.
|
|
6050
|
+
messageListDigest(agentRuntime.agent.state.messages.filter((message) => message.role !== "system")),
|
|
6051
|
+
pendingUserText ?? null,
|
|
6052
|
+
pendingUserText === void 0 ? null : pendingUserImages,
|
|
6053
|
+
eligibility
|
|
6054
|
+
]);
|
|
6055
|
+
};
|
|
6056
|
+
const capturedBreakdown = (snapshot, pendingTokens) => ({
|
|
6057
|
+
systemPromptTokens: snapshot.categories.system,
|
|
6058
|
+
messageTokens: snapshot.categories.messages + (snapshot.categories.toolResults ?? 0),
|
|
6059
|
+
pendingUserTokens: pendingTokens,
|
|
6060
|
+
toolSchemaTokens: snapshot.categories.tools
|
|
6061
|
+
});
|
|
6062
|
+
const optionalProjection = (read) => {
|
|
6063
|
+
if (!read) return null;
|
|
6064
|
+
try {
|
|
6065
|
+
return read();
|
|
6066
|
+
} catch {
|
|
6067
|
+
return null;
|
|
6068
|
+
}
|
|
6069
|
+
};
|
|
6070
|
+
const liveRuntimeAccounting = (agentRuntime, pendingUserText) => {
|
|
6071
|
+
const estimate = liveContextEstimate(agentRuntime, pendingUserText);
|
|
6072
|
+
const details = agentRuntime.runtimeResolution.contextWindowDetails;
|
|
6073
|
+
return {
|
|
6074
|
+
targetId: agentRuntime.targetId,
|
|
6075
|
+
runtimeId: agentRuntime.runtimeId,
|
|
6076
|
+
modelId: agentRuntime.wireModelId,
|
|
6077
|
+
modelApi: agentRuntime.agent.state.model?.api ?? null,
|
|
6078
|
+
effectiveWindow: details.effectiveContextWindow > 0 ? details.effectiveContextWindow : null,
|
|
6079
|
+
windowSource: details.contextWindowSource,
|
|
6080
|
+
estimatedInputTokens: estimate.estimatedTokens,
|
|
6081
|
+
anchoredInputTokens: estimate.reconciledTokens,
|
|
6082
|
+
inputTokens: estimate.tokens,
|
|
6083
|
+
inputSource: estimate.reconciledTokens === null ? "estimated" : "anchored-plus-estimated-tail",
|
|
6084
|
+
historical: false,
|
|
6085
|
+
breakdown: { ...estimate.breakdown },
|
|
6086
|
+
breakdownSource: "live",
|
|
6087
|
+
outputReserveTokens: resolveTurnOutputReserve(agentRuntime, estimate.tokens)
|
|
6088
|
+
};
|
|
6089
|
+
};
|
|
6090
|
+
const historicalAccounting = (snapshot, settings) => {
|
|
6091
|
+
const sameRoute = !snapshot || snapshot.providerId === settings.chat?.target && snapshot.modelId === settings.chat?.model;
|
|
6092
|
+
const window = snapshot && !sameRoute ? {
|
|
6093
|
+
contextWindow: snapshot.effectiveContextWindow,
|
|
6094
|
+
contextWindowSource: snapshotWindowSource(snapshot)
|
|
6095
|
+
} : windowWithoutRuntime(false);
|
|
6096
|
+
const pendingTokens = pendingUserInputTokens();
|
|
6097
|
+
return {
|
|
6098
|
+
targetId: snapshot?.providerId ?? settings.chat?.target ?? null,
|
|
6099
|
+
runtimeId: snapshot?.runtimeId ?? null,
|
|
6100
|
+
modelId: snapshot?.modelId ?? settings.chat?.model ?? null,
|
|
6101
|
+
modelApi: null,
|
|
6102
|
+
effectiveWindow: window.contextWindow > 0 ? window.contextWindow : null,
|
|
6103
|
+
windowSource: window.contextWindowSource,
|
|
6104
|
+
estimatedInputTokens: snapshot?.estimatedTokens ?? null,
|
|
6105
|
+
anchoredInputTokens: snapshot?.reconciledTokens ?? null,
|
|
6106
|
+
inputTokens: snapshot ? snapshotInputTokens(snapshot) + pendingTokens : null,
|
|
6107
|
+
inputSource: snapshot ? "historical" : "unknown",
|
|
6108
|
+
historical: true,
|
|
6109
|
+
breakdown: snapshot ? capturedBreakdown(snapshot, pendingTokens) : null,
|
|
6110
|
+
breakdownSource: snapshot ? "captured" : null,
|
|
6111
|
+
// No resolved route means no honest output reservation, and an unpriced
|
|
6112
|
+
// reserve is unknown rather than zero.
|
|
6113
|
+
outputReserveTokens: null
|
|
6114
|
+
};
|
|
6115
|
+
};
|
|
6116
|
+
const liveBudgetInput = (pendingUserText) => {
|
|
6117
|
+
const settings = deps.getSettings();
|
|
6118
|
+
const agentRuntime = state.runtime;
|
|
6119
|
+
const snapshot = currentContextSnapshot;
|
|
6120
|
+
const promptFingerprint = agentRuntime ? sha256Json(agentRuntime.agent.state.systemPrompt ?? null) : snapshot?.promptHash ?? null;
|
|
6121
|
+
const toolSignature = agentRuntime ? toolSignatureFromState(agentRuntime.agent.state.tools) : snapshot?.toolSignature ?? null;
|
|
6122
|
+
const contentFingerprint = liveBudgetContentFingerprint(
|
|
6123
|
+
agentRuntime,
|
|
6124
|
+
pendingUserText,
|
|
6125
|
+
promptFingerprint,
|
|
6126
|
+
toolSignature
|
|
6127
|
+
);
|
|
6128
|
+
const policyResolution = resolveLiveBudgetPolicy(
|
|
6129
|
+
settings.context.compaction?.threshold,
|
|
6130
|
+
settings.context.workingSet?.target
|
|
6131
|
+
);
|
|
6132
|
+
const accounting = agentRuntime ? liveRuntimeAccounting(agentRuntime, pendingUserText) : historicalAccounting(snapshot, settings);
|
|
6133
|
+
const reductionBasisKey = sha256Json([
|
|
6134
|
+
"reduction-basis/1",
|
|
6135
|
+
contentFingerprint,
|
|
6136
|
+
accounting.effectiveWindow,
|
|
6137
|
+
accounting.estimatedInputTokens,
|
|
6138
|
+
accounting.anchoredInputTokens,
|
|
6139
|
+
accounting.inputTokens,
|
|
6140
|
+
accounting.inputSource,
|
|
6141
|
+
accounting.outputReserveTokens,
|
|
6142
|
+
// The resolved cap can move without moving the reservation, because a
|
|
6143
|
+
// route clamp may be the binding constraint. Both belong in the key.
|
|
6144
|
+
agentRuntime?.runtimeResolution.capabilityDecisions?.maxTokens ?? null,
|
|
6145
|
+
snapshot?.categories.reserve ?? null,
|
|
6146
|
+
policyResolution.policy.reduce,
|
|
6147
|
+
policyResolution.policy.target
|
|
6148
|
+
]);
|
|
6149
|
+
return {
|
|
6150
|
+
...accounting,
|
|
6151
|
+
sessionId: deps.session?.current()?.id ?? snapshot?.sessionId ?? null,
|
|
6152
|
+
branchAnchorTurnId,
|
|
6153
|
+
activeLeafTurnId: state.lastTurnId,
|
|
6154
|
+
activeUserTurnId: state.activeUserTurnId,
|
|
6155
|
+
capturedSnapshotId: snapshot?.snapshotId ?? null,
|
|
6156
|
+
// Compaction headroom recorded by the capture. Carried under its own
|
|
6157
|
+
// name so nothing can mistake it for the output reserve.
|
|
6158
|
+
thresholdReserveTokens: snapshot?.categories.reserve ?? null,
|
|
6159
|
+
policy: policyResolution.policy,
|
|
6160
|
+
policyRejection: policyResolution.rejection,
|
|
6161
|
+
// Reduction has not been asked about unless an automatic attempt for
|
|
6162
|
+
// this exact basis already came back empty.
|
|
6163
|
+
reduction: noUsefulCutBasisKey !== null && noUsefulCutBasisKey === reductionBasisKey ? "no-useful-cut" : "unknown",
|
|
6164
|
+
reductionBasisKey,
|
|
6165
|
+
promptFingerprint,
|
|
6166
|
+
toolSignature,
|
|
6167
|
+
navigationEpoch,
|
|
6168
|
+
lastReduction: lastCompactionEvent ? { ...lastCompactionEvent } : null,
|
|
6169
|
+
pendingHandoff: optionalProjection(deps.getPendingHandoff),
|
|
6170
|
+
lastOutcome: optionalProjection(deps.getLastOutcome)
|
|
6171
|
+
};
|
|
6172
|
+
};
|
|
6173
|
+
const refreshLiveBudget = (pendingUserText) => budgetProducer.publish(liveBudgetInput(pendingUserText));
|
|
4900
6174
|
const carryReconciledAnchorThroughProjection = (agentRuntime, historyTokens, tokensRemoved) => {
|
|
4901
6175
|
if (!reconciledAnchor || historyTokens === null) return;
|
|
6176
|
+
const anchoredMessages = [...agentRuntime.agent.state.messages.filter((message) => message.role !== "system")];
|
|
4902
6177
|
reconciledAnchor = {
|
|
4903
6178
|
...reconciledAnchor,
|
|
4904
6179
|
tokens: Math.max(0, historyTokens - Math.max(0, tokensRemoved)),
|
|
4905
|
-
anchoredMessages
|
|
6180
|
+
anchoredMessages,
|
|
6181
|
+
// Re-anchoring on the projected list is the point of this carry, so its
|
|
6182
|
+
// content identity is retaken here. Keeping the old digest would fail
|
|
6183
|
+
// the next validation and discard the attestation this preserves.
|
|
6184
|
+
contentDigest: messageListDigest(anchoredMessages)
|
|
4906
6185
|
};
|
|
4907
6186
|
};
|
|
4908
6187
|
const refreshAgentMessagesFromSession = (agentRuntime) => {
|
|
@@ -4910,7 +6189,11 @@ function createTurnContext(deps) {
|
|
|
4910
6189
|
replaceEngineMessages(
|
|
4911
6190
|
agentRuntime.agent,
|
|
4912
6191
|
buildModelReplayAgentMessagesFromTurns(refreshedEntries, {
|
|
4913
|
-
...state.lastTurnId ? { activeLeafTurnId: state.lastTurnId } : {}
|
|
6192
|
+
...state.lastTurnId ? { activeLeafTurnId: state.lastTurnId } : {},
|
|
6193
|
+
// The post-compaction rebuild is where an accepted note has to
|
|
6194
|
+
// survive: wiring continuity only into /fork would lose it on the
|
|
6195
|
+
// very refresh the reduction triggers.
|
|
6196
|
+
continuity: continuityContextFromSession(deps.session)
|
|
4914
6197
|
})
|
|
4915
6198
|
);
|
|
4916
6199
|
state.replayedContextMessages = [];
|
|
@@ -4948,9 +6231,11 @@ function createTurnContext(deps) {
|
|
|
4948
6231
|
usage.targetId === void 0 && usage.modelId === void 0 ? agentRuntime.runtimeResolution.costProvenance : usage.cost.total > 0 ? "estimated" : "unknown"
|
|
4949
6232
|
);
|
|
4950
6233
|
};
|
|
4951
|
-
const
|
|
6234
|
+
const performAutoCompact = async (agentRuntime, force, instructions, triggerOverride, pendingUserText, pendingSkillPolicy, signal, handoff) => {
|
|
4952
6235
|
if (!deps.readSessionEntries) return false;
|
|
4953
|
-
const
|
|
6236
|
+
const originSession = deps.session?.current()?.id;
|
|
6237
|
+
const originNavigation = navigationEpoch;
|
|
6238
|
+
const useRequestBudget = !force || triggerOverride === "overflow" || handoff !== void 0;
|
|
4954
6239
|
const activeAutoTurnId = useRequestBudget ? state.activeUserTurnId : null;
|
|
4955
6240
|
const skillContextState = mainSkillContextState(
|
|
4956
6241
|
filterEntriesToActivePath(deps.readSessionEntries(), state.lastTurnId ?? void 0),
|
|
@@ -4961,10 +6246,11 @@ function createTurnContext(deps) {
|
|
|
4961
6246
|
const autoEnabled = cfg?.auto !== false;
|
|
4962
6247
|
if (!force && !autoEnabled) return false;
|
|
4963
6248
|
const compactionThreshold = cfg?.threshold ?? DEFAULT_COMPACTION_THRESHOLD;
|
|
4964
|
-
const
|
|
4965
|
-
|
|
6249
|
+
const requiredFit = triggerOverride === "overflow";
|
|
6250
|
+
const pressureEstimate = force && !requiredFit ? null : liveContextEstimate(agentRuntime, pendingUserText);
|
|
6251
|
+
if (pressureEstimate && !requiredFit && !shouldCompact(pressureEstimate.tokens, compactionThreshold, pressureEstimate.contextWindow).shouldCompact)
|
|
4966
6252
|
return false;
|
|
4967
|
-
const attemptKey = !force && activeAutoTurnId ?
|
|
6253
|
+
const attemptKey = !force && activeAutoTurnId ? createHash4("sha256").update(
|
|
4968
6254
|
JSON.stringify({
|
|
4969
6255
|
turn: activeAutoTurnId,
|
|
4970
6256
|
leaf: state.lastTurnId,
|
|
@@ -4988,7 +6274,9 @@ function createTurnContext(deps) {
|
|
|
4988
6274
|
let preSummaryStageActed = false;
|
|
4989
6275
|
let evictionSkipNotice = null;
|
|
4990
6276
|
const rememberEmptyAutomaticAttempt = () => {
|
|
4991
|
-
if (
|
|
6277
|
+
if (force || preSummaryStageActed || !attemptKey) return;
|
|
6278
|
+
emptyAutoCompactContextKey = attemptKey;
|
|
6279
|
+
noUsefulCutBasisKey = liveBudgetInput(pendingUserText).reductionBasisKey;
|
|
4992
6280
|
};
|
|
4993
6281
|
const trigger = triggerOverride ?? (force ? "force" : "auto");
|
|
4994
6282
|
if (pressureEstimate) {
|
|
@@ -4996,7 +6284,7 @@ function createTurnContext(deps) {
|
|
|
4996
6284
|
const verdict = shouldCompact(estimate.tokens, compactionThreshold, estimate.contextWindow);
|
|
4997
6285
|
if (deps.session?.current()) {
|
|
4998
6286
|
const beforeSnapshotId = currentContextSnapshot?.snapshotId ?? null;
|
|
4999
|
-
if (process.env.CLIO_CODER_LEGACY_MASK === "1") {
|
|
6287
|
+
if (process.env.CLIO_CODER_LEGACY_MASK === "1" && !handoff) {
|
|
5000
6288
|
let masked;
|
|
5001
6289
|
try {
|
|
5002
6290
|
masked = maskStaleObservations(deps.readSessionEntries() ?? [], 6);
|
|
@@ -5049,8 +6337,10 @@ function createTurnContext(deps) {
|
|
|
5049
6337
|
deps.emitNotice(
|
|
5050
6338
|
`[context engine] mask_observations: ${masked.maskedObservations} observations masked${thinkingNote}; ~${estimate.tokens} tokens -> ~${tokensAfterMask} tokens`
|
|
5051
6339
|
);
|
|
6340
|
+
refreshLiveBudget(pendingUserText);
|
|
5052
6341
|
const after = liveContextEstimate(agentRuntime, pendingUserText);
|
|
5053
|
-
if (!shouldCompact(after.tokens, compactionThreshold, after.contextWindow).shouldCompact)
|
|
6342
|
+
if (requiredFit ? requestFits(after.tokens, resolveTurnOutputReserve(agentRuntime, after.tokens), after.contextWindow) : !shouldCompact(after.tokens, compactionThreshold, after.contextWindow).shouldCompact)
|
|
6343
|
+
return true;
|
|
5054
6344
|
}
|
|
5055
6345
|
} else if (settings.context.workingSet.enabled) {
|
|
5056
6346
|
let planned;
|
|
@@ -5070,8 +6360,14 @@ function createTurnContext(deps) {
|
|
|
5070
6360
|
pressure: {
|
|
5071
6361
|
tokens: estimate.tokens,
|
|
5072
6362
|
contextWindow: estimate.contextWindow,
|
|
5073
|
-
threshold:
|
|
5074
|
-
|
|
6363
|
+
threshold: requiredFit ? Math.min(
|
|
6364
|
+
compactionThreshold,
|
|
6365
|
+
Math.max(0, 1 - resolveTurnOutputReserve(agentRuntime, estimate.tokens) / estimate.contextWindow)
|
|
6366
|
+
) : compactionThreshold,
|
|
6367
|
+
target: requiredFit ? Math.min(
|
|
6368
|
+
settings.context.workingSet.target,
|
|
6369
|
+
Math.max(0, 1 - resolveTurnOutputReserve(agentRuntime, estimate.tokens) / estimate.contextWindow)
|
|
6370
|
+
) : settings.context.workingSet.target
|
|
5075
6371
|
},
|
|
5076
6372
|
estimateTokens
|
|
5077
6373
|
});
|
|
@@ -5087,7 +6383,7 @@ function createTurnContext(deps) {
|
|
|
5087
6383
|
emitCompactionActivity("started", "compacting context (working-set eviction)");
|
|
5088
6384
|
try {
|
|
5089
6385
|
const historyTokens = reconciledHistoryTokens(agentRuntime);
|
|
5090
|
-
deps.session.appendEntry({
|
|
6386
|
+
const evictionEntry = deps.session.appendEntry({
|
|
5091
6387
|
...buildEvictionFields(planned, {
|
|
5092
6388
|
trigger: "pressure",
|
|
5093
6389
|
pressureBefore: verdict.pressure,
|
|
@@ -5097,6 +6393,10 @@ function createTurnContext(deps) {
|
|
|
5097
6393
|
// cursor is the leaf the next message will extend.
|
|
5098
6394
|
parentTurnId: state.lastTurnId
|
|
5099
6395
|
});
|
|
6396
|
+
if (deps.session.flushAppends) {
|
|
6397
|
+
deps.session.flushAppends();
|
|
6398
|
+
if (!handoff) notifyMemoryCommit(evictionEntry.turnId, "summary", "evicted");
|
|
6399
|
+
}
|
|
5100
6400
|
noteColdReason("working_set_evict");
|
|
5101
6401
|
refreshAgentMessagesFromSession(agentRuntime);
|
|
5102
6402
|
carryReconciledAnchorThroughProjection(agentRuntime, historyTokens, planned.tokensBefore - planned.tokensAfter);
|
|
@@ -5130,8 +6430,10 @@ function createTurnContext(deps) {
|
|
|
5130
6430
|
deps.emitNotice(
|
|
5131
6431
|
`[context engine] working set: ${planned.items.length} ${itemsWord} evicted by ${planned.policyId}; ~${planned.tokensBefore} -> ~${planned.tokensAfter} tokens, recall by ref with context(scope="recall")`
|
|
5132
6432
|
);
|
|
6433
|
+
refreshLiveBudget(pendingUserText);
|
|
5133
6434
|
const after = liveContextEstimate(agentRuntime, pendingUserText);
|
|
5134
|
-
if (!shouldCompact(after.tokens, compactionThreshold, after.contextWindow).shouldCompact)
|
|
6435
|
+
if (requiredFit ? requestFits(after.tokens, resolveTurnOutputReserve(agentRuntime, after.tokens), after.contextWindow) : !shouldCompact(after.tokens, compactionThreshold, after.contextWindow).shouldCompact)
|
|
6436
|
+
return true;
|
|
5135
6437
|
} catch (error) {
|
|
5136
6438
|
emitCompactionActivity("failed", compactionFailureMessage(error));
|
|
5137
6439
|
throw error;
|
|
@@ -5173,14 +6475,7 @@ function createTurnContext(deps) {
|
|
|
5173
6475
|
let budget = skillContextState !== void 0 ? { skillContextState } : void 0;
|
|
5174
6476
|
if (useRequestBudget) {
|
|
5175
6477
|
const estimate = liveContextEstimate(agentRuntime, pendingUserText);
|
|
5176
|
-
const output =
|
|
5177
|
-
resolveReservedOutputTokens(agentRuntime.agent.state.model?.maxTokens, {
|
|
5178
|
-
api: agentRuntime.agent.state.model?.api ?? "",
|
|
5179
|
-
contextWindow: estimate.contextWindow,
|
|
5180
|
-
inputTokens: estimate.tokens
|
|
5181
|
-
}),
|
|
5182
|
-
settings.chat.maxOutputTokens > 0 ? settings.chat.maxOutputTokens : Number.POSITIVE_INFINITY
|
|
5183
|
-
);
|
|
6478
|
+
const output = resolveTurnOutputReserve(agentRuntime, estimate.tokens);
|
|
5184
6479
|
const inputTarget = Math.min(estimate.contextWindow * compactionThreshold, estimate.contextWindow - output);
|
|
5185
6480
|
const staticTokens = estimate.breakdown.systemPromptTokens + estimate.breakdown.toolSchemaTokens;
|
|
5186
6481
|
const calibration = Math.max(
|
|
@@ -5203,6 +6498,7 @@ function createTurnContext(deps) {
|
|
|
5203
6498
|
try {
|
|
5204
6499
|
return await deps.autoCompact?.(instructions, trigger, {
|
|
5205
6500
|
...budget,
|
|
6501
|
+
...handoff,
|
|
5206
6502
|
signal: summarySignal
|
|
5207
6503
|
}) ?? null;
|
|
5208
6504
|
} finally {
|
|
@@ -5228,6 +6524,14 @@ function createTurnContext(deps) {
|
|
|
5228
6524
|
if (!summaryLifecycleStarted) startSummaryLifecycle();
|
|
5229
6525
|
deps.bus?.emit(BusChannels.CompactionEnd, { trigger, at: Date.now() });
|
|
5230
6526
|
recordCompactionUsage(agentRuntime, result);
|
|
6527
|
+
if (deps.memoryCommitBridge && !handoff && deps.session?.flushAppends) {
|
|
6528
|
+
deps.session.flushAppends();
|
|
6529
|
+
await deps.session.checkpoint("context-summary");
|
|
6530
|
+
if (originSession !== deps.session.current()?.id || originNavigation !== navigationEpoch || signal?.aborted)
|
|
6531
|
+
throw new Error("Context ownership changed during checkpoint.");
|
|
6532
|
+
const summary = [...deps.readSessionEntries()].reverse().find((entry) => entry.kind === "compactionSummary");
|
|
6533
|
+
if (summary) notifyMemoryCommit(summary.turnId, "summary", "summarized");
|
|
6534
|
+
}
|
|
5231
6535
|
refreshAgentMessagesFromSession(agentRuntime);
|
|
5232
6536
|
reconciledAnchor = null;
|
|
5233
6537
|
const postCompactSnapshot = captureRuntimeContextSnapshot(
|
|
@@ -5265,6 +6569,67 @@ function createTurnContext(deps) {
|
|
|
5265
6569
|
isSplitTurn: result.isSplitTurn
|
|
5266
6570
|
})
|
|
5267
6571
|
);
|
|
6572
|
+
refreshLiveBudget(pendingUserText);
|
|
6573
|
+
return true;
|
|
6574
|
+
};
|
|
6575
|
+
let reductionInFlight = null;
|
|
6576
|
+
const runAutoCompact = (...args) => {
|
|
6577
|
+
if (reductionInFlight) {
|
|
6578
|
+
if (args[7]) return Promise.reject(new Error("Another context reduction is already in progress."));
|
|
6579
|
+
return reductionInFlight;
|
|
6580
|
+
}
|
|
6581
|
+
const operation = performAutoCompact(...args);
|
|
6582
|
+
reductionInFlight = operation;
|
|
6583
|
+
void operation.finally(() => {
|
|
6584
|
+
if (reductionInFlight === operation) reductionInFlight = null;
|
|
6585
|
+
}).catch(() => {
|
|
6586
|
+
});
|
|
6587
|
+
return operation;
|
|
6588
|
+
};
|
|
6589
|
+
const bindMemoryScope = () => {
|
|
6590
|
+
const sessionId = deps.session?.current()?.id;
|
|
6591
|
+
if (!sessionId) return null;
|
|
6592
|
+
const scope = { sessionId, branchAnchorTurnId };
|
|
6593
|
+
deps.memoryCommitBridge?.bindCommitScope(scope);
|
|
6594
|
+
return scope;
|
|
6595
|
+
};
|
|
6596
|
+
const notifyMemoryCommit = (commitId, kind, outcome) => {
|
|
6597
|
+
const scope = bindMemoryScope();
|
|
6598
|
+
if (scope) deps.memoryCommitBridge?.notifyContextCommitted({ ...scope, commitId, kind, outcome });
|
|
6599
|
+
};
|
|
6600
|
+
const installMemoryRestoration = (runtime, pendingText) => {
|
|
6601
|
+
const bridge = deps.memoryCommitBridge;
|
|
6602
|
+
if (!bridge || !bindMemoryScope()) return false;
|
|
6603
|
+
const entries = filterEntriesToActivePath(deps.readSessionEntries?.() ?? [], state.lastTurnId ?? void 0);
|
|
6604
|
+
const latest = [...entries].reverse().find((entry) => entry.kind === "continuityCommit" || entry.kind === "compactionSummary");
|
|
6605
|
+
const currentState = latest?.kind === "continuityCommit" ? { kind: "handoff", text: latest.continuity.accepted.note } : latest?.kind === "compactionSummary" ? { kind: "summary", text: latest.summary } : null;
|
|
6606
|
+
const view = refreshLiveBudget(pendingText);
|
|
6607
|
+
const available = Math.max(
|
|
6608
|
+
0,
|
|
6609
|
+
(view.effectiveWindow ?? 0) - (view.outputReserveTokens ?? 0) - (view.inputTokens ?? 0) - 64
|
|
6610
|
+
);
|
|
6611
|
+
const offer = bridge.prepareRestoration(currentState, available);
|
|
6612
|
+
if (!offer) return false;
|
|
6613
|
+
if (!offer.message) {
|
|
6614
|
+
bridge.acknowledgeRestoration(offer);
|
|
6615
|
+
return false;
|
|
6616
|
+
}
|
|
6617
|
+
const message = {
|
|
6618
|
+
role: "user",
|
|
6619
|
+
content: `<system-reminder>
|
|
6620
|
+
${offer.message}
|
|
6621
|
+
</system-reminder>`,
|
|
6622
|
+
timestamp: Date.now()
|
|
6623
|
+
};
|
|
6624
|
+
const cost = estimateAgentMessageTokens(message);
|
|
6625
|
+
if (!requestFits((view.inputTokens ?? Infinity) + cost, view.outputReserveTokens, view.effectiveWindow)) return false;
|
|
6626
|
+
const prior = [...runtime.agent.state.messages];
|
|
6627
|
+
replaceEngineMessages(runtime.agent, [...prior, message]);
|
|
6628
|
+
if (!bridge.acknowledgeRestoration(offer)) {
|
|
6629
|
+
replaceEngineMessages(runtime.agent, prior);
|
|
6630
|
+
return false;
|
|
6631
|
+
}
|
|
6632
|
+
refreshLiveBudget(pendingText);
|
|
5268
6633
|
return true;
|
|
5269
6634
|
};
|
|
5270
6635
|
const toolResultTail = (agentRuntime) => {
|
|
@@ -5281,28 +6646,73 @@ function createTurnContext(deps) {
|
|
|
5281
6646
|
thinkingLevel: agentRuntime.agent.state.thinkingLevel
|
|
5282
6647
|
});
|
|
5283
6648
|
return {
|
|
6649
|
+
notifyMemoryCommit,
|
|
6650
|
+
installMemoryRestoration,
|
|
6651
|
+
prepareMemoryTurn(runtime, input) {
|
|
6652
|
+
bindMemoryScope();
|
|
6653
|
+
pendingUserImages = [...input.images ?? []];
|
|
6654
|
+
if (input.continuation && memoryTurn !== null) return;
|
|
6655
|
+
const sessionId = deps.session?.current()?.id ?? null;
|
|
6656
|
+
memoryTurnSequence += 1;
|
|
6657
|
+
memoryTurn = {
|
|
6658
|
+
id: String(memoryTurnSequence),
|
|
6659
|
+
sessionId,
|
|
6660
|
+
sessionAuthority: JSON.stringify([memoryAuthorityEpoch, sessionId ?? `pending:${memoryTurnSequence}`]),
|
|
6661
|
+
origin: memoryOrigin(runtime),
|
|
6662
|
+
taskText: input.taskText,
|
|
6663
|
+
activePaths: Object.freeze([...sessionWorkingContextPaths])
|
|
6664
|
+
};
|
|
6665
|
+
},
|
|
6666
|
+
commitMemoryTurn(runtime) {
|
|
6667
|
+
pendingUserImages = [];
|
|
6668
|
+
if (memoryTurn?.sessionId === null && memoryTurn.origin === memoryOrigin(runtime)) {
|
|
6669
|
+
memoryTurn.sessionId = deps.session?.current()?.id ?? null;
|
|
6670
|
+
}
|
|
6671
|
+
},
|
|
5284
6672
|
captureRuntimeContextSnapshot,
|
|
5285
6673
|
persistContextSnapshot,
|
|
5286
6674
|
liveContextEstimate,
|
|
6675
|
+
refreshLiveBudget,
|
|
5287
6676
|
rememberedLoadedContextWindow,
|
|
5288
6677
|
refreshAgentMessagesFromSession,
|
|
5289
6678
|
runAutoCompact,
|
|
6679
|
+
navigationRevision: () => navigationEpoch,
|
|
5290
6680
|
cancelCompaction: () => compactionController?.abort(),
|
|
6681
|
+
liveBudget: () => budgetProducer.current() ?? refreshLiveBudget(),
|
|
6682
|
+
inspectLiveBudget() {
|
|
6683
|
+
const targetId = deps.getSettings().chat?.target;
|
|
6684
|
+
const target = !state.runtime && targetId ? deps.providers.getTarget(targetId) : null;
|
|
6685
|
+
const runtime = state.runtime?.runtimeResolution.runtime ?? (target ? deps.providers.getRuntime(target.runtime) : null);
|
|
6686
|
+
if (runtime && (!isOrchestratorEligibleRuntime(runtime) || runtime.externalAgentLoop))
|
|
6687
|
+
return {
|
|
6688
|
+
status: "unsupported",
|
|
6689
|
+
reason: "The external agent owns its context; native request accounting is unavailable."
|
|
6690
|
+
};
|
|
6691
|
+
if (!runtime)
|
|
6692
|
+
return {
|
|
6693
|
+
status: "unavailable",
|
|
6694
|
+
reason: "No native runtime descriptor is resolved. Inspection does not initialize a runtime."
|
|
6695
|
+
};
|
|
6696
|
+
return { status: "available", capability: "native", view: refreshLiveBudget() };
|
|
6697
|
+
},
|
|
5291
6698
|
setCurrentSnapshot(snapshot) {
|
|
5292
6699
|
currentContextSnapshot = snapshot;
|
|
6700
|
+
refreshLiveBudget(snapshot.pendingUserInput);
|
|
5293
6701
|
},
|
|
5294
6702
|
flushReconciledSnapshot() {
|
|
5295
|
-
if (
|
|
5296
|
-
|
|
6703
|
+
if (snapshotPersistPending && currentContextSnapshot) persistContextSnapshot(currentContextSnapshot);
|
|
6704
|
+
refreshLiveBudget();
|
|
5297
6705
|
},
|
|
5298
6706
|
reconcileUsage(usage) {
|
|
5299
6707
|
const promptTokens = (usage.input || 0) + (usage.cacheRead || 0) + (usage.cacheWrite || 0);
|
|
5300
6708
|
const runtime = state.runtime;
|
|
5301
6709
|
if (promptTokens > 0 && runtime) {
|
|
5302
6710
|
const breakdown = estimateAgentContextBreakdown({ ...runtime.agent.state, messages: [] });
|
|
6711
|
+
const anchoredMessages = [...runtime.agent.state.messages.filter((message) => message.role !== "system")];
|
|
5303
6712
|
reconciledAnchor = {
|
|
5304
6713
|
tokens: promptTokens + (usage.output || 0),
|
|
5305
|
-
anchoredMessages
|
|
6714
|
+
anchoredMessages,
|
|
6715
|
+
contentDigest: messageListDigest(anchoredMessages),
|
|
5306
6716
|
runtime,
|
|
5307
6717
|
model: runtime.agent.state.model,
|
|
5308
6718
|
modelKey: anchorModelKey(runtime),
|
|
@@ -5313,7 +6723,10 @@ function createTurnContext(deps) {
|
|
|
5313
6723
|
toolSchemaTokens: breakdown.toolSchemaTokens
|
|
5314
6724
|
};
|
|
5315
6725
|
}
|
|
5316
|
-
if (!currentContextSnapshot)
|
|
6726
|
+
if (!currentContextSnapshot) {
|
|
6727
|
+
refreshLiveBudget();
|
|
6728
|
+
return;
|
|
6729
|
+
}
|
|
5317
6730
|
if (runtime) {
|
|
5318
6731
|
const messages = runtime.agent.state.messages.filter((message) => message.role !== "system");
|
|
5319
6732
|
const promptMessages = messages.at(-1)?.role === "assistant" ? messages.slice(0, -1) : messages;
|
|
@@ -5331,6 +6744,7 @@ function createTurnContext(deps) {
|
|
|
5331
6744
|
}
|
|
5332
6745
|
currentContextSnapshot = reconcileSnapshot(currentContextSnapshot, usage);
|
|
5333
6746
|
snapshotPersistPending = true;
|
|
6747
|
+
refreshLiveBudget();
|
|
5334
6748
|
},
|
|
5335
6749
|
promptSideTokens() {
|
|
5336
6750
|
return currentContextSnapshot ? snapshotInputTokens(currentContextSnapshot) : 0;
|
|
@@ -5375,7 +6789,20 @@ function createTurnContext(deps) {
|
|
|
5375
6789
|
};
|
|
5376
6790
|
if (deps.getMemorySection) {
|
|
5377
6791
|
try {
|
|
5378
|
-
|
|
6792
|
+
if (memoryTurn !== null && memoryTurn.sessionId !== (sessionId || null)) {
|
|
6793
|
+
memoryAuthorityEpoch += 1;
|
|
6794
|
+
memoryTurn = null;
|
|
6795
|
+
}
|
|
6796
|
+
const memorySection = deps.getMemorySection({
|
|
6797
|
+
turnId: memoryTurn?.id ?? null,
|
|
6798
|
+
sessionAuthority: memoryTurn?.sessionAuthority ?? JSON.stringify([memoryAuthorityEpoch, sessionId]),
|
|
6799
|
+
cwd,
|
|
6800
|
+
targetId: agentRuntime.targetId,
|
|
6801
|
+
runtimeId: agentRuntime.runtimeId,
|
|
6802
|
+
modelId: agentRuntime.wireModelId,
|
|
6803
|
+
taskText: memoryTurn?.taskText ?? "",
|
|
6804
|
+
activePaths: memoryTurn?.activePaths ?? []
|
|
6805
|
+
});
|
|
5379
6806
|
if (memorySection.length > 0) sessionInputs.memorySection = memorySection;
|
|
5380
6807
|
} catch (err) {
|
|
5381
6808
|
deps.emitNotice(
|
|
@@ -5481,15 +6908,25 @@ function createTurnContext(deps) {
|
|
|
5481
6908
|
async postToolContinuationGuard(agentRuntime, signal, contextChanged = false) {
|
|
5482
6909
|
if (signal?.aborted || !contextChanged && !toolResultTail(agentRuntime)) return void 0;
|
|
5483
6910
|
const reminder = contextChanged ? agentRuntime.agent.state.messages.at(-1) : void 0;
|
|
6911
|
+
const beforeView = refreshLiveBudget();
|
|
5484
6912
|
const before = liveContextEstimate(agentRuntime);
|
|
5485
|
-
if (before.contextWindow <= 0
|
|
6913
|
+
if (before.contextWindow <= 0) throw new Error("Context window is unavailable; continuation refused.");
|
|
5486
6914
|
const settings = deps.getSettings();
|
|
5487
6915
|
const threshold = settings.context.compaction?.threshold ?? DEFAULT_COMPACTION_THRESHOLD;
|
|
5488
6916
|
const verdict = shouldCompact(before.tokens, threshold, before.contextWindow);
|
|
5489
6917
|
let compacted = false;
|
|
5490
|
-
|
|
6918
|
+
const mustFit = !requestFits(beforeView.inputTokens, beforeView.outputReserveTokens, beforeView.effectiveWindow);
|
|
6919
|
+
if (mustFit || verdict.shouldCompact) {
|
|
5491
6920
|
try {
|
|
5492
|
-
compacted = await runAutoCompact(
|
|
6921
|
+
compacted = await runAutoCompact(
|
|
6922
|
+
agentRuntime,
|
|
6923
|
+
mustFit,
|
|
6924
|
+
void 0,
|
|
6925
|
+
mustFit ? "overflow" : "auto",
|
|
6926
|
+
void 0,
|
|
6927
|
+
void 0,
|
|
6928
|
+
signal
|
|
6929
|
+
);
|
|
5493
6930
|
} catch (err) {
|
|
5494
6931
|
throw new Error(
|
|
5495
6932
|
`[Clio Coder] post-tool context guard could not compact before continuation: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -5499,28 +6936,23 @@ function createTurnContext(deps) {
|
|
|
5499
6936
|
if (reminder && !agentRuntime.agent.state.messages.includes(reminder)) {
|
|
5500
6937
|
agentRuntime.agent.state.messages.push(reminder);
|
|
5501
6938
|
}
|
|
5502
|
-
const
|
|
5503
|
-
if (
|
|
6939
|
+
const afterView = refreshLiveBudget();
|
|
6940
|
+
if (!requestFits(afterView.inputTokens, afterView.outputReserveTokens, afterView.effectiveWindow)) {
|
|
5504
6941
|
throw new Error(
|
|
5505
|
-
`[Clio Coder] post-tool context guard stopped continuation before provider call: estimated ${
|
|
6942
|
+
`[Clio Coder] post-tool context guard stopped continuation before provider call: estimated input ${afterView.inputTokens} plus reserved output ${afterView.outputReserveTokens} tokens does not fit context window ${afterView.effectiveWindow}. Use /context compact, narrower reads, or a follow-up turn with smaller observations.`
|
|
5506
6943
|
);
|
|
5507
6944
|
}
|
|
5508
6945
|
return compacted ? continuationContextUpdate(agentRuntime) : void 0;
|
|
5509
6946
|
},
|
|
5510
6947
|
contextUsage() {
|
|
5511
|
-
const
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
systemPromptTokens: currentContextSnapshot.categories.system,
|
|
5519
|
-
messageTokens: currentContextSnapshot.categories.messages + (currentContextSnapshot.categories.toolResults ?? 0),
|
|
5520
|
-
pendingUserTokens: pendingTokens,
|
|
5521
|
-
toolSchemaTokens: currentContextSnapshot.categories.tools
|
|
6948
|
+
const view = budgetProducer.current() ?? refreshLiveBudget();
|
|
6949
|
+
return {
|
|
6950
|
+
...contextUsageSnapshot(view.inputTokens, view.effectiveWindow, view.breakdown ?? void 0),
|
|
6951
|
+
revision: view.revision,
|
|
6952
|
+
inputSource: view.inputSource,
|
|
6953
|
+
historical: view.historical,
|
|
6954
|
+
breakdownSource: view.breakdownSource
|
|
5522
6955
|
};
|
|
5523
|
-
return contextUsageSnapshot(totalUsed > 0 ? totalUsed : null, effectiveWindow, breakdown);
|
|
5524
6956
|
},
|
|
5525
6957
|
contextLedger() {
|
|
5526
6958
|
const settings = deps.getSettings();
|
|
@@ -5530,7 +6962,7 @@ function createTurnContext(deps) {
|
|
|
5530
6962
|
contextWindow: state.runtime.runtimeResolution.contextWindowDetails.effectiveContextWindow,
|
|
5531
6963
|
contextWindowSource: state.runtime.runtimeResolution.contextWindowDetails.contextWindowSource,
|
|
5532
6964
|
contextWindowSlots: state.runtime.runtimeResolution.contextWindowDetails.contextWindowSlots
|
|
5533
|
-
} : windowWithoutRuntime();
|
|
6965
|
+
} : windowWithoutRuntime(false);
|
|
5534
6966
|
const provider = state.runtime?.targetId ?? settings.chat?.target ?? null;
|
|
5535
6967
|
const model = state.runtime?.wireModelId ?? settings.chat?.model ?? null;
|
|
5536
6968
|
const liveToolCount = state.runtime?.agent.state.tools.length ?? 0;
|
|
@@ -5642,7 +7074,9 @@ function createTurnContext(deps) {
|
|
|
5642
7074
|
};
|
|
5643
7075
|
}
|
|
5644
7076
|
},
|
|
5645
|
-
resetForSession() {
|
|
7077
|
+
resetForSession(incomingBranchAnchorTurnId = null) {
|
|
7078
|
+
memoryTurn = null;
|
|
7079
|
+
memoryAuthorityEpoch += 1;
|
|
5646
7080
|
compactionController?.abort();
|
|
5647
7081
|
if (sessionPromptHash !== null) noteColdReason("prompt_recompiled");
|
|
5648
7082
|
lastPromptCache = null;
|
|
@@ -5655,7 +7089,12 @@ function createTurnContext(deps) {
|
|
|
5655
7089
|
sessionWorkingContextPaths.clear();
|
|
5656
7090
|
pendingPromptLogEntry = null;
|
|
5657
7091
|
emptyAutoCompactContextKey = null;
|
|
7092
|
+
noUsefulCutBasisKey = null;
|
|
5658
7093
|
reconciledAnchor = null;
|
|
7094
|
+
branchAnchorTurnId = incomingBranchAnchorTurnId;
|
|
7095
|
+
navigationEpoch += 1;
|
|
7096
|
+
bindMemoryScope();
|
|
7097
|
+
budgetProducer.reset();
|
|
5659
7098
|
const session = deps.session?.current();
|
|
5660
7099
|
currentContextSnapshot = session ? getLatestContextSnapshot(session) : null;
|
|
5661
7100
|
},
|
|
@@ -5671,9 +7110,17 @@ init_esm_shims();
|
|
|
5671
7110
|
function createTurnMiddleware(deps) {
|
|
5672
7111
|
const { state, middlewareToolChoice } = deps;
|
|
5673
7112
|
const pendingReminders = [];
|
|
5674
|
-
const
|
|
7113
|
+
const dropStale = () => {
|
|
7114
|
+
for (let index = pendingReminders.length - 1; index >= 0; index--) {
|
|
7115
|
+
if (pendingReminders[index]?.isCurrent?.() === false) pendingReminders.splice(index, 1);
|
|
7116
|
+
}
|
|
7117
|
+
};
|
|
7118
|
+
const bufferReminder = (message, severity, deferred = false, isCurrent) => {
|
|
7119
|
+
dropStale();
|
|
7120
|
+
isCurrent ??= message.startsWith("Memory:") ? deps.memoryContentGuard?.() : void 0;
|
|
7121
|
+
if (isCurrent?.() === false) return;
|
|
5675
7122
|
if (pendingReminders.some((entry) => entry.message === message && entry.severity === severity)) return;
|
|
5676
|
-
pendingReminders.push({ message, severity, deferred });
|
|
7123
|
+
pendingReminders.push({ message, severity, deferred, isCurrent });
|
|
5677
7124
|
};
|
|
5678
7125
|
const runMiddlewareTurnHook = (input) => {
|
|
5679
7126
|
if (!deps.middleware) return [];
|
|
@@ -5752,6 +7199,7 @@ function createTurnMiddleware(deps) {
|
|
|
5752
7199
|
[]
|
|
5753
7200
|
);
|
|
5754
7201
|
if (!current()) return false;
|
|
7202
|
+
dropStale();
|
|
5755
7203
|
const ready = pendingReminders.filter((entry) => entry.deferred);
|
|
5756
7204
|
if (ready.length === 0) return false;
|
|
5757
7205
|
const content = `<system-reminder>
|
|
@@ -5860,7 +7308,19 @@ ${[...new Set(ready.map((entry) => entry.message))].join("\n\n")}
|
|
|
5860
7308
|
metadata
|
|
5861
7309
|
});
|
|
5862
7310
|
},
|
|
7311
|
+
takePendingReminderProjection() {
|
|
7312
|
+
const entries = pendingReminders.splice(0);
|
|
7313
|
+
return () => {
|
|
7314
|
+
const messages = [
|
|
7315
|
+
...new Set(entries.filter((entry) => entry.isCurrent?.() !== false).map((entry) => entry.message))
|
|
7316
|
+
];
|
|
7317
|
+
return messages.length ? `<system-reminder>
|
|
7318
|
+
${messages.join("\n\n")}
|
|
7319
|
+
</system-reminder>` : "";
|
|
7320
|
+
};
|
|
7321
|
+
},
|
|
5863
7322
|
flushPendingReminders() {
|
|
7323
|
+
dropStale();
|
|
5864
7324
|
if (pendingReminders.length === 0) return "";
|
|
5865
7325
|
const messages = [...new Set(pendingReminders.map((entry) => entry.message))];
|
|
5866
7326
|
pendingReminders.length = 0;
|
|
@@ -5871,12 +7331,14 @@ ${messages.join("\n\n")}
|
|
|
5871
7331
|
clearPendingReminders() {
|
|
5872
7332
|
pendingReminders.length = 0;
|
|
5873
7333
|
},
|
|
5874
|
-
injectDeferredReminder(message, severity = "advisory") {
|
|
7334
|
+
injectDeferredReminder(message, severity = "advisory", isCurrent) {
|
|
7335
|
+
dropStale();
|
|
7336
|
+
if (isCurrent?.() === false) return;
|
|
5875
7337
|
const text = message.trim();
|
|
5876
7338
|
if (text.length === 0) return;
|
|
5877
7339
|
const level = severity === "hard-block" ? "advisory" : severity;
|
|
5878
7340
|
if (pendingReminders.some((entry) => entry.message === text)) return;
|
|
5879
|
-
bufferReminder(text, level, true);
|
|
7341
|
+
bufferReminder(text, level, true, isCurrent);
|
|
5880
7342
|
appendMiddlewareReminderEntry(text, level);
|
|
5881
7343
|
deps.emitNotice(text);
|
|
5882
7344
|
},
|
|
@@ -5979,7 +7441,7 @@ function createTurnPersistence(deps) {
|
|
|
5979
7441
|
costUsd: (total.costUsd ?? 0) + summary.costUsd
|
|
5980
7442
|
};
|
|
5981
7443
|
};
|
|
5982
|
-
const appendAssistantTurn = (message, timing) => {
|
|
7444
|
+
const appendAssistantTurn = (message, timing, deliveryId) => {
|
|
5983
7445
|
if (message?.role !== "assistant") return;
|
|
5984
7446
|
if (persistedAssistantMessages.has(message)) return;
|
|
5985
7447
|
if (state.activeInterruptReason !== null && isEmptyAbortedAssistantMessage(message)) return;
|
|
@@ -5987,6 +7449,10 @@ function createTurnPersistence(deps) {
|
|
|
5987
7449
|
const failure2 = terminalFailureFromAssistantMessage(message);
|
|
5988
7450
|
const payload = assistantSessionPayload(message, failure2);
|
|
5989
7451
|
if (timing) payload.timing = timing;
|
|
7452
|
+
if (deliveryId) {
|
|
7453
|
+
payload.continuityDeliveryId = deliveryId;
|
|
7454
|
+
payload.stopReason = message.stopReason;
|
|
7455
|
+
}
|
|
5990
7456
|
const usage = message.usage;
|
|
5991
7457
|
if (usage && typeof usage === "object") {
|
|
5992
7458
|
const backendTimings = message.backendTimings;
|
|
@@ -6023,6 +7489,7 @@ function createTurnPersistence(deps) {
|
|
|
6023
7489
|
tokens: traceUsage?.totalTokens ?? null
|
|
6024
7490
|
});
|
|
6025
7491
|
if (!turnContinues) finishTracedTurn(failure2 ? "fail" : "success", failure2?.errorMessage ?? null);
|
|
7492
|
+
return turn.id;
|
|
6026
7493
|
};
|
|
6027
7494
|
return {
|
|
6028
7495
|
wasPersisted(message) {
|
|
@@ -6196,7 +7663,7 @@ function createTurnPersistence(deps) {
|
|
|
6196
7663
|
|
|
6197
7664
|
// src/interactive/turn-prewarm.ts
|
|
6198
7665
|
init_esm_shims();
|
|
6199
|
-
import { createHash as
|
|
7666
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
6200
7667
|
|
|
6201
7668
|
// src/interactive/prewarm.ts
|
|
6202
7669
|
init_esm_shims();
|
|
@@ -6322,7 +7789,7 @@ function createTurnPrewarm(deps) {
|
|
|
6322
7789
|
if (Date.now() - started > 3e4) return { ran: false, reason: "expired" };
|
|
6323
7790
|
if (deployment.endpoint && (endpointCapacityUsage()[deployment.endpoint] ?? 0) > 0)
|
|
6324
7791
|
return { ran: false, reason: "dispatch-active" };
|
|
6325
|
-
const prefix =
|
|
7792
|
+
const prefix = createHash5("sha256").update(
|
|
6326
7793
|
JSON.stringify({
|
|
6327
7794
|
model: runtime.agent.state.model,
|
|
6328
7795
|
system: runtime.agent.state.systemPrompt,
|
|
@@ -7139,6 +8606,33 @@ function createTurnRuntime(deps) {
|
|
|
7139
8606
|
},
|
|
7140
8607
|
maxRetryDelayMs: deps.retrySettings().maxDelayMs,
|
|
7141
8608
|
...gatewaySessionId ? { sessionId: gatewaySessionId } : {},
|
|
8609
|
+
beforeToolBatch: ({ assistantMessage }) => {
|
|
8610
|
+
const calls = assistantMessage.content.filter((block) => block.type === "toolCall");
|
|
8611
|
+
if (calls.some((call) => call.name === "self_compact") && calls.length !== 1) {
|
|
8612
|
+
return { reason: "self_compact must be the only call in its batch; no sibling was executed." };
|
|
8613
|
+
}
|
|
8614
|
+
return void 0;
|
|
8615
|
+
},
|
|
8616
|
+
beforeStreamRequest: ({ context: request }) => {
|
|
8617
|
+
setGlobalDefaultMaxOutputTokens(deps.getSettings().chat.maxOutputTokens);
|
|
8618
|
+
if (state.activeInterruptReason !== null || state.runtime !== localRuntime) {
|
|
8619
|
+
return { block: true, reason: "Request ownership changed before invocation." };
|
|
8620
|
+
}
|
|
8621
|
+
if (deps.hasQueuedSteering?.() && deps.continuity?.admission().block === false) {
|
|
8622
|
+
const handoff = deps.continuity.admission();
|
|
8623
|
+
if (!handoff.block && handoff.correlationId)
|
|
8624
|
+
return { block: true, reason: "Operator steering arrived during handoff preparation; handoff paused." };
|
|
8625
|
+
}
|
|
8626
|
+
const view = context.refreshLiveBudget();
|
|
8627
|
+
const resolved = resolvedRequestContext(request);
|
|
8628
|
+
const actual = state.synthesisToolLock ? { ...resolved, systemPrompt: lockedSynthesisSystemPrompt(resolved.systemPrompt ?? "") } : request;
|
|
8629
|
+
const input = Math.max(estimateInputTokensFromContext(actual), view.inputTokens ?? 0);
|
|
8630
|
+
const output = resolveTurnOutputReserve(localRuntime, input);
|
|
8631
|
+
return requestFits(input, output, view.effectiveWindow) ? deps.continuity?.admission() ?? { block: false } : {
|
|
8632
|
+
block: true,
|
|
8633
|
+
reason: `Context window exceeded: input ${input} + output ${output}, window ${view.effectiveWindow ?? "unknown"}.`
|
|
8634
|
+
};
|
|
8635
|
+
},
|
|
7142
8636
|
onStreamInvocation: () => {
|
|
7143
8637
|
setGlobalDefaultMaxOutputTokens(deps.getSettings().chat.maxOutputTokens);
|
|
7144
8638
|
apiCallStartedAt = performance3.now();
|
|
@@ -7218,14 +8712,17 @@ function createTurnRuntime(deps) {
|
|
|
7218
8712
|
);
|
|
7219
8713
|
stallTimer.unref?.();
|
|
7220
8714
|
};
|
|
7221
|
-
handle.agent.
|
|
8715
|
+
handle.agent.prepareNextTurnWithContext = async (_completed, signal) => {
|
|
7222
8716
|
stallSuspendDepth += 1;
|
|
7223
8717
|
try {
|
|
7224
8718
|
if (signal?.aborted || state.activeInterruptReason !== null) return void 0;
|
|
7225
|
-
|
|
8719
|
+
if (deps.hasQueuedSteering?.()) await deps.continuity?.pause();
|
|
8720
|
+
const handoffChanged = await deps.continuity?.settle(signal) ?? false;
|
|
8721
|
+
const contextChanged = await middleware.prepareToolContinuation(localRuntime, signal) || handoffChanged;
|
|
7226
8722
|
const update = await context.postToolContinuationGuard(localRuntime, signal, contextChanged);
|
|
8723
|
+
const restored = context.installMemoryRestoration(localRuntime);
|
|
7227
8724
|
if (signal?.aborted || state.activeInterruptReason !== null) return void 0;
|
|
7228
|
-
return update ?? (contextChanged ? {
|
|
8725
|
+
return (!restored ? update : void 0) ?? (contextChanged || restored ? {
|
|
7229
8726
|
context: {
|
|
7230
8727
|
messages: [...localRuntime.agent.state.messages],
|
|
7231
8728
|
tools: [...localRuntime.agent.state.tools]
|
|
@@ -7434,7 +8931,9 @@ function createTurnRuntime(deps) {
|
|
|
7434
8931
|
ttftMs: apiCallFirstDeltaAt !== null ? Math.round(Math.max(0, apiCallFirstDeltaAt - apiCallStartedAt)) : null,
|
|
7435
8932
|
apiMs: Math.round(Math.max(0, eventClock - apiCallStartedAt))
|
|
7436
8933
|
} : null;
|
|
7437
|
-
|
|
8934
|
+
const correlationId = event.type === "message_end" ? handle.requestCorrelationId(event.message) : void 0;
|
|
8935
|
+
const persistedId = persistence.appendAssistantTurn(enrichedEvent.message, timing, correlationId);
|
|
8936
|
+
await deps.continuity?.response(persistedId, correlationId);
|
|
7438
8937
|
if (isAssistant) apiCallStartedAt = null;
|
|
7439
8938
|
const usage = enrichedEvent.message.usage;
|
|
7440
8939
|
if (isAssistant && usage && typeof usage === "object" && runFirstCallVerdict === null) {
|
|
@@ -7455,6 +8954,7 @@ function createTurnRuntime(deps) {
|
|
|
7455
8954
|
pendingTerminalToolResult = enrichedEvent.result?.terminate === true ? { toolCallId: enrichedEvent.toolCallId, toolName: enrichedEvent.toolName } : null;
|
|
7456
8955
|
}
|
|
7457
8956
|
if (enrichedEvent.type === "agent_end") {
|
|
8957
|
+
await deps.continuity?.pause();
|
|
7458
8958
|
clearStallTimer();
|
|
7459
8959
|
const terminal = pendingTerminalToolResult;
|
|
7460
8960
|
pendingTerminalToolResult = null;
|
|
@@ -7633,6 +9133,7 @@ function createChatLoop(deps) {
|
|
|
7633
9133
|
submit: (text, options) => submitTracked(text, options)
|
|
7634
9134
|
});
|
|
7635
9135
|
const middleware = createTurnMiddleware({
|
|
9136
|
+
memoryContentGuard: deps.memoryCommitBridge?.isContentCurrent,
|
|
7636
9137
|
state,
|
|
7637
9138
|
middleware: deps.middleware,
|
|
7638
9139
|
session: deps.session,
|
|
@@ -7641,7 +9142,9 @@ function createChatLoop(deps) {
|
|
|
7641
9142
|
emitFooterNotice
|
|
7642
9143
|
});
|
|
7643
9144
|
try {
|
|
7644
|
-
deps.registerDeferredReminderSink?.(
|
|
9145
|
+
deps.registerDeferredReminderSink?.(
|
|
9146
|
+
(message, isCurrent) => middleware.injectDeferredReminder(message, "advisory", isCurrent)
|
|
9147
|
+
);
|
|
7645
9148
|
deps.registerDeferredNoticeSink?.((text) => middleware.emitDeferredNotice(text));
|
|
7646
9149
|
} catch {
|
|
7647
9150
|
}
|
|
@@ -7658,10 +9161,108 @@ function createChatLoop(deps) {
|
|
|
7658
9161
|
readSessionEntries: deps.readSessionEntries,
|
|
7659
9162
|
autoCompact: deps.autoCompact,
|
|
7660
9163
|
getMemorySection: deps.getMemorySection,
|
|
9164
|
+
memoryCommitBridge: deps.memoryCommitBridge,
|
|
7661
9165
|
getReadySkillCount: deps.getReadySkillCount,
|
|
9166
|
+
getPendingHandoff: () => {
|
|
9167
|
+
const sessionId = deps.session?.current()?.id;
|
|
9168
|
+
if (!sessionId) return null;
|
|
9169
|
+
const fold = resolveContinuityProjection({
|
|
9170
|
+
entries: filterEntriesToActivePath(deps.readSessionEntries?.() ?? [], state.lastTurnId ?? void 0),
|
|
9171
|
+
sessionId
|
|
9172
|
+
}).current;
|
|
9173
|
+
return fold?.identity && fold.phase !== "acknowledged" ? {
|
|
9174
|
+
id: fold.identity.handoffId,
|
|
9175
|
+
preparedAt: fold.policy ? new Date(fold.policy.preparedAtMs).toISOString() : null,
|
|
9176
|
+
sourceRevision: fold.identity.sourceRevision
|
|
9177
|
+
} : null;
|
|
9178
|
+
},
|
|
9179
|
+
getLastOutcome: () => {
|
|
9180
|
+
const sessionId = deps.session?.current()?.id;
|
|
9181
|
+
if (!sessionId) return null;
|
|
9182
|
+
const fold = resolveContinuityProjection({
|
|
9183
|
+
entries: filterEntriesToActivePath(deps.readSessionEntries?.() ?? [], state.lastTurnId ?? void 0),
|
|
9184
|
+
sessionId
|
|
9185
|
+
}).current;
|
|
9186
|
+
return fold?.identity ? { outcome: fold.phase, at: null, detail: fold.commit?.outcome ?? null } : null;
|
|
9187
|
+
},
|
|
7662
9188
|
middleware,
|
|
7663
9189
|
emitNotice
|
|
7664
9190
|
});
|
|
9191
|
+
let continuityReplayInstalled = false;
|
|
9192
|
+
const continuity = new ContinuityController({
|
|
9193
|
+
captureOrigin: () => {
|
|
9194
|
+
continuityReplayInstalled = false;
|
|
9195
|
+
const session = deps.session;
|
|
9196
|
+
const meta = session?.current();
|
|
9197
|
+
const runtime = state.runtime;
|
|
9198
|
+
const leaf = state.lastTurnId;
|
|
9199
|
+
const operator = state.activeUserTurnId;
|
|
9200
|
+
if (!session || !meta || !runtime || !leaf || !operator || context.inspectLiveBudget().status !== "available") {
|
|
9201
|
+
throw new Error("Self-compaction requires a native runtime and a persisted operator turn.");
|
|
9202
|
+
}
|
|
9203
|
+
const revision = context.navigationRevision();
|
|
9204
|
+
const route = `${deps.getSettings().chat.target}/${deps.getSettings().chat.model}`;
|
|
9205
|
+
return {
|
|
9206
|
+
sessionId: meta.id,
|
|
9207
|
+
leafTurnId: leaf,
|
|
9208
|
+
initiatingTurnId: operator,
|
|
9209
|
+
sourceRevision: context.refreshLiveBudget().revision,
|
|
9210
|
+
ports: createContinuityPersistencePorts({
|
|
9211
|
+
session,
|
|
9212
|
+
origin: {
|
|
9213
|
+
sessionId: meta.id,
|
|
9214
|
+
cwdHash: meta.cwdHash,
|
|
9215
|
+
stillCurrent: () => context.navigationRevision() === revision && state.runtime === runtime && state.activeUserTurnId === operator && `${deps.getSettings().chat.target}/${deps.getSettings().chat.model}` === route
|
|
9216
|
+
}
|
|
9217
|
+
})
|
|
9218
|
+
};
|
|
9219
|
+
},
|
|
9220
|
+
entries: () => filterEntriesToActivePath(deps.readSessionEntries?.() ?? [], state.lastTurnId ?? void 0),
|
|
9221
|
+
leaf: () => state.lastTurnId,
|
|
9222
|
+
admitNote: (accepted) => {
|
|
9223
|
+
const view = context.refreshLiveBudget();
|
|
9224
|
+
if (!view.breakdown || view.historical) return false;
|
|
9225
|
+
const messages = state.runtime?.agent.state.messages ?? [];
|
|
9226
|
+
const operator = [...messages].reverse().find((message) => message.role === "user");
|
|
9227
|
+
const note = continuityReplayText({
|
|
9228
|
+
note: accepted.note,
|
|
9229
|
+
handoffId: "pending",
|
|
9230
|
+
commitId: "pending",
|
|
9231
|
+
originSessionId: view.sessionId ?? "",
|
|
9232
|
+
phase: "prepared",
|
|
9233
|
+
authority: "execution"
|
|
9234
|
+
});
|
|
9235
|
+
const protectedSkills = messages.filter((message) => message.role === "toolResult" && message.toolName === "context").reduce((sum, message) => sum + estimateAgentMessageTokens(message), 0);
|
|
9236
|
+
const floor = view.breakdown.systemPromptTokens + view.breakdown.toolSchemaTokens + protectedSkills + (operator ? estimateAgentMessageTokens(operator) : 0) + estimateAgentMessageTokens({ role: "assistant", content: [{ type: "text", text: note }] }) + 512;
|
|
9237
|
+
return requestFits(floor, view.outputReserveTokens, view.effectiveWindow);
|
|
9238
|
+
},
|
|
9239
|
+
fits: () => {
|
|
9240
|
+
const view = context.refreshLiveBudget();
|
|
9241
|
+
return requestFits(view.inputTokens, view.outputReserveTokens, view.effectiveWindow);
|
|
9242
|
+
},
|
|
9243
|
+
inputTokens: () => context.refreshLiveBudget().inputTokens ?? 0,
|
|
9244
|
+
reduce: async (hooks, signal) => {
|
|
9245
|
+
if (!state.runtime) throw new Error("Native runtime was detached.");
|
|
9246
|
+
continuityReplayInstalled = await context.runAutoCompact(
|
|
9247
|
+
state.runtime,
|
|
9248
|
+
true,
|
|
9249
|
+
void 0,
|
|
9250
|
+
"overflow",
|
|
9251
|
+
void 0,
|
|
9252
|
+
void 0,
|
|
9253
|
+
signal,
|
|
9254
|
+
hooks
|
|
9255
|
+
);
|
|
9256
|
+
},
|
|
9257
|
+
installReplay: () => {
|
|
9258
|
+
if (state.runtime && !continuityReplayInstalled) {
|
|
9259
|
+
context.refreshAgentMessagesFromSession(state.runtime);
|
|
9260
|
+
continuityReplayInstalled = true;
|
|
9261
|
+
}
|
|
9262
|
+
},
|
|
9263
|
+
onCommit: (commitId, outcome) => context.notifyMemoryCommit(commitId, "continuity", outcome),
|
|
9264
|
+
notice: emitNotice
|
|
9265
|
+
});
|
|
7665
9266
|
const persistence = createTurnPersistence({
|
|
7666
9267
|
state,
|
|
7667
9268
|
session: deps.session,
|
|
@@ -7697,6 +9298,8 @@ function createChatLoop(deps) {
|
|
|
7697
9298
|
knownTargets: deps.knownTargets,
|
|
7698
9299
|
observability: deps.observability,
|
|
7699
9300
|
createAgent,
|
|
9301
|
+
continuity,
|
|
9302
|
+
hasQueuedSteering: () => queues.queuedMessages().steer.length > 0,
|
|
7700
9303
|
middlewareToolChoice,
|
|
7701
9304
|
persistence,
|
|
7702
9305
|
context,
|
|
@@ -7919,6 +9522,11 @@ function createChatLoop(deps) {
|
|
|
7919
9522
|
const images = options.images && options.images.length > 0 ? [...options.images] : void 0;
|
|
7920
9523
|
const pendingSkillRequests = state.currentTurnConstraints?.skills === "disabled" ? [] : options.pendingSkillRequests ?? [];
|
|
7921
9524
|
context.addWorkingContextPaths(options.workingContextPaths ?? []);
|
|
9525
|
+
context.prepareMemoryTurn(agentRuntime, {
|
|
9526
|
+
taskText: text,
|
|
9527
|
+
continuation: options.requestContinuation === true,
|
|
9528
|
+
images
|
|
9529
|
+
});
|
|
7922
9530
|
const pendingSkillPolicy = withModelSkillActivation(
|
|
7923
9531
|
createPendingSkillToolPolicy(pendingSkillRequests) ?? state.activeSkillSurface,
|
|
7924
9532
|
state.currentTurnConstraints?.skills !== "disabled" && modelMayActivateSkills(deps.getAutonomy?.() ?? deps.getSettings().safety.autonomy)
|
|
@@ -7933,7 +9541,7 @@ function createChatLoop(deps) {
|
|
|
7933
9541
|
const toolSignature = toolSignatureFromState(agentRuntime.agent.state.tools);
|
|
7934
9542
|
const askUserPolicy = createAskUserToolPolicy(agentRuntime.agent.state.tools);
|
|
7935
9543
|
middleware.fireTurnStart(agentRuntime, text, pendingSkillRequests.length, options.requestContinuation === true);
|
|
7936
|
-
const
|
|
9544
|
+
const reminderProjection = middleware.takePendingReminderProjection();
|
|
7937
9545
|
const skillPreamble = pendingSkillRequestPreamble(pendingSkillRequests);
|
|
7938
9546
|
let taskMemoryHandoffSource = "";
|
|
7939
9547
|
if (pendingSkillRequests.some((request) => request.name.trim() === "context-handoff")) {
|
|
@@ -7942,7 +9550,8 @@ function createChatLoop(deps) {
|
|
|
7942
9550
|
} catch {
|
|
7943
9551
|
}
|
|
7944
9552
|
}
|
|
7945
|
-
const
|
|
9553
|
+
const composeSubmittedText = () => [reminderProjection(), skillPreamble, taskMemoryHandoffSource, text].filter((part) => part.length > 0).join("\n\n");
|
|
9554
|
+
let submittedText = composeSubmittedText();
|
|
7946
9555
|
const forceNow = process.env.CLIO_CODER_FORCE_COMPACT === "1";
|
|
7947
9556
|
try {
|
|
7948
9557
|
setTurnPreparation("compacting");
|
|
@@ -7954,6 +9563,7 @@ function createChatLoop(deps) {
|
|
|
7954
9563
|
endPreparationCompaction();
|
|
7955
9564
|
}
|
|
7956
9565
|
const compiledPrompt = await context.ensureSessionPrompt(agentRuntime);
|
|
9566
|
+
submittedText = composeSubmittedText();
|
|
7957
9567
|
const compactionThreshold = deps.getSettings().context.compaction?.threshold ?? null;
|
|
7958
9568
|
const captureTurnSnapshot = (turnId) => context.captureRuntimeContextSnapshot(agentRuntime, turnId, compactionThreshold, {
|
|
7959
9569
|
promptSegments: compiledPrompt ? compiledPrompt.sections.map((s) => ({ id: s.id, tokenEstimate: s.tokenEstimate })) : void 0,
|
|
@@ -7962,52 +9572,24 @@ function createChatLoop(deps) {
|
|
|
7962
9572
|
promptHash: compiledPrompt?.systemPromptHash,
|
|
7963
9573
|
toolSignature
|
|
7964
9574
|
});
|
|
7965
|
-
const effectiveWindow = agentRuntime.runtimeResolution.contextWindowDetails.effectiveContextWindow;
|
|
7966
|
-
const outputForInput = (inputTokens) => resolveReservedOutputTokens(agentRuntime.runtimeResolution.capabilityDecisions.maxTokens, {
|
|
7967
|
-
api: agentRuntime.agent.state.model?.api ?? "",
|
|
7968
|
-
contextWindow: effectiveWindow,
|
|
7969
|
-
inputTokens
|
|
7970
|
-
});
|
|
7971
|
-
const pendingInputTokens = ceilChars(submittedText.length);
|
|
7972
9575
|
let turnSnapshot = captureTurnSnapshot("pending");
|
|
7973
|
-
|
|
7974
|
-
|
|
7975
|
-
context.liveContextEstimate(agentRuntime, submittedText).tokens
|
|
7976
|
-
);
|
|
7977
|
-
const inputEstimate = budgetedPromptTokens(turnSnapshot);
|
|
7978
|
-
const reservedOutput = outputForInput(inputEstimate);
|
|
7979
|
-
const totalEstimate = inputEstimate + reservedOutput;
|
|
7980
|
-
if (effectiveWindow > 0 && totalEstimate > effectiveWindow) {
|
|
7981
|
-
emitNotice(
|
|
7982
|
-
`[Clio Coder] Estimated request size ${totalEstimate} tokens (input ${totalEstimate - reservedOutput} + output budget ${reservedOutput}) exceeds the effective context window of ${effectiveWindow} tokens. Running compaction before sending...`
|
|
7983
|
-
);
|
|
9576
|
+
let admission = context.refreshLiveBudget(submittedText);
|
|
9577
|
+
if (!requestFits(admission.inputTokens, admission.outputReserveTokens, admission.effectiveWindow)) {
|
|
7984
9578
|
setTurnPreparation("compacting");
|
|
7985
|
-
let
|
|
7986
|
-
|
|
7987
|
-
|
|
7988
|
-
return false;
|
|
9579
|
+
let failure2;
|
|
9580
|
+
await context.runAutoCompact(agentRuntime, true, void 0, "overflow", submittedText, pendingSkillPolicy).catch((error) => {
|
|
9581
|
+
failure2 = error instanceof Error ? error.message : String(error);
|
|
7989
9582
|
}).finally(endPreparationCompaction);
|
|
7990
|
-
|
|
9583
|
+
submittedText = composeSubmittedText();
|
|
9584
|
+
admission = context.refreshLiveBudget(submittedText);
|
|
9585
|
+
if (!requestFits(admission.inputTokens, admission.outputReserveTokens, admission.effectiveWindow)) {
|
|
7991
9586
|
emitAdmissionNotice(
|
|
7992
|
-
`[Clio Coder] Request exceeds the context window
|
|
9587
|
+
`[Clio Coder] Request exceeds the available context window (input ${admission.inputTokens ?? "unknown"} + output ${admission.outputReserveTokens ?? "unknown"}, window ${admission.effectiveWindow ?? "unknown"}).${failure2 ? ` ${failure2}` : ""} Trim the prompt or reduce active tools.`,
|
|
7993
9588
|
"context-window-exceeded"
|
|
7994
9589
|
);
|
|
7995
9590
|
return;
|
|
7996
9591
|
}
|
|
7997
|
-
context.refreshAgentMessagesFromSession(agentRuntime);
|
|
7998
9592
|
turnSnapshot = captureTurnSnapshot("pending");
|
|
7999
|
-
const postInputEstimate = budgetedPromptTokens(turnSnapshot);
|
|
8000
|
-
const postTotalEstimate = postInputEstimate + outputForInput(postInputEstimate);
|
|
8001
|
-
if (postTotalEstimate > effectiveWindow) {
|
|
8002
|
-
emitAdmissionNotice(
|
|
8003
|
-
`[Clio Coder] Request still exceeds the effective window after compaction (${postTotalEstimate} > ${effectiveWindow}). Request blocked.`,
|
|
8004
|
-
"context-window-exceeded"
|
|
8005
|
-
);
|
|
8006
|
-
return;
|
|
8007
|
-
}
|
|
8008
|
-
emitNotice(
|
|
8009
|
-
`[Clio Coder] Context budget check passed post-compaction (${postTotalEstimate} <= ${effectiveWindow}). Proceeding.`
|
|
8010
|
-
);
|
|
8011
9593
|
}
|
|
8012
9594
|
const userTurnId = persistence.appendSubmittedUserTurn(
|
|
8013
9595
|
agentRuntime,
|
|
@@ -8017,6 +9599,8 @@ function createChatLoop(deps) {
|
|
|
8017
9599
|
text,
|
|
8018
9600
|
options.display?.text
|
|
8019
9601
|
);
|
|
9602
|
+
context.installMemoryRestoration(agentRuntime, submittedText);
|
|
9603
|
+
context.commitMemoryTurn(agentRuntime);
|
|
8020
9604
|
if (interrupted)
|
|
8021
9605
|
emit({
|
|
8022
9606
|
type: "queued_user_turn",
|
|
@@ -8164,6 +9748,7 @@ function createChatLoop(deps) {
|
|
|
8164
9748
|
}
|
|
8165
9749
|
},
|
|
8166
9750
|
cancel(options) {
|
|
9751
|
+
continuity.cancel();
|
|
8167
9752
|
const wasStreaming = state.streaming;
|
|
8168
9753
|
context.cancelCompaction();
|
|
8169
9754
|
recovery.cancelRetryCountdown();
|
|
@@ -8220,9 +9805,14 @@ function createChatLoop(deps) {
|
|
|
8220
9805
|
contextUsage: () => context.contextUsage(),
|
|
8221
9806
|
currentTurnConstraints: () => state.currentTurnConstraints,
|
|
8222
9807
|
contextLedger: () => context.contextLedger(),
|
|
9808
|
+
liveBudget: () => context.liveBudget(),
|
|
9809
|
+
inspectLiveBudget: () => context.inspectLiveBudget(),
|
|
9810
|
+
refreshLiveBudget: () => context.refreshLiveBudget(),
|
|
8223
9811
|
whenSettled: () => activeSubmit,
|
|
8224
9812
|
whenPrewarmSettled: () => prewarm.settled(),
|
|
8225
9813
|
resetForSession(leafTurnId, replayMessages) {
|
|
9814
|
+
continuity.cancel();
|
|
9815
|
+
void continuity.pause();
|
|
8226
9816
|
state.currentTurnConstraints = void 0;
|
|
8227
9817
|
if (state.runtime) {
|
|
8228
9818
|
state.runtime.agent.abort();
|
|
@@ -8235,7 +9825,7 @@ function createChatLoop(deps) {
|
|
|
8235
9825
|
middlewareToolChoice.reset();
|
|
8236
9826
|
state.lastTurnId = leafTurnId;
|
|
8237
9827
|
state.lastRunSnapshot = null;
|
|
8238
|
-
context.resetForSession();
|
|
9828
|
+
context.resetForSession(leafTurnId);
|
|
8239
9829
|
void turnRuntime.ensureLiveCapabilitiesForSelectedModel().catch(() => {
|
|
8240
9830
|
});
|
|
8241
9831
|
state.replayedContextMessages = replayMessages ? [...replayMessages] : [];
|
|
@@ -8327,6 +9917,26 @@ function createChatLoop(deps) {
|
|
|
8327
9917
|
recordOutOfTurnUsage(prepared.runtime, result.usage, "handoff");
|
|
8328
9918
|
return result.aborted ? { status: "aborted", text: result.text } : { status: "answered", text: result.text };
|
|
8329
9919
|
},
|
|
9920
|
+
requestSelfCompact: (note, toolCallId, signal) => continuity.request(note, toolCallId, signal),
|
|
9921
|
+
async recoverHandoff(handoffId, action) {
|
|
9922
|
+
if (state.streaming || state.turnPreparation !== "idle")
|
|
9923
|
+
throw new Error("Wait for the current turn to settle before recovery.");
|
|
9924
|
+
const runtime = turnRuntime.ensureRuntime();
|
|
9925
|
+
if (!runtime) throw new Error("No native runtime is configured.");
|
|
9926
|
+
state.activeInterruptReason = null;
|
|
9927
|
+
if (!state.activeUserTurnId) {
|
|
9928
|
+
const operator = [...filterEntriesToActivePath(deps.readSessionEntries?.() ?? [], state.lastTurnId ?? void 0)].reverse().find((entry) => entry.kind === "message" && entry.role === "user");
|
|
9929
|
+
state.activeUserTurnId = operator?.turnId ?? null;
|
|
9930
|
+
}
|
|
9931
|
+
state.streaming = true;
|
|
9932
|
+
try {
|
|
9933
|
+
await continuity.recover(handoffId, action);
|
|
9934
|
+
await continueEngineWithoutInput(runtime.agent);
|
|
9935
|
+
} finally {
|
|
9936
|
+
state.streaming = false;
|
|
9937
|
+
await continuity.pause();
|
|
9938
|
+
}
|
|
9939
|
+
},
|
|
8330
9940
|
async compact(instructions) {
|
|
8331
9941
|
if (!deps.session?.current()) {
|
|
8332
9942
|
emitNotice("[/context compact] no current session to compact; start one with /new or /resume first");
|
|
@@ -10001,7 +11611,7 @@ function createDispatchTool(inputDeps, surfaceOptions = {}) {
|
|
|
10001
11611
|
const admission = createDispatchAdmissionController(deps);
|
|
10002
11612
|
let runnerPromise = null;
|
|
10003
11613
|
const loadRunner = () => {
|
|
10004
|
-
runnerPromise ??= (surfaceOptions.loadRunner ?? (() => import("./dispatch-runner-
|
|
11614
|
+
runnerPromise ??= (surfaceOptions.loadRunner ?? (() => import("./dispatch-runner-VKVXVTWJ.js")))();
|
|
10005
11615
|
return runnerPromise;
|
|
10006
11616
|
};
|
|
10007
11617
|
return {
|
|
@@ -10038,6 +11648,32 @@ function createDispatchTool(inputDeps, surfaceOptions = {}) {
|
|
|
10038
11648
|
};
|
|
10039
11649
|
}
|
|
10040
11650
|
|
|
11651
|
+
// src/tools/self-compact.ts
|
|
11652
|
+
init_esm_shims();
|
|
11653
|
+
function createSelfCompactTool(request) {
|
|
11654
|
+
return {
|
|
11655
|
+
name: ToolNames.SelfCompact,
|
|
11656
|
+
description: "Save an exact handoff note and compact context before continuing this task. Call alone, with no sibling tools. Include current objective, decisions, evidence, paths, and next steps. A pending receipt is not proof of completion.",
|
|
11657
|
+
parameters: typebox_exports.Object({
|
|
11658
|
+
note_to_self: typebox_exports.String({
|
|
11659
|
+
maxLength: 8192,
|
|
11660
|
+
description: "Assistant-authored handoff text; nonblank, at most 8192 UTF-8 bytes. Preserved exactly."
|
|
11661
|
+
})
|
|
11662
|
+
}),
|
|
11663
|
+
baseActionClass: "read",
|
|
11664
|
+
executionMode: "sequential",
|
|
11665
|
+
async run(args, options) {
|
|
11666
|
+
try {
|
|
11667
|
+
const note = args.note_to_self;
|
|
11668
|
+
const output = await request(note, options?.toolCallId ?? "", options?.signal);
|
|
11669
|
+
return { kind: "ok", output };
|
|
11670
|
+
} catch (error) {
|
|
11671
|
+
return { kind: "error", message: error instanceof Error ? error.message : String(error) };
|
|
11672
|
+
}
|
|
11673
|
+
}
|
|
11674
|
+
};
|
|
11675
|
+
}
|
|
11676
|
+
|
|
10041
11677
|
// src/tools/bootstrap.ts
|
|
10042
11678
|
function registerAllTools(registry, deps = {}) {
|
|
10043
11679
|
const cwd = deps.session?.current()?.cwd ?? process.cwd();
|
|
@@ -10047,6 +11683,10 @@ function registerAllTools(registry, deps = {}) {
|
|
|
10047
11683
|
...coreDeps,
|
|
10048
11684
|
...mcpCapabilities ? { mcpCapabilities } : {}
|
|
10049
11685
|
});
|
|
11686
|
+
if (deps.requestSelfCompact)
|
|
11687
|
+
registry.register(
|
|
11688
|
+
builtin(createSelfCompactTool(deps.requestSelfCompact), { path: "src/tools/self-compact.ts", scope: "core" })
|
|
11689
|
+
);
|
|
10050
11690
|
if (deps.dispatch) {
|
|
10051
11691
|
const dispatch = deps.dispatch;
|
|
10052
11692
|
const dispatchRunEvents = createDispatchRunEventRegistry({ journal: null });
|
|
@@ -10076,7 +11716,7 @@ function registerAllTools(registry, deps = {}) {
|
|
|
10076
11716
|
...builtin(
|
|
10077
11717
|
lazyTool(
|
|
10078
11718
|
monitorToolSurface,
|
|
10079
|
-
async () => (await import("./monitor-
|
|
11719
|
+
async () => (await import("./monitor-2HD3MC67.js")).createMonitorTool({ dispatch, runEvents: dispatchRunEvents })
|
|
10080
11720
|
),
|
|
10081
11721
|
{
|
|
10082
11722
|
path: "src/tools/monitor.ts",
|
|
@@ -10086,7 +11726,7 @@ function registerAllTools(registry, deps = {}) {
|
|
|
10086
11726
|
});
|
|
10087
11727
|
registry.register({
|
|
10088
11728
|
...builtin(
|
|
10089
|
-
lazyTool(steerToolSurface, async () => (await import("./steer-
|
|
11729
|
+
lazyTool(steerToolSurface, async () => (await import("./steer-D7RTAPCM.js")).createSteerTool({ dispatch })),
|
|
10090
11730
|
{
|
|
10091
11731
|
path: "src/tools/steer.ts",
|
|
10092
11732
|
scope: "core"
|
|
@@ -10098,7 +11738,7 @@ function registerAllTools(registry, deps = {}) {
|
|
|
10098
11738
|
const panes = deps.panes;
|
|
10099
11739
|
registry.register({
|
|
10100
11740
|
...builtin(
|
|
10101
|
-
lazyTool(panesToolSurface, async () => (await import("./panes-
|
|
11741
|
+
lazyTool(panesToolSurface, async () => (await import("./panes-TTPPSYCL.js")).createPanesTool({ panes })),
|
|
10102
11742
|
{ path: "src/tools/panes.ts", scope: "core" }
|
|
10103
11743
|
)
|
|
10104
11744
|
});
|
|
@@ -10598,6 +12238,15 @@ async function runCompactionFlow(session, settings, providers, instructions, tri
|
|
|
10598
12238
|
const isOriginCurrent = () => session.current()?.id === meta.id && (session.tree(meta.id).leafId ?? void 0) === activeLeafTurnId;
|
|
10599
12239
|
const entries = filterEntriesToActivePath(readSessionEntriesForCompact(meta.id), activeLeafTurnId);
|
|
10600
12240
|
if (entries.length === 0) return null;
|
|
12241
|
+
const continuity = resolveContinuityProjection({
|
|
12242
|
+
entries,
|
|
12243
|
+
sessionId: meta.id,
|
|
12244
|
+
...meta.parentSessionId && meta.parentTurnId ? { fork: { parentSessionId: meta.parentSessionId, parentTurnId: meta.parentTurnId } } : {}
|
|
12245
|
+
});
|
|
12246
|
+
const continuityNote = {
|
|
12247
|
+
tokens: continuityProjectionTokens(continuity),
|
|
12248
|
+
anchorTurnId: continuity.noteAnchorTurnId
|
|
12249
|
+
};
|
|
10601
12250
|
budget?.signal?.throwIfAborted();
|
|
10602
12251
|
const systemPrompt = await readCompactionSystemPrompt(settings.context.compaction.systemPrompt, meta.cwd);
|
|
10603
12252
|
budget?.signal?.throwIfAborted();
|
|
@@ -10625,6 +12274,7 @@ async function runCompactionFlow(session, settings, providers, instructions, tri
|
|
|
10625
12274
|
try {
|
|
10626
12275
|
result = await compact({
|
|
10627
12276
|
entries,
|
|
12277
|
+
continuityNote,
|
|
10628
12278
|
...budget,
|
|
10629
12279
|
...summarize ? { summarize } : {},
|
|
10630
12280
|
onCall: (call) => calls.push(call),
|
|
@@ -10660,9 +12310,15 @@ async function runCompactionFlow(session, settings, providers, instructions, tri
|
|
|
10660
12310
|
if (result.usage) {
|
|
10661
12311
|
result.usage = { ...result.usage, targetId: resolved.targetId, modelId: resolved.wireModelId };
|
|
10662
12312
|
}
|
|
12313
|
+
const settledContinuity = resolveContinuityProjection({
|
|
12314
|
+
entries: filterEntriesToActivePath(readSessionEntriesForCompact(meta.id), activeLeafTurnId),
|
|
12315
|
+
sessionId: meta.id,
|
|
12316
|
+
...meta.parentSessionId && meta.parentTurnId ? { fork: { parentSessionId: meta.parentSessionId, parentTurnId: meta.parentTurnId } } : {}
|
|
12317
|
+
});
|
|
12318
|
+
const continuityCarry = settledContinuity.current === null ? null : continuityPayloadFromFold(settledContinuity.current);
|
|
10663
12319
|
const entry = {
|
|
10664
12320
|
kind: "compactionSummary",
|
|
10665
|
-
turnId:
|
|
12321
|
+
turnId: randomUUID3(),
|
|
10666
12322
|
parentTurnId: result.firstKeptTurnId ?? null,
|
|
10667
12323
|
summary: result.summary,
|
|
10668
12324
|
...result.skillContext ? { skillContext: result.skillContext } : {},
|
|
@@ -10671,12 +12327,23 @@ async function runCompactionFlow(session, settings, providers, instructions, tri
|
|
|
10671
12327
|
firstKeptTurnId: result.firstKeptTurnId ?? "",
|
|
10672
12328
|
messagesSummarized: result.messagesSummarized,
|
|
10673
12329
|
isSplitTurn: result.isSplitTurn,
|
|
10674
|
-
tokensAfter: estimateTokensAfterCompaction(entries, result),
|
|
12330
|
+
tokensAfter: estimateTokensAfterCompaction(entries, result, continuityNote.tokens),
|
|
12331
|
+
// The latest validated fold, carried so the transaction survives the cut
|
|
12332
|
+
// that is about to remove its earlier records from replay. It preserves
|
|
12333
|
+
// the immutable identity, accepted note, original policy and commit; it
|
|
12334
|
+
// never manufactures a commit and never turns an eviction-only outcome
|
|
12335
|
+
// into a summarized one. A later ordinary compaction with no handoff of
|
|
12336
|
+
// its own still carries the newest validated payload forward, which is
|
|
12337
|
+
// what keeps an eviction-only commit's state alive across summary cycles.
|
|
12338
|
+
...continuityCarry === null ? {} : { continuity: continuityCarry },
|
|
10675
12339
|
// The summarization call is a real model call. Persisting its provider
|
|
10676
|
-
// usage on the entry is what puts it in front of `/
|
|
12340
|
+
// usage on the entry is what puts it in front of `/usage` and `clio-coder usage
|
|
10677
12341
|
// report`, which folded the ledger and so counted every call but this one.
|
|
10678
12342
|
...result.usage !== void 0 ? { usage: result.usage } : {}
|
|
10679
12343
|
};
|
|
12344
|
+
if (budget?.checkpointForSummary) {
|
|
12345
|
+
entry.continuity = budget.checkpointForSummary(entry.turnId, entry.tokensBefore, entry.tokensAfter ?? 0);
|
|
12346
|
+
}
|
|
10680
12347
|
if (trigger !== void 0) entry.trigger = trigger;
|
|
10681
12348
|
try {
|
|
10682
12349
|
session.appendEntry(entry);
|
|
@@ -10724,11 +12391,11 @@ function estimateTokensFromSummary(result) {
|
|
|
10724
12391
|
...result.userContext ? { userContext: result.userContext } : {}
|
|
10725
12392
|
});
|
|
10726
12393
|
}
|
|
10727
|
-
function estimateTokensAfterCompaction(entries, result) {
|
|
12394
|
+
function estimateTokensAfterCompaction(entries, result, continuityNoteTokens = 0) {
|
|
10728
12395
|
let droppedTokens = 0;
|
|
10729
12396
|
for (const entry of entries.slice(0, result.firstKeptEntryIndex)) droppedTokens += estimateTokens(entry);
|
|
10730
12397
|
const summaryTokens = estimateTokensFromSummary(result);
|
|
10731
|
-
return Math.max(summaryTokens, result.tokensBefore - droppedTokens + summaryTokens);
|
|
12398
|
+
return Math.max(summaryTokens + continuityNoteTokens, result.tokensBefore - droppedTokens + summaryTokens);
|
|
10732
12399
|
}
|
|
10733
12400
|
function advanceScopedTarget(settings, direction) {
|
|
10734
12401
|
const scope = settings.chat.modelPicker.cycleSet ?? [];
|
|
@@ -11135,7 +12802,7 @@ async function bootOrchestrator(options = {}) {
|
|
|
11135
12802
|
// A headless run submits no further turn, so a detached step could only
|
|
11136
12803
|
// finish after the process that would have read it has exited.
|
|
11137
12804
|
deliversDeferredReminders: options.headless === void 0,
|
|
11138
|
-
onDeferredReminder: (message) => deferredMemoryReminderSink?.(message),
|
|
12805
|
+
onDeferredReminder: (message, isCurrent) => deferredMemoryReminderSink?.(message, isCurrent),
|
|
11139
12806
|
getSettings: () => {
|
|
11140
12807
|
const memory = effectiveSettingsForDispatch?.().context.memory ?? memorySettings;
|
|
11141
12808
|
return {
|
|
@@ -11315,6 +12982,8 @@ async function bootOrchestrator(options = {}) {
|
|
|
11315
12982
|
getCwd: () => process.cwd()
|
|
11316
12983
|
}) : null;
|
|
11317
12984
|
const toolBootstrap = registerAllTools(toolRegistry, {
|
|
12985
|
+
getContextBudget: () => chat.inspectLiveBudget(),
|
|
12986
|
+
requestSelfCompact: (note, toolCallId, signal) => chat.requestSelfCompact(note, toolCallId, signal),
|
|
11318
12987
|
getSettings: () => getCurrentSettings(),
|
|
11319
12988
|
termination,
|
|
11320
12989
|
captureWorkerContext: () => chat.captureWorkerContext?.() ?? null,
|
|
@@ -11589,21 +13258,7 @@ async function bootOrchestrator(options = {}) {
|
|
|
11589
13258
|
bus,
|
|
11590
13259
|
...prompts ? { prompts } : {},
|
|
11591
13260
|
...session ? { session } : {},
|
|
11592
|
-
getMemorySection: (
|
|
11593
|
-
try {
|
|
11594
|
-
const records = loadMemoryRecordsSync(clioDataDir());
|
|
11595
|
-
const settings = getCurrentSettings();
|
|
11596
|
-
const targetId = session?.current()?.target ?? settings.chat?.target;
|
|
11597
|
-
const runtimeId = targetId ? providers.getTarget(targetId)?.runtime : void 0;
|
|
11598
|
-
return buildMemoryPromptSection(records, {
|
|
11599
|
-
scopes: ["global", "repo", "runtime"],
|
|
11600
|
-
activeRepository: canonicalMemoryRepositoryIdentity(process.cwd()),
|
|
11601
|
-
activeRuntime: runtimeId === void 0 ? null : { kind: "runtime", key: runtimeId }
|
|
11602
|
-
}).section;
|
|
11603
|
-
} catch {
|
|
11604
|
-
return "";
|
|
11605
|
-
}
|
|
11606
|
-
},
|
|
13261
|
+
getMemorySection: createMemoryPromptReader({ getDataDir: clioDataDir }),
|
|
11607
13262
|
getTaskMemoryHandoffSource: () => {
|
|
11608
13263
|
const meta = session?.current();
|
|
11609
13264
|
if (!meta) throw new Error("task memory handoff requires an active session");
|
|
@@ -11617,6 +13272,7 @@ async function bootOrchestrator(options = {}) {
|
|
|
11617
13272
|
agentIds: []
|
|
11618
13273
|
});
|
|
11619
13274
|
},
|
|
13275
|
+
memoryCommitBridge: memoryIntervention,
|
|
11620
13276
|
registerDeferredReminderSink: (sink) => {
|
|
11621
13277
|
deferredMemoryReminderSink = sink;
|
|
11622
13278
|
},
|
|
@@ -11659,10 +13315,14 @@ async function bootOrchestrator(options = {}) {
|
|
|
11659
13315
|
try {
|
|
11660
13316
|
chat.resetForSession(
|
|
11661
13317
|
leafTurnId,
|
|
11662
|
-
buildModelReplayAgentMessagesFromTurns(
|
|
11663
|
-
|
|
11664
|
-
|
|
11665
|
-
|
|
13318
|
+
buildModelReplayAgentMessagesFromTurns(readCurrentSessionEntries(), {
|
|
13319
|
+
...leafTurnId ? { activeLeafTurnId: leafTurnId } : {},
|
|
13320
|
+
// The same ownership the interactive /resume overlay supplies.
|
|
13321
|
+
// Without it this reader owns nothing, the fold finds no
|
|
13322
|
+
// current origin, and a resumed session boots with its accepted
|
|
13323
|
+
// note silently missing from the provider context.
|
|
13324
|
+
continuity: continuityContextFromSession(session)
|
|
13325
|
+
})
|
|
11666
13326
|
);
|
|
11667
13327
|
} catch (err) {
|
|
11668
13328
|
chat.resetForSession(leafTurnId);
|
|
@@ -11700,7 +13360,14 @@ async function bootOrchestrator(options = {}) {
|
|
|
11700
13360
|
...session ? { session } : {},
|
|
11701
13361
|
...session ? {
|
|
11702
13362
|
readSessionEntries: readSessionEntriesForCompact,
|
|
11703
|
-
|
|
13363
|
+
// Ownership is read at call time, not captured: an ACP client
|
|
13364
|
+
// can switch sessions between turns, and a fork opened this way
|
|
13365
|
+
// must separate its own transactions from the ones it inherited
|
|
13366
|
+
// exactly as the interactive path does.
|
|
13367
|
+
buildReplayMessages: (entries, leafTurnId) => buildModelReplayAgentMessagesFromTurns(entries, {
|
|
13368
|
+
...leafTurnId === null ? {} : { activeLeafTurnId: leafTurnId },
|
|
13369
|
+
continuity: continuityContextFromSession(session)
|
|
13370
|
+
})
|
|
11704
13371
|
} : {},
|
|
11705
13372
|
providers,
|
|
11706
13373
|
// The fleet controls `clio-coder/dispatch/steer` reaches. The server
|
|
@@ -11737,7 +13404,7 @@ async function bootOrchestrator(options = {}) {
|
|
|
11737
13404
|
providers,
|
|
11738
13405
|
cwd: process.cwd(),
|
|
11739
13406
|
runDoctor: async ({ deep }) => {
|
|
11740
|
-
const { collectDoctorFindings, doctorNotice } = await import("./doctor-
|
|
13407
|
+
const { collectDoctorFindings, doctorNotice } = await import("./doctor-53AVQXAO.js");
|
|
11741
13408
|
return doctorNotice(
|
|
11742
13409
|
await collectDoctorFindings({
|
|
11743
13410
|
workspaceRoot: process.cwd(),
|
|
@@ -11886,7 +13553,7 @@ async function bootOrchestrator(options = {}) {
|
|
|
11886
13553
|
dashboardPlugins = activePluginIds();
|
|
11887
13554
|
});
|
|
11888
13555
|
termination.onTerminate(() => unsubscribeDashboardPlugins());
|
|
11889
|
-
const { startInteractive } = await import("./interactive-
|
|
13556
|
+
const { startInteractive } = await import("./interactive-JRCBENLZ.js");
|
|
11890
13557
|
await startInteractive({
|
|
11891
13558
|
getConnections: () => ({
|
|
11892
13559
|
mcp: toolBootstrap.mcpCapabilities?.connectedIds({ readyOnly: true }) ?? [],
|
|
@@ -12089,6 +13756,7 @@ async function bootOrchestrator(options = {}) {
|
|
|
12089
13756
|
);
|
|
12090
13757
|
}
|
|
12091
13758
|
},
|
|
13759
|
+
onRecoverHandoff: (handoffId, action) => chat.recoverHandoff(handoffId, action),
|
|
12092
13760
|
onCompact: async (instructions) => {
|
|
12093
13761
|
await chat.compact(instructions);
|
|
12094
13762
|
}
|
|
@@ -12114,4 +13782,4 @@ export {
|
|
|
12114
13782
|
createBackgroundMemoryRouting,
|
|
12115
13783
|
createProductionAutoCompact
|
|
12116
13784
|
};
|
|
12117
|
-
//# sourceMappingURL=orchestrator-
|
|
13785
|
+
//# sourceMappingURL=orchestrator-OUW3ZN6Y.js.map
|