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
|
@@ -2857,6 +2857,12 @@ export async function executeTool(name, args, context = {}) {
|
|
|
2857
2857
|
// 用量归因: shared per-run sink for child-loop (sub-agent / isolated
|
|
2858
2858
|
// skill) token usage, drained by agentLoop as attributed events.
|
|
2859
2859
|
subAgentUsageSink: context.subAgentUsageSink || null,
|
|
2860
|
+
strictUsageTelemetry: context.strictUsageTelemetry === true,
|
|
2861
|
+
onUsageBoundary: context.onUsageBoundary || null,
|
|
2862
|
+
onUsageSettlement: context.onUsageSettlement || null,
|
|
2863
|
+
onToolCallBoundary: context.onToolCallBoundary || null,
|
|
2864
|
+
onToolCallSettlement: context.onToolCallSettlement || null,
|
|
2865
|
+
backgroundUsageFailureState: context.backgroundUsageFailureState || null,
|
|
2860
2866
|
planManager,
|
|
2861
2867
|
permissionRules: context.permissionRules || null,
|
|
2862
2868
|
effectiveAllowedToolNames: context.effectiveAllowedToolNames ?? null,
|
|
@@ -4259,6 +4265,12 @@ async function executeToolInner(
|
|
|
4259
4265
|
signal = null,
|
|
4260
4266
|
backgroundSubAgents = null,
|
|
4261
4267
|
subAgentUsageSink = null,
|
|
4268
|
+
strictUsageTelemetry = false,
|
|
4269
|
+
onUsageBoundary = null,
|
|
4270
|
+
onUsageSettlement = null,
|
|
4271
|
+
onToolCallBoundary = null,
|
|
4272
|
+
onToolCallSettlement = null,
|
|
4273
|
+
backgroundUsageFailureState = null,
|
|
4262
4274
|
toolAdmission = null,
|
|
4263
4275
|
unattendedActionPolicy = null,
|
|
4264
4276
|
managedCheckpoint = false,
|
|
@@ -5715,6 +5727,12 @@ async function executeToolInner(
|
|
|
5715
5727
|
signal,
|
|
5716
5728
|
backgroundSubAgents,
|
|
5717
5729
|
subAgentUsageSink,
|
|
5730
|
+
strictUsageTelemetry,
|
|
5731
|
+
onUsageBoundary,
|
|
5732
|
+
onUsageSettlement,
|
|
5733
|
+
onToolCallBoundary,
|
|
5734
|
+
onToolCallSettlement,
|
|
5735
|
+
backgroundUsageFailureState,
|
|
5718
5736
|
toolAdmission,
|
|
5719
5737
|
}),
|
|
5720
5738
|
);
|
|
@@ -6045,6 +6063,7 @@ async function executeToolInner(
|
|
|
6045
6063
|
const entry = store.createCron({
|
|
6046
6064
|
prompt: args.prompt,
|
|
6047
6065
|
cron: args.cron,
|
|
6066
|
+
timeZone: args.timezone || null,
|
|
6048
6067
|
label: args.label || null,
|
|
6049
6068
|
expiresInMs,
|
|
6050
6069
|
jitterMs,
|
|
@@ -6596,7 +6615,75 @@ async function executeToolInner(
|
|
|
6596
6615
|
const skillUsageSink = Array.isArray(subAgentUsageSink)
|
|
6597
6616
|
? subAgentUsageSink
|
|
6598
6617
|
: null;
|
|
6618
|
+
if (strictUsageTelemetry === true) {
|
|
6619
|
+
_assertStrictUsageObserver(onUsageBoundary, "boundary");
|
|
6620
|
+
_assertStrictUsageObserver(onUsageSettlement, "settlement");
|
|
6621
|
+
}
|
|
6599
6622
|
let skillSubRef = null;
|
|
6623
|
+
const projectSkillUsage = (event) =>
|
|
6624
|
+
event && event.attribution
|
|
6625
|
+
? event
|
|
6626
|
+
: {
|
|
6627
|
+
...event,
|
|
6628
|
+
source:
|
|
6629
|
+
event?.source === "semantic-compaction"
|
|
6630
|
+
? "semantic-compaction"
|
|
6631
|
+
: "subagent",
|
|
6632
|
+
attribution: {
|
|
6633
|
+
origin: "skill",
|
|
6634
|
+
skill: args.skill_name,
|
|
6635
|
+
subagentId: skillSubRef?.id || null,
|
|
6636
|
+
parentSessionId: sessionId || null,
|
|
6637
|
+
depth: (subAgentDepth || 0) + 1,
|
|
6638
|
+
},
|
|
6639
|
+
};
|
|
6640
|
+
const observeSkillBoundary =
|
|
6641
|
+
strictUsageTelemetry === true
|
|
6642
|
+
? (event) =>
|
|
6643
|
+
_notifyStrictUsageBoundary(
|
|
6644
|
+
onUsageBoundary,
|
|
6645
|
+
projectSkillUsage(event),
|
|
6646
|
+
)
|
|
6647
|
+
: null;
|
|
6648
|
+
const observeSkillSettlement =
|
|
6649
|
+
strictUsageTelemetry === true
|
|
6650
|
+
? (event) =>
|
|
6651
|
+
_notifyStrictUsageSettlement(
|
|
6652
|
+
onUsageSettlement,
|
|
6653
|
+
projectSkillUsage(event),
|
|
6654
|
+
)
|
|
6655
|
+
: null;
|
|
6656
|
+
const projectSkillTool = (event) => ({
|
|
6657
|
+
...event,
|
|
6658
|
+
attribution: event?.attribution || projectSkillUsage({}).attribution,
|
|
6659
|
+
});
|
|
6660
|
+
const observeSkillToolBoundary =
|
|
6661
|
+
strictUsageTelemetry === true
|
|
6662
|
+
? (event) =>
|
|
6663
|
+
_notifyStrictToolObserver(
|
|
6664
|
+
onToolCallBoundary,
|
|
6665
|
+
projectSkillTool(event),
|
|
6666
|
+
"boundary",
|
|
6667
|
+
)
|
|
6668
|
+
: null;
|
|
6669
|
+
const observeSkillToolSettlement =
|
|
6670
|
+
strictUsageTelemetry === true
|
|
6671
|
+
? (event) =>
|
|
6672
|
+
_notifyStrictToolObserver(
|
|
6673
|
+
onToolCallSettlement,
|
|
6674
|
+
projectSkillTool(event),
|
|
6675
|
+
"settlement",
|
|
6676
|
+
)
|
|
6677
|
+
: null;
|
|
6678
|
+
const skillLlmOptions = { ...(llmOptions || {}) };
|
|
6679
|
+
if (typeof llmOptions?.onStreamRetry === "function") {
|
|
6680
|
+
skillLlmOptions.onStreamRetry = (attempt, error, telemetry = {}) =>
|
|
6681
|
+
_notifyStrictRetryObserver(llmOptions.onStreamRetry, [
|
|
6682
|
+
attempt,
|
|
6683
|
+
error,
|
|
6684
|
+
projectSkillUsage(telemetry),
|
|
6685
|
+
]);
|
|
6686
|
+
}
|
|
6600
6687
|
// Run skill through isolated sub-agent context
|
|
6601
6688
|
let subCtx;
|
|
6602
6689
|
try {
|
|
@@ -6612,7 +6699,7 @@ async function executeToolInner(
|
|
|
6612
6699
|
signal: skillExecutionSignal,
|
|
6613
6700
|
toolAdmission,
|
|
6614
6701
|
cwd,
|
|
6615
|
-
llmOptions:
|
|
6702
|
+
llmOptions: skillLlmOptions,
|
|
6616
6703
|
...(sessionBudget ? { sessionBudget } : {}),
|
|
6617
6704
|
...(permissionRules ? { permissionRules } : {}),
|
|
6618
6705
|
...(hostManagedToolPolicy
|
|
@@ -6636,29 +6723,29 @@ async function executeToolInner(
|
|
|
6636
6723
|
...(mcpConflictScheduler ? { mcpConflictScheduler } : {}),
|
|
6637
6724
|
onUsage: skillUsageSink
|
|
6638
6725
|
? (u) => {
|
|
6726
|
+
const forwarded = projectSkillUsage(u);
|
|
6639
6727
|
try {
|
|
6640
|
-
skillUsageSink.push(
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
origin: "skill",
|
|
6650
|
-
skill: args.skill_name,
|
|
6651
|
-
subagentId: skillSubRef?.id || null,
|
|
6652
|
-
parentSessionId: sessionId || null,
|
|
6653
|
-
depth: (subAgentDepth || 0) + 1,
|
|
6654
|
-
},
|
|
6655
|
-
},
|
|
6656
|
-
);
|
|
6657
|
-
} catch (_e) {
|
|
6658
|
-
// usage forwarding is best-effort
|
|
6728
|
+
skillUsageSink.push(forwarded);
|
|
6729
|
+
} catch (error) {
|
|
6730
|
+
if (strictUsageTelemetry === true) {
|
|
6731
|
+
throw _runtimeUsageBoundaryFailure(
|
|
6732
|
+
error,
|
|
6733
|
+
"CC_USAGE_FORWARDING_FAILED",
|
|
6734
|
+
"Isolated skill usage forwarding failed",
|
|
6735
|
+
);
|
|
6736
|
+
}
|
|
6659
6737
|
}
|
|
6660
6738
|
}
|
|
6661
6739
|
: null,
|
|
6740
|
+
...(strictUsageTelemetry === true
|
|
6741
|
+
? {
|
|
6742
|
+
strictUsageTelemetry: true,
|
|
6743
|
+
onUsageBoundary: observeSkillBoundary,
|
|
6744
|
+
onUsageSettlement: observeSkillSettlement,
|
|
6745
|
+
onToolCallBoundary: observeSkillToolBoundary,
|
|
6746
|
+
onToolCallSettlement: observeSkillToolSettlement,
|
|
6747
|
+
}
|
|
6748
|
+
: {}),
|
|
6662
6749
|
});
|
|
6663
6750
|
} catch (error) {
|
|
6664
6751
|
skillExecutionLease?.release?.();
|
|
@@ -6703,6 +6790,7 @@ async function executeToolInner(
|
|
|
6703
6790
|
toolsUsed: result.toolsUsed,
|
|
6704
6791
|
});
|
|
6705
6792
|
} catch (err) {
|
|
6793
|
+
if (err?.runtimeLedgerPersistence === true) throw err;
|
|
6706
6794
|
if (
|
|
6707
6795
|
signal?.aborted ||
|
|
6708
6796
|
skillExecutionSignal?.aborted ||
|
|
@@ -7838,6 +7926,34 @@ function _backgroundSubAgentResultText(entry) {
|
|
|
7838
7926
|
);
|
|
7839
7927
|
}
|
|
7840
7928
|
|
|
7929
|
+
function _throwBackgroundSubAgentUsageFailure(entry) {
|
|
7930
|
+
const error = entry?.outcome?.fatalError;
|
|
7931
|
+
if (error?.runtimeLedgerPersistence === true) throw error;
|
|
7932
|
+
}
|
|
7933
|
+
|
|
7934
|
+
function _throwSettledBackgroundUsageFailure(map) {
|
|
7935
|
+
if (!(map instanceof Map)) return;
|
|
7936
|
+
for (const entry of map.values()) {
|
|
7937
|
+
if (entry?.settled === true) {
|
|
7938
|
+
_throwBackgroundSubAgentUsageFailure(entry);
|
|
7939
|
+
}
|
|
7940
|
+
}
|
|
7941
|
+
}
|
|
7942
|
+
|
|
7943
|
+
function _throwBackgroundUsageFailureState(state) {
|
|
7944
|
+
const error = state?.error;
|
|
7945
|
+
if (error?.runtimeLedgerPersistence === true) throw error;
|
|
7946
|
+
}
|
|
7947
|
+
|
|
7948
|
+
async function _awaitBackgroundUsageSettlement(map, state) {
|
|
7949
|
+
_throwBackgroundUsageFailureState(state);
|
|
7950
|
+
if (map instanceof Map && map.size > 0) {
|
|
7951
|
+
await Promise.all([...map.values()].map((entry) => entry.promise));
|
|
7952
|
+
}
|
|
7953
|
+
_throwBackgroundUsageFailureState(state);
|
|
7954
|
+
_throwSettledBackgroundUsageFailure(map);
|
|
7955
|
+
}
|
|
7956
|
+
|
|
7841
7957
|
/**
|
|
7842
7958
|
* Drain the run's attributed child-loop usage sink (spawn_sub_agent /
|
|
7843
7959
|
* isolated run_skill — see toolContext.subAgentUsageSink), re-yielding each
|
|
@@ -7849,13 +7965,48 @@ function _backgroundSubAgentResultText(entry) {
|
|
|
7849
7965
|
function* _drainSubAgentUsage(sink) {
|
|
7850
7966
|
while (Array.isArray(sink) && sink.length > 0) {
|
|
7851
7967
|
const u = sink.shift();
|
|
7968
|
+
if (u?.type === "model-usage-unknown") {
|
|
7969
|
+
const boundary = {
|
|
7970
|
+
callId: u.callId,
|
|
7971
|
+
provider: u.provider ?? null,
|
|
7972
|
+
model: u.model ?? null,
|
|
7973
|
+
source: u.source || "subagent",
|
|
7974
|
+
attribution: u.attribution || null,
|
|
7975
|
+
};
|
|
7976
|
+
if (u.callId && u.boundaryNotified !== true) {
|
|
7977
|
+
yield { type: "model-usage-started", ...boundary };
|
|
7978
|
+
}
|
|
7979
|
+
yield {
|
|
7980
|
+
type: "model-usage-unknown",
|
|
7981
|
+
...boundary,
|
|
7982
|
+
code: u.code || "provider_transport_outcome_unknown",
|
|
7983
|
+
...(u.ledgerPersisted === true ? { ledgerPersisted: true } : {}),
|
|
7984
|
+
};
|
|
7985
|
+
continue;
|
|
7986
|
+
}
|
|
7987
|
+
if (u?.callId && u.boundaryNotified !== true) {
|
|
7988
|
+
yield {
|
|
7989
|
+
type: "model-usage-started",
|
|
7990
|
+
callId: u.callId,
|
|
7991
|
+
provider: u.provider ?? null,
|
|
7992
|
+
model: u.model ?? null,
|
|
7993
|
+
source: u.source || "subagent",
|
|
7994
|
+
attribution: u.attribution || null,
|
|
7995
|
+
};
|
|
7996
|
+
}
|
|
7852
7997
|
yield {
|
|
7853
7998
|
type: "token-usage",
|
|
7999
|
+
...(u?.callId ? { callId: u.callId } : {}),
|
|
7854
8000
|
provider: u?.provider ?? null,
|
|
7855
8001
|
model: u?.model ?? null,
|
|
7856
8002
|
usage: u?.usage || {},
|
|
7857
|
-
...(u?.source
|
|
8003
|
+
...(u?.source
|
|
8004
|
+
? { source: u.source }
|
|
8005
|
+
: u?.callId
|
|
8006
|
+
? { source: "subagent" }
|
|
8007
|
+
: {}),
|
|
7858
8008
|
attribution: u?.attribution || null,
|
|
8009
|
+
...(u?.ledgerPersisted === true ? { ledgerPersisted: true } : {}),
|
|
7859
8010
|
};
|
|
7860
8011
|
}
|
|
7861
8012
|
}
|
|
@@ -8312,32 +8463,126 @@ async function _executeSpawnSubAgent(args, ctx) {
|
|
|
8312
8463
|
const usageSink = Array.isArray(ctx.subAgentUsageSink)
|
|
8313
8464
|
? ctx.subAgentUsageSink
|
|
8314
8465
|
: null;
|
|
8466
|
+
if (ctx.strictUsageTelemetry === true) {
|
|
8467
|
+
_assertStrictUsageObserver(ctx.onUsageBoundary, "boundary");
|
|
8468
|
+
_assertStrictUsageObserver(ctx.onUsageSettlement, "settlement");
|
|
8469
|
+
}
|
|
8315
8470
|
let subCtxRef = null;
|
|
8471
|
+
const latchBackgroundUsageFailure = (error) => {
|
|
8472
|
+
if (
|
|
8473
|
+
error?.runtimeLedgerPersistence === true &&
|
|
8474
|
+
ctx.backgroundUsageFailureState &&
|
|
8475
|
+
!ctx.backgroundUsageFailureState.error
|
|
8476
|
+
) {
|
|
8477
|
+
ctx.backgroundUsageFailureState.error = error;
|
|
8478
|
+
}
|
|
8479
|
+
return error;
|
|
8480
|
+
};
|
|
8481
|
+
const projectSubagentUsage = (u) =>
|
|
8482
|
+
u && u.attribution
|
|
8483
|
+
? u
|
|
8484
|
+
: {
|
|
8485
|
+
...u,
|
|
8486
|
+
source:
|
|
8487
|
+
u?.source === "semantic-compaction"
|
|
8488
|
+
? "semantic-compaction"
|
|
8489
|
+
: "subagent",
|
|
8490
|
+
attribution: {
|
|
8491
|
+
origin: "subagent",
|
|
8492
|
+
subagentId: subCtxRef?.id || null,
|
|
8493
|
+
role: subCtxRef?.role || role || null,
|
|
8494
|
+
parentSessionId,
|
|
8495
|
+
depth: currentDepth + 1,
|
|
8496
|
+
},
|
|
8497
|
+
};
|
|
8316
8498
|
const onUsage = usageSink
|
|
8317
8499
|
? (u) => {
|
|
8500
|
+
const forwarded = projectSubagentUsage(u);
|
|
8318
8501
|
try {
|
|
8319
|
-
usageSink.push(
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
origin: "subagent",
|
|
8329
|
-
subagentId: subCtxRef?.id || null,
|
|
8330
|
-
role: subCtxRef?.role || role || null,
|
|
8331
|
-
parentSessionId,
|
|
8332
|
-
depth: currentDepth + 1,
|
|
8333
|
-
},
|
|
8334
|
-
},
|
|
8335
|
-
);
|
|
8336
|
-
} catch (_e) {
|
|
8337
|
-
// usage forwarding is best-effort
|
|
8502
|
+
usageSink.push(forwarded);
|
|
8503
|
+
} catch (error) {
|
|
8504
|
+
if (ctx.strictUsageTelemetry === true) {
|
|
8505
|
+
throw _runtimeUsageBoundaryFailure(
|
|
8506
|
+
error,
|
|
8507
|
+
"CC_USAGE_FORWARDING_FAILED",
|
|
8508
|
+
"Sub-agent usage forwarding failed",
|
|
8509
|
+
);
|
|
8510
|
+
}
|
|
8338
8511
|
}
|
|
8339
8512
|
}
|
|
8340
8513
|
: null;
|
|
8514
|
+
const observeSubagentBoundary =
|
|
8515
|
+
ctx.strictUsageTelemetry === true
|
|
8516
|
+
? (event) => {
|
|
8517
|
+
try {
|
|
8518
|
+
return _notifyStrictUsageBoundary(
|
|
8519
|
+
ctx.onUsageBoundary,
|
|
8520
|
+
projectSubagentUsage(event),
|
|
8521
|
+
);
|
|
8522
|
+
} catch (error) {
|
|
8523
|
+
throw latchBackgroundUsageFailure(error);
|
|
8524
|
+
}
|
|
8525
|
+
}
|
|
8526
|
+
: null;
|
|
8527
|
+
const observeSubagentSettlement =
|
|
8528
|
+
ctx.strictUsageTelemetry === true
|
|
8529
|
+
? (event) => {
|
|
8530
|
+
try {
|
|
8531
|
+
return _notifyStrictUsageSettlement(
|
|
8532
|
+
ctx.onUsageSettlement,
|
|
8533
|
+
projectSubagentUsage(event),
|
|
8534
|
+
);
|
|
8535
|
+
} catch (error) {
|
|
8536
|
+
throw latchBackgroundUsageFailure(error);
|
|
8537
|
+
}
|
|
8538
|
+
}
|
|
8539
|
+
: null;
|
|
8540
|
+
const projectSubagentTool = (event) => ({
|
|
8541
|
+
...event,
|
|
8542
|
+
attribution:
|
|
8543
|
+
event?.attribution || projectSubagentUsage({}).attribution || null,
|
|
8544
|
+
});
|
|
8545
|
+
const observeSubagentToolBoundary =
|
|
8546
|
+
ctx.strictUsageTelemetry === true
|
|
8547
|
+
? (event) => {
|
|
8548
|
+
try {
|
|
8549
|
+
return _notifyStrictToolObserver(
|
|
8550
|
+
ctx.onToolCallBoundary,
|
|
8551
|
+
projectSubagentTool(event),
|
|
8552
|
+
"boundary",
|
|
8553
|
+
);
|
|
8554
|
+
} catch (error) {
|
|
8555
|
+
throw latchBackgroundUsageFailure(error);
|
|
8556
|
+
}
|
|
8557
|
+
}
|
|
8558
|
+
: null;
|
|
8559
|
+
const observeSubagentToolSettlement =
|
|
8560
|
+
ctx.strictUsageTelemetry === true
|
|
8561
|
+
? (event) => {
|
|
8562
|
+
try {
|
|
8563
|
+
return _notifyStrictToolObserver(
|
|
8564
|
+
ctx.onToolCallSettlement,
|
|
8565
|
+
projectSubagentTool(event),
|
|
8566
|
+
"settlement",
|
|
8567
|
+
);
|
|
8568
|
+
} catch (error) {
|
|
8569
|
+
throw latchBackgroundUsageFailure(error);
|
|
8570
|
+
}
|
|
8571
|
+
}
|
|
8572
|
+
: null;
|
|
8573
|
+
if (typeof parentLlm.onStreamRetry === "function") {
|
|
8574
|
+
subLlmOptions.onStreamRetry = (attempt, error, telemetry = {}) => {
|
|
8575
|
+
try {
|
|
8576
|
+
return _notifyStrictRetryObserver(parentLlm.onStreamRetry, [
|
|
8577
|
+
attempt,
|
|
8578
|
+
error,
|
|
8579
|
+
projectSubagentUsage(telemetry),
|
|
8580
|
+
]);
|
|
8581
|
+
} catch (observerError) {
|
|
8582
|
+
throw latchBackgroundUsageFailure(observerError);
|
|
8583
|
+
}
|
|
8584
|
+
};
|
|
8585
|
+
}
|
|
8341
8586
|
|
|
8342
8587
|
// Worktree sparse-checkout + dependency symlink (large-monorepo lever): when
|
|
8343
8588
|
// the child runs in an isolated worktree, only materialize the packages it
|
|
@@ -8393,6 +8638,15 @@ async function _executeSpawnSubAgent(args, ctx) {
|
|
|
8393
8638
|
subAgentBudget: ctx.subAgentBudget || null,
|
|
8394
8639
|
...(ctx.sessionBudget ? { sessionBudget: ctx.sessionBudget } : {}),
|
|
8395
8640
|
onUsage,
|
|
8641
|
+
...(ctx.strictUsageTelemetry === true
|
|
8642
|
+
? {
|
|
8643
|
+
strictUsageTelemetry: true,
|
|
8644
|
+
onUsageBoundary: observeSubagentBoundary,
|
|
8645
|
+
onUsageSettlement: observeSubagentSettlement,
|
|
8646
|
+
onToolCallBoundary: observeSubagentToolBoundary,
|
|
8647
|
+
onToolCallSettlement: observeSubagentToolSettlement,
|
|
8648
|
+
}
|
|
8649
|
+
: {}),
|
|
8396
8650
|
// Extended contract (gap 2026-07-11): per-agent iteration cap + opt-in
|
|
8397
8651
|
// worktree isolation. undefined keeps the profile/flag defaults intact.
|
|
8398
8652
|
...(subMaxTurns ? { maxIterations: subMaxTurns } : {}),
|
|
@@ -8573,7 +8827,13 @@ async function _executeSpawnSubAgent(args, ctx) {
|
|
|
8573
8827
|
(result) => ({ result, error: null }),
|
|
8574
8828
|
(err) => {
|
|
8575
8829
|
subCtx.forceComplete(err.message);
|
|
8576
|
-
return {
|
|
8830
|
+
return {
|
|
8831
|
+
result: subCtx.result,
|
|
8832
|
+
error: err.message,
|
|
8833
|
+
...(err?.runtimeLedgerPersistence === true
|
|
8834
|
+
? { fatalError: err }
|
|
8835
|
+
: {}),
|
|
8836
|
+
};
|
|
8577
8837
|
},
|
|
8578
8838
|
)
|
|
8579
8839
|
.then((outcome) => {
|
|
@@ -8703,6 +8963,8 @@ async function _executeSpawnSubAgent(args, ctx) {
|
|
|
8703
8963
|
completedAt: subCtx.completedAt,
|
|
8704
8964
|
});
|
|
8705
8965
|
|
|
8966
|
+
if (err?.runtimeLedgerPersistence === true) throw err;
|
|
8967
|
+
|
|
8706
8968
|
return {
|
|
8707
8969
|
error: `Sub-agent failed: ${err.message}`,
|
|
8708
8970
|
subAgentId: subCtx.id,
|
|
@@ -8738,6 +9000,49 @@ function getEffectiveToolDefinitions(options = {}) {
|
|
|
8738
9000
|
});
|
|
8739
9001
|
}
|
|
8740
9002
|
|
|
9003
|
+
function _isNonNegativeSafeInteger(value) {
|
|
9004
|
+
return Number.isSafeInteger(value) && value >= 0;
|
|
9005
|
+
}
|
|
9006
|
+
|
|
9007
|
+
function _providerUsageCount(usage, canonical, alias) {
|
|
9008
|
+
if (!usage || typeof usage !== "object" || Array.isArray(usage)) return null;
|
|
9009
|
+
const hasCanonical = Object.prototype.hasOwnProperty.call(usage, canonical);
|
|
9010
|
+
const hasAlias = Object.prototype.hasOwnProperty.call(usage, alias);
|
|
9011
|
+
if (!hasCanonical && !hasAlias) return null;
|
|
9012
|
+
if (hasCanonical && hasAlias && usage[canonical] !== usage[alias])
|
|
9013
|
+
return null;
|
|
9014
|
+
const value = hasCanonical ? usage[canonical] : usage[alias];
|
|
9015
|
+
return _isNonNegativeSafeInteger(value) ? value : null;
|
|
9016
|
+
}
|
|
9017
|
+
|
|
9018
|
+
function _optionalProviderUsageCount(usage, canonical, alias) {
|
|
9019
|
+
if (!usage || typeof usage !== "object" || Array.isArray(usage)) return null;
|
|
9020
|
+
const hasCanonical = Object.prototype.hasOwnProperty.call(usage, canonical);
|
|
9021
|
+
const hasAlias = Object.prototype.hasOwnProperty.call(usage, alias);
|
|
9022
|
+
if (!hasCanonical && !hasAlias) return 0;
|
|
9023
|
+
if (hasCanonical && hasAlias && usage[canonical] !== usage[alias])
|
|
9024
|
+
return null;
|
|
9025
|
+
const value = hasCanonical ? usage[canonical] : usage[alias];
|
|
9026
|
+
return _isNonNegativeSafeInteger(value) ? value : null;
|
|
9027
|
+
}
|
|
9028
|
+
|
|
9029
|
+
function _hasCompleteProviderUsage(usage) {
|
|
9030
|
+
return (
|
|
9031
|
+
_providerUsageCount(usage, "input_tokens", "prompt_tokens") != null &&
|
|
9032
|
+
_providerUsageCount(usage, "output_tokens", "completion_tokens") != null &&
|
|
9033
|
+
_optionalProviderUsageCount(
|
|
9034
|
+
usage,
|
|
9035
|
+
"cache_read_input_tokens",
|
|
9036
|
+
"cache_read_tokens",
|
|
9037
|
+
) != null &&
|
|
9038
|
+
_optionalProviderUsageCount(
|
|
9039
|
+
usage,
|
|
9040
|
+
"cache_creation_input_tokens",
|
|
9041
|
+
"cache_creation_tokens",
|
|
9042
|
+
) != null
|
|
9043
|
+
);
|
|
9044
|
+
}
|
|
9045
|
+
|
|
8741
9046
|
/**
|
|
8742
9047
|
* Send a chat completion request with tool definitions.
|
|
8743
9048
|
* Supports 8 providers: ollama, anthropic, openai, deepseek, dashscope, gemini, mistral, volcengine
|
|
@@ -8801,12 +9106,17 @@ export async function chatWithTools(rawMessages, options) {
|
|
|
8801
9106
|
),
|
|
8802
9107
|
{
|
|
8803
9108
|
signal,
|
|
8804
|
-
|
|
8805
|
-
|
|
8806
|
-
|
|
8807
|
-
|
|
8808
|
-
|
|
8809
|
-
|
|
9109
|
+
strictRetryObserver: options.strictUsageTelemetry === true,
|
|
9110
|
+
...(typeof options.onStreamRetry === "function"
|
|
9111
|
+
? {
|
|
9112
|
+
onRetry: (attempt, error, telemetry) =>
|
|
9113
|
+
options.onStreamRetry(attempt, error, {
|
|
9114
|
+
...telemetry,
|
|
9115
|
+
provider: "ollama",
|
|
9116
|
+
model: model || null,
|
|
9117
|
+
}),
|
|
9118
|
+
}
|
|
9119
|
+
: {}),
|
|
8810
9120
|
},
|
|
8811
9121
|
);
|
|
8812
9122
|
}
|
|
@@ -8828,11 +9138,16 @@ export async function chatWithTools(rawMessages, options) {
|
|
|
8828
9138
|
throw new Error(await formatProviderResponseError("ollama", response));
|
|
8829
9139
|
}
|
|
8830
9140
|
const data = await response.json();
|
|
8831
|
-
if (
|
|
9141
|
+
if (
|
|
9142
|
+
_isNonNegativeSafeInteger(data.prompt_eval_count) &&
|
|
9143
|
+
_isNonNegativeSafeInteger(data.eval_count)
|
|
9144
|
+
) {
|
|
8832
9145
|
data.usage = {
|
|
8833
|
-
input_tokens: data.prompt_eval_count
|
|
8834
|
-
output_tokens: data.eval_count
|
|
9146
|
+
input_tokens: data.prompt_eval_count,
|
|
9147
|
+
output_tokens: data.eval_count,
|
|
8835
9148
|
};
|
|
9149
|
+
} else {
|
|
9150
|
+
delete data.usage;
|
|
8836
9151
|
}
|
|
8837
9152
|
return data;
|
|
8838
9153
|
}
|
|
@@ -8940,12 +9255,17 @@ export async function chatWithTools(rawMessages, options) {
|
|
|
8940
9255
|
),
|
|
8941
9256
|
{
|
|
8942
9257
|
signal,
|
|
8943
|
-
|
|
8944
|
-
|
|
8945
|
-
|
|
8946
|
-
|
|
8947
|
-
|
|
8948
|
-
|
|
9258
|
+
strictRetryObserver: options.strictUsageTelemetry === true,
|
|
9259
|
+
...(typeof options.onStreamRetry === "function"
|
|
9260
|
+
? {
|
|
9261
|
+
onRetry: (attempt, error, telemetry) =>
|
|
9262
|
+
options.onStreamRetry(attempt, error, {
|
|
9263
|
+
...telemetry,
|
|
9264
|
+
provider: "anthropic",
|
|
9265
|
+
model: effModel,
|
|
9266
|
+
}),
|
|
9267
|
+
}
|
|
9268
|
+
: {}),
|
|
8949
9269
|
},
|
|
8950
9270
|
);
|
|
8951
9271
|
}
|
|
@@ -8967,17 +9287,32 @@ export async function chatWithTools(rawMessages, options) {
|
|
|
8967
9287
|
|
|
8968
9288
|
const data = await response.json();
|
|
8969
9289
|
const normalized = _normalizeAnthropicResponse(data);
|
|
8970
|
-
if (data.usage) {
|
|
9290
|
+
if (_hasCompleteProviderUsage(data.usage)) {
|
|
8971
9291
|
normalized.usage = {
|
|
8972
9292
|
// With prompt caching, Anthropic splits input into uncached
|
|
8973
9293
|
// `input_tokens` + cache read/write — capture all three so cost
|
|
8974
9294
|
// accounting prices the cached prefix correctly (read ≈ 0.1×,
|
|
8975
9295
|
// write ≈ 1.25× input). Absent (caching off) → 0, byte-identical.
|
|
8976
|
-
input_tokens:
|
|
8977
|
-
|
|
8978
|
-
|
|
8979
|
-
|
|
8980
|
-
|
|
9296
|
+
input_tokens: _providerUsageCount(
|
|
9297
|
+
data.usage,
|
|
9298
|
+
"input_tokens",
|
|
9299
|
+
"prompt_tokens",
|
|
9300
|
+
),
|
|
9301
|
+
output_tokens: _providerUsageCount(
|
|
9302
|
+
data.usage,
|
|
9303
|
+
"output_tokens",
|
|
9304
|
+
"completion_tokens",
|
|
9305
|
+
),
|
|
9306
|
+
cache_read_input_tokens: _optionalProviderUsageCount(
|
|
9307
|
+
data.usage,
|
|
9308
|
+
"cache_read_input_tokens",
|
|
9309
|
+
"cache_read_tokens",
|
|
9310
|
+
),
|
|
9311
|
+
cache_creation_input_tokens: _optionalProviderUsageCount(
|
|
9312
|
+
data.usage,
|
|
9313
|
+
"cache_creation_input_tokens",
|
|
9314
|
+
"cache_creation_tokens",
|
|
9315
|
+
),
|
|
8981
9316
|
};
|
|
8982
9317
|
}
|
|
8983
9318
|
return normalized;
|
|
@@ -9055,12 +9390,17 @@ export async function chatWithTools(rawMessages, options) {
|
|
|
9055
9390
|
),
|
|
9056
9391
|
{
|
|
9057
9392
|
signal,
|
|
9058
|
-
|
|
9059
|
-
|
|
9060
|
-
|
|
9061
|
-
|
|
9062
|
-
|
|
9063
|
-
|
|
9393
|
+
strictRetryObserver: options.strictUsageTelemetry === true,
|
|
9394
|
+
...(typeof options.onStreamRetry === "function"
|
|
9395
|
+
? {
|
|
9396
|
+
onRetry: (attempt, error, telemetry) =>
|
|
9397
|
+
options.onStreamRetry(attempt, error, {
|
|
9398
|
+
...telemetry,
|
|
9399
|
+
provider,
|
|
9400
|
+
model: model || defaultModels[provider] || "gpt-4o-mini",
|
|
9401
|
+
}),
|
|
9402
|
+
}
|
|
9403
|
+
: {}),
|
|
9064
9404
|
},
|
|
9065
9405
|
);
|
|
9066
9406
|
}
|
|
@@ -9092,16 +9432,28 @@ export async function chatWithTools(rawMessages, options) {
|
|
|
9092
9432
|
}
|
|
9093
9433
|
const choice = data.choices[0];
|
|
9094
9434
|
const out = { message: choice.message };
|
|
9095
|
-
if (data.usage) {
|
|
9435
|
+
if (_hasCompleteProviderUsage(data.usage)) {
|
|
9096
9436
|
// OpenAI/DeepSeek/volcengine report cached prompt tokens AS PART of
|
|
9097
9437
|
// prompt_tokens — split them out so cost prices the cached prefix at the
|
|
9098
9438
|
// provider's cache rate, not full input. 0 (or absent) → input unchanged.
|
|
9439
|
+
const promptTokens = _providerUsageCount(
|
|
9440
|
+
data.usage,
|
|
9441
|
+
"input_tokens",
|
|
9442
|
+
"prompt_tokens",
|
|
9443
|
+
);
|
|
9444
|
+
const completionTokens = _providerUsageCount(
|
|
9445
|
+
data.usage,
|
|
9446
|
+
"output_tokens",
|
|
9447
|
+
"completion_tokens",
|
|
9448
|
+
);
|
|
9099
9449
|
const cached = _openaiCachedTokens(data.usage);
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9450
|
+
if (cached != null && cached <= promptTokens) {
|
|
9451
|
+
out.usage = {
|
|
9452
|
+
input_tokens: promptTokens - cached,
|
|
9453
|
+
output_tokens: completionTokens,
|
|
9454
|
+
cache_read_input_tokens: cached,
|
|
9455
|
+
};
|
|
9456
|
+
}
|
|
9105
9457
|
}
|
|
9106
9458
|
return out;
|
|
9107
9459
|
}
|
|
@@ -9120,8 +9472,9 @@ function _ollamaInitState() {
|
|
|
9120
9472
|
role: "assistant",
|
|
9121
9473
|
content: "",
|
|
9122
9474
|
toolCalls: null,
|
|
9123
|
-
promptEval:
|
|
9124
|
-
evalCount:
|
|
9475
|
+
promptEval: null,
|
|
9476
|
+
evalCount: null,
|
|
9477
|
+
usageInvalid: false,
|
|
9125
9478
|
};
|
|
9126
9479
|
}
|
|
9127
9480
|
|
|
@@ -9187,8 +9540,20 @@ function _ollamaReduceLine(state, line, onToken) {
|
|
|
9187
9540
|
state.toolCalls = (state.toolCalls || []).concat(msg.tool_calls);
|
|
9188
9541
|
}
|
|
9189
9542
|
}
|
|
9190
|
-
if (obj
|
|
9191
|
-
|
|
9543
|
+
if (Object.prototype.hasOwnProperty.call(obj, "prompt_eval_count")) {
|
|
9544
|
+
if (_isNonNegativeSafeInteger(obj.prompt_eval_count)) {
|
|
9545
|
+
state.promptEval = obj.prompt_eval_count;
|
|
9546
|
+
} else {
|
|
9547
|
+
state.usageInvalid = true;
|
|
9548
|
+
}
|
|
9549
|
+
}
|
|
9550
|
+
if (Object.prototype.hasOwnProperty.call(obj, "eval_count")) {
|
|
9551
|
+
if (_isNonNegativeSafeInteger(obj.eval_count)) {
|
|
9552
|
+
state.evalCount = obj.eval_count;
|
|
9553
|
+
} else {
|
|
9554
|
+
state.usageInvalid = true;
|
|
9555
|
+
}
|
|
9556
|
+
}
|
|
9192
9557
|
return state;
|
|
9193
9558
|
}
|
|
9194
9559
|
|
|
@@ -9198,7 +9563,11 @@ function _ollamaFinalize(state) {
|
|
|
9198
9563
|
message.tool_calls = state.toolCalls;
|
|
9199
9564
|
}
|
|
9200
9565
|
const data = { message };
|
|
9201
|
-
if (
|
|
9566
|
+
if (
|
|
9567
|
+
state.usageInvalid !== true &&
|
|
9568
|
+
_isNonNegativeSafeInteger(state.promptEval) &&
|
|
9569
|
+
_isNonNegativeSafeInteger(state.evalCount)
|
|
9570
|
+
) {
|
|
9202
9571
|
data.usage = {
|
|
9203
9572
|
input_tokens: state.promptEval,
|
|
9204
9573
|
output_tokens: state.evalCount,
|
|
@@ -9291,7 +9660,7 @@ const _STREAM_STALL = Symbol("stream-stall");
|
|
|
9291
9660
|
* last error — strictly better than today (one drop → instant error).
|
|
9292
9661
|
*
|
|
9293
9662
|
* @param {() => Promise<any>} streamFn invokes one `_chat*Streaming` attempt
|
|
9294
|
-
* @param {object} opts { signal?, retries?, baseDelayMs?, onRetry?, sleep? }
|
|
9663
|
+
* @param {object} opts { signal?, retries?, baseDelayMs?, onRetry?, strictRetryObserver?, sleep? }
|
|
9295
9664
|
*/
|
|
9296
9665
|
export async function _retryStreamingChat(streamFn, opts = {}) {
|
|
9297
9666
|
// Default budget honors CC_MAX_RETRIES / CLAUDE_CODE_MAX_RETRIES (capped 15);
|
|
@@ -9310,13 +9679,46 @@ export async function _retryStreamingChat(streamFn, opts = {}) {
|
|
|
9310
9679
|
if (attempt >= retries || !_isRetryableStreamError(err, signal))
|
|
9311
9680
|
throw err;
|
|
9312
9681
|
attempt++;
|
|
9682
|
+
if (
|
|
9683
|
+
opts.strictRetryObserver === true &&
|
|
9684
|
+
typeof opts.onRetry !== "function"
|
|
9685
|
+
) {
|
|
9686
|
+
throw _runtimeUsageBoundaryFailure(
|
|
9687
|
+
null,
|
|
9688
|
+
"CC_RETRY_OBSERVER_REQUIRED",
|
|
9689
|
+
"Strict streaming retry requires a synchronous persistence observer",
|
|
9690
|
+
);
|
|
9691
|
+
}
|
|
9313
9692
|
if (typeof opts.onRetry === "function") {
|
|
9314
9693
|
try {
|
|
9315
|
-
opts.onRetry(attempt, err, {
|
|
9694
|
+
const observation = opts.onRetry(attempt, err, {
|
|
9316
9695
|
durationMs: Math.max(0, now() - attemptStartedAt),
|
|
9317
9696
|
});
|
|
9318
|
-
|
|
9319
|
-
|
|
9697
|
+
if (observation && typeof observation.then === "function") {
|
|
9698
|
+
void Promise.resolve(observation).catch(() => {});
|
|
9699
|
+
if (opts.strictRetryObserver === true) {
|
|
9700
|
+
const observerError = new Error(
|
|
9701
|
+
"Strict retry observer must be synchronous",
|
|
9702
|
+
);
|
|
9703
|
+
observerError.code = "CC_RETRY_OBSERVER_ASYNC";
|
|
9704
|
+
throw observerError;
|
|
9705
|
+
}
|
|
9706
|
+
}
|
|
9707
|
+
} catch (observerError) {
|
|
9708
|
+
// A persisted usage ledger must record the failed attempt before a
|
|
9709
|
+
// second billable transport attempt starts. Strict hosts opt into a
|
|
9710
|
+
// fail-closed observer; legacy/unpersisted callers retain the former
|
|
9711
|
+
// best-effort notification behavior.
|
|
9712
|
+
if (
|
|
9713
|
+
opts.strictRetryObserver === true ||
|
|
9714
|
+
observerError?.code === "CC_SESSION_PERSISTENCE_FAILED"
|
|
9715
|
+
) {
|
|
9716
|
+
throw _runtimeUsageBoundaryFailure(
|
|
9717
|
+
observerError,
|
|
9718
|
+
observerError?.code || "CC_RETRY_PERSISTENCE_FAILED",
|
|
9719
|
+
"Streaming retry persistence failed",
|
|
9720
|
+
);
|
|
9721
|
+
}
|
|
9320
9722
|
}
|
|
9321
9723
|
}
|
|
9322
9724
|
await sleep(base * Math.pow(2, attempt - 1));
|
|
@@ -9488,10 +9890,11 @@ function _anthropicInitState() {
|
|
|
9488
9890
|
return {
|
|
9489
9891
|
text: "",
|
|
9490
9892
|
blocks: {},
|
|
9491
|
-
inputTokens:
|
|
9492
|
-
outputTokens:
|
|
9893
|
+
inputTokens: null,
|
|
9894
|
+
outputTokens: null,
|
|
9493
9895
|
cacheReadTokens: 0,
|
|
9494
9896
|
cacheCreationTokens: 0,
|
|
9897
|
+
usageInvalid: false,
|
|
9495
9898
|
};
|
|
9496
9899
|
}
|
|
9497
9900
|
|
|
@@ -9507,13 +9910,35 @@ function _anthropicReduceLine(state, raw, onToken, onThinking) {
|
|
|
9507
9910
|
return state;
|
|
9508
9911
|
}
|
|
9509
9912
|
if (obj.type === "message_start") {
|
|
9510
|
-
const
|
|
9511
|
-
|
|
9512
|
-
|
|
9513
|
-
|
|
9514
|
-
|
|
9515
|
-
|
|
9516
|
-
|
|
9913
|
+
const usage = obj.message?.usage;
|
|
9914
|
+
if (usage != null) {
|
|
9915
|
+
const inputTokens = _providerUsageCount(
|
|
9916
|
+
usage,
|
|
9917
|
+
"input_tokens",
|
|
9918
|
+
"prompt_tokens",
|
|
9919
|
+
);
|
|
9920
|
+
const cacheReadTokens = _optionalProviderUsageCount(
|
|
9921
|
+
usage,
|
|
9922
|
+
"cache_read_input_tokens",
|
|
9923
|
+
"cache_read_tokens",
|
|
9924
|
+
);
|
|
9925
|
+
const cacheCreationTokens = _optionalProviderUsageCount(
|
|
9926
|
+
usage,
|
|
9927
|
+
"cache_creation_input_tokens",
|
|
9928
|
+
"cache_creation_tokens",
|
|
9929
|
+
);
|
|
9930
|
+
if (
|
|
9931
|
+
inputTokens == null ||
|
|
9932
|
+
cacheReadTokens == null ||
|
|
9933
|
+
cacheCreationTokens == null
|
|
9934
|
+
) {
|
|
9935
|
+
state.usageInvalid = true;
|
|
9936
|
+
} else {
|
|
9937
|
+
state.inputTokens = inputTokens;
|
|
9938
|
+
state.cacheReadTokens = cacheReadTokens;
|
|
9939
|
+
state.cacheCreationTokens = cacheCreationTokens;
|
|
9940
|
+
}
|
|
9941
|
+
}
|
|
9517
9942
|
} else if (obj.type === "content_block_start") {
|
|
9518
9943
|
const cb = obj.content_block || {};
|
|
9519
9944
|
state.blocks[obj.index] =
|
|
@@ -9552,7 +9977,18 @@ function _anthropicReduceLine(state, raw, onToken, onThinking) {
|
|
|
9552
9977
|
(state.blocks[obj.index].signature || "") + (d.signature || "");
|
|
9553
9978
|
}
|
|
9554
9979
|
} else if (obj.type === "message_delta") {
|
|
9555
|
-
|
|
9980
|
+
if (obj.usage != null) {
|
|
9981
|
+
const outputTokens = _providerUsageCount(
|
|
9982
|
+
obj.usage,
|
|
9983
|
+
"output_tokens",
|
|
9984
|
+
"completion_tokens",
|
|
9985
|
+
);
|
|
9986
|
+
if (outputTokens == null) {
|
|
9987
|
+
state.usageInvalid = true;
|
|
9988
|
+
} else {
|
|
9989
|
+
state.outputTokens = outputTokens;
|
|
9990
|
+
}
|
|
9991
|
+
}
|
|
9556
9992
|
}
|
|
9557
9993
|
return state;
|
|
9558
9994
|
}
|
|
@@ -9593,10 +10029,9 @@ function _anthropicFinalize(state) {
|
|
|
9593
10029
|
if (thinkingBlocks.length) message._thinkingBlocks = thinkingBlocks;
|
|
9594
10030
|
const out = { message };
|
|
9595
10031
|
if (
|
|
9596
|
-
state.
|
|
9597
|
-
state.
|
|
9598
|
-
state.
|
|
9599
|
-
state.cacheCreationTokens
|
|
10032
|
+
state.usageInvalid !== true &&
|
|
10033
|
+
_isNonNegativeSafeInteger(state.inputTokens) &&
|
|
10034
|
+
_isNonNegativeSafeInteger(state.outputTokens)
|
|
9600
10035
|
) {
|
|
9601
10036
|
out.usage = {
|
|
9602
10037
|
input_tokens: state.inputTokens,
|
|
@@ -9682,21 +10117,49 @@ async function _chatAnthropicStreaming(
|
|
|
9682
10117
|
// cached prefix twice. Verified live against volcengine (field present, 0 when
|
|
9683
10118
|
// the provider does not auto-cache).
|
|
9684
10119
|
function _openaiCachedTokens(usage) {
|
|
9685
|
-
if (!usage || typeof usage !== "object") return
|
|
9686
|
-
const
|
|
9687
|
-
|
|
9688
|
-
|
|
9689
|
-
|
|
9690
|
-
|
|
10120
|
+
if (!usage || typeof usage !== "object" || Array.isArray(usage)) return null;
|
|
10121
|
+
const candidates = [];
|
|
10122
|
+
const hasDirect =
|
|
10123
|
+
Object.prototype.hasOwnProperty.call(usage, "cache_read_input_tokens") ||
|
|
10124
|
+
Object.prototype.hasOwnProperty.call(usage, "cache_read_tokens");
|
|
10125
|
+
if (hasDirect) {
|
|
10126
|
+
const direct = _optionalProviderUsageCount(
|
|
10127
|
+
usage,
|
|
10128
|
+
"cache_read_input_tokens",
|
|
10129
|
+
"cache_read_tokens",
|
|
10130
|
+
);
|
|
10131
|
+
if (direct == null) return null;
|
|
10132
|
+
candidates.push(direct);
|
|
10133
|
+
}
|
|
10134
|
+
|
|
10135
|
+
if (Object.prototype.hasOwnProperty.call(usage, "prompt_tokens_details")) {
|
|
10136
|
+
const details = usage.prompt_tokens_details;
|
|
10137
|
+
if (!details || typeof details !== "object" || Array.isArray(details)) {
|
|
10138
|
+
return null;
|
|
10139
|
+
}
|
|
10140
|
+
if (Object.prototype.hasOwnProperty.call(details, "cached_tokens")) {
|
|
10141
|
+
if (!_isNonNegativeSafeInteger(details.cached_tokens)) return null;
|
|
10142
|
+
candidates.push(details.cached_tokens);
|
|
10143
|
+
}
|
|
10144
|
+
}
|
|
10145
|
+
|
|
10146
|
+
if (Object.prototype.hasOwnProperty.call(usage, "prompt_cache_hit_tokens")) {
|
|
10147
|
+
if (!_isNonNegativeSafeInteger(usage.prompt_cache_hit_tokens)) return null;
|
|
10148
|
+
candidates.push(usage.prompt_cache_hit_tokens);
|
|
10149
|
+
}
|
|
10150
|
+
|
|
10151
|
+
if (candidates.some((value) => value !== candidates[0])) return null;
|
|
10152
|
+
return candidates[0] ?? 0;
|
|
9691
10153
|
}
|
|
9692
10154
|
|
|
9693
10155
|
function _openaiInitState() {
|
|
9694
10156
|
return {
|
|
9695
10157
|
text: "",
|
|
9696
10158
|
tools: [],
|
|
9697
|
-
inputTokens:
|
|
9698
|
-
outputTokens:
|
|
10159
|
+
inputTokens: null,
|
|
10160
|
+
outputTokens: null,
|
|
9699
10161
|
cacheReadTokens: 0,
|
|
10162
|
+
usageInvalid: false,
|
|
9700
10163
|
};
|
|
9701
10164
|
}
|
|
9702
10165
|
|
|
@@ -9733,14 +10196,26 @@ function _openaiReduceLine(state, raw, onToken) {
|
|
|
9733
10196
|
state.tools[idx].args += tc.function.arguments;
|
|
9734
10197
|
}
|
|
9735
10198
|
}
|
|
9736
|
-
if (obj.usage) {
|
|
10199
|
+
if (obj.usage != null) {
|
|
10200
|
+
const usage = obj.usage;
|
|
10201
|
+
const prompt = _providerUsageCount(usage, "input_tokens", "prompt_tokens");
|
|
10202
|
+
const completion = _providerUsageCount(
|
|
10203
|
+
usage,
|
|
10204
|
+
"output_tokens",
|
|
10205
|
+
"completion_tokens",
|
|
10206
|
+
);
|
|
9737
10207
|
const cached = _openaiCachedTokens(obj.usage);
|
|
9738
|
-
|
|
9739
|
-
|
|
10208
|
+
if (
|
|
10209
|
+
!_hasCompleteProviderUsage(usage) ||
|
|
10210
|
+
cached == null ||
|
|
10211
|
+
cached > prompt
|
|
10212
|
+
) {
|
|
10213
|
+
state.usageInvalid = true;
|
|
10214
|
+
} else {
|
|
9740
10215
|
state.inputTokens = Math.max(0, prompt - cached);
|
|
9741
|
-
|
|
9742
|
-
|
|
9743
|
-
|
|
10216
|
+
state.outputTokens = completion;
|
|
10217
|
+
state.cacheReadTokens = cached;
|
|
10218
|
+
}
|
|
9744
10219
|
}
|
|
9745
10220
|
return state;
|
|
9746
10221
|
}
|
|
@@ -9754,11 +10229,15 @@ function _openaiFinalize(state) {
|
|
|
9754
10229
|
const message = { role: "assistant", content: state.text };
|
|
9755
10230
|
if (toolCalls.length) message.tool_calls = toolCalls;
|
|
9756
10231
|
const out = { message };
|
|
9757
|
-
if (
|
|
10232
|
+
if (
|
|
10233
|
+
state.usageInvalid !== true &&
|
|
10234
|
+
_isNonNegativeSafeInteger(state.inputTokens) &&
|
|
10235
|
+
_isNonNegativeSafeInteger(state.outputTokens)
|
|
10236
|
+
) {
|
|
9758
10237
|
out.usage = {
|
|
9759
10238
|
input_tokens: state.inputTokens,
|
|
9760
10239
|
output_tokens: state.outputTokens,
|
|
9761
|
-
cache_read_input_tokens: state.cacheReadTokens
|
|
10240
|
+
cache_read_input_tokens: state.cacheReadTokens,
|
|
9762
10241
|
};
|
|
9763
10242
|
}
|
|
9764
10243
|
return out;
|
|
@@ -10118,11 +10597,293 @@ function _managedCheckpointUncoveredWriterReason(toolContext) {
|
|
|
10118
10597
|
* { type: "checkpoint", id, tool } — auto-checkpoint before a mutating tool
|
|
10119
10598
|
* { type: "tool-executing", tool, args }
|
|
10120
10599
|
* { type: "tool-result", tool, result, error }
|
|
10600
|
+
* { type: "model-usage-started", callId, provider, model, source }
|
|
10601
|
+
* { type: "token-usage", callId, provider, model, usage, source? }
|
|
10602
|
+
* { type: "model-usage-unknown", callId, provider, model, source, code }
|
|
10121
10603
|
* { type: "response-complete", content }
|
|
10122
10604
|
*
|
|
10123
10605
|
* @param {Array} messages - mutable messages array (will be appended to)
|
|
10124
10606
|
* @param {object} options - provider, model, baseUrl, apiKey, contextEngine, hookDb, skillLoader, cwd, slotFiller, interaction
|
|
10125
10607
|
*/
|
|
10608
|
+
const _autoCompactionUsageStates = new WeakMap();
|
|
10609
|
+
const _autoCompactorInstrumentation = new WeakMap();
|
|
10610
|
+
|
|
10611
|
+
function _newModelUsageCallId(source = "model") {
|
|
10612
|
+
// UUIDs are generated locally and contain no session/run/user material. The
|
|
10613
|
+
// fixed prefixes keep the identifier useful in diagnostics while remaining
|
|
10614
|
+
// far below the persisted ledger's 128-character ceiling.
|
|
10615
|
+
const prefix =
|
|
10616
|
+
source === "semantic-compaction"
|
|
10617
|
+
? "cmp"
|
|
10618
|
+
: source === "subagent"
|
|
10619
|
+
? "sub"
|
|
10620
|
+
: "mdl";
|
|
10621
|
+
return `${prefix}-${randomUUID()}`;
|
|
10622
|
+
}
|
|
10623
|
+
|
|
10624
|
+
function _runtimeUsageBoundaryFailure(error, code, fallbackMessage) {
|
|
10625
|
+
const failure =
|
|
10626
|
+
error && (typeof error === "object" || typeof error === "function")
|
|
10627
|
+
? error
|
|
10628
|
+
: new Error(fallbackMessage);
|
|
10629
|
+
try {
|
|
10630
|
+
failure.runtimeLedgerPersistence = true;
|
|
10631
|
+
if (!failure.code && code) failure.code = code;
|
|
10632
|
+
} catch {
|
|
10633
|
+
const wrapped = new Error(fallbackMessage, { cause: error });
|
|
10634
|
+
wrapped.runtimeLedgerPersistence = true;
|
|
10635
|
+
wrapped.code = code;
|
|
10636
|
+
return wrapped;
|
|
10637
|
+
}
|
|
10638
|
+
return failure;
|
|
10639
|
+
}
|
|
10640
|
+
|
|
10641
|
+
/**
|
|
10642
|
+
* Strict child loops are consumed inside executeTool, so their yielded model
|
|
10643
|
+
* boundaries cannot reach the parent host before provider work. Require the
|
|
10644
|
+
* parent's synchronous persistence observer and prewrite one conservative
|
|
10645
|
+
* subagent call. The matching unknown event is forwarded after child settlement.
|
|
10646
|
+
*/
|
|
10647
|
+
function _notifyStrictUsageBoundary(observer, boundary) {
|
|
10648
|
+
if (typeof observer !== "function") {
|
|
10649
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10650
|
+
null,
|
|
10651
|
+
"CC_USAGE_BOUNDARY_OBSERVER_REQUIRED",
|
|
10652
|
+
"Strict child usage telemetry requires a synchronous boundary observer",
|
|
10653
|
+
);
|
|
10654
|
+
}
|
|
10655
|
+
let observation;
|
|
10656
|
+
try {
|
|
10657
|
+
observation = observer(boundary);
|
|
10658
|
+
} catch (error) {
|
|
10659
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10660
|
+
error,
|
|
10661
|
+
"CC_USAGE_BOUNDARY_PERSISTENCE_FAILED",
|
|
10662
|
+
"Child usage boundary persistence failed",
|
|
10663
|
+
);
|
|
10664
|
+
}
|
|
10665
|
+
let isThenable = false;
|
|
10666
|
+
try {
|
|
10667
|
+
isThenable = Boolean(observation && typeof observation.then === "function");
|
|
10668
|
+
} catch (error) {
|
|
10669
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10670
|
+
error,
|
|
10671
|
+
"CC_USAGE_BOUNDARY_OBSERVER_ASYNC",
|
|
10672
|
+
"Child usage boundary observer must be synchronous",
|
|
10673
|
+
);
|
|
10674
|
+
}
|
|
10675
|
+
if (isThenable) {
|
|
10676
|
+
void Promise.resolve(observation).catch(() => {});
|
|
10677
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10678
|
+
null,
|
|
10679
|
+
"CC_USAGE_BOUNDARY_OBSERVER_ASYNC",
|
|
10680
|
+
"Child usage boundary observer must be synchronous",
|
|
10681
|
+
);
|
|
10682
|
+
}
|
|
10683
|
+
}
|
|
10684
|
+
|
|
10685
|
+
function _notifyStrictUsageSettlement(observer, settlement) {
|
|
10686
|
+
if (typeof observer !== "function") {
|
|
10687
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10688
|
+
null,
|
|
10689
|
+
"CC_USAGE_SETTLEMENT_OBSERVER_REQUIRED",
|
|
10690
|
+
"Strict child usage telemetry requires a synchronous settlement observer",
|
|
10691
|
+
);
|
|
10692
|
+
}
|
|
10693
|
+
let observation;
|
|
10694
|
+
try {
|
|
10695
|
+
observation = observer(settlement);
|
|
10696
|
+
} catch (error) {
|
|
10697
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10698
|
+
error,
|
|
10699
|
+
"CC_USAGE_SETTLEMENT_PERSISTENCE_FAILED",
|
|
10700
|
+
"Child usage settlement persistence failed",
|
|
10701
|
+
);
|
|
10702
|
+
}
|
|
10703
|
+
let isThenable = false;
|
|
10704
|
+
try {
|
|
10705
|
+
isThenable = Boolean(observation && typeof observation.then === "function");
|
|
10706
|
+
} catch (error) {
|
|
10707
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10708
|
+
error,
|
|
10709
|
+
"CC_USAGE_SETTLEMENT_OBSERVER_ASYNC",
|
|
10710
|
+
"Child usage settlement observer must be synchronous",
|
|
10711
|
+
);
|
|
10712
|
+
}
|
|
10713
|
+
if (isThenable) {
|
|
10714
|
+
void Promise.resolve(observation).catch(() => {});
|
|
10715
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10716
|
+
null,
|
|
10717
|
+
"CC_USAGE_SETTLEMENT_OBSERVER_ASYNC",
|
|
10718
|
+
"Child usage settlement observer must be synchronous",
|
|
10719
|
+
);
|
|
10720
|
+
}
|
|
10721
|
+
}
|
|
10722
|
+
|
|
10723
|
+
function _notifyStrictToolObserver(observer, event, phase) {
|
|
10724
|
+
const upper = phase.toUpperCase();
|
|
10725
|
+
if (typeof observer !== "function") {
|
|
10726
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10727
|
+
null,
|
|
10728
|
+
`CC_TOOL_${upper}_OBSERVER_REQUIRED`,
|
|
10729
|
+
`Strict child tool ${phase} requires a synchronous persistence observer`,
|
|
10730
|
+
);
|
|
10731
|
+
}
|
|
10732
|
+
let observation;
|
|
10733
|
+
try {
|
|
10734
|
+
observation = observer(event);
|
|
10735
|
+
} catch (error) {
|
|
10736
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10737
|
+
error,
|
|
10738
|
+
`CC_TOOL_${upper}_PERSISTENCE_FAILED`,
|
|
10739
|
+
`Child tool ${phase} persistence failed`,
|
|
10740
|
+
);
|
|
10741
|
+
}
|
|
10742
|
+
if (observation && typeof observation.then === "function") {
|
|
10743
|
+
void Promise.resolve(observation).catch(() => {});
|
|
10744
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10745
|
+
null,
|
|
10746
|
+
`CC_TOOL_${upper}_OBSERVER_ASYNC`,
|
|
10747
|
+
`Child tool ${phase} observer must be synchronous`,
|
|
10748
|
+
);
|
|
10749
|
+
}
|
|
10750
|
+
}
|
|
10751
|
+
|
|
10752
|
+
function _notifyStrictRetryObserver(observer, args) {
|
|
10753
|
+
if (typeof observer !== "function") {
|
|
10754
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10755
|
+
null,
|
|
10756
|
+
"CC_RETRY_OBSERVER_REQUIRED",
|
|
10757
|
+
"Strict child streaming retry requires a synchronous persistence observer",
|
|
10758
|
+
);
|
|
10759
|
+
}
|
|
10760
|
+
let observation;
|
|
10761
|
+
try {
|
|
10762
|
+
observation = observer(...args);
|
|
10763
|
+
} catch (error) {
|
|
10764
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10765
|
+
error,
|
|
10766
|
+
"CC_RETRY_PERSISTENCE_FAILED",
|
|
10767
|
+
"Child streaming retry persistence failed",
|
|
10768
|
+
);
|
|
10769
|
+
}
|
|
10770
|
+
if (observation && typeof observation.then === "function") {
|
|
10771
|
+
void Promise.resolve(observation).catch(() => {});
|
|
10772
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10773
|
+
null,
|
|
10774
|
+
"CC_RETRY_OBSERVER_ASYNC",
|
|
10775
|
+
"Child streaming retry observer must be synchronous",
|
|
10776
|
+
);
|
|
10777
|
+
}
|
|
10778
|
+
}
|
|
10779
|
+
|
|
10780
|
+
function _assertStrictUsageObserver(observer, phase) {
|
|
10781
|
+
if (typeof observer !== "function") {
|
|
10782
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10783
|
+
null,
|
|
10784
|
+
`CC_USAGE_${phase.toUpperCase()}_OBSERVER_REQUIRED`,
|
|
10785
|
+
`Strict child usage telemetry requires a synchronous ${phase} observer`,
|
|
10786
|
+
);
|
|
10787
|
+
}
|
|
10788
|
+
}
|
|
10789
|
+
|
|
10790
|
+
function _autoCompactionUsageState(options) {
|
|
10791
|
+
let state = _autoCompactionUsageStates.get(options);
|
|
10792
|
+
if (!state) {
|
|
10793
|
+
state = { calls: [] };
|
|
10794
|
+
_autoCompactionUsageStates.set(options, state);
|
|
10795
|
+
}
|
|
10796
|
+
return state;
|
|
10797
|
+
}
|
|
10798
|
+
|
|
10799
|
+
/**
|
|
10800
|
+
* Wrap only the compressor's actual provider-query seam. `shouldAutoCompact`,
|
|
10801
|
+
* microcompact, and extractive/count-only compaction never enter this wrapper,
|
|
10802
|
+
* so they cannot manufacture a billable-call boundary.
|
|
10803
|
+
*/
|
|
10804
|
+
function _instrumentAutoCompactorUsage(compactor, options) {
|
|
10805
|
+
if (!compactor || typeof compactor.llmQuery !== "function") return compactor;
|
|
10806
|
+
const installed = _autoCompactorInstrumentation.get(compactor);
|
|
10807
|
+
if (
|
|
10808
|
+
installed?.options === options &&
|
|
10809
|
+
compactor.llmQuery === installed.wrapper
|
|
10810
|
+
) {
|
|
10811
|
+
return compactor;
|
|
10812
|
+
}
|
|
10813
|
+
|
|
10814
|
+
const original = installed?.original || compactor.llmQuery;
|
|
10815
|
+
const state = _autoCompactionUsageState(options);
|
|
10816
|
+
const wrapper = async function instrumentedCompactionQuery(...args) {
|
|
10817
|
+
const call = {
|
|
10818
|
+
callId: _newModelUsageCallId("semantic-compaction"),
|
|
10819
|
+
provider: options.provider || null,
|
|
10820
|
+
model: options.model || null,
|
|
10821
|
+
source: "semantic-compaction",
|
|
10822
|
+
observerError: null,
|
|
10823
|
+
observerFailed: false,
|
|
10824
|
+
boundaryNotified: false,
|
|
10825
|
+
};
|
|
10826
|
+
state.calls.push(call);
|
|
10827
|
+
try {
|
|
10828
|
+
if (typeof options.onUsageBoundary === "function") {
|
|
10829
|
+
// Synchronous and before `original`: a host can durably append the
|
|
10830
|
+
// start row, and any append failure prevents provider spend.
|
|
10831
|
+
const observation = options.onUsageBoundary({
|
|
10832
|
+
type: "model-usage-started",
|
|
10833
|
+
callId: call.callId,
|
|
10834
|
+
provider: call.provider,
|
|
10835
|
+
model: call.model,
|
|
10836
|
+
source: call.source,
|
|
10837
|
+
});
|
|
10838
|
+
if (observation && typeof observation.then === "function") {
|
|
10839
|
+
void Promise.resolve(observation).catch(() => {});
|
|
10840
|
+
const error = new Error(
|
|
10841
|
+
"Automatic compaction usage boundary observer must be synchronous",
|
|
10842
|
+
);
|
|
10843
|
+
error.code = "CC_USAGE_BOUNDARY_OBSERVER_ASYNC";
|
|
10844
|
+
throw error;
|
|
10845
|
+
}
|
|
10846
|
+
call.boundaryNotified = true;
|
|
10847
|
+
}
|
|
10848
|
+
} catch (error) {
|
|
10849
|
+
call.observerError = error;
|
|
10850
|
+
call.observerFailed = true;
|
|
10851
|
+
throw error;
|
|
10852
|
+
}
|
|
10853
|
+
|
|
10854
|
+
return await original.apply(this, args);
|
|
10855
|
+
};
|
|
10856
|
+
|
|
10857
|
+
try {
|
|
10858
|
+
compactor.llmQuery = wrapper;
|
|
10859
|
+
} catch (error) {
|
|
10860
|
+
if (options.strictUsageTelemetry === true) {
|
|
10861
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10862
|
+
error,
|
|
10863
|
+
"CC_COMPACTION_USAGE_INSTRUMENTATION_REQUIRED",
|
|
10864
|
+
"Strict semantic compaction requires an instrumentable provider boundary",
|
|
10865
|
+
);
|
|
10866
|
+
}
|
|
10867
|
+
// A frozen injected compactor cannot be instrumented safely. Production
|
|
10868
|
+
// PromptCompressor instances are mutable; legacy injected fakes stay as-is.
|
|
10869
|
+
return compactor;
|
|
10870
|
+
}
|
|
10871
|
+
if (compactor.llmQuery === wrapper) {
|
|
10872
|
+
_autoCompactorInstrumentation.set(compactor, {
|
|
10873
|
+
original,
|
|
10874
|
+
options,
|
|
10875
|
+
wrapper,
|
|
10876
|
+
});
|
|
10877
|
+
} else if (options.strictUsageTelemetry === true) {
|
|
10878
|
+
throw _runtimeUsageBoundaryFailure(
|
|
10879
|
+
null,
|
|
10880
|
+
"CC_COMPACTION_USAGE_INSTRUMENTATION_REQUIRED",
|
|
10881
|
+
"Strict semantic compaction requires an instrumentable provider boundary",
|
|
10882
|
+
);
|
|
10883
|
+
}
|
|
10884
|
+
return compactor;
|
|
10885
|
+
}
|
|
10886
|
+
|
|
10126
10887
|
/**
|
|
10127
10888
|
* Lazily build (and cache on `options`) the PromptCompressor used for in-loop
|
|
10128
10889
|
* auto-compaction. Returns null when the feature is off or the module can't be
|
|
@@ -10131,7 +10892,7 @@ function _managedCheckpointUncoveredWriterReason(toolContext) {
|
|
|
10131
10892
|
*/
|
|
10132
10893
|
async function _getAutoCompactor(options) {
|
|
10133
10894
|
if (Object.prototype.hasOwnProperty.call(options, "_autoCompactor")) {
|
|
10134
|
-
return options._autoCompactor;
|
|
10895
|
+
return _instrumentAutoCompactorUsage(options._autoCompactor, options);
|
|
10135
10896
|
}
|
|
10136
10897
|
let compressor = null;
|
|
10137
10898
|
try {
|
|
@@ -10179,6 +10940,7 @@ async function _getAutoCompactor(options) {
|
|
|
10179
10940
|
llmQuery,
|
|
10180
10941
|
summaryInputMaxChars: options.compactionInputMaxChars,
|
|
10181
10942
|
});
|
|
10943
|
+
compressor = _instrumentAutoCompactorUsage(compressor, options);
|
|
10182
10944
|
}
|
|
10183
10945
|
} catch {
|
|
10184
10946
|
compressor = null;
|
|
@@ -10193,19 +10955,38 @@ async function _getAutoCompactor(options) {
|
|
|
10193
10955
|
|
|
10194
10956
|
function _compactionTokenUsage(stats) {
|
|
10195
10957
|
const summaryUsage = stats?.summaryUsage;
|
|
10196
|
-
if (
|
|
10197
|
-
|
|
10198
|
-
|
|
10199
|
-
|
|
10958
|
+
if (
|
|
10959
|
+
!summaryUsage ||
|
|
10960
|
+
typeof summaryUsage !== "object" ||
|
|
10961
|
+
Array.isArray(summaryUsage) ||
|
|
10962
|
+
!_isNonNegativeSafeInteger(summaryUsage.inputTokens) ||
|
|
10963
|
+
!_isNonNegativeSafeInteger(summaryUsage.outputTokens)
|
|
10964
|
+
) {
|
|
10965
|
+
return null;
|
|
10966
|
+
}
|
|
10967
|
+
const optionalTokenCount = (key) => {
|
|
10968
|
+
if (!Object.prototype.hasOwnProperty.call(summaryUsage, key)) return 0;
|
|
10969
|
+
return _isNonNegativeSafeInteger(summaryUsage[key])
|
|
10970
|
+
? summaryUsage[key]
|
|
10971
|
+
: null;
|
|
10200
10972
|
};
|
|
10973
|
+
const cacheReadTokens = optionalTokenCount("cacheReadTokens");
|
|
10974
|
+
const cacheCreationTokens = optionalTokenCount("cacheCreationTokens");
|
|
10975
|
+
if (cacheReadTokens == null || cacheCreationTokens == null) return null;
|
|
10201
10976
|
return {
|
|
10202
|
-
input_tokens:
|
|
10203
|
-
output_tokens:
|
|
10204
|
-
cache_read_input_tokens:
|
|
10205
|
-
cache_creation_input_tokens:
|
|
10977
|
+
input_tokens: summaryUsage.inputTokens,
|
|
10978
|
+
output_tokens: summaryUsage.outputTokens,
|
|
10979
|
+
cache_read_input_tokens: cacheReadTokens,
|
|
10980
|
+
cache_creation_input_tokens: cacheCreationTokens,
|
|
10206
10981
|
};
|
|
10207
10982
|
}
|
|
10208
10983
|
|
|
10984
|
+
function _compactionUsageUnknownReason(stats) {
|
|
10985
|
+
return stats?.summaryUsageUnknownReason === "provider_usage_not_reported"
|
|
10986
|
+
? "provider_usage_not_reported"
|
|
10987
|
+
: "provider_transport_outcome_unknown";
|
|
10988
|
+
}
|
|
10989
|
+
|
|
10209
10990
|
function _sameMessageSnapshot(messages, expectedMessages) {
|
|
10210
10991
|
return (
|
|
10211
10992
|
messages.length === expectedMessages.length &&
|
|
@@ -10518,7 +11299,30 @@ export async function* agentLoop(messages, options) {
|
|
|
10518
11299
|
model: options.model || null,
|
|
10519
11300
|
baseUrl: options.baseUrl || null,
|
|
10520
11301
|
apiKey: options.apiKey || null,
|
|
11302
|
+
...(typeof options.onUsageBoundary === "function"
|
|
11303
|
+
? { onUsageBoundary: options.onUsageBoundary }
|
|
11304
|
+
: {}),
|
|
11305
|
+
...(typeof options.onUsageSettlement === "function"
|
|
11306
|
+
? { onUsageSettlement: options.onUsageSettlement }
|
|
11307
|
+
: {}),
|
|
11308
|
+
...(typeof options.onStreamRetry === "function"
|
|
11309
|
+
? { onStreamRetry: options.onStreamRetry }
|
|
11310
|
+
: {}),
|
|
11311
|
+
...(typeof options.onToolCallBoundary === "function"
|
|
11312
|
+
? { onToolCallBoundary: options.onToolCallBoundary }
|
|
11313
|
+
: {}),
|
|
11314
|
+
...(typeof options.onToolCallSettlement === "function"
|
|
11315
|
+
? { onToolCallSettlement: options.onToolCallSettlement }
|
|
11316
|
+
: {}),
|
|
11317
|
+
...(options.strictUsageTelemetry === true
|
|
11318
|
+
? { strictUsageTelemetry: true }
|
|
11319
|
+
: {}),
|
|
10521
11320
|
},
|
|
11321
|
+
strictUsageTelemetry: options.strictUsageTelemetry === true,
|
|
11322
|
+
onUsageBoundary: options.onUsageBoundary || null,
|
|
11323
|
+
onUsageSettlement: options.onUsageSettlement || null,
|
|
11324
|
+
onToolCallBoundary: options.onToolCallBoundary || null,
|
|
11325
|
+
onToolCallSettlement: options.onToolCallSettlement || null,
|
|
10522
11326
|
parentMessages: messages, // pass parent messages for sub-agent auto-condensation
|
|
10523
11327
|
interaction: options.interaction || null,
|
|
10524
11328
|
shellPolicyOverrides: options.shellPolicyOverrides || null,
|
|
@@ -10582,6 +11386,10 @@ export async function* agentLoop(messages, options) {
|
|
|
10582
11386
|
// any are still running (it waits, injects, and gives the model one more
|
|
10583
11387
|
// turn) so a background result can never be silently lost.
|
|
10584
11388
|
backgroundSubAgents: new Map(),
|
|
11389
|
+
// A background child reports strict observer failure synchronously here,
|
|
11390
|
+
// before its promise rejection necessarily reaches the entry's `settled`
|
|
11391
|
+
// continuation. Provider/tool admission fences consult this latch directly.
|
|
11392
|
+
backgroundUsageFailureState: { error: null },
|
|
10585
11393
|
// 用量归因: per-run sink for child-loop (spawn_sub_agent / isolated
|
|
10586
11394
|
// run_skill) token usage. Child loops consume their own generator events,
|
|
10587
11395
|
// so their real usage never reaches this loop's consumers — the spawn
|
|
@@ -10593,6 +11401,7 @@ export async function* agentLoop(messages, options) {
|
|
|
10593
11401
|
: [],
|
|
10594
11402
|
};
|
|
10595
11403
|
const backgroundSubAgents = toolContext.backgroundSubAgents;
|
|
11404
|
+
const backgroundUsageFailureState = toolContext.backgroundUsageFailureState;
|
|
10596
11405
|
const subAgentUsageSink = toolContext.subAgentUsageSink;
|
|
10597
11406
|
const lifecycleHookEmitter = hermeticExecution ? () => {} : emitHooksV2Event;
|
|
10598
11407
|
|
|
@@ -10657,7 +11466,15 @@ export async function* agentLoop(messages, options) {
|
|
|
10657
11466
|
// wrong / expired, self-heal to a provider we can actually run (endpoint-
|
|
10658
11467
|
// inferred, then env-keyed) instead of failing the turn. Opt out with
|
|
10659
11468
|
// `runnableProviderFallback: false`. Transparent on the happy path.
|
|
10660
|
-
|
|
11469
|
+
// A runnable fallback may perform an additional (and cross-provider) model
|
|
11470
|
+
// attempt inside one logical `llmCall`, where this generator cannot durably
|
|
11471
|
+
// bracket each transport attempt. Strict call-ledger sessions therefore
|
|
11472
|
+
// disable that recovery path and surface the configured provider's failure
|
|
11473
|
+
// as unknown; legacy sessions keep the existing self-healing behavior.
|
|
11474
|
+
if (
|
|
11475
|
+
options.runnableProviderFallback !== false &&
|
|
11476
|
+
options.strictUsageTelemetry !== true
|
|
11477
|
+
) {
|
|
10661
11478
|
const { makeRunnableProviderFallback } =
|
|
10662
11479
|
await import("../lib/runnable-provider.js");
|
|
10663
11480
|
llmCall = makeRunnableProviderFallback(llmCall, {
|
|
@@ -10741,6 +11558,12 @@ export async function* agentLoop(messages, options) {
|
|
|
10741
11558
|
budget.consume();
|
|
10742
11559
|
throwIfAborted(signal);
|
|
10743
11560
|
|
|
11561
|
+
// A detached child may fail its synchronous ledger write between parent
|
|
11562
|
+
// turns. Surface that original marked error before any further paid parent
|
|
11563
|
+
// provider call is admitted.
|
|
11564
|
+
_throwBackgroundUsageFailureState(backgroundUsageFailureState);
|
|
11565
|
+
_throwSettledBackgroundUsageFailure(backgroundSubAgents);
|
|
11566
|
+
|
|
10744
11567
|
// Surface attributed child-loop usage collected since the last boundary
|
|
10745
11568
|
// (blocking spawns push during executeTool; background spawns push live).
|
|
10746
11569
|
yield* _drainSubAgentUsage(subAgentUsageSink);
|
|
@@ -10786,9 +11609,14 @@ export async function* agentLoop(messages, options) {
|
|
|
10786
11609
|
!automaticCompactionSettlementBlocked &&
|
|
10787
11610
|
messages.length > 4
|
|
10788
11611
|
) {
|
|
11612
|
+
let compactionUsageState = null;
|
|
11613
|
+
let compactionUsageCall = null;
|
|
11614
|
+
let compactionObserverFailure = null;
|
|
10789
11615
|
try {
|
|
10790
11616
|
const compactor = await _getAutoCompactor(options);
|
|
10791
11617
|
if (compactor && compactor.shouldAutoCompact(messages)) {
|
|
11618
|
+
compactionUsageState = _autoCompactionUsageState(options);
|
|
11619
|
+
compactionUsageState.calls = [];
|
|
10792
11620
|
// This is the canonical pre-provider authority snapshot. A local
|
|
10793
11621
|
// micro-compact may change the working input, but the durable CAS must
|
|
10794
11622
|
// still compare against the transcript state that existed before any
|
|
@@ -10875,36 +11703,88 @@ export async function* agentLoop(messages, options) {
|
|
|
10875
11703
|
preserveToolPairs: true,
|
|
10876
11704
|
...pinOpts,
|
|
10877
11705
|
});
|
|
11706
|
+
const observerFailure = compactionUsageState.calls.find(
|
|
11707
|
+
(call) => call.observerFailed,
|
|
11708
|
+
);
|
|
11709
|
+
if (observerFailure) {
|
|
11710
|
+
compactionObserverFailure = observerFailure.observerError;
|
|
11711
|
+
compactionUsageState.calls = [];
|
|
11712
|
+
throw compactionObserverFailure;
|
|
11713
|
+
}
|
|
11714
|
+
compactionUsageCall = compactionUsageState.calls.at(-1) || null;
|
|
10878
11715
|
const compactionUsage = _compactionTokenUsage(stats);
|
|
10879
11716
|
if (stats.degraded === true) {
|
|
11717
|
+
const usageOutcomeUnknown = stats.summaryUsageUnknown === true;
|
|
11718
|
+
const projectedStats = usageOutcomeUnknown
|
|
11719
|
+
? {
|
|
11720
|
+
...stats,
|
|
11721
|
+
degradedReason: "semantic-summary-provider-outcome-unknown",
|
|
11722
|
+
summaryUsageUnknownReason:
|
|
11723
|
+
_compactionUsageUnknownReason(stats),
|
|
11724
|
+
}
|
|
11725
|
+
: stats;
|
|
10880
11726
|
yield {
|
|
10881
11727
|
type: "compaction-degraded",
|
|
10882
11728
|
runId,
|
|
10883
|
-
reason:
|
|
11729
|
+
reason: usageOutcomeUnknown
|
|
11730
|
+
? "semantic-summary-provider-outcome-unknown"
|
|
11731
|
+
: stats.degradedReason || "semantic-summary-degraded",
|
|
10884
11732
|
summaryMode: stats.summaryMode || "extractive-fallback",
|
|
10885
|
-
stats,
|
|
11733
|
+
stats: projectedStats,
|
|
10886
11734
|
};
|
|
10887
11735
|
}
|
|
11736
|
+
const compactionUsageMissing =
|
|
11737
|
+
stats.summaryUsageUnknown !== true &&
|
|
11738
|
+
compactionUsageCall != null &&
|
|
11739
|
+
compactionUsage == null;
|
|
11740
|
+
if (stats.summaryUsageUnknown === true || compactionUsageMissing) {
|
|
11741
|
+
automaticCompactionSettlementBlocked = true;
|
|
11742
|
+
const unknownReason = compactionUsageMissing
|
|
11743
|
+
? "provider_usage_not_reported"
|
|
11744
|
+
: _compactionUsageUnknownReason(stats);
|
|
11745
|
+
if (
|
|
11746
|
+
options.strictUsageTelemetry === true &&
|
|
11747
|
+
!compactionUsageCall?.callId
|
|
11748
|
+
) {
|
|
11749
|
+
throw _runtimeUsageBoundaryFailure(
|
|
11750
|
+
null,
|
|
11751
|
+
"CC_COMPACTION_USAGE_BOUNDARY_MISSING",
|
|
11752
|
+
"Strict semantic compaction produced usage without a real call boundary",
|
|
11753
|
+
);
|
|
11754
|
+
}
|
|
11755
|
+
yield {
|
|
11756
|
+
type: "compaction-usage-unknown",
|
|
11757
|
+
callId:
|
|
11758
|
+
compactionUsageCall?.callId ||
|
|
11759
|
+
_newModelUsageCallId("semantic-compaction"),
|
|
11760
|
+
runId,
|
|
11761
|
+
provider:
|
|
11762
|
+
compactionUsageCall?.boundaryNotified === true
|
|
11763
|
+
? compactionUsageCall.provider
|
|
11764
|
+
: stats.summaryProvider || options.provider || null,
|
|
11765
|
+
model:
|
|
11766
|
+
compactionUsageCall?.boundaryNotified === true
|
|
11767
|
+
? compactionUsageCall.model
|
|
11768
|
+
: stats.summaryModel || options.model || null,
|
|
11769
|
+
reason: unknownReason,
|
|
11770
|
+
code:
|
|
11771
|
+
unknownReason === "provider_usage_not_reported"
|
|
11772
|
+
? "provider_usage_missing"
|
|
11773
|
+
: "provider_call_failed",
|
|
11774
|
+
source: "semantic-compaction",
|
|
11775
|
+
};
|
|
11776
|
+
// Unknown compaction spend makes every hard budget unverifiable;
|
|
11777
|
+
// never apply the fallback or initiate the main model call.
|
|
11778
|
+
await _awaitBackgroundUsageSettlement(
|
|
11779
|
+
backgroundSubAgents,
|
|
11780
|
+
backgroundUsageFailureState,
|
|
11781
|
+
);
|
|
11782
|
+
return;
|
|
11783
|
+
}
|
|
10888
11784
|
if (
|
|
10889
11785
|
stats.saved > 0 &&
|
|
10890
11786
|
!_sameMessageSnapshot(compacted, authorityExpectedMessages)
|
|
10891
11787
|
) {
|
|
10892
|
-
if (stats.summaryUsageUnknown === true) {
|
|
10893
|
-
automaticCompactionSettlementBlocked = true;
|
|
10894
|
-
yield {
|
|
10895
|
-
type: "compaction-usage-unknown",
|
|
10896
|
-
runId,
|
|
10897
|
-
provider: stats.summaryProvider || options.provider || null,
|
|
10898
|
-
model: stats.summaryModel || options.model || null,
|
|
10899
|
-
reason:
|
|
10900
|
-
stats.summaryUsageUnknownReason ||
|
|
10901
|
-
"provider_transport_outcome_unknown",
|
|
10902
|
-
source: "semantic-compaction",
|
|
10903
|
-
};
|
|
10904
|
-
// Do not apply the fallback or start another paid model request.
|
|
10905
|
-
// A transport failure may already have incurred unknown usage.
|
|
10906
|
-
return;
|
|
10907
|
-
}
|
|
10908
11788
|
const liveExpectedMessages = [...messages];
|
|
10909
11789
|
try {
|
|
10910
11790
|
await _settleAutomaticCompaction({
|
|
@@ -10930,8 +11810,17 @@ export async function* agentLoop(messages, options) {
|
|
|
10930
11810
|
if (compactionUsage) {
|
|
10931
11811
|
yield {
|
|
10932
11812
|
type: "token-usage",
|
|
10933
|
-
|
|
10934
|
-
|
|
11813
|
+
...(compactionUsageCall
|
|
11814
|
+
? { callId: compactionUsageCall.callId }
|
|
11815
|
+
: {}),
|
|
11816
|
+
provider:
|
|
11817
|
+
compactionUsageCall?.boundaryNotified === true
|
|
11818
|
+
? compactionUsageCall.provider
|
|
11819
|
+
: stats.summaryProvider || options.provider || null,
|
|
11820
|
+
model:
|
|
11821
|
+
compactionUsageCall?.boundaryNotified === true
|
|
11822
|
+
? compactionUsageCall.model
|
|
11823
|
+
: stats.summaryModel || options.model || null,
|
|
10935
11824
|
usage: compactionUsage,
|
|
10936
11825
|
source: "semantic-compaction",
|
|
10937
11826
|
runId,
|
|
@@ -10939,6 +11828,10 @@ export async function* agentLoop(messages, options) {
|
|
|
10939
11828
|
}
|
|
10940
11829
|
// The paid summary call is never retried, and an unknown/stale
|
|
10941
11830
|
// canonical settlement cannot be followed by another model call.
|
|
11831
|
+
await _awaitBackgroundUsageSettlement(
|
|
11832
|
+
backgroundSubAgents,
|
|
11833
|
+
backgroundUsageFailureState,
|
|
11834
|
+
);
|
|
10942
11835
|
return;
|
|
10943
11836
|
}
|
|
10944
11837
|
if (!hermeticExecution) {
|
|
@@ -10966,8 +11859,17 @@ export async function* agentLoop(messages, options) {
|
|
|
10966
11859
|
// next model call, without entering the normal response path.
|
|
10967
11860
|
yield {
|
|
10968
11861
|
type: "token-usage",
|
|
10969
|
-
|
|
10970
|
-
|
|
11862
|
+
...(compactionUsageCall
|
|
11863
|
+
? { callId: compactionUsageCall.callId }
|
|
11864
|
+
: {}),
|
|
11865
|
+
provider:
|
|
11866
|
+
compactionUsageCall?.boundaryNotified === true
|
|
11867
|
+
? compactionUsageCall.provider
|
|
11868
|
+
: stats.summaryProvider || options.provider || null,
|
|
11869
|
+
model:
|
|
11870
|
+
compactionUsageCall?.boundaryNotified === true
|
|
11871
|
+
? compactionUsageCall.model
|
|
11872
|
+
: stats.summaryModel || options.model || null,
|
|
10971
11873
|
usage: compactionUsage,
|
|
10972
11874
|
source: "semantic-compaction",
|
|
10973
11875
|
runId,
|
|
@@ -10976,6 +11878,35 @@ export async function* agentLoop(messages, options) {
|
|
|
10976
11878
|
}
|
|
10977
11879
|
} catch (_e) {
|
|
10978
11880
|
if (isAbortError(_e) || signal?.aborted) throw _e;
|
|
11881
|
+
if (_e?.runtimeLedgerPersistence === true) throw _e;
|
|
11882
|
+
if (compactionObserverFailure === _e) throw _e;
|
|
11883
|
+
const observerFailure = compactionUsageState?.calls?.find(
|
|
11884
|
+
(call) => call.observerFailed && call.observerError === _e,
|
|
11885
|
+
);
|
|
11886
|
+
if (observerFailure) {
|
|
11887
|
+
compactionUsageState.calls = [];
|
|
11888
|
+
throw _e;
|
|
11889
|
+
}
|
|
11890
|
+
compactionUsageCall =
|
|
11891
|
+
compactionUsageCall || compactionUsageState?.calls?.at(-1) || null;
|
|
11892
|
+
if (compactionUsageCall) {
|
|
11893
|
+
automaticCompactionSettlementBlocked = true;
|
|
11894
|
+
yield {
|
|
11895
|
+
type: "compaction-usage-unknown",
|
|
11896
|
+
callId: compactionUsageCall.callId,
|
|
11897
|
+
runId,
|
|
11898
|
+
provider: compactionUsageCall.provider,
|
|
11899
|
+
model: compactionUsageCall.model,
|
|
11900
|
+
reason: "provider_transport_outcome_unknown",
|
|
11901
|
+
code: "provider_call_failed",
|
|
11902
|
+
source: "semantic-compaction",
|
|
11903
|
+
};
|
|
11904
|
+
await _awaitBackgroundUsageSettlement(
|
|
11905
|
+
backgroundSubAgents,
|
|
11906
|
+
backgroundUsageFailureState,
|
|
11907
|
+
);
|
|
11908
|
+
return;
|
|
11909
|
+
}
|
|
10979
11910
|
yield {
|
|
10980
11911
|
type: "compaction-degraded",
|
|
10981
11912
|
runId,
|
|
@@ -10993,6 +11924,7 @@ export async function* agentLoop(messages, options) {
|
|
|
10993
11924
|
for (const entry of _takeSettledBackgroundSubAgents(
|
|
10994
11925
|
backgroundSubAgents,
|
|
10995
11926
|
)) {
|
|
11927
|
+
_throwBackgroundSubAgentUsageFailure(entry);
|
|
10996
11928
|
// SubagentStop fires at RESULT time for background spawns (the
|
|
10997
11929
|
// spawn-time handle skips it); a block reason rides along as feedback.
|
|
10998
11930
|
if (!hermeticExecution && options.settingsHooks) {
|
|
@@ -11032,6 +11964,12 @@ export async function* agentLoop(messages, options) {
|
|
|
11032
11964
|
}
|
|
11033
11965
|
}
|
|
11034
11966
|
|
|
11967
|
+
// Result-delivery hooks and context preparation can yield long enough for
|
|
11968
|
+
// a detached child's synchronous ledger failure to settle. Keep the final
|
|
11969
|
+
// dispatch fence adjacent to construction of the paid parent request.
|
|
11970
|
+
_throwBackgroundUsageFailureState(backgroundUsageFailureState);
|
|
11971
|
+
_throwSettledBackgroundUsageFailure(backgroundSubAgents);
|
|
11972
|
+
|
|
11035
11973
|
// Turn-scoped context injection (open-agents prepareCall parity).
|
|
11036
11974
|
// prepareCall runs fresh each iteration and returns an ephemeral
|
|
11037
11975
|
// system-message supplement that is NOT persisted to messages history.
|
|
@@ -11070,67 +12008,139 @@ export async function* agentLoop(messages, options) {
|
|
|
11070
12008
|
promptId: `${runId}:t${budget.consumed}:p`,
|
|
11071
12009
|
})
|
|
11072
12010
|
: null;
|
|
11073
|
-
|
|
11074
|
-
|
|
11075
|
-
|
|
11076
|
-
|
|
11077
|
-
|
|
11078
|
-
|
|
11079
|
-
|
|
11080
|
-
|
|
11081
|
-
|
|
11082
|
-
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
|
|
11087
|
-
|
|
11088
|
-
|
|
11089
|
-
|
|
11090
|
-
|
|
11091
|
-
|
|
11092
|
-
|
|
11093
|
-
|
|
11094
|
-
|
|
11095
|
-
|
|
11096
|
-
|
|
11097
|
-
|
|
11098
|
-
|
|
11099
|
-
|
|
11100
|
-
|
|
11101
|
-
|
|
11102
|
-
|
|
11103
|
-
|
|
11104
|
-
|
|
11105
|
-
|
|
11106
|
-
|
|
11107
|
-
|
|
11108
|
-
|
|
12011
|
+
throwIfAborted(signal);
|
|
12012
|
+
_throwBackgroundUsageFailureState(backgroundUsageFailureState);
|
|
12013
|
+
_throwSettledBackgroundUsageFailure(backgroundSubAgents);
|
|
12014
|
+
const modelUsageCall = {
|
|
12015
|
+
type: "model-usage-started",
|
|
12016
|
+
callId: _newModelUsageCallId("model"),
|
|
12017
|
+
provider: options.provider || "ollama",
|
|
12018
|
+
model: options.model || "unknown",
|
|
12019
|
+
source: "model",
|
|
12020
|
+
};
|
|
12021
|
+
// The consumer receives this boundary before `.next()` resumes into the
|
|
12022
|
+
// provider call, so a durable append failure can prevent spend.
|
|
12023
|
+
yield modelUsageCall;
|
|
12024
|
+
// A background child can fail its synchronous settlement write while the
|
|
12025
|
+
// parent boundary is being persisted by the host. Re-check at the last
|
|
12026
|
+
// synchronous admission point before dispatching this paid call.
|
|
12027
|
+
try {
|
|
12028
|
+
_throwBackgroundUsageFailureState(backgroundUsageFailureState);
|
|
12029
|
+
_throwSettledBackgroundUsageFailure(backgroundSubAgents);
|
|
12030
|
+
} catch (backgroundFailure) {
|
|
12031
|
+
// The host has already persisted this parent boundary. Close it with the
|
|
12032
|
+
// same id before surfacing the detached child's authoritative failure.
|
|
12033
|
+
yield {
|
|
12034
|
+
type: "model-usage-unknown",
|
|
12035
|
+
callId: modelUsageCall.callId,
|
|
12036
|
+
provider: modelUsageCall.provider,
|
|
12037
|
+
model: modelUsageCall.model,
|
|
12038
|
+
source: modelUsageCall.source,
|
|
12039
|
+
code: "provider_call_failed",
|
|
12040
|
+
};
|
|
12041
|
+
throw backgroundFailure;
|
|
12042
|
+
}
|
|
12043
|
+
|
|
12044
|
+
let result;
|
|
12045
|
+
try {
|
|
12046
|
+
result = await _withSpan(
|
|
12047
|
+
recorder,
|
|
12048
|
+
"agent.model",
|
|
12049
|
+
{
|
|
12050
|
+
"gen_ai.system": options.provider || "ollama",
|
|
12051
|
+
"gen_ai.request.model": options.model || "unknown",
|
|
12052
|
+
"agent.iteration": budget.consumed,
|
|
12053
|
+
...(modelIdAttrs || {}),
|
|
12054
|
+
},
|
|
12055
|
+
() => llmCall(callMessages, effectiveToolOptions),
|
|
12056
|
+
(span, r) => {
|
|
12057
|
+
const t = _usageTokens(r?.usage);
|
|
12058
|
+
if (t) {
|
|
12059
|
+
if (t.input != null)
|
|
12060
|
+
span.setAttribute("gen_ai.usage.input_tokens", t.input);
|
|
12061
|
+
if (t.output != null)
|
|
12062
|
+
span.setAttribute("gen_ai.usage.output_tokens", t.output);
|
|
12063
|
+
// Cache read/write tokens — the prompt-caching hit rate the plan's
|
|
12064
|
+
// reliability telemetry cares about.
|
|
12065
|
+
if (t.cacheRead != null)
|
|
12066
|
+
span.setAttribute("gen_ai.usage.cache_read_tokens", t.cacheRead);
|
|
12067
|
+
if (t.cacheWrite != null)
|
|
12068
|
+
span.setAttribute(
|
|
12069
|
+
"gen_ai.usage.cache_write_tokens",
|
|
12070
|
+
t.cacheWrite,
|
|
12071
|
+
);
|
|
12072
|
+
}
|
|
12073
|
+
span.setAttribute(
|
|
12074
|
+
"agent.has_tool_calls",
|
|
12075
|
+
Array.isArray(r?.message?.tool_calls) &&
|
|
12076
|
+
r.message.tool_calls.length > 0,
|
|
11109
12077
|
);
|
|
11110
|
-
|
|
11111
|
-
|
|
11112
|
-
|
|
11113
|
-
|
|
12078
|
+
// response CONTENT is opt-in (--otlp-content): stamped only when
|
|
12079
|
+
// enabled, redacted + length-capped through the same normalizer; the
|
|
12080
|
+
// field is entirely absent by default so default OTLP stays unchanged.
|
|
12081
|
+
if (options.otlpIncludeContent === true && r?.message?.content) {
|
|
12082
|
+
const respAttrs = buildTelemetryAttributes(
|
|
12083
|
+
{ response: r.message.content },
|
|
12084
|
+
{ includeContent: true },
|
|
11114
12085
|
);
|
|
12086
|
+
if (respAttrs["content.response"] != null) {
|
|
12087
|
+
span.setAttribute(
|
|
12088
|
+
"content.response",
|
|
12089
|
+
respAttrs["content.response"],
|
|
12090
|
+
);
|
|
12091
|
+
}
|
|
11115
12092
|
}
|
|
11116
|
-
}
|
|
11117
|
-
|
|
11118
|
-
|
|
11119
|
-
)
|
|
12093
|
+
},
|
|
12094
|
+
"model_error",
|
|
12095
|
+
);
|
|
12096
|
+
} catch (error) {
|
|
12097
|
+
// Never retain provider error text in the usage ledger. Pause on a fixed
|
|
12098
|
+
// unknown settlement, then rethrow only after the consumer resumes.
|
|
12099
|
+
yield {
|
|
12100
|
+
type: "model-usage-unknown",
|
|
12101
|
+
callId: modelUsageCall.callId,
|
|
12102
|
+
provider: modelUsageCall.provider,
|
|
12103
|
+
model: modelUsageCall.model,
|
|
12104
|
+
source: modelUsageCall.source,
|
|
12105
|
+
code: "provider_call_failed",
|
|
12106
|
+
};
|
|
12107
|
+
await _awaitBackgroundUsageSettlement(
|
|
12108
|
+
backgroundSubAgents,
|
|
12109
|
+
backgroundUsageFailureState,
|
|
12110
|
+
);
|
|
12111
|
+
throw error;
|
|
12112
|
+
}
|
|
11120
12113
|
if (recorder) recorder.counter("agent.model.calls", 1);
|
|
11121
|
-
throwIfAborted(signal);
|
|
11122
12114
|
const msg = result?.message;
|
|
11123
12115
|
|
|
11124
|
-
|
|
12116
|
+
// Close the already-persisted call boundary before honoring an abort that
|
|
12117
|
+
// raced with a successful provider response. Once the transport returned,
|
|
12118
|
+
// dropping this settlement would strand a durable `started` row forever.
|
|
12119
|
+
if (_hasCompleteProviderUsage(result?.usage)) {
|
|
11125
12120
|
yield {
|
|
11126
12121
|
type: "token-usage",
|
|
11127
|
-
|
|
11128
|
-
|
|
12122
|
+
callId: modelUsageCall.callId,
|
|
12123
|
+
provider: modelUsageCall.provider,
|
|
12124
|
+
model: modelUsageCall.model,
|
|
11129
12125
|
usage: result.usage,
|
|
11130
12126
|
};
|
|
12127
|
+
} else {
|
|
12128
|
+
yield {
|
|
12129
|
+
type: "model-usage-unknown",
|
|
12130
|
+
callId: modelUsageCall.callId,
|
|
12131
|
+
provider: modelUsageCall.provider,
|
|
12132
|
+
model: modelUsageCall.model,
|
|
12133
|
+
source: modelUsageCall.source,
|
|
12134
|
+
code: "provider_usage_missing",
|
|
12135
|
+
};
|
|
11131
12136
|
}
|
|
12137
|
+
throwIfAborted(signal);
|
|
11132
12138
|
|
|
11133
12139
|
if (!msg) {
|
|
12140
|
+
await _awaitBackgroundUsageSettlement(
|
|
12141
|
+
backgroundSubAgents,
|
|
12142
|
+
backgroundUsageFailureState,
|
|
12143
|
+
);
|
|
11134
12144
|
yield { type: "response-complete", content: "(No response from LLM)" };
|
|
11135
12145
|
yield { type: "run-ended", runId, reason: "no-response" };
|
|
11136
12146
|
return;
|
|
@@ -11153,11 +12163,13 @@ export async function* agentLoop(messages, options) {
|
|
|
11153
12163
|
await Promise.all(
|
|
11154
12164
|
[...backgroundSubAgents.values()].map((e) => e.promise),
|
|
11155
12165
|
);
|
|
12166
|
+
_throwBackgroundUsageFailureState(backgroundUsageFailureState);
|
|
11156
12167
|
throwIfAborted(signal);
|
|
11157
12168
|
messages.push({ role: "assistant", content: msg.content || "" });
|
|
11158
12169
|
for (const entry of _takeSettledBackgroundSubAgents(
|
|
11159
12170
|
backgroundSubAgents,
|
|
11160
12171
|
)) {
|
|
12172
|
+
_throwBackgroundSubAgentUsageFailure(entry);
|
|
11161
12173
|
messages.push({
|
|
11162
12174
|
role: "user",
|
|
11163
12175
|
content:
|
|
@@ -11297,9 +12309,9 @@ export async function* agentLoop(messages, options) {
|
|
|
11297
12309
|
// no process spawn, no shared-state writes) and there is no interactive
|
|
11298
12310
|
// confirmer in play, run them concurrently so wall-clock drops from the SUM
|
|
11299
12311
|
// of the reads to their MAX — the common "read these N files" case. Crucially,
|
|
11300
|
-
// `tool-executing
|
|
11301
|
-
//
|
|
11302
|
-
// correlation
|
|
12312
|
+
// Every `tool-executing` boundary is YIELDED before dispatch, giving the
|
|
12313
|
+
// host a chance to durably record every call. Tool results stay in call order;
|
|
12314
|
+
// correlation stays deterministic even though the reads themselves overlap.
|
|
11303
12315
|
// Any mutating/unknown/MCP tool in the batch, a single call, an interactive
|
|
11304
12316
|
// session (concurrent prompts would race), or `parallelReadOnlyTools: false`
|
|
11305
12317
|
// falls through to the strictly sequential loop below.
|
|
@@ -11316,10 +12328,7 @@ export async function* agentLoop(messages, options) {
|
|
|
11316
12328
|
throwIfAborted(signal);
|
|
11317
12329
|
const turnId = `${runId}:t${budget.consumed}`;
|
|
11318
12330
|
const toolBatchRecords = [];
|
|
11319
|
-
|
|
11320
|
-
// promise can never surface as an unhandled rejection if the loop aborts
|
|
11321
|
-
// before it is consumed.
|
|
11322
|
-
const inflight = toolCalls.map((call) => {
|
|
12331
|
+
const prepared = toolCalls.map((call) => {
|
|
11323
12332
|
let toolArgs;
|
|
11324
12333
|
try {
|
|
11325
12334
|
toolArgs =
|
|
@@ -11329,6 +12338,44 @@ export async function* agentLoop(messages, options) {
|
|
|
11329
12338
|
} catch {
|
|
11330
12339
|
toolArgs = {};
|
|
11331
12340
|
}
|
|
12341
|
+
return { call, toolArgs };
|
|
12342
|
+
});
|
|
12343
|
+
// Yield every start boundary before dispatch. Async-generator consumers
|
|
12344
|
+
// persist each boundary before asking for the next item, so by the time
|
|
12345
|
+
// this loop finishes all parallel calls have durable started records.
|
|
12346
|
+
const startedPrepared = [];
|
|
12347
|
+
try {
|
|
12348
|
+
throwIfAborted(signal);
|
|
12349
|
+
_throwBackgroundUsageFailureState(backgroundUsageFailureState);
|
|
12350
|
+
for (const { call, toolArgs } of prepared) {
|
|
12351
|
+
yield {
|
|
12352
|
+
type: "tool-executing",
|
|
12353
|
+
tool: call.function.name,
|
|
12354
|
+
args: toolArgs,
|
|
12355
|
+
tool_use_id: call.id,
|
|
12356
|
+
turn_id: `${runId}:t${budget.consumed}`,
|
|
12357
|
+
};
|
|
12358
|
+
startedPrepared.push({ call, toolArgs });
|
|
12359
|
+
throwIfAborted(signal);
|
|
12360
|
+
}
|
|
12361
|
+
_throwBackgroundUsageFailureState(backgroundUsageFailureState);
|
|
12362
|
+
} catch (admissionFailure) {
|
|
12363
|
+
for (const { call } of startedPrepared) {
|
|
12364
|
+
yield {
|
|
12365
|
+
type: "tool-result",
|
|
12366
|
+
tool: call.function.name,
|
|
12367
|
+
result: { error: "Tool execution cancelled before dispatch" },
|
|
12368
|
+
error: "tool execution cancelled before dispatch",
|
|
12369
|
+
tool_use_id: call.id,
|
|
12370
|
+
turn_id: `${runId}:t${budget.consumed}`,
|
|
12371
|
+
};
|
|
12372
|
+
}
|
|
12373
|
+
throw admissionFailure;
|
|
12374
|
+
}
|
|
12375
|
+
// Only after every start has been consumed do we kick every read off.
|
|
12376
|
+
// Settle each promise into {result,error} so an abort before its ordered
|
|
12377
|
+
// result is consumed can never surface an unhandled rejection.
|
|
12378
|
+
const inflight = prepared.map(({ call, toolArgs }) => {
|
|
11332
12379
|
const promise = executeTool(call.function.name, toolArgs, {
|
|
11333
12380
|
...toolContext,
|
|
11334
12381
|
toolCallId: call.id,
|
|
@@ -11341,13 +12388,7 @@ export async function* agentLoop(messages, options) {
|
|
|
11341
12388
|
});
|
|
11342
12389
|
for (const { call, toolArgs, promise } of inflight) {
|
|
11343
12390
|
throwIfAborted(signal);
|
|
11344
|
-
|
|
11345
|
-
type: "tool-executing",
|
|
11346
|
-
tool: call.function.name,
|
|
11347
|
-
args: toolArgs,
|
|
11348
|
-
tool_use_id: call.id,
|
|
11349
|
-
turn_id: `${runId}:t${budget.consumed}`,
|
|
11350
|
-
};
|
|
12391
|
+
_throwBackgroundUsageFailureState(backgroundUsageFailureState);
|
|
11351
12392
|
const { result: toolResult, error: toolError } = await promise;
|
|
11352
12393
|
throwIfAborted(signal);
|
|
11353
12394
|
const failed = emitToolHookLifecycle({
|
|
@@ -11409,6 +12450,7 @@ export async function* agentLoop(messages, options) {
|
|
|
11409
12450
|
const toolBatchRecords = [];
|
|
11410
12451
|
for (const call of toolCalls) {
|
|
11411
12452
|
throwIfAborted(signal);
|
|
12453
|
+
_throwBackgroundUsageFailureState(backgroundUsageFailureState);
|
|
11412
12454
|
const fn = call?.function;
|
|
11413
12455
|
const toolName = fn?.name;
|
|
11414
12456
|
// A malformed tool call (no `function` / no `name` — a provider quirk or a
|
|
@@ -11591,6 +12633,25 @@ export async function* agentLoop(messages, options) {
|
|
|
11591
12633
|
tool_use_id: call.id,
|
|
11592
12634
|
turn_id: `${runId}:t${budget.consumed}`,
|
|
11593
12635
|
};
|
|
12636
|
+
// The event yield is a host persistence boundary. A detached child's
|
|
12637
|
+
// fatal usage write can settle while the consumer handles it; fence
|
|
12638
|
+
// the next (possibly provider-backed) tool immediately before start.
|
|
12639
|
+
try {
|
|
12640
|
+
_throwBackgroundUsageFailureState(backgroundUsageFailureState);
|
|
12641
|
+
} catch (backgroundFailure) {
|
|
12642
|
+
yield {
|
|
12643
|
+
type: "tool-result",
|
|
12644
|
+
tool: toolName,
|
|
12645
|
+
result: {
|
|
12646
|
+
error:
|
|
12647
|
+
"Tool execution blocked by an authoritative background usage persistence failure",
|
|
12648
|
+
},
|
|
12649
|
+
error: "authoritative background usage persistence failure",
|
|
12650
|
+
tool_use_id: call.id,
|
|
12651
|
+
turn_id: `${runId}:t${budget.consumed}`,
|
|
12652
|
+
};
|
|
12653
|
+
throw backgroundFailure;
|
|
12654
|
+
}
|
|
11594
12655
|
}
|
|
11595
12656
|
|
|
11596
12657
|
let toolResult;
|
|
@@ -11675,6 +12736,7 @@ export async function* agentLoop(messages, options) {
|
|
|
11675
12736
|
"tool_error",
|
|
11676
12737
|
);
|
|
11677
12738
|
} catch (err) {
|
|
12739
|
+
if (err?.runtimeLedgerPersistence === true) throw err;
|
|
11678
12740
|
toolResult = { error: err.message };
|
|
11679
12741
|
toolError = err.message;
|
|
11680
12742
|
}
|
|
@@ -11844,6 +12906,10 @@ export async function* agentLoop(messages, options) {
|
|
|
11844
12906
|
|
|
11845
12907
|
// Budget exhausted — flush any child usage the final iteration produced,
|
|
11846
12908
|
// then yield exhaustion event + final message
|
|
12909
|
+
await _awaitBackgroundUsageSettlement(
|
|
12910
|
+
backgroundSubAgents,
|
|
12911
|
+
backgroundUsageFailureState,
|
|
12912
|
+
);
|
|
11847
12913
|
yield* _drainSubAgentUsage(subAgentUsageSink);
|
|
11848
12914
|
yield { type: "iteration-budget-exhausted", budget: budget.toSummary() };
|
|
11849
12915
|
yield {
|
|
@@ -11912,7 +12978,7 @@ export function formatToolArgs(name, args) {
|
|
|
11912
12978
|
}
|
|
11913
12979
|
case "schedule":
|
|
11914
12980
|
return args.action === "cron"
|
|
11915
|
-
? `cron ${args.cron || ""}`.trim()
|
|
12981
|
+
? `cron ${args.cron || ""}${args.timezone ? ` [${args.timezone}]` : ""}`.trim()
|
|
11916
12982
|
: args.action === "monitor"
|
|
11917
12983
|
? `monitor ${(args.command || "").substring(0, 40)}`.trim()
|
|
11918
12984
|
: args.action === "wakeup"
|