chainlesschain 0.162.183 → 0.162.185
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/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-BapS7lz4.js → AIOps-Co4ipAKx.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CXYdXEUI.js → ActionButton-BpsoDrDq.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CKR5Lexn.js → Analytics-DMUqeBik.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DATVUOXB.js → AppLayout-C6fD_dXr.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-vb_0ZlV1.js → Artifacts-DW0YlQlV.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BI1l9GWt.js → Audit-DXtHiiFK.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BFXbaUEf.js → BackgroundAgents-BgmF62U-.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DEYBJJ6H.js → Backup-D8vhVLQC.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-COdzeO0M.js → BaseInput-D7nCtY2X.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-oSN6sfM5.js → Chat-CBZLEV2G.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CI_jT0ru.js → ChatBubbleRenderer-CtDb-2Qu.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BezEa4tm.js → Checkbox-DJLkeD4M.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CNEL0Ife.js → Codegen-Cs6xO8Fd.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Bf2Y2Bn1.js → Col-Dtx9wxfT.js} +1 -1
- package/src/assets/web-panel/assets/{Community-BfUlu4Hc.js → Community-DiigJg4n.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BN4xWP9e.js → Compact-B67oMDDL.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Bt6BKmEP.js → Compliance-BBDl-Jos.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DKLp8YxO.js → Cowork-Ba98hSsa.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-o7Hhw6ky.js → Cron-DBWQZIz7.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-DaNXWJIw.js → Crosschain-OcrKzxAt.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B-Qa2mha.js → DID-mW2eSbjM.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CMX0Qnxw.js → Dashboard-BmsDPmKJ.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BLuLyRu_.js → Dropdown-CVzmCyRx.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CFBAeMij.js → EmailListRenderer-vVgqKzhh.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DWzXQ67V.js → FamilyGuardDashboard-CWY5t_ZJ.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DB1QSLgr.js → Federation-ZGomhjxr.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-C-OKCToP.js → FormItemContext-DyaknbLr.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DMJFtFZf.js → GenericCardRenderer-CmIvN1qr.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DsGSujOV.js → Git-DQOJIYkG.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-B0iS9NEW.js → Governance-CMiY-EEp.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CH004H7c.js → Inference-D6IXuucf.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Q9MTQ83c.js → KnowledgeGraph-6jkTL0hV.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-B_fyjZK9.js → Logs-N0jD-349.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BL1IVXm-.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-BIStF9d1.js → Marketplace-WhYuhBxm.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-pGfal768.js → McpTools-DTeO28xy.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-xbNqpIqB.js → Memory-MSHzPSE-.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-B5EQGrIK.js → MobileBridge-Cyqs3J3W.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-7IN2hWHg.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-a_rmfxJH.js → Mtc-MWBnezNM.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-BmKuofUr.js → MtcAudit-DQu35Nu-.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BQbJ-CAN.js → Multisig-CQS_M-DP.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-JtPJKX25.js → NLProgramming-WD16vQvY.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-ZFKznTSG.js → Notes-DqsiSwOq.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-B6aHRBBR.js → NotificationSettings-D3LoxO-P.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DdcsOqEz.js → OrderTableRenderer-C5jPoTd6.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BFDTAUgS.js → Organization-48aMBJso.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-0FoTfbWH.js → Overflow-j-a2XkhR.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CWd90etw.js → P2P-BYpBNYnh.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DtCGC-W-.js → PdhVaultBrowser-CYCsrrLg.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CvQ7nr7T.js → Permissions-ZRXGXDFb.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-rdNPcR-Z.js → PersonalDataHub-6OWUPHyL.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-CmrfiNOs.js → Pipeline-FcjlDK9E.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-D7ep1h_t.js → Privacy-vD_6Tldp.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-C0xKINHS.js → ProjectInit-B_CHOLXp.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-AOmZFp-F.js → ProjectSettings-rEiqQ2da.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BWHSkXZP.js → Projects-Bg8obRAM.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-Cb7JCTPL.js → Providers-Dgtt97B4.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BDMehcXC.js → QrScannerModal-DaGVylZO.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BF6_1nvx.js → QuickAsk-DP2_2x3u.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BHfT-A28.js → Recommend-D29yj4ki.js} +1 -1
- package/src/assets/web-panel/assets/RemoteSession-Ue2wnBLp.js +5 -0
- package/src/assets/web-panel/assets/{Reputation-CsWHLEcj.js → Reputation-CrxIHqeC.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D6srnWhm.js → Row-BgSzJPCn.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-Xhr-KyVd.js → RssFeed-AwhYOrP9.js} +3 -3
- package/src/assets/web-panel/assets/{Search-vIbIJvwL.js → Search-D2shpEcm.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Bzi5Aiko.js → Security-BtKzhTbT.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BHtVX52P.js → Services-BY0DsUSm.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-C0R8B2jf.js → Skeleton-B3Sb0UI9.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DtT6rWOX.js → Skills-Ne5w0bDs.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-0B37mxVU.js → Sla-C8VkaP4T.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-0V2jE1Bs.js → SpeechSettings-BQdIEYP9.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CYedRzaj.js → SyncSettings-CwFafrUg.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-yJuKoDlR.js +1 -0
- package/src/assets/web-panel/assets/{Templates-BKoHztGT.js → Templates-DYn9qCmx.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant--17nwVNZ.js → Tenant-DkKReHvn.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-r6bd-owt.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-C5jx4AE3.js → TimelineRenderer-Mq2juUC3.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DYJKYa9t.js → Tokens-BnMw7MRi.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DChpWiQ9.js → Trigger-CTzKp4o9.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DfWG52EA.js → Trust-BBrSZm9U.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CMugYcyA.js → UkeySign-D9fDvEMq.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BOSmrHAd.js → VideoEditing-DUi5ve-0.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-D5g3k3Sa.js → Wallet-C8Fi1P8_.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-D-7u4Mkc.js → WebAuthn-s1LppYi2.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-CFzZMSUJ.js → WorkflowEditor-DJL2C4lj.js} +1 -1
- package/src/assets/web-panel/assets/{chat-VbR6l6mc.js → chat-D3F2ndOB.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BSZn8EDS.js → colors-B7739-e3.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-y74obMEq.js → compact-item-CcJbFTF4.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-C326bjex.js → createContext-CuP_DEFS.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-Cj_36GHq.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-D_INJQT_.js → hasIn-6YEXfIik.js} +1 -1
- package/src/assets/web-panel/assets/{index-DuIkfnTF.js → index-4h3lpWJ3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBkzrpiL.js → index-BIID4XcP.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7SrC-On.js → index-BOHUo3aM.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnSfnSMP.js → index-BYYSLEjn.js} +1 -1
- package/src/assets/web-panel/assets/{index-KF9Zmqln.js → index-Bh4hcNWW.js} +1 -1
- package/src/assets/web-panel/assets/{index-C327pLbw.js → index-BhIKnQAW.js} +1 -1
- package/src/assets/web-panel/assets/{index-E_v1ZCTP.js → index-Bru_kpZl.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bfw2hf2s.js → index-BsdSnHQE.js} +1 -1
- package/src/assets/web-panel/assets/{index-jYaogFE8.js → index-BxSqVMGh.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dlxh9D8D.js → index-C3ZA_h1j.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdyjrCAu.js → index-C3pctdCb.js} +1 -1
- package/src/assets/web-panel/assets/{index-abmn_8Yz.js → index-CRuoRapN.js} +1 -1
- package/src/assets/web-panel/assets/{index-qMA4GYdQ.js → index-CY0zd_jc.js} +1 -1
- package/src/assets/web-panel/assets/index-CezFrAmD.js +1 -0
- package/src/assets/web-panel/assets/index-Cxgguez6.js +1 -0
- package/src/assets/web-panel/assets/{index-Cr3uuz0C.js → index-CxradkS6.js} +19 -19
- package/src/assets/web-panel/assets/{index-DwHSZLXg.js → index-D0K_rFC1.js} +1 -1
- package/src/assets/web-panel/assets/{index-CMHqs3Jb.js → index-D0zdPyTD.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bnua8IX3.js → index-D3haorUt.js} +1 -1
- package/src/assets/web-panel/assets/{index-BY8-nCgs.js → index-D6Ij_2uw.js} +1 -1
- package/src/assets/web-panel/assets/{index-FQBsuExX.js → index-DDRlBaDt.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-ZCaUJc.js → index-DGsE7MQz.js} +1 -1
- package/src/assets/web-panel/assets/{index-BjcWKg1S.js → index-DHvxXXNA.js} +1 -1
- package/src/assets/web-panel/assets/{index-GA80ir_u.js → index-DV11jpeO.js} +1 -1
- package/src/assets/web-panel/assets/{index-CsovTpx9.js → index-DXdnfDVK.js} +1 -1
- package/src/assets/web-panel/assets/{index-nSn2-C4N.js → index-D_75jYWk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BJi3UqBt.js → index-DjI9MkId.js} +1 -1
- package/src/assets/web-panel/assets/{index-gINyI1rh.js → index-DlSvpNMf.js} +1 -1
- package/src/assets/web-panel/assets/{index-CfLJ42kv.js → index-Dox44j29.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2NyllnW.js → index-DpEKmjoa.js} +1 -1
- package/src/assets/web-panel/assets/{index-Iw0FfqUz.js → index-Dsy7_x4s.js} +1 -1
- package/src/assets/web-panel/assets/{index-4eyH-eC2.js → index-Gxw09e9R.js} +1 -1
- package/src/assets/web-panel/assets/{index-4PIeTM--.js → index-LfRlSmqe.js} +1 -1
- package/src/assets/web-panel/assets/{index-IZAWt0H8.js → index-Nz-MUHD1.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUU2606o.js → index-b9cuvFEv.js} +1 -1
- package/src/assets/web-panel/assets/{index-CzE53HiB.js → index-eR6H6NR7.js} +1 -1
- package/src/assets/web-panel/assets/{index-9PIVuXqo.js → index-fWgUQZ9d.js} +1 -1
- package/src/assets/web-panel/assets/{index-DkH1JvEt.js → index-mfWQRSLn.js} +1 -1
- package/src/assets/web-panel/assets/{index-DNMxIsDg.js → index-yOZYSNmG.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DI0Zaf8-.js → initDefaultProps-CJ1Bq2L3.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BZDKSy3Z.js → motion-rYJN_vzf.js} +1 -1
- package/src/assets/web-panel/assets/{move-DsIW01Vp.js → move-DnDK2gTP.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CohkDhsf.js → mtc-parser-CKnXy7ES.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DpiN5rzg.js → omit-3nRc3hWT.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-qbuqni3y.js → pickAttrs-Ddjj3sLu.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-mBky6714.js → placementArrow-CbsbphQY.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-Bas3eQ2K.js → responsiveObserve-D9aZ4VDJ.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CBx_SKoK.js → slide-D4pvdFj0.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BlYguJSV.js → statusUtils-C2W-vY-S.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BCYQmRGv.js → styleChecker-Cbq5150d.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Dp5dybLM.js → useFlexGapSupport-BA2B7R82.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DHAMBgA2.js → useFs-CLrwg3xg.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-W6jsSw76.js → usePersonalDataHub-DQeAI5qs.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BkI6aayc.js → vnode-8BDGy-YU.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-C_IMGueq.js → zoom-B2SzFprl.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agenda.js +74 -1
- package/src/commands/background-session.js +11 -1
- package/src/commands/batch.js +160 -5
- package/src/commands/plugin.js +90 -27
- package/src/commands/session.js +31 -1
- package/src/commands/team.js +212 -6
- package/src/data/changelog.json +26 -0
- package/src/gateways/terminal/PtyManager.js +45 -15
- package/src/gateways/ws/ws-agent-handler.js +15 -1
- package/src/gateways/ws/ws-session-gateway.js +88 -0
- package/src/harness/background-task-command-runner.js +234 -0
- package/src/harness/background-task-manager.js +150 -20
- package/src/harness/background-task-worker.js +17 -11
- package/src/harness/jsonl-session-store.js +57 -6
- package/src/harness/mcp-client.js +65 -43
- package/src/lib/agent-batch.js +4 -1
- package/src/lib/agent-team/team-worktree.js +3 -0
- package/src/lib/async-hook-supervisor.cjs +82 -10
- package/src/lib/async-hook-supervisor.js +50 -4
- package/src/lib/background-agent-supervisor.js +46 -0
- package/src/lib/collaboration-run-store.js +362 -0
- package/src/lib/event-runtime-host.js +12 -10
- package/src/lib/hook-runner.cjs +105 -18
- package/src/lib/hook-runner.js +79 -6
- package/src/lib/hook-shell-command.cjs +148 -0
- package/src/lib/hooks-v2-runtime.js +280 -81
- package/src/lib/hooks-v2-workspace-context.js +258 -0
- package/src/lib/jsonl-session-store.js +2 -0
- package/src/lib/lsp/__tests__/lsp-client.test.js +15 -0
- package/src/lib/lsp/lsp-client.js +12 -1
- package/src/lib/plugin-monitor-supervisor.js +53 -16
- package/src/lib/plugin-runtime/bin.js +21 -5
- package/src/lib/plugin-runtime/install.js +249 -57
- package/src/lib/plugin-runtime/mcp.js +21 -2
- package/src/lib/plugin-runtime/monitors.js +19 -3
- package/src/lib/plugin-runtime/sandbox-policy.js +100 -4
- package/src/lib/process-execution-broker/index.js +1151 -44
- package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +1557 -0
- package/src/lib/process-execution-broker/linux-generic-bwrap.js +1378 -0
- package/src/lib/process-execution-broker/platform-sandbox.js +586 -58
- package/src/lib/session-usage.js +202 -2
- package/src/lib/stream-retry.js +29 -0
- package/src/repl/agent-repl.js +40 -3
- package/src/runtime/agent-core.js +304 -42
- package/src/runtime/headless-runner.js +48 -1
- package/src/runtime/headless-stream.js +42 -2
- package/src/workers/background-agent-worker.js +5 -11
- package/src/assets/web-panel/assets/MarkdownRenderer-C0o4FtpD.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-VTc3gT1y.js +0 -1
- package/src/assets/web-panel/assets/RemoteSession-B6EEf8hh.js +0 -5
- package/src/assets/web-panel/assets/Tasks-D-R1x8vm.js +0 -1
- package/src/assets/web-panel/assets/Terminal-Dnkos7vW.js +0 -3
- package/src/assets/web-panel/assets/devWarning-D3Bho_6u.js +0 -1
- package/src/assets/web-panel/assets/index-5iAFwYx1.js +0 -1
- package/src/assets/web-panel/assets/index-BfnB7LPx.js +0 -1
package/src/lib/session-usage.js
CHANGED
|
@@ -32,6 +32,33 @@ function toNumber(v) {
|
|
|
32
32
|
return Number.isFinite(n) ? n : 0;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
const MAX_OBSERVED_DURATION_MS = 7 * 24 * 60 * 60 * 1000;
|
|
36
|
+
|
|
37
|
+
function observedDuration(value) {
|
|
38
|
+
if (value === null || value === undefined || value === "") return null;
|
|
39
|
+
const number = Number(value);
|
|
40
|
+
if (!Number.isFinite(number) || number < 0) return null;
|
|
41
|
+
return Math.min(MAX_OBSERVED_DURATION_MS, Math.round(number));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function eventDuration(event) {
|
|
45
|
+
return observedDuration(
|
|
46
|
+
event?.data?.duration_ms ??
|
|
47
|
+
event?.data?.durationMs ??
|
|
48
|
+
event?.data?.result?.toolTelemetryRecord?.durationMs,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function addObservedDuration(row, durationMs) {
|
|
53
|
+
if (durationMs === null) return;
|
|
54
|
+
row.durationMs = (row.durationMs || 0) + durationMs;
|
|
55
|
+
row.timedCalls = (row.timedCalls || 0) + 1;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function addObservedRetry(row) {
|
|
59
|
+
row.retries = (row.retries || 0) + 1;
|
|
60
|
+
}
|
|
61
|
+
|
|
35
62
|
/**
|
|
36
63
|
* Extract the optional usage-attribution frame (用量归因) persisted alongside
|
|
37
64
|
* a token_usage event's data: `{ origin, skill?, subagentId?, role?,
|
|
@@ -209,6 +236,56 @@ function _isToolResultError(event) {
|
|
|
209
236
|
);
|
|
210
237
|
}
|
|
211
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Aggregate compact `llm_retry` events. Each event represents one failed
|
|
241
|
+
* streaming attempt that the runtime actually retried and includes only a
|
|
242
|
+
* controlled reason plus its elapsed time — never the raw provider error.
|
|
243
|
+
*/
|
|
244
|
+
export function aggregateLlmRetries(events) {
|
|
245
|
+
const byReason = new Map();
|
|
246
|
+
const byModel = new Map();
|
|
247
|
+
let totalRetries = 0;
|
|
248
|
+
let durationMs = 0;
|
|
249
|
+
|
|
250
|
+
const add = (map, key, seed, elapsed) => {
|
|
251
|
+
const row = map.get(key) || { ...seed, retries: 0, durationMs: 0 };
|
|
252
|
+
row.retries++;
|
|
253
|
+
row.durationMs += elapsed;
|
|
254
|
+
map.set(key, row);
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
for (const event of events || []) {
|
|
258
|
+
if (event?.type !== "llm_retry") continue;
|
|
259
|
+
const data = event.data || {};
|
|
260
|
+
const elapsed = eventDuration(event) ?? 0;
|
|
261
|
+
const reason =
|
|
262
|
+
typeof data.reason === "string" && data.reason ? data.reason : "unknown";
|
|
263
|
+
const provider =
|
|
264
|
+
typeof data.provider === "string" && data.provider ? data.provider : null;
|
|
265
|
+
const model =
|
|
266
|
+
typeof data.model === "string" && data.model ? data.model : null;
|
|
267
|
+
totalRetries++;
|
|
268
|
+
durationMs += elapsed;
|
|
269
|
+
add(byReason, reason, { reason }, elapsed);
|
|
270
|
+
add(
|
|
271
|
+
byModel,
|
|
272
|
+
`${provider || "?"}/${model || "?"}`,
|
|
273
|
+
{ provider, model },
|
|
274
|
+
elapsed,
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (totalRetries === 0) return null;
|
|
279
|
+
const byRetriesDesc = (a, b) =>
|
|
280
|
+
b.retries - a.retries || b.durationMs - a.durationMs;
|
|
281
|
+
return {
|
|
282
|
+
totalRetries,
|
|
283
|
+
durationMs,
|
|
284
|
+
byReason: Array.from(byReason.values()).sort(byRetriesDesc),
|
|
285
|
+
byModel: Array.from(byModel.values()).sort(byRetriesDesc),
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
212
289
|
/**
|
|
213
290
|
* Aggregate the transcript's tool events: per-tool call/error counts, an MCP
|
|
214
291
|
* server bucket (`mcp__<server>__*`), and a turn-associated token figure.
|
|
@@ -232,6 +309,9 @@ export function aggregateToolCalls(events) {
|
|
|
232
309
|
const byPlugin = new Map();
|
|
233
310
|
let totalCalls = 0;
|
|
234
311
|
let totalErrors = 0;
|
|
312
|
+
let totalDurationMs = 0;
|
|
313
|
+
let timedCalls = 0;
|
|
314
|
+
let retryCalls = 0;
|
|
235
315
|
|
|
236
316
|
const bumpTool = (name) => {
|
|
237
317
|
let t = byTool.get(name);
|
|
@@ -276,6 +356,8 @@ export function aggregateToolCalls(events) {
|
|
|
276
356
|
let turnPlugins = new Set();
|
|
277
357
|
let turnTokens = 0;
|
|
278
358
|
let pendingPlugin = null;
|
|
359
|
+
let pendingObservation = null;
|
|
360
|
+
let failedToolsInTurn = new Set();
|
|
279
361
|
const flushTurn = () => {
|
|
280
362
|
if (turnTokens > 0) {
|
|
281
363
|
for (const name of turnTools) bumpTool(name).turnTokens += turnTokens;
|
|
@@ -291,6 +373,8 @@ export function aggregateToolCalls(events) {
|
|
|
291
373
|
turnPlugins = new Set();
|
|
292
374
|
turnTokens = 0;
|
|
293
375
|
pendingPlugin = null;
|
|
376
|
+
pendingObservation = null;
|
|
377
|
+
failedToolsInTurn = new Set();
|
|
294
378
|
};
|
|
295
379
|
|
|
296
380
|
for (const evt of events || []) {
|
|
@@ -301,20 +385,35 @@ export function aggregateToolCalls(events) {
|
|
|
301
385
|
}
|
|
302
386
|
if (evt.type === "tool_call") {
|
|
303
387
|
const name = evt.data?.tool || "?";
|
|
388
|
+
const durationMs = eventDuration(evt);
|
|
389
|
+
const isRetry = failedToolsInTurn.has(name);
|
|
304
390
|
totalCalls++;
|
|
305
391
|
const t = bumpTool(name);
|
|
306
392
|
t.calls++;
|
|
307
393
|
const isErr = evt.data?.is_error === true;
|
|
394
|
+
if (durationMs !== null) {
|
|
395
|
+
totalDurationMs += durationMs;
|
|
396
|
+
timedCalls++;
|
|
397
|
+
addObservedDuration(t, durationMs);
|
|
398
|
+
}
|
|
399
|
+
if (isRetry) {
|
|
400
|
+
retryCalls++;
|
|
401
|
+
addObservedRetry(t);
|
|
402
|
+
}
|
|
308
403
|
if (isErr) {
|
|
309
404
|
totalErrors++;
|
|
310
405
|
t.errors++;
|
|
311
406
|
}
|
|
407
|
+
if (isErr) failedToolsInTurn.add(name);
|
|
408
|
+
else failedToolsInTurn.delete(name);
|
|
312
409
|
turnTools.add(name);
|
|
313
410
|
const server = mcpServerOf(name);
|
|
314
411
|
if (server) {
|
|
315
412
|
const s = bumpServer(server);
|
|
316
413
|
s.calls++;
|
|
317
414
|
if (isErr) s.errors++;
|
|
415
|
+
addObservedDuration(s, durationMs);
|
|
416
|
+
if (isRetry) addObservedRetry(s);
|
|
318
417
|
turnServers.add(server);
|
|
319
418
|
}
|
|
320
419
|
const plugin =
|
|
@@ -326,24 +425,43 @@ export function aggregateToolCalls(events) {
|
|
|
326
425
|
? evt.data.plugin_version
|
|
327
426
|
: null;
|
|
328
427
|
pendingPlugin = { tool: name, plugin, version: pluginVersion };
|
|
428
|
+
pendingObservation = {
|
|
429
|
+
tool: name,
|
|
430
|
+
durationCounted: durationMs !== null,
|
|
431
|
+
errorCounted: isErr,
|
|
432
|
+
};
|
|
329
433
|
if (plugin) {
|
|
330
434
|
const p = bumpPlugin(plugin, pluginVersion);
|
|
331
435
|
p.calls++;
|
|
332
436
|
if (isErr) p.errors++;
|
|
437
|
+
addObservedDuration(p, durationMs);
|
|
438
|
+
if (isRetry) addObservedRetry(p);
|
|
333
439
|
turnPlugins.add(`${plugin}@${pluginVersion || "?"}`);
|
|
334
440
|
}
|
|
335
441
|
continue;
|
|
336
442
|
}
|
|
337
443
|
if (evt.type === "tool_result") {
|
|
338
444
|
const name = evt.data?.tool || "?";
|
|
445
|
+
const durationMs = eventDuration(evt);
|
|
339
446
|
turnTools.add(name);
|
|
340
447
|
const server = mcpServerOf(name);
|
|
341
448
|
if (server) turnServers.add(server);
|
|
342
|
-
|
|
449
|
+
const isErr = _isToolResultError(evt);
|
|
450
|
+
const pairedObservation =
|
|
451
|
+
pendingObservation?.tool === name ? pendingObservation : null;
|
|
452
|
+
if (isErr && !pairedObservation?.errorCounted) {
|
|
343
453
|
totalErrors++;
|
|
344
454
|
bumpTool(name).errors++;
|
|
345
455
|
if (server) bumpServer(server).errors++;
|
|
346
456
|
}
|
|
457
|
+
if (isErr) failedToolsInTurn.add(name);
|
|
458
|
+
else failedToolsInTurn.delete(name);
|
|
459
|
+
if (durationMs !== null && !pairedObservation?.durationCounted) {
|
|
460
|
+
totalDurationMs += durationMs;
|
|
461
|
+
timedCalls++;
|
|
462
|
+
addObservedDuration(bumpTool(name), durationMs);
|
|
463
|
+
if (server) addObservedDuration(bumpServer(server), durationMs);
|
|
464
|
+
}
|
|
347
465
|
const extracted = extractPluginUsageAttribution(evt.data?.result);
|
|
348
466
|
const plugin =
|
|
349
467
|
typeof evt.data?.plugin === "string" && evt.data.plugin
|
|
@@ -360,10 +478,14 @@ export function aggregateToolCalls(events) {
|
|
|
360
478
|
pendingPlugin?.plugin === plugin &&
|
|
361
479
|
(pendingPlugin?.version || null) === (pluginVersion || null);
|
|
362
480
|
if (!countedByCall) p.calls++;
|
|
363
|
-
if (
|
|
481
|
+
if (isErr && !countedByCall) p.errors++;
|
|
482
|
+
if (!countedByCall || !pairedObservation?.durationCounted) {
|
|
483
|
+
addObservedDuration(p, durationMs);
|
|
484
|
+
}
|
|
364
485
|
turnPlugins.add(`${plugin}@${pluginVersion || "?"}`);
|
|
365
486
|
}
|
|
366
487
|
pendingPlugin = null;
|
|
488
|
+
pendingObservation = null;
|
|
367
489
|
continue;
|
|
368
490
|
}
|
|
369
491
|
const u = extractUsage(evt);
|
|
@@ -375,6 +497,8 @@ export function aggregateToolCalls(events) {
|
|
|
375
497
|
return {
|
|
376
498
|
totalCalls,
|
|
377
499
|
totalErrors,
|
|
500
|
+
...(timedCalls > 0 ? { totalDurationMs, timedCalls } : {}),
|
|
501
|
+
...(retryCalls > 0 ? { retryCalls } : {}),
|
|
378
502
|
byTool: Array.from(byTool.values()).sort(byCallsDesc),
|
|
379
503
|
byMcpServer: Array.from(byServer.values()).sort(byCallsDesc),
|
|
380
504
|
byPlugin: Array.from(byPlugin.values()).sort(byCallsDesc),
|
|
@@ -386,9 +510,11 @@ export function aggregateToolCalls(events) {
|
|
|
386
510
|
* roll-ups + the tool/MCP call aggregation. Pure.
|
|
387
511
|
*/
|
|
388
512
|
export function sessionAttribution(events) {
|
|
513
|
+
const retries = aggregateLlmRetries(events);
|
|
389
514
|
return {
|
|
390
515
|
...aggregateUsageAttribution(events),
|
|
391
516
|
tools: aggregateToolCalls(events),
|
|
517
|
+
...(retries ? { retries } : {}),
|
|
392
518
|
};
|
|
393
519
|
}
|
|
394
520
|
|
|
@@ -519,8 +645,15 @@ export function allSessionsUsage({ limit = 1000 } = {}) {
|
|
|
519
645
|
const gTool = new Map();
|
|
520
646
|
const gServer = new Map();
|
|
521
647
|
const gPlugin = new Map();
|
|
648
|
+
const gRetryReason = new Map();
|
|
649
|
+
const gRetryModel = new Map();
|
|
522
650
|
let gToolCalls = 0;
|
|
523
651
|
let gToolErrors = 0;
|
|
652
|
+
let gToolDurationMs = 0;
|
|
653
|
+
let gTimedToolCalls = 0;
|
|
654
|
+
let gToolRetryCalls = 0;
|
|
655
|
+
let gLlmRetries = 0;
|
|
656
|
+
let gLlmRetryDurationMs = 0;
|
|
524
657
|
const mergeRow = (map, key, row, seed) => {
|
|
525
658
|
const entry = map.get(key) || { ...seed, ..._newSums() };
|
|
526
659
|
_addSums(entry, row);
|
|
@@ -545,6 +678,9 @@ export function allSessionsUsage({ limit = 1000 } = {}) {
|
|
|
545
678
|
const tools = a.tools || {};
|
|
546
679
|
gToolCalls += tools.totalCalls || 0;
|
|
547
680
|
gToolErrors += tools.totalErrors || 0;
|
|
681
|
+
gToolDurationMs += tools.totalDurationMs || 0;
|
|
682
|
+
gTimedToolCalls += tools.timedCalls || 0;
|
|
683
|
+
gToolRetryCalls += tools.retryCalls || 0;
|
|
548
684
|
for (const row of tools.byTool || []) {
|
|
549
685
|
const entry = gTool.get(row.tool) || {
|
|
550
686
|
tool: row.tool,
|
|
@@ -556,6 +692,12 @@ export function allSessionsUsage({ limit = 1000 } = {}) {
|
|
|
556
692
|
entry.calls += row.calls || 0;
|
|
557
693
|
entry.errors += row.errors || 0;
|
|
558
694
|
entry.turnTokens += row.turnTokens || 0;
|
|
695
|
+
if (row.durationMs !== undefined) {
|
|
696
|
+
entry.durationMs = (entry.durationMs || 0) + (row.durationMs || 0);
|
|
697
|
+
entry.timedCalls = (entry.timedCalls || 0) + (row.timedCalls || 0);
|
|
698
|
+
}
|
|
699
|
+
if (row.retries !== undefined)
|
|
700
|
+
entry.retries = (entry.retries || 0) + (row.retries || 0);
|
|
559
701
|
gTool.set(row.tool, entry);
|
|
560
702
|
}
|
|
561
703
|
for (const row of tools.byMcpServer || []) {
|
|
@@ -568,6 +710,12 @@ export function allSessionsUsage({ limit = 1000 } = {}) {
|
|
|
568
710
|
entry.calls += row.calls || 0;
|
|
569
711
|
entry.errors += row.errors || 0;
|
|
570
712
|
entry.turnTokens += row.turnTokens || 0;
|
|
713
|
+
if (row.durationMs !== undefined) {
|
|
714
|
+
entry.durationMs = (entry.durationMs || 0) + (row.durationMs || 0);
|
|
715
|
+
entry.timedCalls = (entry.timedCalls || 0) + (row.timedCalls || 0);
|
|
716
|
+
}
|
|
717
|
+
if (row.retries !== undefined)
|
|
718
|
+
entry.retries = (entry.retries || 0) + (row.retries || 0);
|
|
571
719
|
gServer.set(row.server, entry);
|
|
572
720
|
}
|
|
573
721
|
for (const row of tools.byPlugin || []) {
|
|
@@ -582,10 +730,45 @@ export function allSessionsUsage({ limit = 1000 } = {}) {
|
|
|
582
730
|
entry.calls += row.calls || 0;
|
|
583
731
|
entry.errors += row.errors || 0;
|
|
584
732
|
entry.turnTokens += row.turnTokens || 0;
|
|
733
|
+
if (row.durationMs !== undefined) {
|
|
734
|
+
entry.durationMs = (entry.durationMs || 0) + (row.durationMs || 0);
|
|
735
|
+
entry.timedCalls = (entry.timedCalls || 0) + (row.timedCalls || 0);
|
|
736
|
+
}
|
|
737
|
+
if (row.retries !== undefined)
|
|
738
|
+
entry.retries = (entry.retries || 0) + (row.retries || 0);
|
|
585
739
|
gPlugin.set(key, entry);
|
|
586
740
|
}
|
|
741
|
+
const retries = a.retries || null;
|
|
742
|
+
if (retries) {
|
|
743
|
+
gLlmRetries += retries.totalRetries || 0;
|
|
744
|
+
gLlmRetryDurationMs += retries.durationMs || 0;
|
|
745
|
+
for (const row of retries.byReason || []) {
|
|
746
|
+
const entry = gRetryReason.get(row.reason) || {
|
|
747
|
+
reason: row.reason,
|
|
748
|
+
retries: 0,
|
|
749
|
+
durationMs: 0,
|
|
750
|
+
};
|
|
751
|
+
entry.retries += row.retries || 0;
|
|
752
|
+
entry.durationMs += row.durationMs || 0;
|
|
753
|
+
gRetryReason.set(row.reason, entry);
|
|
754
|
+
}
|
|
755
|
+
for (const row of retries.byModel || []) {
|
|
756
|
+
const key = `${row.provider || "?"}/${row.model || "?"}`;
|
|
757
|
+
const entry = gRetryModel.get(key) || {
|
|
758
|
+
provider: row.provider || null,
|
|
759
|
+
model: row.model || null,
|
|
760
|
+
retries: 0,
|
|
761
|
+
durationMs: 0,
|
|
762
|
+
};
|
|
763
|
+
entry.retries += row.retries || 0;
|
|
764
|
+
entry.durationMs += row.durationMs || 0;
|
|
765
|
+
gRetryModel.set(key, entry);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
587
768
|
}
|
|
588
769
|
const byCallsDesc = (a, b) => b.calls - a.calls;
|
|
770
|
+
const byRetriesDesc = (a, b) =>
|
|
771
|
+
b.retries - a.retries || b.durationMs - a.durationMs;
|
|
589
772
|
|
|
590
773
|
return {
|
|
591
774
|
sessions: perSession,
|
|
@@ -601,10 +784,27 @@ export function allSessionsUsage({ limit = 1000 } = {}) {
|
|
|
601
784
|
tools: {
|
|
602
785
|
totalCalls: gToolCalls,
|
|
603
786
|
totalErrors: gToolErrors,
|
|
787
|
+
...(gTimedToolCalls > 0
|
|
788
|
+
? {
|
|
789
|
+
totalDurationMs: gToolDurationMs,
|
|
790
|
+
timedCalls: gTimedToolCalls,
|
|
791
|
+
}
|
|
792
|
+
: {}),
|
|
793
|
+
...(gToolRetryCalls > 0 ? { retryCalls: gToolRetryCalls } : {}),
|
|
604
794
|
byTool: Array.from(gTool.values()).sort(byCallsDesc),
|
|
605
795
|
byMcpServer: Array.from(gServer.values()).sort(byCallsDesc),
|
|
606
796
|
byPlugin: Array.from(gPlugin.values()).sort(byCallsDesc),
|
|
607
797
|
},
|
|
798
|
+
...(gLlmRetries > 0
|
|
799
|
+
? {
|
|
800
|
+
retries: {
|
|
801
|
+
totalRetries: gLlmRetries,
|
|
802
|
+
durationMs: gLlmRetryDurationMs,
|
|
803
|
+
byReason: Array.from(gRetryReason.values()).sort(byRetriesDesc),
|
|
804
|
+
byModel: Array.from(gRetryModel.values()).sort(byRetriesDesc),
|
|
805
|
+
},
|
|
806
|
+
}
|
|
807
|
+
: {}),
|
|
608
808
|
},
|
|
609
809
|
};
|
|
610
810
|
}
|
package/src/lib/stream-retry.js
CHANGED
|
@@ -81,3 +81,32 @@ export function isRetryableStreamError(err, signal) {
|
|
|
81
81
|
msg,
|
|
82
82
|
);
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Reduce a retryable stream failure to a small, secret-free reason vocabulary
|
|
87
|
+
* suitable for persisted usage telemetry. Never persist the provider's raw
|
|
88
|
+
* error message: it can contain a request URL, tenant id, or proxy details.
|
|
89
|
+
*/
|
|
90
|
+
export function classifyStreamRetryReason(err) {
|
|
91
|
+
const code = String(err?.code || err?.cause?.code || "").toUpperCase();
|
|
92
|
+
if (code === "ETIMEDOUT") return "timeout";
|
|
93
|
+
if (["EAI_AGAIN", "ENOTFOUND"].includes(code)) return "dns";
|
|
94
|
+
if (code === "ECONNREFUSED") return "connection_refused";
|
|
95
|
+
if (code === "ENETUNREACH") return "network_unreachable";
|
|
96
|
+
if (["ECONNRESET", "EPIPE", "UND_ERR_SOCKET"].includes(code)) {
|
|
97
|
+
return "connection_reset";
|
|
98
|
+
}
|
|
99
|
+
const msg = String(err?.message || err || "").toLowerCase();
|
|
100
|
+
if (/timed?\s*out|etimedout/.test(msg)) return "timeout";
|
|
101
|
+
if (/eai_again|enotfound|dns/.test(msg)) return "dns";
|
|
102
|
+
if (/econnrefused/.test(msg)) return "connection_refused";
|
|
103
|
+
if (/network unreachable|enetunreach/.test(msg)) return "network_unreachable";
|
|
104
|
+
if (
|
|
105
|
+
/econnreset|socket hang ?up|terminated|fetch failed|network error|premature close/.test(
|
|
106
|
+
msg,
|
|
107
|
+
)
|
|
108
|
+
) {
|
|
109
|
+
return "connection_reset";
|
|
110
|
+
}
|
|
111
|
+
return "unknown";
|
|
112
|
+
}
|
package/src/repl/agent-repl.js
CHANGED
|
@@ -48,10 +48,12 @@ import {
|
|
|
48
48
|
appendCompactEvent,
|
|
49
49
|
appendTokenUsage,
|
|
50
50
|
appendToolCallCompact,
|
|
51
|
+
appendLlmRetryCompact,
|
|
51
52
|
appendEvent,
|
|
52
53
|
rebuildMessages,
|
|
53
54
|
sessionExists,
|
|
54
55
|
} from "../harness/jsonl-session-store.js";
|
|
56
|
+
import { classifyStreamRetryReason } from "../lib/stream-retry.js";
|
|
55
57
|
import { CLISkillLoader } from "../lib/skill-loader.js";
|
|
56
58
|
import { storeMemory, consolidateMemory } from "../lib/hierarchical-memory.js";
|
|
57
59
|
import { CLIContextEngineering } from "../lib/cli-context-engineering.js";
|
|
@@ -119,6 +121,7 @@ import {
|
|
|
119
121
|
questionWithIdleTimeout,
|
|
120
122
|
} from "./permission-prompt.js";
|
|
121
123
|
import { describeAskContext, raceLocalAndRemote } from "./remote-approval.js";
|
|
124
|
+
import { runWithHostHooksV2Workspace } from "../lib/hooks-v2-workspace-context.js";
|
|
122
125
|
import {
|
|
123
126
|
parsePermissionTier,
|
|
124
127
|
parsePermissionModeArg,
|
|
@@ -353,13 +356,25 @@ export async function agentLoop(messages, options) {
|
|
|
353
356
|
chalk.gray(` ⎌ checkpoint ${event.id} (before ${event.tool})\n`),
|
|
354
357
|
);
|
|
355
358
|
} else if (event.type === "tool-executing") {
|
|
356
|
-
_lastExec = {
|
|
359
|
+
_lastExec = {
|
|
360
|
+
tool: event.tool,
|
|
361
|
+
args: event.args,
|
|
362
|
+
startedAt: options.now ? options.now() : Date.now(),
|
|
363
|
+
};
|
|
357
364
|
process.stdout.write(
|
|
358
365
|
chalk.gray(
|
|
359
366
|
` [${event.tool}] ${formatToolArgs(event.tool, event.args)}\n`,
|
|
360
367
|
),
|
|
361
368
|
);
|
|
362
369
|
} else if (event.type === "tool-result") {
|
|
370
|
+
const durationMs =
|
|
371
|
+
event.result?.toolTelemetryRecord?.durationMs ??
|
|
372
|
+
(_lastExec?.tool === event.tool
|
|
373
|
+
? Math.max(
|
|
374
|
+
0,
|
|
375
|
+
(options.now ? options.now() : Date.now()) - _lastExec.startedAt,
|
|
376
|
+
)
|
|
377
|
+
: undefined);
|
|
363
378
|
// 用量归因: persist a compact tool_call record (name + error flag +
|
|
364
379
|
// skill/plugin hints — never args, which can carry whole file bodies)
|
|
365
380
|
// so `cc session usage --by tool|mcp|plugin` and `cc insights` can
|
|
@@ -375,6 +390,7 @@ export async function agentLoop(messages, options) {
|
|
|
375
390
|
? _lastExec.args?.skill_name
|
|
376
391
|
: undefined,
|
|
377
392
|
...extractPluginUsageAttribution(event.result),
|
|
393
|
+
durationMs,
|
|
378
394
|
});
|
|
379
395
|
} catch (_e) {
|
|
380
396
|
// persistence is best-effort — never break the turn
|
|
@@ -462,6 +478,13 @@ export async function agentLoop(messages, options) {
|
|
|
462
478
|
* Start the agentic REPL
|
|
463
479
|
*/
|
|
464
480
|
export async function startAgentRepl(options = {}) {
|
|
481
|
+
const trustedWorkspaceRoot = process.cwd();
|
|
482
|
+
return runWithHostHooksV2Workspace(trustedWorkspaceRoot, () =>
|
|
483
|
+
startAgentReplInWorkspace(options),
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
async function startAgentReplInWorkspace(options = {}) {
|
|
465
488
|
// EPIPE guard: if the REPL's stdout is piped and the consumer closes (e.g.
|
|
466
489
|
// `cc agent | head`), the async stream `error` would otherwise crash the
|
|
467
490
|
// process. Route a broken pipe into the REPL's own graceful shutdown (the
|
|
@@ -5570,12 +5593,26 @@ export async function startAgentRepl(options = {}) {
|
|
|
5570
5593
|
// streaming call hits a transient connection drop and retries, tell the
|
|
5571
5594
|
// user instead of leaving them staring at a silent pause. To stderr so
|
|
5572
5595
|
// it never corrupts the streamed answer on stdout.
|
|
5573
|
-
onStreamRetry: (attempt) =>
|
|
5596
|
+
onStreamRetry: (attempt, error, telemetry = {}) => {
|
|
5574
5597
|
process.stderr.write(
|
|
5575
5598
|
chalk.dim(
|
|
5576
5599
|
` ⟳ connection dropped — retrying (attempt ${attempt})…\n`,
|
|
5577
5600
|
),
|
|
5578
|
-
)
|
|
5601
|
+
);
|
|
5602
|
+
if (useJsonl && sessionId) {
|
|
5603
|
+
try {
|
|
5604
|
+
appendLlmRetryCompact(sessionId, {
|
|
5605
|
+
attempt,
|
|
5606
|
+
durationMs: telemetry.durationMs,
|
|
5607
|
+
provider: telemetry.provider || provider,
|
|
5608
|
+
model: telemetry.model || activeModel,
|
|
5609
|
+
reason: classifyStreamRetryReason(error),
|
|
5610
|
+
});
|
|
5611
|
+
} catch {
|
|
5612
|
+
/* usage telemetry is best-effort */
|
|
5613
|
+
}
|
|
5614
|
+
}
|
|
5615
|
+
},
|
|
5579
5616
|
// Stream-stall hint (Claude-Code 2.1.185): the connection is alive but
|
|
5580
5617
|
// the API has gone silent mid-response — tell the user we're still
|
|
5581
5618
|
// waiting instead of leaving a frozen spinner. stderr so it never
|