chainlesschain 0.163.5 → 0.163.7
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/completions/_cc +1 -1
- package/completions/cc.bash +1 -1
- package/completions/cc.fish +1 -1
- package/completions/cc.ps1 +1 -1
- package/package.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-Cv2EE1Zy.js → AIOps-axqQfwv8.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CcpxMLuW.js → ActionButton-DV-Ro0By.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DE8mJoMI.js → Analytics-Bt72WEVu.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DKn9dk9L.js → AppLayout-BtepG55E.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-Cp3mG3Py.js → Artifacts-B7KaJ7S_.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-zvsQfF2C.js → Audit-FNFaUg7A.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-Bi85SsjN.js → BackgroundAgents-DFb6J2wQ.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-Cw47Dj6s.js → Backup-CC7YBhyj.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-C5Ip2afH.js → BaseInput-RkgTNVtj.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-C0iAFkJv.js → Chat-hHEmGZy-.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BV9Wv7wO.js → ChatBubbleRenderer-CAP9YhHv.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-3KZZCiAF.js → Checkbox-z5wXOQP1.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-C8OMbBAz.js → Codegen-DVaDJnxy.js} +1 -1
- package/src/assets/web-panel/assets/{Col-B-MB84LJ.js → Col-CJmaRDR5.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DpR7Dxao.js → Community-DF29_2bI.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CyDtz0OS.js → Compact-DtkQkBzn.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-5tiRa2An.js → Compliance-xoHDxp7I.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DnQaKZ5x.js → Cowork-BUm-R7ht.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-BaWfoEDf.js → Cron-Cgl14ZkB.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-Bu0HoHhb.js → Crosschain-BNcbmoqh.js} +1 -1
- package/src/assets/web-panel/assets/{DID-31zk8upX.js → DID-Bwja0Zo9.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-BmVne-e2.js → Dashboard-Bk5XjEdJ.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-B4PkoOWd.js → Dropdown-Ci36Oitq.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BZ6tyFtI.js → EmailListRenderer--U04ZN4q.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Osozn4Ds.js → FamilyGuardDashboard-B2gNPR2s.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DaH8TOAP.js → Federation-C4KghYn7.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-tbU0uwis.js → FormItemContext-QL7x_Q_0.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-Df8LQBrL.js → GenericCardRenderer-F3Ryltwm.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DsMB6-14.js → Git-2HassK5k.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BnH0dZzd.js → Governance-DoBIp7oe.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DhnN1N_P.js → Inference--W01QhZ-.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DnNshAgn.js → KnowledgeGraph-DmvwqGpT.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BmBFX3_N.js → Logs-BBJ4yAel.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-DCslfQU3.js → MarkdownRenderer-BLCZMzhJ.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-CPEgWDc3.js → Marketplace-D5lNngSI.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-C36qjgF9.js → McpTools-CkEVOMKH.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-tNHvrgqN.js → Memory-B1Ow1xVE.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Xaf6cKjc.js → MobileBridge-SgYbUfb6.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-D2E5TTeO.js → MobileProjects-BWdOvQAj.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-D4AJ2dwV.js → Mtc-DcTXSSma.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-Df-gtn2_.js → MtcAudit-Dt3WG4oj.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-DTCHLWld.js → Multisig-B9B38UZx.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-DruZ_1Jb.js → NLProgramming-B0S4GGvG.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Dx3pdGDs.js → Notes-DZ5U58Ng.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-Bi3L69oL.js → NotificationSettings-PjL5ZW34.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-BHY33m7C.js → OrderTableRenderer-DrAX2ESt.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BG2ZVEV-.js → Organization-Cv1GYs-c.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Viwtg4Mn.js → Overflow-Bbkp_PL3.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Clm_yc1Z.js → P2P-BD8QUgoZ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-NKmmDiOw.js → PdhVaultBrowser-BO-2PeaB.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-DIL8u9Nk.js → Permissions-D_OPVa02.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-B-jM4wt-.js → PersonalDataHub-mh-pEmaB.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-627I__H5.js → Pipeline-6JC2EDdb.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-2DN2qrkW.js → Privacy-CUshzUAG.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CN4wC0sF.js → ProjectInit-Cs2Aalri.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-K35vsh5H.js → ProjectSettings-1ak49tcj.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-B_wQadhX.js → Projects-BV4oApsm.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-MckaQUhQ.js → Providers-CXXxvafH.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BS3mtA_O.js → QrScannerModal-PTcDsF58.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BHp_nofL.js → QuickAsk-CDwucrJw.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DlmnPuZj.js → Recommend-CJlLVRXR.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-tsyFbvpy.js → RemoteSession-DlN-ETsO.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-Ba1iWv2D.js → Reputation-DI23LR6m.js} +1 -1
- package/src/assets/web-panel/assets/{Row-NnlGC--f.js → Row-Cl7UQMrM.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CjThSIRv.js → RssFeed-CexHNfh8.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CojUyC5x.js → Search-BneBWvRN.js} +1 -1
- package/src/assets/web-panel/assets/{Security-c-sxeJEc.js → Security-DX7Phgrp.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CtcKEEmF.js → Services-BWXO8Mte.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CIBBXflN.js → Skeleton-DCyOjKPJ.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-D1XOOK9n.js → Skills-CXqERsTB.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-hRfEp5Sn.js → Sla-bhbrbz8E.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Dexb1f_6.js → SpeechSettings-3IPU0HBZ.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BJsSFGYy.js → SyncSettings-DBNTQLbM.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CfSZ8A1L.js → Tasks-quP0bkN-.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-idDf47W-.js → Templates-BouWmgho.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-C-UsX6w6.js → Tenant-qv0D9s7z.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-BgJtX5n1.js → Terminal-BxvbE8BB.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DP0BLKTl.js → TimelineRenderer-D-IeLnJ2.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-LwCzqETp.js → Tokens-CFMKKyVG.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-D_9tVch0.js → Trigger-L8as3UuJ.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BH2UlEWh.js → Trust-MxmA4VZG.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CIpD0nYb.js → UkeySign-C0VvJYRi.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-9ShhYxK_.js → VideoEditing-Bf5QZj8N.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-C7afGNIG.js → Wallet-BIJ9riRz.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-bUKn6i5R.js → WebAuthn-B8p9Mhkw.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-CxgQaGyp.js → WorkflowEditor-BVsuaPen.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DMVkmJwx.js → chat-BfkjoKpV.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CDzQh5nS.js → colors-DeAlsWK8.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-C51kEF4D.js → compact-item-Cs97bz5j.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BTk9bXBn.js → createContext-BqbG60LH.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DPty0mGN.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CMje33rb.js → hasIn-i_RY0b1X.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpcrFxMI.js → index-0-agYlWL.js} +1 -1
- package/src/assets/web-panel/assets/{index-BW4F5YDF.js → index-79V_zv1s.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRG-aqOs.js → index-B-3tEpTc.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCRvG9lq.js → index-B-JVTrpr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DgivOKHA.js → index-B1CbOH1i.js} +1 -1
- package/src/assets/web-panel/assets/{index-BzCkNylB.js → index-B5UkyA3c.js} +1 -1
- package/src/assets/web-panel/assets/{index-x53Vf7la.js → index-BESLFt4q.js} +1 -1
- package/src/assets/web-panel/assets/{index-CCLj9hcD.js → index-BOVkf1K3.js} +1 -1
- package/src/assets/web-panel/assets/{index-CypsfcEq.js → index-BYUVuwKt.js} +1 -1
- package/src/assets/web-panel/assets/{index-BtlEqHLP.js → index-BcUXAB2s.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ld_4mFmC.js → index-BkBi5TmC.js} +1 -1
- package/src/assets/web-panel/assets/{index-DqU9njjT.js → index-Bm7lLR4c.js} +1 -1
- package/src/assets/web-panel/assets/index-Bt7g0Vq_.js +1 -0
- package/src/assets/web-panel/assets/{index-CwGPwjUu.js → index-BuLQobzW.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5IWTMVl.js → index-CE2VtTlp.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJfnCuMq.js → index-CED2PL_y.js} +1 -1
- package/src/assets/web-panel/assets/{index-hg_emBsi.js → index-CG3PRyAL.js} +1 -1
- package/src/assets/web-panel/assets/{index-togc_uYn.js → index-CIG8fQ2_.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4rQCS8T.js → index-COdGA-8n.js} +1 -1
- package/src/assets/web-panel/assets/{index-0Auljb10.js → index-CeWoNHau.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cd0hmPxD.js → index-Cf3WCLmy.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXQBPLyE.js → index-CgsqdnRV.js} +1 -1
- package/src/assets/web-panel/assets/index-ChVT0p9u.js +1 -0
- package/src/assets/web-panel/assets/{index-h31MwrME.js → index-D2B4VPyP.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1oZReaY.js → index-D9evtvg2.js} +1 -1
- package/src/assets/web-panel/assets/{index-CfC-piWZ.js → index-DUUrv141.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9rC-fGW.js → index-DiSkx4UB.js} +3 -3
- package/src/assets/web-panel/assets/{index-CvSeVzqe.js → index-Dk2qouAz.js} +1 -1
- package/src/assets/web-panel/assets/{index-CtM8OT_7.js → index-Dk7-v4hP.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBz9LIMS.js → index-DmbfhJUP.js} +1 -1
- package/src/assets/web-panel/assets/{index-BAfY7m7i.js → index-DqBgBpgp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BVePe_Rf.js → index-PT_5sBMA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDLkNkLj.js → index-U4f5izHz.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTlsE8Df.js → index-YXgLng0K.js} +1 -1
- package/src/assets/web-panel/assets/{index-BeEaAEIp.js → index-ZxO_-E8a.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0-zMtKA.js → index-dIHr4B_u.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1oZQmAA.js → index-gyFpvL7l.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRLQyp2A.js → index-s1opAL-M.js} +1 -1
- package/src/assets/web-panel/assets/{index-OS-vfbTA.js → index-yObj1O4n.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-vrA8K-ac.js → initDefaultProps-C9h9yKL3.js} +1 -1
- package/src/assets/web-panel/assets/{motion-ByEzwIAl.js → motion-BvmLsPdu.js} +1 -1
- package/src/assets/web-panel/assets/{move-Ck4AWjw-.js → move-CoL4ekU1.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-6p0l9SrB.js → mtc-parser-C4pMy6xV.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B1CUPQ6R.js → omit-DPuJfNxx.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-B1STg1iW.js → pickAttrs-D0KEeaK2.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DTTllkBV.js → placementArrow-BpkyINxt.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-AIrrCfBb.js → responsiveObserve-DQI_wOq8.js} +1 -1
- package/src/assets/web-panel/assets/{slide-C_fPMjdR.js → slide-DYfdDiRg.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-D5ow2yIP.js → statusUtils-B5dtvb0D.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Dy3hEA--.js → styleChecker-CF310mSj.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-WfzcfSh4.js → useFlexGapSupport-D1Qp4BLp.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CKSejfas.js → useFs-C7_iyvJK.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-od3zpPBN.js → usePersonalDataHub-DZUt_fIm.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DRD_2DFA.js → vnode-D3dsi0lZ.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DmNrEtgf.js → zoom-WdbOlvdQ.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +5 -5
- package/src/command-manifest.json +1 -1
- package/src/commands/agenda.js +76 -4
- package/src/commands/agent.js +90 -1
- package/src/commands/automation.js +462 -3
- package/src/commands/background-session.js +102 -1
- package/src/commands/chat.js +11 -2
- package/src/commands/compact.js +106 -23
- package/src/commands/cowork.js +6 -1
- package/src/commands/loop.js +187 -38
- package/src/commands/routine.js +12 -5
- package/src/commands/scheduler-daemon.js +807 -0
- package/src/commands/session-observability.js +305 -0
- package/src/commands/session.js +38 -0
- package/src/data/changelog.json +28 -2
- package/src/gateways/ws/ws-agent-handler.js +439 -5
- package/src/harness/jsonl-session-store.js +463 -125
- package/src/harness/prompt-compressor.js +86 -13
- package/src/harness/provider-backed-compaction.js +100 -27
- package/src/lib/advisor-runtime.js +3 -1
- package/src/lib/agent-schedule-store.js +737 -47
- package/src/lib/agent-team/team-adjudication.js +40 -1
- package/src/lib/automation-center-routines.js +363 -0
- package/src/lib/automation-center.js +435 -0
- package/src/lib/automation-engine.js +568 -19
- package/src/lib/automation-execution-authority.js +736 -0
- package/src/lib/background-agent-supervisor.js +871 -215
- package/src/lib/background-command-argv.js +24 -0
- package/src/lib/background-interaction-journal.js +361 -52
- package/src/lib/background-interaction-resolver.js +32 -0
- package/src/lib/background-launch-profile.js +2 -0
- package/src/lib/background-needs-input-incident.js +221 -0
- package/src/lib/causal-observability.js +2661 -0
- package/src/lib/chat-session-admission.js +76 -0
- package/src/lib/cost-budget.js +5 -7
- package/src/lib/cowork/ab-comparator-cli.js +11 -0
- package/src/lib/cowork/debate-review-cli.js +12 -0
- package/src/lib/cowork-adapter.js +159 -38
- package/src/lib/cowork-cron.js +673 -19
- package/src/lib/cowork-observe.js +5 -1
- package/src/lib/cowork-task-runner.js +112 -17
- package/src/lib/delivery-coordinator.js +142 -0
- package/src/lib/direct-model-usage.js +121 -0
- package/src/lib/file-lines.js +183 -47
- package/src/lib/llm-pricing.js +12 -17
- package/src/lib/loop.js +62 -3
- package/src/lib/permission-engine.js +14 -7
- package/src/lib/public-ide-capability-manifest.js +2 -0
- package/src/lib/routine-store.js +546 -86
- package/src/lib/runtime-usage-ledger.js +182 -0
- package/src/lib/scheduler-kernel/agenda-adapter.js +604 -29
- package/src/lib/scheduler-kernel/authority-resolver.js +163 -0
- package/src/lib/scheduler-kernel/automation-adapter.js +994 -0
- package/src/lib/scheduler-kernel/automation-event-adapter.js +757 -0
- package/src/lib/scheduler-kernel/contract.js +11 -3
- package/src/lib/scheduler-kernel/cowork-cron-adapter.js +343 -15
- package/src/lib/scheduler-kernel/loop-adapter.js +913 -0
- package/src/lib/scheduler-kernel/migration-admin.js +346 -0
- package/src/lib/scheduler-kernel/migration-rollback-admin.js +932 -0
- package/src/lib/scheduler-kernel/routine-adapter.js +691 -22
- package/src/lib/scheduler-kernel/runtime.js +63 -1
- package/src/lib/scheduler-kernel/service.js +328 -0
- package/src/lib/scheduler-kernel/source-locator-path.js +142 -0
- package/src/lib/scheduler-kernel/store.js +3439 -206
- package/src/lib/session-host-lease.js +171 -2
- package/src/lib/session-host-snapshot.js +14 -3
- package/src/lib/session-persistence-failure.js +1 -0
- package/src/lib/session-tail.js +179 -34
- package/src/lib/session-transcript-structure.js +96 -0
- package/src/lib/sub-agent-context.js +328 -22
- package/src/lib/ws-agent-handler.js +4 -1
- package/src/repl/agent-repl.js +732 -91
- package/src/repl/chat-repl.js +5 -1
- package/src/runtime/agent-core.js +1274 -208
- package/src/runtime/coding-agent-contract-shared.cjs +5 -0
- package/src/runtime/fallback-model.js +5 -0
- package/src/runtime/headless-runner.js +324 -82
- package/src/runtime/headless-stream.js +232 -26
- package/src/runtime/policies/agent-policy.js +4 -0
- package/src/workers/background-agent-worker.js +468 -98
- package/src/assets/web-panel/assets/devWarning-CdwPwYj8.js +0 -1
- package/src/assets/web-panel/assets/index-BEeOdfEe.js +0 -1
- package/src/assets/web-panel/assets/index-BTe0TOu6.js +0 -1
package/src/repl/agent-repl.js
CHANGED
|
@@ -59,6 +59,14 @@ import {
|
|
|
59
59
|
forkSession,
|
|
60
60
|
} from "../harness/jsonl-session-store.js";
|
|
61
61
|
import { classifyStreamRetryReason } from "../lib/stream-retry.js";
|
|
62
|
+
import {
|
|
63
|
+
markRuntimeLedgerPersistenceError,
|
|
64
|
+
projectRuntimeTokenUsage,
|
|
65
|
+
projectRuntimeUsageBoundary,
|
|
66
|
+
runtimeUsageEventType,
|
|
67
|
+
runtimeToolCallId,
|
|
68
|
+
} from "../lib/runtime-usage-ledger.js";
|
|
69
|
+
import { runMeteredDirectModelCall } from "../lib/direct-model-usage.js";
|
|
62
70
|
import {
|
|
63
71
|
createSessionMcpLedgerSink,
|
|
64
72
|
formatMcpLedgerRecoveryNotice,
|
|
@@ -180,6 +188,219 @@ import {
|
|
|
180
188
|
nextTier,
|
|
181
189
|
} from "./permission-tier.js";
|
|
182
190
|
|
|
191
|
+
export const REPL_RUNTIME_LEDGER_PERSISTENCE_FAILURE_MESSAGE =
|
|
192
|
+
"CC_RUNTIME_USAGE_LEDGER_FAILED: runtime usage telemetry was not durably persisted; restart this session";
|
|
193
|
+
|
|
194
|
+
/** One fail-closed latch is created for each REPL process/session host. */
|
|
195
|
+
export function createReplRuntimeLedgerTerminalLatch(options = {}) {
|
|
196
|
+
const onTrip = typeof options.onTrip === "function" ? options.onTrip : null;
|
|
197
|
+
let terminalError = null;
|
|
198
|
+
return Object.freeze({
|
|
199
|
+
trip(error) {
|
|
200
|
+
if (terminalError) return terminalError;
|
|
201
|
+
if (error?.runtimeLedgerPersistence !== true) return null;
|
|
202
|
+
terminalError = new Error(
|
|
203
|
+
REPL_RUNTIME_LEDGER_PERSISTENCE_FAILURE_MESSAGE,
|
|
204
|
+
{ cause: error },
|
|
205
|
+
);
|
|
206
|
+
terminalError.code = "CC_RUNTIME_USAGE_LEDGER_FAILED";
|
|
207
|
+
terminalError.runtimeLedgerPersistence = true;
|
|
208
|
+
try {
|
|
209
|
+
onTrip?.(terminalError);
|
|
210
|
+
} catch {
|
|
211
|
+
// Terminal state must survive a best-effort host notification failure.
|
|
212
|
+
}
|
|
213
|
+
return terminalError;
|
|
214
|
+
},
|
|
215
|
+
assertOpen() {
|
|
216
|
+
if (terminalError) throw terminalError;
|
|
217
|
+
},
|
|
218
|
+
isTripped() {
|
|
219
|
+
return terminalError !== null;
|
|
220
|
+
},
|
|
221
|
+
error() {
|
|
222
|
+
return terminalError;
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Persisted sessions may only use the deterministic local suggestion engine. */
|
|
228
|
+
export function resolveReplPromptSuggestionGenerator(useJsonl, generator) {
|
|
229
|
+
return useJsonl ? undefined : generator;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function resolveReplMeteredSessionId(useJsonl, sessionId) {
|
|
233
|
+
return useJsonl && sessionId ? sessionId : null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function attachReplCompactionLedgerMetadata(error, callId, settled) {
|
|
237
|
+
let target = error;
|
|
238
|
+
if (!target || (typeof target !== "object" && typeof target !== "function")) {
|
|
239
|
+
target = new Error("semantic compaction provider call failed", {
|
|
240
|
+
cause: error,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
Object.defineProperties(target, {
|
|
245
|
+
compactionCallId: {
|
|
246
|
+
configurable: true,
|
|
247
|
+
value: callId || undefined,
|
|
248
|
+
},
|
|
249
|
+
usageLedgerSettled: {
|
|
250
|
+
configurable: true,
|
|
251
|
+
value: settled === true,
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
return target;
|
|
255
|
+
} catch {
|
|
256
|
+
const wrapped = new Error("semantic compaction provider call failed", {
|
|
257
|
+
cause: error,
|
|
258
|
+
});
|
|
259
|
+
Object.defineProperties(wrapped, {
|
|
260
|
+
compactionCallId: {
|
|
261
|
+
configurable: true,
|
|
262
|
+
value: callId || undefined,
|
|
263
|
+
},
|
|
264
|
+
usageLedgerSettled: {
|
|
265
|
+
configurable: true,
|
|
266
|
+
value: settled === true,
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
return wrapped;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function asReplRuntimeLedgerPersistenceError(error, message) {
|
|
274
|
+
if (error && (typeof error === "object" || typeof error === "function")) {
|
|
275
|
+
try {
|
|
276
|
+
const marked = markRuntimeLedgerPersistenceError(error);
|
|
277
|
+
if (marked?.runtimeLedgerPersistence === true) return marked;
|
|
278
|
+
} catch {
|
|
279
|
+
// Frozen/non-extensible errors are wrapped below.
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const wrapped = new Error(message, { cause: error });
|
|
283
|
+
return markRuntimeLedgerPersistenceError(wrapped);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** Meter one direct REPL call and expose only secret-free ledger metadata. */
|
|
287
|
+
export async function runReplMeteredModelCallWithLedger({
|
|
288
|
+
sessionId,
|
|
289
|
+
persist,
|
|
290
|
+
provider,
|
|
291
|
+
model,
|
|
292
|
+
source = "model",
|
|
293
|
+
call,
|
|
294
|
+
attachErrorMetadata = false,
|
|
295
|
+
}) {
|
|
296
|
+
let callId = null;
|
|
297
|
+
let usageLedgerSettled = false;
|
|
298
|
+
try {
|
|
299
|
+
const result = await runMeteredDirectModelCall({
|
|
300
|
+
sessionId,
|
|
301
|
+
persist: sessionId
|
|
302
|
+
? async (type, data) => {
|
|
303
|
+
await persist(type, data);
|
|
304
|
+
if (type === "model_usage_started") callId = data.callId;
|
|
305
|
+
else usageLedgerSettled = true;
|
|
306
|
+
}
|
|
307
|
+
: null,
|
|
308
|
+
provider,
|
|
309
|
+
model,
|
|
310
|
+
source,
|
|
311
|
+
call,
|
|
312
|
+
});
|
|
313
|
+
return Object.freeze({ result, callId, usageLedgerSettled });
|
|
314
|
+
} catch (error) {
|
|
315
|
+
if (attachErrorMetadata) {
|
|
316
|
+
throw attachReplCompactionLedgerMetadata(
|
|
317
|
+
error,
|
|
318
|
+
callId,
|
|
319
|
+
usageLedgerSettled,
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
throw error;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Execute a REPL-owned direct tool surface behind the same durable call ledger
|
|
328
|
+
* used by the main agent loop. `/auto` and `/plan execute` do not yield
|
|
329
|
+
* `tool-executing` / `tool-result` events, so their host must bracket the real
|
|
330
|
+
* execution here instead of relying on the loop wrapper.
|
|
331
|
+
*/
|
|
332
|
+
export async function runReplDirectToolWithLedger({
|
|
333
|
+
sessionId = null,
|
|
334
|
+
tool,
|
|
335
|
+
args,
|
|
336
|
+
execute,
|
|
337
|
+
persistStarted = appendEvent,
|
|
338
|
+
persistSettlement = appendToolCallCompact,
|
|
339
|
+
now = Date.now,
|
|
340
|
+
callId,
|
|
341
|
+
terminalLatch = null,
|
|
342
|
+
}) {
|
|
343
|
+
if (typeof execute !== "function") {
|
|
344
|
+
throw new TypeError("direct REPL tool execution requires an executor");
|
|
345
|
+
}
|
|
346
|
+
terminalLatch?.assertOpen();
|
|
347
|
+
const id = runtimeToolCallId(callId);
|
|
348
|
+
if (sessionId) {
|
|
349
|
+
try {
|
|
350
|
+
await persistStarted(sessionId, "tool_call_started", { id, tool });
|
|
351
|
+
} catch (error) {
|
|
352
|
+
const persistenceError = asReplRuntimeLedgerPersistenceError(
|
|
353
|
+
error,
|
|
354
|
+
"direct REPL tool start was not durable",
|
|
355
|
+
);
|
|
356
|
+
throw terminalLatch?.trip(persistenceError) || persistenceError;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const startedAt = now();
|
|
361
|
+
let result;
|
|
362
|
+
let executionError;
|
|
363
|
+
let executionFailed = false;
|
|
364
|
+
try {
|
|
365
|
+
result = await execute(tool, args);
|
|
366
|
+
} catch (error) {
|
|
367
|
+
executionFailed = true;
|
|
368
|
+
executionError = error;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const observedDuration = result?.toolTelemetryRecord?.durationMs;
|
|
372
|
+
const durationMs =
|
|
373
|
+
observedDuration ?? Math.max(0, Number(now()) - Number(startedAt));
|
|
374
|
+
if (sessionId) {
|
|
375
|
+
try {
|
|
376
|
+
await persistSettlement(sessionId, {
|
|
377
|
+
id,
|
|
378
|
+
tool,
|
|
379
|
+
isError: Boolean(
|
|
380
|
+
executionFailed ||
|
|
381
|
+
result?.error ||
|
|
382
|
+
result?.is_error ||
|
|
383
|
+
result?.isError,
|
|
384
|
+
),
|
|
385
|
+
skill: tool === "run_skill" ? args?.skill_name : undefined,
|
|
386
|
+
...extractPluginUsageAttribution(result),
|
|
387
|
+
durationMs,
|
|
388
|
+
});
|
|
389
|
+
} catch (error) {
|
|
390
|
+
const persistenceError = asReplRuntimeLedgerPersistenceError(
|
|
391
|
+
error,
|
|
392
|
+
"direct REPL tool settlement was not durable",
|
|
393
|
+
);
|
|
394
|
+
throw terminalLatch?.trip(persistenceError) || persistenceError;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (executionFailed) {
|
|
399
|
+
throw terminalLatch?.trip(executionError) || executionError;
|
|
400
|
+
}
|
|
401
|
+
return result;
|
|
402
|
+
}
|
|
403
|
+
|
|
183
404
|
/**
|
|
184
405
|
* Reference to the runtime DB for hook execution (set during startAgentRepl)
|
|
185
406
|
*/
|
|
@@ -342,6 +563,17 @@ export async function agentLoop(messages, options) {
|
|
|
342
563
|
const writeOut =
|
|
343
564
|
options.writeOut || ((text) => process.stdout.write(String(text)));
|
|
344
565
|
const waitForOutput = options.waitForOutput;
|
|
566
|
+
const persistBoundary = options._appendUsageBoundary || appendEvent;
|
|
567
|
+
const persistTokenUsage = options._appendTokenUsage || appendTokenUsage;
|
|
568
|
+
const persistToolCall =
|
|
569
|
+
options._appendToolCallCompact || appendToolCallCompact;
|
|
570
|
+
const persistRuntimeLedger = (action) => {
|
|
571
|
+
try {
|
|
572
|
+
return action();
|
|
573
|
+
} catch (error) {
|
|
574
|
+
throw markRuntimeLedgerPersistenceError(error);
|
|
575
|
+
}
|
|
576
|
+
};
|
|
345
577
|
// Resume-degenerate role merge (Claude Code 2.1.187 parity), gated by the
|
|
346
578
|
// one-shot `mergeRoles` flag so it fires only on the first model call after
|
|
347
579
|
// resuming a session whose prior run produced no assistant response. Collapse
|
|
@@ -370,9 +602,95 @@ export async function agentLoop(messages, options) {
|
|
|
370
602
|
// `_coreLoop` is an injectable seam (defaults to agent-core's loop) so the
|
|
371
603
|
// wrapper's event translation can be unit-tested without a live model.
|
|
372
604
|
const runCoreLoop = options._coreLoop || coreAgentLoop;
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
605
|
+
const onUsageBoundary =
|
|
606
|
+
options.onUsageBoundary ||
|
|
607
|
+
(options.persistUsageTelemetry === true && options.sessionId
|
|
608
|
+
? (event) => {
|
|
609
|
+
persistRuntimeLedger(() =>
|
|
610
|
+
persistBoundary(
|
|
611
|
+
options.sessionId,
|
|
612
|
+
runtimeUsageEventType("started"),
|
|
613
|
+
projectRuntimeUsageBoundary(event, "started"),
|
|
614
|
+
),
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
: undefined);
|
|
618
|
+
const onUsageSettlement =
|
|
619
|
+
options.onUsageSettlement ||
|
|
620
|
+
(options.persistUsageTelemetry === true && options.sessionId
|
|
621
|
+
? (event) => {
|
|
622
|
+
if (event?.type === "token-usage") {
|
|
623
|
+
persistRuntimeLedger(() =>
|
|
624
|
+
persistTokenUsage(
|
|
625
|
+
options.sessionId,
|
|
626
|
+
projectRuntimeTokenUsage(event),
|
|
627
|
+
),
|
|
628
|
+
);
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
persistRuntimeLedger(() =>
|
|
632
|
+
persistBoundary(
|
|
633
|
+
options.sessionId,
|
|
634
|
+
runtimeUsageEventType("unknown"),
|
|
635
|
+
projectRuntimeUsageBoundary(
|
|
636
|
+
event?.type === "compaction-usage-unknown"
|
|
637
|
+
? {
|
|
638
|
+
...event,
|
|
639
|
+
code: event.code || "provider_transport_outcome_unknown",
|
|
640
|
+
}
|
|
641
|
+
: event,
|
|
642
|
+
"unknown",
|
|
643
|
+
),
|
|
644
|
+
),
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
: undefined);
|
|
648
|
+
const childToolExecs = new Map();
|
|
649
|
+
const onToolCallBoundary =
|
|
650
|
+
options.onToolCallBoundary ||
|
|
651
|
+
(options.persistUsageTelemetry === true && options.sessionId
|
|
652
|
+
? (event) => {
|
|
653
|
+
const id = runtimeToolCallId(event?.tool_use_id);
|
|
654
|
+
childToolExecs.set(id, {
|
|
655
|
+
tool: event?.tool || "?",
|
|
656
|
+
startedAt: options.now ? options.now() : Date.now(),
|
|
657
|
+
});
|
|
658
|
+
persistRuntimeLedger(() =>
|
|
659
|
+
persistBoundary(options.sessionId, "tool_call_started", {
|
|
660
|
+
id,
|
|
661
|
+
tool: event?.tool || "?",
|
|
662
|
+
}),
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
: undefined);
|
|
666
|
+
const onToolCallSettlement =
|
|
667
|
+
options.onToolCallSettlement ||
|
|
668
|
+
(options.persistUsageTelemetry === true && options.sessionId
|
|
669
|
+
? (event) => {
|
|
670
|
+
const id = runtimeToolCallId(event?.tool_use_id);
|
|
671
|
+
const started = childToolExecs.get(id);
|
|
672
|
+
childToolExecs.delete(id);
|
|
673
|
+
persistRuntimeLedger(() =>
|
|
674
|
+
persistToolCall(options.sessionId, {
|
|
675
|
+
id,
|
|
676
|
+
tool: event?.tool || started?.tool || "?",
|
|
677
|
+
isError: Boolean(event?.error || event?.result?.error),
|
|
678
|
+
skill: event?.attribution?.skill,
|
|
679
|
+
durationMs: started
|
|
680
|
+
? Math.max(
|
|
681
|
+
0,
|
|
682
|
+
(options.now ? options.now() : Date.now()) -
|
|
683
|
+
started.startedAt,
|
|
684
|
+
)
|
|
685
|
+
: undefined,
|
|
686
|
+
}),
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
: undefined);
|
|
690
|
+
// Tool results carry a stable provider id. Keep every in-flight call keyed by
|
|
691
|
+
// that id because read-only batches may expose all starts before any result.
|
|
692
|
+
const _activeExecs = new Map();
|
|
693
|
+
const _unsettledExecs = [];
|
|
376
694
|
// The core loop runs tools serially. A classified non-MCP side effect stays
|
|
377
695
|
// live from its yielded `tool-executing` boundary until the matching result.
|
|
378
696
|
let _currentSideEffectOpId = null;
|
|
@@ -383,6 +701,10 @@ export async function agentLoop(messages, options) {
|
|
|
383
701
|
// too would trim the same history twice. Placed AFTER the spread so a
|
|
384
702
|
// caller's options.autoCompact can never silently re-enable the double pass.
|
|
385
703
|
autoCompact: false,
|
|
704
|
+
onUsageBoundary,
|
|
705
|
+
onUsageSettlement,
|
|
706
|
+
onToolCallBoundary,
|
|
707
|
+
onToolCallSettlement,
|
|
386
708
|
onProviderFallback,
|
|
387
709
|
})) {
|
|
388
710
|
// P1 explicit turn→checkpoint binding — the REPL as PRODUCER: fold every
|
|
@@ -419,11 +741,23 @@ export async function agentLoop(messages, options) {
|
|
|
419
741
|
chalk.gray(` ⎌ checkpoint ${event.id} (before ${event.tool})\n`),
|
|
420
742
|
);
|
|
421
743
|
} else if (event.type === "tool-executing") {
|
|
422
|
-
|
|
744
|
+
const exec = {
|
|
745
|
+
id: runtimeToolCallId(event.tool_use_id),
|
|
746
|
+
providerId: event.tool_use_id || null,
|
|
423
747
|
tool: event.tool,
|
|
424
748
|
args: event.args,
|
|
425
749
|
startedAt: options.now ? options.now() : Date.now(),
|
|
426
750
|
};
|
|
751
|
+
_unsettledExecs.push(exec);
|
|
752
|
+
if (exec.providerId) _activeExecs.set(exec.providerId, exec);
|
|
753
|
+
if (options.persistUsageTelemetry === true && options.sessionId) {
|
|
754
|
+
persistRuntimeLedger(() =>
|
|
755
|
+
persistBoundary(options.sessionId, "tool_call_started", {
|
|
756
|
+
id: exec.id,
|
|
757
|
+
tool: event.tool,
|
|
758
|
+
}),
|
|
759
|
+
);
|
|
760
|
+
}
|
|
427
761
|
_currentSideEffectOpId = null;
|
|
428
762
|
if (options.sideEffects) {
|
|
429
763
|
const sideEffect = classifyToolSideEffect(event.tool, event.args);
|
|
@@ -455,6 +789,20 @@ export async function agentLoop(messages, options) {
|
|
|
455
789
|
),
|
|
456
790
|
);
|
|
457
791
|
} else if (event.type === "tool-result") {
|
|
792
|
+
const exec =
|
|
793
|
+
(event.tool_use_id ? _activeExecs.get(event.tool_use_id) : null) ||
|
|
794
|
+
_unsettledExecs.find(
|
|
795
|
+
(candidate) =>
|
|
796
|
+
!candidate.settled &&
|
|
797
|
+
(!event.tool || candidate.tool === event.tool),
|
|
798
|
+
) ||
|
|
799
|
+
null;
|
|
800
|
+
if (exec) {
|
|
801
|
+
exec.settled = true;
|
|
802
|
+
if (exec.providerId) _activeExecs.delete(exec.providerId);
|
|
803
|
+
const activeIndex = _unsettledExecs.indexOf(exec);
|
|
804
|
+
if (activeIndex >= 0) _unsettledExecs.splice(activeIndex, 1);
|
|
805
|
+
}
|
|
458
806
|
if (options.sideEffects && _currentSideEffectOpId) {
|
|
459
807
|
const sideEffectError = event.error || event.result?.error || null;
|
|
460
808
|
if (event.permission_decision) {
|
|
@@ -475,10 +823,10 @@ export async function agentLoop(messages, options) {
|
|
|
475
823
|
}
|
|
476
824
|
const durationMs =
|
|
477
825
|
event.result?.toolTelemetryRecord?.durationMs ??
|
|
478
|
-
(
|
|
826
|
+
(exec?.tool === event.tool
|
|
479
827
|
? Math.max(
|
|
480
828
|
0,
|
|
481
|
-
(options.now ? options.now() : Date.now()) -
|
|
829
|
+
(options.now ? options.now() : Date.now()) - exec.startedAt,
|
|
482
830
|
)
|
|
483
831
|
: undefined);
|
|
484
832
|
// 用量归因: persist a compact tool_call record (name + error flag +
|
|
@@ -488,18 +836,22 @@ export async function agentLoop(messages, options) {
|
|
|
488
836
|
// options.persistToolCalls === false.
|
|
489
837
|
if (options.sessionId && options.persistToolCalls !== false) {
|
|
490
838
|
try {
|
|
491
|
-
|
|
839
|
+
persistToolCall(options.sessionId, {
|
|
840
|
+
id: exec?.id,
|
|
492
841
|
tool: event.tool,
|
|
493
842
|
isError: Boolean(event.error || event.result?.error),
|
|
494
843
|
skill:
|
|
495
|
-
event.tool === "run_skill" &&
|
|
496
|
-
?
|
|
844
|
+
event.tool === "run_skill" && exec?.tool === "run_skill"
|
|
845
|
+
? exec.args?.skill_name
|
|
497
846
|
: undefined,
|
|
498
847
|
...extractPluginUsageAttribution(event.result),
|
|
499
848
|
durationMs,
|
|
500
849
|
});
|
|
501
850
|
} catch (_e) {
|
|
502
|
-
|
|
851
|
+
if (options.persistUsageTelemetry === true) {
|
|
852
|
+
throw markRuntimeLedgerPersistenceError(_e);
|
|
853
|
+
}
|
|
854
|
+
// Legacy non-JSONL persistence remains best-effort.
|
|
503
855
|
}
|
|
504
856
|
}
|
|
505
857
|
if (event.error || event.result?.error) {
|
|
@@ -514,8 +866,8 @@ export async function agentLoop(messages, options) {
|
|
|
514
866
|
result: event.result,
|
|
515
867
|
error: event.error,
|
|
516
868
|
argsSummary:
|
|
517
|
-
|
|
518
|
-
? formatToolArgs(event.tool,
|
|
869
|
+
exec && exec.tool === event.tool
|
|
870
|
+
? formatToolArgs(event.tool, exec.args)
|
|
519
871
|
: "",
|
|
520
872
|
});
|
|
521
873
|
if (denial) {
|
|
@@ -565,6 +917,43 @@ export async function agentLoop(messages, options) {
|
|
|
565
917
|
}
|
|
566
918
|
} else if (event.type === "token-usage") {
|
|
567
919
|
usageEvents.push(event);
|
|
920
|
+
if (
|
|
921
|
+
event.ledgerPersisted !== true &&
|
|
922
|
+
options.persistUsageTelemetry === true &&
|
|
923
|
+
options.sessionId
|
|
924
|
+
) {
|
|
925
|
+
persistRuntimeLedger(() =>
|
|
926
|
+
persistTokenUsage(options.sessionId, projectRuntimeTokenUsage(event)),
|
|
927
|
+
);
|
|
928
|
+
}
|
|
929
|
+
} else if (
|
|
930
|
+
event.type === "model-usage-started" ||
|
|
931
|
+
event.type === "model-usage-unknown" ||
|
|
932
|
+
event.type === "compaction-usage-unknown"
|
|
933
|
+
) {
|
|
934
|
+
if (
|
|
935
|
+
event.ledgerPersisted !== true &&
|
|
936
|
+
options.persistUsageTelemetry === true &&
|
|
937
|
+
options.sessionId
|
|
938
|
+
) {
|
|
939
|
+
const outcome =
|
|
940
|
+
event.type === "model-usage-started" ? "started" : "unknown";
|
|
941
|
+
persistRuntimeLedger(() =>
|
|
942
|
+
persistBoundary(
|
|
943
|
+
options.sessionId,
|
|
944
|
+
runtimeUsageEventType(outcome),
|
|
945
|
+
projectRuntimeUsageBoundary(
|
|
946
|
+
event.type === "compaction-usage-unknown"
|
|
947
|
+
? {
|
|
948
|
+
...event,
|
|
949
|
+
code: event.code || "provider_transport_outcome_unknown",
|
|
950
|
+
}
|
|
951
|
+
: event,
|
|
952
|
+
outcome,
|
|
953
|
+
),
|
|
954
|
+
),
|
|
955
|
+
);
|
|
956
|
+
}
|
|
568
957
|
} else if (event.type === "iteration-warning") {
|
|
569
958
|
writeOut(chalk.yellow(`\n ${event.message}\n`));
|
|
570
959
|
} else if (event.type === "iteration-budget-exhausted") {
|
|
@@ -1336,32 +1725,57 @@ export function settleReplCompactionCandidate({
|
|
|
1336
1725
|
appendUsage = appendTokenUsage,
|
|
1337
1726
|
}) {
|
|
1338
1727
|
if (usageUnknownEvent) {
|
|
1728
|
+
const block = Object.freeze({
|
|
1729
|
+
code: "CC_COMPACTION_USAGE_UNKNOWN",
|
|
1730
|
+
reason: usageUnknownEvent.reason || "provider_transport_outcome_unknown",
|
|
1731
|
+
commitState: "provider-usage-unknown",
|
|
1732
|
+
usageOutcome: "unknown",
|
|
1733
|
+
});
|
|
1734
|
+
if (
|
|
1735
|
+
useJsonl &&
|
|
1736
|
+
sessionId &&
|
|
1737
|
+
usageUnknownEvent.usageLedgerSettled !== true
|
|
1738
|
+
) {
|
|
1739
|
+
const usagePersistenceError = asReplRuntimeLedgerPersistenceError(
|
|
1740
|
+
new Error("semantic compaction usage-unknown row was not durable"),
|
|
1741
|
+
"semantic compaction usage-unknown row was not durable",
|
|
1742
|
+
);
|
|
1743
|
+
return {
|
|
1744
|
+
applied: false,
|
|
1745
|
+
error: usagePersistenceError,
|
|
1746
|
+
usagePersistenceError,
|
|
1747
|
+
block,
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1339
1750
|
return {
|
|
1340
1751
|
applied: false,
|
|
1341
|
-
block
|
|
1342
|
-
code: "CC_COMPACTION_USAGE_UNKNOWN",
|
|
1343
|
-
reason:
|
|
1344
|
-
usageUnknownEvent.reason || "provider_transport_outcome_unknown",
|
|
1345
|
-
commitState: "provider-usage-unknown",
|
|
1346
|
-
usageOutcome: "unknown",
|
|
1347
|
-
}),
|
|
1752
|
+
block,
|
|
1348
1753
|
};
|
|
1349
1754
|
}
|
|
1350
1755
|
|
|
1351
|
-
let usagePersistenceError = null;
|
|
1352
1756
|
if (usageEvent) {
|
|
1353
1757
|
addUsage(costStore, [usageEvent]);
|
|
1354
|
-
if (useJsonl && sessionId) {
|
|
1758
|
+
if (useJsonl && sessionId && usageEvent.usageLedgerSettled !== true) {
|
|
1355
1759
|
try {
|
|
1356
1760
|
appendUsage(sessionId, {
|
|
1357
1761
|
provider: usageEvent.provider,
|
|
1358
1762
|
model: usageEvent.model,
|
|
1359
1763
|
usage: usageEvent.usage,
|
|
1764
|
+
...(usageEvent.callId ? { callId: usageEvent.callId } : {}),
|
|
1765
|
+
...(usageEvent.source ? { source: usageEvent.source } : {}),
|
|
1360
1766
|
});
|
|
1361
1767
|
} catch (error) {
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1768
|
+
const usagePersistenceError = asReplRuntimeLedgerPersistenceError(
|
|
1769
|
+
error,
|
|
1770
|
+
"semantic compaction token usage was not durable",
|
|
1771
|
+
);
|
|
1772
|
+
// The paid request is accounted in-memory exactly once, but compaction
|
|
1773
|
+
// and all later input must stop when the durable settlement is unknown.
|
|
1774
|
+
return {
|
|
1775
|
+
applied: false,
|
|
1776
|
+
error: usagePersistenceError,
|
|
1777
|
+
usagePersistenceError,
|
|
1778
|
+
};
|
|
1365
1779
|
}
|
|
1366
1780
|
}
|
|
1367
1781
|
}
|
|
@@ -1374,7 +1788,7 @@ export function settleReplCompactionCandidate({
|
|
|
1374
1788
|
"REPL messages changed while provider compaction was running",
|
|
1375
1789
|
);
|
|
1376
1790
|
error.code = "CC_COMPACTION_LOCAL_STATE_CHANGED";
|
|
1377
|
-
return { applied: false, error
|
|
1791
|
+
return { applied: false, error };
|
|
1378
1792
|
}
|
|
1379
1793
|
|
|
1380
1794
|
if (useJsonl && sessionId && stats?.strategy !== "none") {
|
|
@@ -1385,13 +1799,13 @@ export function settleReplCompactionCandidate({
|
|
|
1385
1799
|
messages: compacted,
|
|
1386
1800
|
});
|
|
1387
1801
|
} catch (error) {
|
|
1388
|
-
return { applied: false, error
|
|
1802
|
+
return { applied: false, error };
|
|
1389
1803
|
}
|
|
1390
1804
|
}
|
|
1391
1805
|
|
|
1392
1806
|
messages.length = 0;
|
|
1393
1807
|
messages.push(...compacted);
|
|
1394
|
-
return { applied: true
|
|
1808
|
+
return { applied: true };
|
|
1395
1809
|
}
|
|
1396
1810
|
|
|
1397
1811
|
function validateRawReplReplayMessages(rebuiltMessages) {
|
|
@@ -2145,6 +2559,14 @@ export function createReplMcpHostRuntimeManager(dependencies = {}) {
|
|
|
2145
2559
|
* the public startAgentRepl() below always supplies the real fixed bindings.
|
|
2146
2560
|
*/
|
|
2147
2561
|
export async function runReplStartupBoundary(options, startupDependencies) {
|
|
2562
|
+
if (options.observabilityScope != null && options.ephemeral === true) {
|
|
2563
|
+
throw Object.assign(
|
|
2564
|
+
new Error(
|
|
2565
|
+
"observability scope requires durable session persistence and cannot be combined with ephemeral mode",
|
|
2566
|
+
),
|
|
2567
|
+
{ code: "CC_OBSERVABILITY_SCOPE_EPHEMERAL_CONFLICT" },
|
|
2568
|
+
);
|
|
2569
|
+
}
|
|
2148
2570
|
const prepareStartup = dependencyDataFunction(
|
|
2149
2571
|
startupDependencies,
|
|
2150
2572
|
"prepareReplStartupResume",
|
|
@@ -2163,6 +2585,25 @@ export async function runReplStartupBoundary(options, startupDependencies) {
|
|
|
2163
2585
|
),
|
|
2164
2586
|
);
|
|
2165
2587
|
const startupCandidate = startupAdmission.candidate;
|
|
2588
|
+
if (
|
|
2589
|
+
options.observabilityScope != null &&
|
|
2590
|
+
startupAdmission.useJsonl !== true
|
|
2591
|
+
) {
|
|
2592
|
+
throw Object.assign(
|
|
2593
|
+
new Error(
|
|
2594
|
+
"observability scope requires durable JSONL session persistence, but JSONL storage is unavailable",
|
|
2595
|
+
),
|
|
2596
|
+
{ code: "CC_OBSERVABILITY_SCOPE_JSONL_REQUIRED" },
|
|
2597
|
+
);
|
|
2598
|
+
}
|
|
2599
|
+
if (options.observabilityScope != null && startupCandidate?.ok === true) {
|
|
2600
|
+
throw Object.assign(
|
|
2601
|
+
new Error(
|
|
2602
|
+
"an existing REPL session scope cannot be overwritten; create a new scoped session",
|
|
2603
|
+
),
|
|
2604
|
+
{ code: "CC_OBSERVABILITY_SCOPE_IMMUTABLE" },
|
|
2605
|
+
);
|
|
2606
|
+
}
|
|
2166
2607
|
if (startupCandidate && !startupCandidate.ok) {
|
|
2167
2608
|
const refuseStartup = dependencyDataFunction(
|
|
2168
2609
|
startupDependencies,
|
|
@@ -2222,6 +2663,36 @@ export async function runReplStartupBoundary(options, startupDependencies) {
|
|
|
2222
2663
|
);
|
|
2223
2664
|
}
|
|
2224
2665
|
|
|
2666
|
+
/** Start a REPL JSONL session while preserving legacy best-effort behavior. */
|
|
2667
|
+
export function startReplJsonlSession(
|
|
2668
|
+
startSession,
|
|
2669
|
+
requestedId,
|
|
2670
|
+
meta,
|
|
2671
|
+
observabilityScope,
|
|
2672
|
+
) {
|
|
2673
|
+
try {
|
|
2674
|
+
const sessionId = startSession(requestedId, {
|
|
2675
|
+
...meta,
|
|
2676
|
+
...(observabilityScope != null ? { observabilityScope } : {}),
|
|
2677
|
+
});
|
|
2678
|
+
if (
|
|
2679
|
+
observabilityScope != null &&
|
|
2680
|
+
(typeof sessionId !== "string" || !sessionId)
|
|
2681
|
+
) {
|
|
2682
|
+
throw new Error("JSONL session creation returned no durable session id");
|
|
2683
|
+
}
|
|
2684
|
+
return sessionId || null;
|
|
2685
|
+
} catch (error) {
|
|
2686
|
+
if (observabilityScope == null) return null;
|
|
2687
|
+
const failure = new Error(
|
|
2688
|
+
"scoped JSONL session could not be durably created",
|
|
2689
|
+
{ cause: error },
|
|
2690
|
+
);
|
|
2691
|
+
failure.code = "CC_OBSERVABILITY_SCOPE_START_FAILED";
|
|
2692
|
+
throw failure;
|
|
2693
|
+
}
|
|
2694
|
+
}
|
|
2695
|
+
|
|
2225
2696
|
/** Start the agentic REPL with non-overridable production bindings. */
|
|
2226
2697
|
export async function startAgentRepl(options = {}) {
|
|
2227
2698
|
const sessionHostLeaseScope = { lease: null };
|
|
@@ -2374,6 +2845,85 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
2374
2845
|
}
|
|
2375
2846
|
};
|
|
2376
2847
|
const { useJsonl, candidate: _startupJsonlResume } = startupAdmission;
|
|
2848
|
+
// A usage-ledger durability failure makes this REPL terminal. Keep the latch
|
|
2849
|
+
// above every direct-model surface (Advisor, /btw, /auto, /plan, /goal), and
|
|
2850
|
+
// clear steering immediately so queued work cannot start another paid call.
|
|
2851
|
+
let _processingLine = false;
|
|
2852
|
+
const _pendingLines = [];
|
|
2853
|
+
const _runtimeLedgerTerminalLatch = createReplRuntimeLedgerTerminalLatch({
|
|
2854
|
+
onTrip: (terminalError) => {
|
|
2855
|
+
_pendingLines.length = 0;
|
|
2856
|
+
try {
|
|
2857
|
+
_turnAbort?.abort(terminalError);
|
|
2858
|
+
} catch {
|
|
2859
|
+
// An already-settled turn needs no further cancellation.
|
|
2860
|
+
}
|
|
2861
|
+
},
|
|
2862
|
+
});
|
|
2863
|
+
const _reportRuntimeLedgerTerminal = ({ concurrent = false } = {}) => {
|
|
2864
|
+
const message = REPL_RUNTIME_LEDGER_PERSISTENCE_FAILURE_MESSAGE;
|
|
2865
|
+
if (concurrent) process.stderr.write(`\n${message}\n`);
|
|
2866
|
+
else logger.error(message);
|
|
2867
|
+
};
|
|
2868
|
+
const _runReplMeteredModelCall = async ({
|
|
2869
|
+
call,
|
|
2870
|
+
callProvider,
|
|
2871
|
+
callModel,
|
|
2872
|
+
source = "model",
|
|
2873
|
+
includeLedgerMetadata = false,
|
|
2874
|
+
}) => {
|
|
2875
|
+
_runtimeLedgerTerminalLatch.assertOpen();
|
|
2876
|
+
try {
|
|
2877
|
+
const durableSessionId = resolveReplMeteredSessionId(useJsonl, sessionId);
|
|
2878
|
+
const metered = await runReplMeteredModelCallWithLedger({
|
|
2879
|
+
sessionId: durableSessionId,
|
|
2880
|
+
persist: durableSessionId
|
|
2881
|
+
? (type, data) => appendEvent(durableSessionId, type, data)
|
|
2882
|
+
: null,
|
|
2883
|
+
provider: callProvider || provider,
|
|
2884
|
+
model: callModel || model,
|
|
2885
|
+
source,
|
|
2886
|
+
call,
|
|
2887
|
+
attachErrorMetadata: includeLedgerMetadata,
|
|
2888
|
+
});
|
|
2889
|
+
return includeLedgerMetadata ? metered : metered.result;
|
|
2890
|
+
} catch (error) {
|
|
2891
|
+
const terminalError = _runtimeLedgerTerminalLatch.trip(error);
|
|
2892
|
+
if (terminalError) throw terminalError;
|
|
2893
|
+
throw error;
|
|
2894
|
+
}
|
|
2895
|
+
};
|
|
2896
|
+
// Direct chat helpers keep their public string-returning API while routing
|
|
2897
|
+
// each private provider envelope through the durable per-call REPL meter.
|
|
2898
|
+
const _directChatCallWrapper = ({
|
|
2899
|
+
call,
|
|
2900
|
+
provider: callProvider,
|
|
2901
|
+
model: callModel,
|
|
2902
|
+
}) =>
|
|
2903
|
+
_runReplMeteredModelCall({
|
|
2904
|
+
call,
|
|
2905
|
+
callProvider,
|
|
2906
|
+
callModel,
|
|
2907
|
+
source: "model",
|
|
2908
|
+
});
|
|
2909
|
+
const _runReplDirectTool = async (tool, args) => {
|
|
2910
|
+
_runtimeLedgerTerminalLatch.assertOpen();
|
|
2911
|
+
try {
|
|
2912
|
+
const durableSessionId = resolveReplMeteredSessionId(useJsonl, sessionId);
|
|
2913
|
+
return await runReplDirectToolWithLedger({
|
|
2914
|
+
sessionId: durableSessionId,
|
|
2915
|
+
tool,
|
|
2916
|
+
args,
|
|
2917
|
+
execute: executeTool,
|
|
2918
|
+
now: options.now || Date.now,
|
|
2919
|
+
terminalLatch: _runtimeLedgerTerminalLatch,
|
|
2920
|
+
});
|
|
2921
|
+
} catch (error) {
|
|
2922
|
+
const terminalError = _runtimeLedgerTerminalLatch.trip(error);
|
|
2923
|
+
if (terminalError) throw terminalError;
|
|
2924
|
+
throw error;
|
|
2925
|
+
}
|
|
2926
|
+
};
|
|
2377
2927
|
let model = options.model || "qwen2.5:7b";
|
|
2378
2928
|
let provider = options.provider || "ollama";
|
|
2379
2929
|
// Extended thinking (Anthropic; opt-in via --think/--ultrathink). Carried from
|
|
@@ -2518,24 +3068,36 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
2518
3068
|
model,
|
|
2519
3069
|
provider,
|
|
2520
3070
|
llmQuery: async (prompt) => {
|
|
2521
|
-
const
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
3071
|
+
const {
|
|
3072
|
+
result: response,
|
|
3073
|
+
callId,
|
|
3074
|
+
usageLedgerSettled,
|
|
3075
|
+
} = await _runReplMeteredModelCall({
|
|
3076
|
+
callProvider: provider,
|
|
3077
|
+
callModel: model,
|
|
3078
|
+
source: "semantic-compaction",
|
|
3079
|
+
includeLedgerMetadata: true,
|
|
3080
|
+
call: () =>
|
|
3081
|
+
chatWithTools([{ role: "user", content: prompt }], {
|
|
3082
|
+
provider,
|
|
3083
|
+
model,
|
|
3084
|
+
baseUrl,
|
|
3085
|
+
apiKey,
|
|
3086
|
+
signal: _sessionHostLeaseScope?.lease?.signal,
|
|
3087
|
+
enabledToolNames: [],
|
|
3088
|
+
extraToolDefinitions: [],
|
|
3089
|
+
hostManagedToolPolicy: null,
|
|
3090
|
+
contextEngine: null,
|
|
3091
|
+
maxOutputTokens: 2048,
|
|
3092
|
+
}),
|
|
3093
|
+
});
|
|
2534
3094
|
return {
|
|
2535
3095
|
summary: response?.message?.content || "",
|
|
2536
3096
|
usage: response?.usage || null,
|
|
2537
3097
|
provider,
|
|
2538
3098
|
model,
|
|
3099
|
+
...(callId ? { callId } : {}),
|
|
3100
|
+
...(usageLedgerSettled ? { usageLedgerSettled: true } : {}),
|
|
2539
3101
|
};
|
|
2540
3102
|
},
|
|
2541
3103
|
});
|
|
@@ -2915,11 +3477,12 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
2915
3477
|
model,
|
|
2916
3478
|
};
|
|
2917
3479
|
if (useJsonl) {
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
3480
|
+
sessionId = startReplJsonlSession(
|
|
3481
|
+
jsonlStartSession,
|
|
3482
|
+
options.sessionId || null,
|
|
3483
|
+
meta,
|
|
3484
|
+
options.observabilityScope,
|
|
3485
|
+
);
|
|
2923
3486
|
if (
|
|
2924
3487
|
sessionId &&
|
|
2925
3488
|
_sessionHostLeaseScope &&
|
|
@@ -3760,7 +4323,7 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
3760
4323
|
// transcript snapshot and ZERO tools. Compact call/outcome metadata shares
|
|
3761
4324
|
// the session hash chain, while advice text itself is never persisted.
|
|
3762
4325
|
try {
|
|
3763
|
-
const { createConfiguredAdvisorRuntime } =
|
|
4326
|
+
const { createConfiguredAdvisorRuntime, invokeToolFreeAdvisor } =
|
|
3764
4327
|
await import("../lib/advisor-runtime.js");
|
|
3765
4328
|
const advisorOverrides = {};
|
|
3766
4329
|
if (options.advisorEnabled !== undefined) {
|
|
@@ -3775,6 +4338,13 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
3775
4338
|
baseUrl,
|
|
3776
4339
|
apiKey,
|
|
3777
4340
|
overrides: advisorOverrides,
|
|
4341
|
+
invoke: (request) =>
|
|
4342
|
+
_runReplMeteredModelCall({
|
|
4343
|
+
callProvider: request?.provider,
|
|
4344
|
+
callModel: request?.model,
|
|
4345
|
+
source: "model",
|
|
4346
|
+
call: () => invokeToolFreeAdvisor(request),
|
|
4347
|
+
}),
|
|
3778
4348
|
onEvent: (event) => {
|
|
3779
4349
|
if (!useJsonl || !sessionId) return;
|
|
3780
4350
|
try {
|
|
@@ -4080,7 +4650,10 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
4080
4650
|
getSuggestionContext: () => ({ messages: messages.slice() }),
|
|
4081
4651
|
persistSuggestionEnabled: _persistPromptSuggestionsEnabled,
|
|
4082
4652
|
clipboardBinding: options.clipboardBinding || null,
|
|
4083
|
-
generateSuggestions:
|
|
4653
|
+
generateSuggestions: resolveReplPromptSuggestionGenerator(
|
|
4654
|
+
useJsonl,
|
|
4655
|
+
options.generatePromptSuggestions,
|
|
4656
|
+
),
|
|
4084
4657
|
suggestionDebounceMs: options.promptSuggestionDebounceMs,
|
|
4085
4658
|
screenReader: _screenReaderMode,
|
|
4086
4659
|
write: (text) => process.stdout.write(String(text)),
|
|
@@ -4524,9 +5097,6 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
4524
5097
|
// line instead of racing a second concurrent turn; the queue drains FIFO
|
|
4525
5098
|
// when the current turn finishes. `/btw` is the deliberate exception: its
|
|
4526
5099
|
// tool-free snapshot call may run concurrently without mutating main state.
|
|
4527
|
-
let _processingLine = false;
|
|
4528
|
-
const _pendingLines = [];
|
|
4529
|
-
|
|
4530
5100
|
const runBtwSideQuestion = async (btw, { concurrent = false } = {}) => {
|
|
4531
5101
|
if (!btw || btw.error) {
|
|
4532
5102
|
const message = btw?.error || "usage: /btw [--fork] <question>";
|
|
@@ -4535,7 +5105,13 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
4535
5105
|
return { ok: false, error: message };
|
|
4536
5106
|
}
|
|
4537
5107
|
try {
|
|
4538
|
-
const chatFn = createChatFn({
|
|
5108
|
+
const chatFn = createChatFn({
|
|
5109
|
+
provider,
|
|
5110
|
+
model,
|
|
5111
|
+
baseUrl,
|
|
5112
|
+
apiKey,
|
|
5113
|
+
callWrapper: _directChatCallWrapper,
|
|
5114
|
+
});
|
|
4539
5115
|
const { answer } = await runBtwQuestion({
|
|
4540
5116
|
messages,
|
|
4541
5117
|
question: btw.text,
|
|
@@ -4570,6 +5146,11 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
4570
5146
|
else logger.log(`\n${block}\n`);
|
|
4571
5147
|
return { ok: true, answer, forkedId };
|
|
4572
5148
|
} catch (error) {
|
|
5149
|
+
const terminalError = _runtimeLedgerTerminalLatch.trip(error);
|
|
5150
|
+
if (terminalError) {
|
|
5151
|
+
_reportRuntimeLedgerTerminal({ concurrent });
|
|
5152
|
+
return { ok: false, error: terminalError.message, terminal: true };
|
|
5153
|
+
}
|
|
4573
5154
|
const message = `/btw failed: ${error.message}`;
|
|
4574
5155
|
if (concurrent) process.stderr.write(`\n${message}\n`);
|
|
4575
5156
|
else logger.error(message);
|
|
@@ -4613,6 +5194,16 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
4613
5194
|
prompt();
|
|
4614
5195
|
return;
|
|
4615
5196
|
}
|
|
5197
|
+
if (
|
|
5198
|
+
_runtimeLedgerTerminalLatch.isTripped() &&
|
|
5199
|
+
trimmed !== "/exit" &&
|
|
5200
|
+
trimmed !== "/quit"
|
|
5201
|
+
) {
|
|
5202
|
+
_pendingLines.length = 0;
|
|
5203
|
+
_reportRuntimeLedgerTerminal();
|
|
5204
|
+
prompt();
|
|
5205
|
+
return;
|
|
5206
|
+
}
|
|
4616
5207
|
|
|
4617
5208
|
// Per-turn version-skew check (one-time): catches an `npm i -g` that landed
|
|
4618
5209
|
// while this REPL kept running — the next prompt nudges a restart.
|
|
@@ -6085,6 +6676,12 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
6085
6676
|
) {
|
|
6086
6677
|
throw error;
|
|
6087
6678
|
}
|
|
6679
|
+
const terminalError = _runtimeLedgerTerminalLatch.trip(error);
|
|
6680
|
+
if (terminalError) {
|
|
6681
|
+
_reportRuntimeLedgerTerminal();
|
|
6682
|
+
prompt();
|
|
6683
|
+
return;
|
|
6684
|
+
}
|
|
6088
6685
|
logger.error(`Compaction failed: ${error.message}`);
|
|
6089
6686
|
prompt();
|
|
6090
6687
|
return;
|
|
@@ -6109,9 +6706,14 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
6109
6706
|
costStore: _costStore,
|
|
6110
6707
|
});
|
|
6111
6708
|
if (settlement.usagePersistenceError) {
|
|
6112
|
-
|
|
6113
|
-
|
|
6709
|
+
const terminalError = _runtimeLedgerTerminalLatch.trip(
|
|
6710
|
+
settlement.usagePersistenceError,
|
|
6114
6711
|
);
|
|
6712
|
+
if (terminalError) {
|
|
6713
|
+
_reportRuntimeLedgerTerminal();
|
|
6714
|
+
prompt();
|
|
6715
|
+
return;
|
|
6716
|
+
}
|
|
6115
6717
|
}
|
|
6116
6718
|
if (settlement.block) {
|
|
6117
6719
|
_compactionUsageBlock = settlement.block;
|
|
@@ -6813,7 +7415,13 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
6813
7415
|
const result = await startDebate({
|
|
6814
7416
|
target: targetLabel,
|
|
6815
7417
|
code,
|
|
6816
|
-
llmOptions: {
|
|
7418
|
+
llmOptions: {
|
|
7419
|
+
provider,
|
|
7420
|
+
model,
|
|
7421
|
+
baseUrl,
|
|
7422
|
+
apiKey,
|
|
7423
|
+
callWrapper: _directChatCallWrapper,
|
|
7424
|
+
},
|
|
6817
7425
|
});
|
|
6818
7426
|
for (const review of result.reviews) {
|
|
6819
7427
|
const vc =
|
|
@@ -6835,7 +7443,9 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
6835
7443
|
content: `[Cowork Debate Result] ${result.verdict} (consensus: ${result.consensusScore}%)\n${result.summary.substring(0, 500)}`,
|
|
6836
7444
|
});
|
|
6837
7445
|
} catch (err) {
|
|
6838
|
-
|
|
7446
|
+
const terminalError = _runtimeLedgerTerminalLatch.trip(err);
|
|
7447
|
+
if (terminalError) _reportRuntimeLedgerTerminal();
|
|
7448
|
+
else logger.error(`Debate failed: ${err.message}`);
|
|
6839
7449
|
}
|
|
6840
7450
|
} else if (subCmd === "compare" && coworkInput) {
|
|
6841
7451
|
try {
|
|
@@ -6844,7 +7454,13 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
6844
7454
|
process.stdout.write(chalk.gray("\n Generating variants...\n"));
|
|
6845
7455
|
const result = await compare({
|
|
6846
7456
|
prompt: coworkInput,
|
|
6847
|
-
llmOptions: {
|
|
7457
|
+
llmOptions: {
|
|
7458
|
+
provider,
|
|
7459
|
+
model,
|
|
7460
|
+
baseUrl,
|
|
7461
|
+
apiKey,
|
|
7462
|
+
callWrapper: _directChatCallWrapper,
|
|
7463
|
+
},
|
|
6848
7464
|
});
|
|
6849
7465
|
for (const v of result.variants) {
|
|
6850
7466
|
process.stdout.write(
|
|
@@ -6859,7 +7475,9 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
6859
7475
|
content: `[Cowork Compare Result] Winner: ${result.winner}. ${result.reason}`,
|
|
6860
7476
|
});
|
|
6861
7477
|
} catch (err) {
|
|
6862
|
-
|
|
7478
|
+
const terminalError = _runtimeLedgerTerminalLatch.trip(err);
|
|
7479
|
+
if (terminalError) _reportRuntimeLedgerTerminal();
|
|
7480
|
+
else logger.error(`Compare failed: ${err.message}`);
|
|
6863
7481
|
}
|
|
6864
7482
|
} else if (subCmd === "graph" && coworkInput) {
|
|
6865
7483
|
try {
|
|
@@ -7044,10 +7662,16 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
7044
7662
|
// Submit new goal
|
|
7045
7663
|
// Lazy-init autonomous agent with LLM chat function
|
|
7046
7664
|
if (!autonomousAgent._initialized) {
|
|
7047
|
-
const chatFn = createChatFn({
|
|
7665
|
+
const chatFn = createChatFn({
|
|
7666
|
+
provider,
|
|
7667
|
+
model,
|
|
7668
|
+
baseUrl,
|
|
7669
|
+
apiKey,
|
|
7670
|
+
callWrapper: _directChatCallWrapper,
|
|
7671
|
+
});
|
|
7048
7672
|
autonomousAgent.initialize({
|
|
7049
7673
|
llmChat: chatFn,
|
|
7050
|
-
toolExecutor:
|
|
7674
|
+
toolExecutor: _runReplDirectTool,
|
|
7051
7675
|
});
|
|
7052
7676
|
}
|
|
7053
7677
|
|
|
@@ -7214,7 +7838,7 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
7214
7838
|
process.stdout.write(
|
|
7215
7839
|
chalk.gray(` [${item.tool}] ${item.title}\n`),
|
|
7216
7840
|
);
|
|
7217
|
-
return await
|
|
7841
|
+
return await _runReplDirectTool(item.tool, item.params);
|
|
7218
7842
|
}
|
|
7219
7843
|
return { skipped: true };
|
|
7220
7844
|
},
|
|
@@ -7249,7 +7873,13 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
7249
7873
|
await import("../lib/interactive-planner.js");
|
|
7250
7874
|
const { TerminalInteractionAdapter } =
|
|
7251
7875
|
await import("../lib/interaction-adapter.js");
|
|
7252
|
-
const chatFn = createChatFn({
|
|
7876
|
+
const chatFn = createChatFn({
|
|
7877
|
+
provider,
|
|
7878
|
+
model,
|
|
7879
|
+
baseUrl,
|
|
7880
|
+
apiKey,
|
|
7881
|
+
callWrapper: _directChatCallWrapper,
|
|
7882
|
+
});
|
|
7253
7883
|
const planner = new CLIInteractivePlanner({
|
|
7254
7884
|
llmChat: chatFn,
|
|
7255
7885
|
db,
|
|
@@ -8352,11 +8982,12 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
8352
8982
|
model: telemetry.model || activeModel,
|
|
8353
8983
|
reason: classifyStreamRetryReason(error),
|
|
8354
8984
|
});
|
|
8355
|
-
} catch {
|
|
8356
|
-
|
|
8985
|
+
} catch (persistenceError) {
|
|
8986
|
+
throw markRuntimeLedgerPersistenceError(persistenceError);
|
|
8357
8987
|
}
|
|
8358
8988
|
}
|
|
8359
8989
|
},
|
|
8990
|
+
strictUsageTelemetry: useJsonl,
|
|
8360
8991
|
// Stream-stall hint (Claude-Code 2.1.185): the connection is alive but
|
|
8361
8992
|
// the API has gone silent mid-response — tell the user we're still
|
|
8362
8993
|
// waiting instead of leaving a frozen spinner. stderr so it never
|
|
@@ -8391,6 +9022,7 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
8391
9022
|
contextEngine,
|
|
8392
9023
|
iterationBudget,
|
|
8393
9024
|
sessionId,
|
|
9025
|
+
persistUsageTelemetry: useJsonl,
|
|
8394
9026
|
skillLoader: _replSkillLoader,
|
|
8395
9027
|
cwd: process.cwd(),
|
|
8396
9028
|
additionalDirectories,
|
|
@@ -8459,24 +9091,6 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
8459
9091
|
// Running spend for `/cost` (in-memory, works without persistence).
|
|
8460
9092
|
if (usageEvents?.length) addUsage(_costStore, usageEvents);
|
|
8461
9093
|
|
|
8462
|
-
if (sessionId && usageEvents?.length) {
|
|
8463
|
-
for (const ue of usageEvents) {
|
|
8464
|
-
try {
|
|
8465
|
-
appendTokenUsage(sessionId, {
|
|
8466
|
-
provider: ue.provider,
|
|
8467
|
-
model: ue.model,
|
|
8468
|
-
usage: ue.usage,
|
|
8469
|
-
// 用量归因: sub-agent / isolated-skill usage carries its
|
|
8470
|
-
// attribution frame into the transcript; main-loop events stay
|
|
8471
|
-
// exactly as before (absence ⇒ origin "main").
|
|
8472
|
-
...(ue.attribution ? { attribution: ue.attribution } : {}),
|
|
8473
|
-
});
|
|
8474
|
-
} catch (_e) {
|
|
8475
|
-
/* best-effort */
|
|
8476
|
-
}
|
|
8477
|
-
}
|
|
8478
|
-
}
|
|
8479
|
-
|
|
8480
9094
|
// Feed the status line: the last usage event's input+output ≈ the tokens
|
|
8481
9095
|
// now resident in the context window (what the next call resends). Track
|
|
8482
9096
|
// the active model too, so the built-in readout reflects auto-switches.
|
|
@@ -8507,12 +9121,18 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
8507
9121
|
`Condition: ${cond.text || cond.source}\n\n` +
|
|
8508
9122
|
`Latest assistant output:\n${String(finalText || "").slice(0, 2000)}\n\n` +
|
|
8509
9123
|
`Reply with STRICT JSON only: {"met": true|false, "reason": "<short>"}.`;
|
|
8510
|
-
const jr = await
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
|
|
9124
|
+
const jr = await _runReplMeteredModelCall({
|
|
9125
|
+
callProvider: provider,
|
|
9126
|
+
callModel: activeModel,
|
|
9127
|
+
source: "model",
|
|
9128
|
+
call: () =>
|
|
9129
|
+
chatWithTools([{ role: "user", content: p }], {
|
|
9130
|
+
model: activeModel,
|
|
9131
|
+
provider,
|
|
9132
|
+
baseUrl,
|
|
9133
|
+
apiKey,
|
|
9134
|
+
enabledToolNames: [],
|
|
9135
|
+
}),
|
|
8516
9136
|
});
|
|
8517
9137
|
const text = jr?.message?.content || "";
|
|
8518
9138
|
let met = false;
|
|
@@ -8547,7 +9167,9 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
8547
9167
|
logger.log(chalk.cyan(l));
|
|
8548
9168
|
if (done) _sessionGoal = null; // completed or exhausted → drop
|
|
8549
9169
|
} catch (err) {
|
|
8550
|
-
|
|
9170
|
+
const terminalError = _runtimeLedgerTerminalLatch.trip(err);
|
|
9171
|
+
if (terminalError) _reportRuntimeLedgerTerminal();
|
|
9172
|
+
else logger.verbose(`/goal eval skipped: ${err.message}`);
|
|
8551
9173
|
}
|
|
8552
9174
|
}
|
|
8553
9175
|
|
|
@@ -8660,6 +9282,7 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
8660
9282
|
feature("PROMPT_COMPRESSOR") &&
|
|
8661
9283
|
_compressor &&
|
|
8662
9284
|
!_compactionUsageBlock &&
|
|
9285
|
+
!_runtimeLedgerTerminalLatch.isTripped() &&
|
|
8663
9286
|
_compressor.shouldAutoCompact(messages)
|
|
8664
9287
|
) {
|
|
8665
9288
|
try {
|
|
@@ -8688,9 +9311,10 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
8688
9311
|
costStore: _costStore,
|
|
8689
9312
|
});
|
|
8690
9313
|
if (settlement.usagePersistenceError) {
|
|
8691
|
-
|
|
8692
|
-
|
|
9314
|
+
const terminalError = _runtimeLedgerTerminalLatch.trip(
|
|
9315
|
+
settlement.usagePersistenceError,
|
|
8693
9316
|
);
|
|
9317
|
+
if (terminalError) throw terminalError;
|
|
8694
9318
|
}
|
|
8695
9319
|
if (settlement.block) {
|
|
8696
9320
|
_compactionUsageBlock = settlement.block;
|
|
@@ -8725,6 +9349,7 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
8725
9349
|
) {
|
|
8726
9350
|
throw error;
|
|
8727
9351
|
}
|
|
9352
|
+
if (error?.runtimeLedgerPersistence === true) throw error;
|
|
8728
9353
|
logger.warn(`Auto-compaction failed: ${error.message}`);
|
|
8729
9354
|
}
|
|
8730
9355
|
}
|
|
@@ -8772,6 +9397,12 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
8772
9397
|
}
|
|
8773
9398
|
} catch (err) {
|
|
8774
9399
|
_turnAbort = null;
|
|
9400
|
+
const terminalError = _runtimeLedgerTerminalLatch.trip(err);
|
|
9401
|
+
if (terminalError) {
|
|
9402
|
+
_reportRuntimeLedgerTerminal();
|
|
9403
|
+
prompt();
|
|
9404
|
+
return;
|
|
9405
|
+
}
|
|
8775
9406
|
// Esc interrupt: an aborted turn is normal flow, not an error — the
|
|
8776
9407
|
// partial conversation stays usable and queued lines still drain.
|
|
8777
9408
|
if (err?.name === "AbortError" || /abort/i.test(err?.message || "")) {
|
|
@@ -8806,6 +9437,16 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
8806
9437
|
|
|
8807
9438
|
rl.on("line", async (input) => {
|
|
8808
9439
|
if (!(await _waitForReplOutput())) return;
|
|
9440
|
+
if (_runtimeLedgerTerminalLatch.isTripped()) {
|
|
9441
|
+
const terminalInput = input.trim();
|
|
9442
|
+
if (terminalInput === "/exit" || terminalInput === "/quit") {
|
|
9443
|
+
logger.log(chalk.gray("\nGoodbye!"));
|
|
9444
|
+
rl.close();
|
|
9445
|
+
} else {
|
|
9446
|
+
_reportRuntimeLedgerTerminal();
|
|
9447
|
+
}
|
|
9448
|
+
return;
|
|
9449
|
+
}
|
|
8809
9450
|
if (_processingLine) {
|
|
8810
9451
|
const concurrentBtw = _slashCommandsDisabled
|
|
8811
9452
|
? null
|
|
@@ -8830,7 +9471,7 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
8830
9471
|
try {
|
|
8831
9472
|
await handleLine(input);
|
|
8832
9473
|
if (!(await _waitForReplOutput())) return;
|
|
8833
|
-
while (_pendingLines.length) {
|
|
9474
|
+
while (_pendingLines.length && !_runtimeLedgerTerminalLatch.isTripped()) {
|
|
8834
9475
|
const next = _pendingLines.shift();
|
|
8835
9476
|
logger.log(chalk.cyan(`▶ running queued input: ${next}`));
|
|
8836
9477
|
await handleLine(next);
|