chainlesschain 0.162.158 → 0.162.159
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/assets/{AIOps-BwpTJTN_.js → AIOps-ByIiF5bT.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BtQOoo3l.js → ActionButton-NlgSFZq5.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Duf_rXZa.js → Analytics-D17cOUcb.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-XQK3wjvB.js → AppLayout-B4mEZcbl.js} +4 -4
- package/src/assets/web-panel/assets/Artifacts-CASsmyQw.js +1 -0
- package/src/assets/web-panel/assets/{Audit-DNjOGQLh.js → Audit-DYAia2e2.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-FH9RAfB5.js → BackgroundAgents-C1lvYUSu.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-ZIbrR4-U.js → Backup-B6agK6bA.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DSt3NaND.js → BaseInput-DM43R2vy.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CY-wvbjv.js → Chat-Dtdp3eXp.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BAV9V-t-.js → ChatBubbleRenderer-BL5c_OQ1.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-8JVadE_B.js → Checkbox-D2xf7uZt.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CN83nPYI.js → Codegen-D3j45jJL.js} +1 -1
- package/src/assets/web-panel/assets/{Col-xPSvqdN8.js → Col-voPJ9fUZ.js} +1 -1
- package/src/assets/web-panel/assets/{Community-D78cnIjG.js → Community-DEsyTESF.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CSw6Csbp.js → Compact-OHV_QXLD.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-E_HhjcYR.js → Compliance-eDTJWC-J.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DybeQjmm.js → Cowork-BBvy-6d1.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DS0BJeLY.js → Cron-Dw2eoJxu.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BOwVgkbs.js → Crosschain-DQHms_Bh.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DRUr9YuX.js → DID-Cyu7Id1c.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Cht-yUKW.js → Dashboard-sIDzkG92.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BLr_EJ9X.js → Dropdown-DUW3T2ey.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Drexuh5W.js → EmailListRenderer-CECELXW8.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-D9Q2Kq63.js → FamilyGuardDashboard-BIZR37ov.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-C-Z1xI-T.js → Federation-BEZIQX84.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DLHPMkQF.js → FormItemContext-BcdUMznL.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DxxEdn2r.js → GenericCardRenderer-DsN_fr5H.js} +1 -1
- package/src/assets/web-panel/assets/{Git-syATcaBt.js → Git-63LhjBx2.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CYe_r8Zf.js → Governance-CYtQtIcH.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-GWxErB7k.js → Inference-BwR6UUox.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-qQvVCZoi.js → KnowledgeGraph-D9lVNTUA.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BenAU2W8.js → Logs-C4q5h7Ut.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-7agE3Or1.js → MarkdownRenderer-DexLlXfN.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-D4Jn5fpD.js → Marketplace-Plksliuw.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DtAwoqiQ.js → McpTools-DZUFfeuG.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-BI_O50I8.js → Memory-NoDYt29V.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CQWE2lqx.js → MobileBridge-CEXGTkdh.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CVtTqgtg.js → MobileProjects-DnbJkbZo.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Dnr16qsn.js → Mtc-DTAa0cwy.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-CQ5Xe4-a.js → MtcAudit-CVV7LnNS.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-Bjr8O-wy.js → Multisig-BqqGrjt_.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CEe-KirU.js → NLProgramming-C4WP8DRp.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-spKJIKF9.js → Notes-Zo4DJUVI.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-DRp83LFG.js → NotificationSettings-DBcjRaz2.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-BCQel9bD.js +1 -0
- package/src/assets/web-panel/assets/{Organization-BlgB0IYg.js → Organization-BT9WPBOX.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-a_35HqZI.js → Overflow-D6b4bZ3q.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CSNHCNPC.js → P2P-Cw3OsYx-.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-C8M1JH-1.js → PdhVaultBrowser-C0nyiK2b.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-DmjJi9Ms.js → Permissions-zVBZEB_C.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-DfuwRyf4.js → PersonalDataHub-BOspsFew.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-B2-S4ekE.js → Pipeline-CQWfZ4XH.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-B1dOiBLC.js → Privacy-C2oGJ_WL.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-_pNmc-DX.js → ProjectInit-BZMR4qY1.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DmwG2Ii1.js → ProjectSettings-DAujoP63.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-COATmHxF.js → Projects-DvH_P2Uq.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-C6HSjg1d.js → Providers-D_RGHM-v.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CrDmS7l1.js → QrScannerModal-Mf6KfL2J.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CfKvWt-x.js → QuickAsk-5D8URoI_.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DMa6Kuzv.js → Recommend-Df4kC8Gy.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DrktUo5x.js → RemoteSession-DGi3f3vO.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-BTPQ1vjL.js → Reputation-jmkGFNWb.js} +1 -1
- package/src/assets/web-panel/assets/{Row-B6Q7QkMG.js → Row-DP6Pcu3m.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-B1IJhAmX.js → RssFeed-D60hSuPO.js} +3 -3
- package/src/assets/web-panel/assets/{Search-xbea1kGD.js → Search-0mf1BQUK.js} +1 -1
- package/src/assets/web-panel/assets/{Security-7rs0cO3F.js → Security-CfZtLFYV.js} +4 -4
- package/src/assets/web-panel/assets/{Services-0fjixK0S.js → Services-D9zpZLWz.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-B_rVq9Cu.js → Skeleton-D1_44eMD.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-C5uM90b9.js → Skills-cVFa8zkz.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-U4pYCIZH.js → Sla-Cinpzc3L.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Cdz4yTWx.js → SpeechSettings-bqdiJE_P.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Me3aetHv.js → SyncSettings-Dgl_SLgj.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Cf6aNkL_.js → Tasks-DawWAEhy.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CYatk4tU.js → Templates-Ca0nY651.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DIMKLw7o.js → Tenant-CgaGEhLm.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-C_cp-uSJ.js → Terminal-D-9EnpRx.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-cUPVNADp.js → TimelineRenderer-CSOxDHZ6.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CiaEIXVf.js → Tokens-BpwLZpL3.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DB1WU5lQ.js → Trigger-DgowwBK5.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-Cfht9Ijy.js → Trust-BZutapjE.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-K3P4Vt9S.js → UkeySign-QZPt8_Sp.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DWjhjXRh.js → VideoEditing-DlQx5UDJ.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-D9-Q1Kan.js → Wallet-ZfdTgtWA.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-BDszy-oV.js → WebAuthn-CAp0y_Cr.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-DIhij4rA.js → WorkflowEditor-BVITZEmr.js} +1 -1
- package/src/assets/web-panel/assets/{chat-D7VCiKbh.js → chat-CC2tPaNg.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BvOd9pVn.js → colors-31brc9CA.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DoqXBiAO.js → compact-item-DLMkC9C-.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CrKRzUtp.js → createContext-BMtveI6F.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CB8pPOtd.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BWAev4WC.js → hasIn-DbD6WHW2.js} +1 -1
- package/src/assets/web-panel/assets/{index-B30NvR21.js → index-3oBsXZmF.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cx7M7PSF.js → index-ALvoNTRF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHOcVYrx.js → index-AaIKG60c.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXyl8O23.js → index-BFRLmCR3.js} +1 -1
- package/src/assets/web-panel/assets/{index-YGDy7nNq.js → index-BKAB6-6V.js} +1 -1
- package/src/assets/web-panel/assets/{index-BoYrS_L2.js → index-BOM-VFlv.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bq_ctRpz.js → index-BPpS-lGb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDGLdn12.js → index-Bbc2JeQG.js} +1 -1
- package/src/assets/web-panel/assets/index-BhXiaiev.js +1 -0
- package/src/assets/web-panel/assets/{index-ISvPZ05r.js → index-BiRQUoyE.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0vGEbJT.js → index-BnFLzejT.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bj7EgmOp.js → index-BoO4WEJB.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZGk8AbZ.js → index-C-cGlCDW.js} +1 -1
- package/src/assets/web-panel/assets/{index-BkgnGX7v.js → index-C1PfeI88.js} +1 -1
- package/src/assets/web-panel/assets/{index-HwHdTusY.js → index-C21pdBqs.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bf9YlbDn.js → index-C7LHNw_N.js} +1 -1
- package/src/assets/web-panel/assets/{index-oY45XrkG.js → index-CEXa-4zd.js} +1 -1
- package/src/assets/web-panel/assets/{index-KR1-Em9C.js → index-CEwjBA9q.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5kRmj3P.js → index-CFXKbOek.js} +1 -1
- package/src/assets/web-panel/assets/{index-BN9m4Ux2.js → index-CJhREOlG.js} +1 -1
- package/src/assets/web-panel/assets/{index-PDxGjKRu.js → index-COHHQ9cU.js} +1 -1
- package/src/assets/web-panel/assets/{index-D23L1V76.js → index-CUmLMFsy.js} +1 -1
- package/src/assets/web-panel/assets/{index-zH-tuuGZ.js → index-CWgfipcC.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmJ6xKBO.js → index-C_eUKGYP.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEPHMSih.js → index-CcVszn2b.js} +1 -1
- package/src/assets/web-panel/assets/{index-DV-Rfmfx.js → index-Cod97Urs.js} +3 -3
- package/src/assets/web-panel/assets/{index-BWWsaimP.js → index-Cwbqh0KZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-8g5TJCZ3.js → index-D67kIagl.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEXfKSiI.js → index-D7cV0tu0.js} +1 -1
- package/src/assets/web-panel/assets/{index-CoD31Ndm.js → index-DJvxFyIz.js} +1 -1
- package/src/assets/web-panel/assets/{index-CSb-tnIo.js → index-DZl-UXB6.js} +1 -1
- package/src/assets/web-panel/assets/{index-DvDOpsJB.js → index-Dm0byjm1.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlGu7As6.js → index-DndNnYc0.js} +1 -1
- package/src/assets/web-panel/assets/{index-gmxqu5Kk.js → index-WQUO2vvK.js} +1 -1
- package/src/assets/web-panel/assets/index-WpaYaE3D.js +1 -0
- package/src/assets/web-panel/assets/{index-ww1QtLnX.js → index-bdaJwTXJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-JzUmJMvn.js → index-ep6JchNG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCyP071m.js → index-jG6h22Qg.js} +1 -1
- package/src/assets/web-panel/assets/{index-1poMpMU0.js → index-ntVQqSML.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-XW-OR3mL.js → initDefaultProps-D5UoBRhN.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CeuEHh20.js → motion-DltOw0CR.js} +1 -1
- package/src/assets/web-panel/assets/{move-Dva79Keg.js → move-_oPkk5zj.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-C0B6bD2j.js → mtc-parser-EES8ROCS.js} +1 -1
- package/src/assets/web-panel/assets/{omit-AkZvO-a2.js → omit-B-_39x_M.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-B4r55qGc.js → pickAttrs-l6D0yJHz.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BLH-z7YE.js → placementArrow-DIeUK31L.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-ksEGZ2Wf.js → responsiveObserve-dG4EzUQo.js} +1 -1
- package/src/assets/web-panel/assets/{slide-Cth4OD1Z.js → slide-DWFzYGdH.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-9S83ezxw.js → statusUtils-CECdTA5H.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-7yQmQGZ4.js → styleChecker-D6kP-mMK.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DpGnMmPc.js → useFlexGapSupport-BWfna_rd.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-C4zDZIXH.js → useFs-Bb-j6rzo.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CoLICdUZ.js → usePersonalDataHub-D5OIsYM4.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CKyH-35X.js → vnode-DNpwzFTM.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DRDGit17.js → zoom-vNLpFQBW.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-manifest.json +17 -3
- package/src/commands/agent.js +7 -0
- package/src/commands/background-session.js +143 -3
- package/src/commands/browse.js +86 -0
- package/src/commands/cloud.js +232 -0
- package/src/commands/doctor.js +61 -6
- package/src/commands/mcp.js +61 -0
- package/src/commands/plugin.js +63 -1
- package/src/commands/routine.js +367 -0
- package/src/commands/session.js +326 -0
- package/src/data/changelog.json +7 -2
- package/src/harness/jsonl-session-store.js +82 -2
- package/src/harness/session-index.js +295 -0
- package/src/harness/session-mirror.js +142 -0
- package/src/harness/transcript-integrity.js +182 -0
- package/src/index.js +8 -0
- package/src/lib/background-agent-supervisor.js +126 -2
- package/src/lib/channels/channel-manager.js +126 -0
- package/src/lib/channels/telegram-channel.js +112 -0
- package/src/lib/channels/webhook-channel.js +140 -0
- package/src/lib/chrome-connector.js +386 -0
- package/src/lib/cloud/bundle.js +110 -0
- package/src/lib/cloud/cloud-client.js +152 -0
- package/src/lib/computer-use/authorization.js +173 -0
- package/src/lib/computer-use/computer-use-server.js +276 -0
- package/src/lib/computer-use/control-backend.js +150 -0
- package/src/lib/doctor-checkup.js +652 -0
- package/src/lib/jsonl-session-store.js +4 -0
- package/src/lib/lsp/lsp-server-registry.js +48 -21
- package/src/lib/plugin-runtime/governance.js +174 -0
- package/src/lib/pr-link-ledger.js +221 -0
- package/src/lib/routine-store.js +352 -0
- package/src/lib/session-store-guard.js +40 -0
- package/src/lib/session-usage.js +318 -2
- package/src/lib/sub-agent-context.js +23 -0
- package/src/repl/agent-repl.js +361 -3
- package/src/repl/bg-dashboard.js +355 -0
- package/src/repl/fast-mode.js +103 -0
- package/src/repl/fullscreen-tui.js +197 -0
- package/src/repl/slash-command-registry.js +11 -3
- package/src/repl/voice-dictation.js +132 -0
- package/src/runtime/agent-core.js +242 -1
- package/src/runtime/coding-agent-contract-shared.cjs +88 -0
- package/src/runtime/coding-agent-policy.cjs +17 -0
- package/src/runtime/headless-runner.js +71 -7
- package/src/runtime/headless-stream.js +14 -8
- package/src/runtime/policies/agent-policy.js +3 -0
- package/src/assets/web-panel/assets/Artifacts-DQvJoQ6E.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-h1A0XB2a.js +0 -1
- package/src/assets/web-panel/assets/devWarning-nDB--2xr.js +0 -1
- package/src/assets/web-panel/assets/index-B1_pRTtB.js +0 -1
- package/src/assets/web-panel/assets/index-TMM9FuW-.js +0 -1
package/src/lib/session-usage.js
CHANGED
|
@@ -31,6 +31,30 @@ function toNumber(v) {
|
|
|
31
31
|
return Number.isFinite(n) ? n : 0;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Extract the optional usage-attribution frame (用量归因) persisted alongside
|
|
36
|
+
* a token_usage event's data: `{ origin, skill?, subagentId?, role?,
|
|
37
|
+
* parentSessionId?, depth? }`. Written by the agent drivers for sub-agent /
|
|
38
|
+
* isolated-skill usage; absent on legacy events and on plain main-loop usage
|
|
39
|
+
* (absence ⇒ origin "main"). Returns a normalized copy or null.
|
|
40
|
+
*/
|
|
41
|
+
export function extractAttribution(event) {
|
|
42
|
+
const a = event?.data?.attribution;
|
|
43
|
+
if (!a || typeof a !== "object") return null;
|
|
44
|
+
const origin = typeof a.origin === "string" && a.origin ? a.origin : null;
|
|
45
|
+
if (!origin) return null;
|
|
46
|
+
const out = { origin };
|
|
47
|
+
if (typeof a.skill === "string" && a.skill) out.skill = a.skill;
|
|
48
|
+
if (typeof a.subagentId === "string" && a.subagentId)
|
|
49
|
+
out.subagentId = a.subagentId;
|
|
50
|
+
if (typeof a.role === "string" && a.role) out.role = a.role;
|
|
51
|
+
if (typeof a.parentSessionId === "string" && a.parentSessionId)
|
|
52
|
+
out.parentSessionId = a.parentSessionId;
|
|
53
|
+
const depth = Number(a.depth);
|
|
54
|
+
if (Number.isFinite(depth)) out.depth = depth;
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
|
|
34
58
|
/**
|
|
35
59
|
* Extract a normalized usage record from a single event, or null if none.
|
|
36
60
|
* Accepts both snake_case (OpenAI/Anthropic) and camelCase variants.
|
|
@@ -75,6 +99,9 @@ export function extractUsage(event) {
|
|
|
75
99
|
return null;
|
|
76
100
|
}
|
|
77
101
|
|
|
102
|
+
// Attribution rides along ONLY when present, so records built from legacy
|
|
103
|
+
// events stay byte-identical (callers using exact-equality keep passing).
|
|
104
|
+
const attribution = extractAttribution(event);
|
|
78
105
|
return {
|
|
79
106
|
provider: d.provider || raw.provider || null,
|
|
80
107
|
model: d.model || raw.model || null,
|
|
@@ -84,6 +111,223 @@ export function extractUsage(event) {
|
|
|
84
111
|
cacheReadTokens,
|
|
85
112
|
cacheCreationTokens,
|
|
86
113
|
timestamp: event.timestamp || null,
|
|
114
|
+
...(attribution ? { attribution } : {}),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ── Usage attribution roll-ups (用量归因) ───────────────────────────────────
|
|
119
|
+
|
|
120
|
+
function _newSums() {
|
|
121
|
+
return {
|
|
122
|
+
inputTokens: 0,
|
|
123
|
+
outputTokens: 0,
|
|
124
|
+
totalTokens: 0,
|
|
125
|
+
cacheReadTokens: 0,
|
|
126
|
+
cacheCreationTokens: 0,
|
|
127
|
+
calls: 0,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function _addSums(sums, u) {
|
|
132
|
+
sums.inputTokens += u.inputTokens || 0;
|
|
133
|
+
sums.outputTokens += u.outputTokens || 0;
|
|
134
|
+
sums.totalTokens += u.totalTokens || 0;
|
|
135
|
+
sums.cacheReadTokens += u.cacheReadTokens || 0;
|
|
136
|
+
sums.cacheCreationTokens += u.cacheCreationTokens || 0;
|
|
137
|
+
sums.calls += u.calls != null ? u.calls : 1;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const _byTokensDesc = (a, b) => b.totalTokens - a.totalTokens;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Roll usage events up by attribution: origin (main | subagent | skill —
|
|
144
|
+
* events without an attribution frame count as "main", which keeps every
|
|
145
|
+
* pre-attribution transcript aggregating exactly as before), by skill name,
|
|
146
|
+
* and by individual sub-agent.
|
|
147
|
+
*/
|
|
148
|
+
export function aggregateUsageAttribution(events) {
|
|
149
|
+
const byOrigin = new Map();
|
|
150
|
+
const bySkill = new Map();
|
|
151
|
+
const bySubagent = new Map();
|
|
152
|
+
|
|
153
|
+
for (const evt of events || []) {
|
|
154
|
+
const u = extractUsage(evt);
|
|
155
|
+
if (!u) continue;
|
|
156
|
+
const attr = u.attribution || null;
|
|
157
|
+
const origin = attr?.origin || "main";
|
|
158
|
+
|
|
159
|
+
const o = byOrigin.get(origin) || { origin, ..._newSums() };
|
|
160
|
+
_addSums(o, u);
|
|
161
|
+
byOrigin.set(origin, o);
|
|
162
|
+
|
|
163
|
+
if (origin === "skill") {
|
|
164
|
+
const key = attr?.skill || "?";
|
|
165
|
+
const s = bySkill.get(key) || { skill: key, ..._newSums() };
|
|
166
|
+
_addSums(s, u);
|
|
167
|
+
bySkill.set(key, s);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (attr?.subagentId) {
|
|
171
|
+
const key = attr.subagentId;
|
|
172
|
+
const r = bySubagent.get(key) || {
|
|
173
|
+
subagentId: key,
|
|
174
|
+
role: attr.role || null,
|
|
175
|
+
origin,
|
|
176
|
+
..._newSums(),
|
|
177
|
+
};
|
|
178
|
+
_addSums(r, u);
|
|
179
|
+
bySubagent.set(key, r);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
byOrigin: Array.from(byOrigin.values()).sort(_byTokensDesc),
|
|
185
|
+
bySkill: Array.from(bySkill.values()).sort(_byTokensDesc),
|
|
186
|
+
bySubagent: Array.from(bySubagent.values()).sort(_byTokensDesc),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* MCP tools reach the loop as `mcp__<server>__<tool>`; returns the server
|
|
192
|
+
* segment or null for a non-MCP tool name.
|
|
193
|
+
*/
|
|
194
|
+
export function mcpServerOf(toolName) {
|
|
195
|
+
if (typeof toolName !== "string" || !toolName.startsWith("mcp__"))
|
|
196
|
+
return null;
|
|
197
|
+
const rest = toolName.slice(5);
|
|
198
|
+
const sep = rest.indexOf("__");
|
|
199
|
+
return sep > 0 ? rest.slice(0, sep) : null;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** Lenient tool_result error detection (mirrors session-insights). */
|
|
203
|
+
function _isToolResultError(event) {
|
|
204
|
+
const r = event?.data?.result;
|
|
205
|
+
return Boolean(
|
|
206
|
+
event?.data?.error ||
|
|
207
|
+
(r && typeof r === "object" && (r.error || r.is_error || r.isError)),
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Aggregate the transcript's tool events: per-tool call/error counts, an MCP
|
|
213
|
+
* server bucket (`mcp__<server>__*`), and a turn-associated token figure.
|
|
214
|
+
*
|
|
215
|
+
* `turnTokens` is an APPROXIMATION: turns are delimited by `user_message`
|
|
216
|
+
* events, and every token_usage event inside a turn is attributed to EVERY
|
|
217
|
+
* tool that ran in that turn ("tokens of turns that used tool X"). A turn's
|
|
218
|
+
* tokens therefore count once per distinct tool — do NOT sum turnTokens
|
|
219
|
+
* across tools/servers, it is not a partition. Headless sessions persist one
|
|
220
|
+
* aggregated usage event per run, so there the whole run's tokens associate
|
|
221
|
+
* with each tool the run used.
|
|
222
|
+
*
|
|
223
|
+
* Accepts both the compact `tool_call` shape ({tool, is_error, skill?}) the
|
|
224
|
+
* drivers write now and the legacy `tool_call`({tool, args}) + `tool_result`
|
|
225
|
+
* pair (errors read off the result, calls only off tool_call — no double
|
|
226
|
+
* count). Sessions without tool events aggregate to zeros.
|
|
227
|
+
*/
|
|
228
|
+
export function aggregateToolCalls(events) {
|
|
229
|
+
const byTool = new Map();
|
|
230
|
+
const byServer = new Map();
|
|
231
|
+
let totalCalls = 0;
|
|
232
|
+
let totalErrors = 0;
|
|
233
|
+
|
|
234
|
+
const bumpTool = (name) => {
|
|
235
|
+
let t = byTool.get(name);
|
|
236
|
+
if (!t) {
|
|
237
|
+
t = {
|
|
238
|
+
tool: name,
|
|
239
|
+
mcpServer: mcpServerOf(name),
|
|
240
|
+
calls: 0,
|
|
241
|
+
errors: 0,
|
|
242
|
+
turnTokens: 0,
|
|
243
|
+
};
|
|
244
|
+
byTool.set(name, t);
|
|
245
|
+
}
|
|
246
|
+
return t;
|
|
247
|
+
};
|
|
248
|
+
const bumpServer = (server) => {
|
|
249
|
+
let s = byServer.get(server);
|
|
250
|
+
if (!s) {
|
|
251
|
+
s = { server, calls: 0, errors: 0, turnTokens: 0 };
|
|
252
|
+
byServer.set(server, s);
|
|
253
|
+
}
|
|
254
|
+
return s;
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
let turnTools = new Set();
|
|
258
|
+
let turnServers = new Set();
|
|
259
|
+
let turnTokens = 0;
|
|
260
|
+
const flushTurn = () => {
|
|
261
|
+
if (turnTokens > 0) {
|
|
262
|
+
for (const name of turnTools) bumpTool(name).turnTokens += turnTokens;
|
|
263
|
+
for (const server of turnServers)
|
|
264
|
+
bumpServer(server).turnTokens += turnTokens;
|
|
265
|
+
}
|
|
266
|
+
turnTools = new Set();
|
|
267
|
+
turnServers = new Set();
|
|
268
|
+
turnTokens = 0;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
for (const evt of events || []) {
|
|
272
|
+
if (!evt || typeof evt !== "object") continue;
|
|
273
|
+
if (evt.type === "user_message") {
|
|
274
|
+
flushTurn();
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
if (evt.type === "tool_call") {
|
|
278
|
+
const name = evt.data?.tool || "?";
|
|
279
|
+
totalCalls++;
|
|
280
|
+
const t = bumpTool(name);
|
|
281
|
+
t.calls++;
|
|
282
|
+
const isErr = evt.data?.is_error === true;
|
|
283
|
+
if (isErr) {
|
|
284
|
+
totalErrors++;
|
|
285
|
+
t.errors++;
|
|
286
|
+
}
|
|
287
|
+
turnTools.add(name);
|
|
288
|
+
const server = mcpServerOf(name);
|
|
289
|
+
if (server) {
|
|
290
|
+
const s = bumpServer(server);
|
|
291
|
+
s.calls++;
|
|
292
|
+
if (isErr) s.errors++;
|
|
293
|
+
turnServers.add(server);
|
|
294
|
+
}
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
if (evt.type === "tool_result") {
|
|
298
|
+
const name = evt.data?.tool || "?";
|
|
299
|
+
turnTools.add(name);
|
|
300
|
+
const server = mcpServerOf(name);
|
|
301
|
+
if (server) turnServers.add(server);
|
|
302
|
+
if (_isToolResultError(evt)) {
|
|
303
|
+
totalErrors++;
|
|
304
|
+
bumpTool(name).errors++;
|
|
305
|
+
if (server) bumpServer(server).errors++;
|
|
306
|
+
}
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
const u = extractUsage(evt);
|
|
310
|
+
if (u) turnTokens += u.totalTokens;
|
|
311
|
+
}
|
|
312
|
+
flushTurn();
|
|
313
|
+
|
|
314
|
+
const byCallsDesc = (a, b) => b.calls - a.calls;
|
|
315
|
+
return {
|
|
316
|
+
totalCalls,
|
|
317
|
+
totalErrors,
|
|
318
|
+
byTool: Array.from(byTool.values()).sort(byCallsDesc),
|
|
319
|
+
byMcpServer: Array.from(byServer.values()).sort(byCallsDesc),
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Full attribution section for a transcript: origin/skill/subagent usage
|
|
325
|
+
* roll-ups + the tool/MCP call aggregation. Pure.
|
|
326
|
+
*/
|
|
327
|
+
export function sessionAttribution(events) {
|
|
328
|
+
return {
|
|
329
|
+
...aggregateUsageAttribution(events),
|
|
330
|
+
tools: aggregateToolCalls(events),
|
|
87
331
|
};
|
|
88
332
|
}
|
|
89
333
|
|
|
@@ -141,12 +385,13 @@ export function aggregateUsage(events) {
|
|
|
141
385
|
}
|
|
142
386
|
|
|
143
387
|
/**
|
|
144
|
-
* Roll up usage for a single JSONL session.
|
|
388
|
+
* Roll up usage for a single JSONL session. The pre-attribution keys
|
|
389
|
+
* (total/byModel) are unchanged; `attribution` is additive.
|
|
145
390
|
*/
|
|
146
391
|
export function sessionUsage(sessionId) {
|
|
147
392
|
const events = _deps.readEvents(sessionId);
|
|
148
393
|
const agg = aggregateUsage(events);
|
|
149
|
-
return { sessionId, ...agg };
|
|
394
|
+
return { sessionId, ...agg, attribution: sessionAttribution(events) };
|
|
150
395
|
}
|
|
151
396
|
|
|
152
397
|
/**
|
|
@@ -206,6 +451,66 @@ export function allSessionsUsage({ limit = 1000 } = {}) {
|
|
|
206
451
|
}
|
|
207
452
|
}
|
|
208
453
|
|
|
454
|
+
// Global attribution roll-up: merge each session's attribution rows by key.
|
|
455
|
+
const gOrigin = new Map();
|
|
456
|
+
const gSkill = new Map();
|
|
457
|
+
const gSubagent = new Map();
|
|
458
|
+
const gTool = new Map();
|
|
459
|
+
const gServer = new Map();
|
|
460
|
+
let gToolCalls = 0;
|
|
461
|
+
let gToolErrors = 0;
|
|
462
|
+
const mergeRow = (map, key, row, seed) => {
|
|
463
|
+
const entry = map.get(key) || { ...seed, ..._newSums() };
|
|
464
|
+
_addSums(entry, row);
|
|
465
|
+
map.set(key, entry);
|
|
466
|
+
};
|
|
467
|
+
for (const s of perSession) {
|
|
468
|
+
const a = s.attribution;
|
|
469
|
+
if (!a) continue;
|
|
470
|
+
for (const row of a.byOrigin || []) {
|
|
471
|
+
mergeRow(gOrigin, row.origin, row, { origin: row.origin });
|
|
472
|
+
}
|
|
473
|
+
for (const row of a.bySkill || []) {
|
|
474
|
+
mergeRow(gSkill, row.skill, row, { skill: row.skill });
|
|
475
|
+
}
|
|
476
|
+
for (const row of a.bySubagent || []) {
|
|
477
|
+
mergeRow(gSubagent, row.subagentId, row, {
|
|
478
|
+
subagentId: row.subagentId,
|
|
479
|
+
role: row.role || null,
|
|
480
|
+
origin: row.origin,
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
const tools = a.tools || {};
|
|
484
|
+
gToolCalls += tools.totalCalls || 0;
|
|
485
|
+
gToolErrors += tools.totalErrors || 0;
|
|
486
|
+
for (const row of tools.byTool || []) {
|
|
487
|
+
const entry = gTool.get(row.tool) || {
|
|
488
|
+
tool: row.tool,
|
|
489
|
+
mcpServer: row.mcpServer || null,
|
|
490
|
+
calls: 0,
|
|
491
|
+
errors: 0,
|
|
492
|
+
turnTokens: 0,
|
|
493
|
+
};
|
|
494
|
+
entry.calls += row.calls || 0;
|
|
495
|
+
entry.errors += row.errors || 0;
|
|
496
|
+
entry.turnTokens += row.turnTokens || 0;
|
|
497
|
+
gTool.set(row.tool, entry);
|
|
498
|
+
}
|
|
499
|
+
for (const row of tools.byMcpServer || []) {
|
|
500
|
+
const entry = gServer.get(row.server) || {
|
|
501
|
+
server: row.server,
|
|
502
|
+
calls: 0,
|
|
503
|
+
errors: 0,
|
|
504
|
+
turnTokens: 0,
|
|
505
|
+
};
|
|
506
|
+
entry.calls += row.calls || 0;
|
|
507
|
+
entry.errors += row.errors || 0;
|
|
508
|
+
entry.turnTokens += row.turnTokens || 0;
|
|
509
|
+
gServer.set(row.server, entry);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
const byCallsDesc = (a, b) => b.calls - a.calls;
|
|
513
|
+
|
|
209
514
|
return {
|
|
210
515
|
sessions: perSession,
|
|
211
516
|
skipped,
|
|
@@ -213,6 +518,17 @@ export function allSessionsUsage({ limit = 1000 } = {}) {
|
|
|
213
518
|
byModel: Array.from(byKey.values()).sort(
|
|
214
519
|
(a, b) => b.totalTokens - a.totalTokens,
|
|
215
520
|
),
|
|
521
|
+
attribution: {
|
|
522
|
+
byOrigin: Array.from(gOrigin.values()).sort(_byTokensDesc),
|
|
523
|
+
bySkill: Array.from(gSkill.values()).sort(_byTokensDesc),
|
|
524
|
+
bySubagent: Array.from(gSubagent.values()).sort(_byTokensDesc),
|
|
525
|
+
tools: {
|
|
526
|
+
totalCalls: gToolCalls,
|
|
527
|
+
totalErrors: gToolErrors,
|
|
528
|
+
byTool: Array.from(gTool.values()).sort(byCallsDesc),
|
|
529
|
+
byMcpServer: Array.from(gServer.values()).sort(byCallsDesc),
|
|
530
|
+
},
|
|
531
|
+
},
|
|
216
532
|
};
|
|
217
533
|
}
|
|
218
534
|
|
|
@@ -115,6 +115,14 @@ export class SubAgentContext {
|
|
|
115
115
|
// Optional progress callback for streaming events to consumers
|
|
116
116
|
this._onProgress = options.onProgress || null;
|
|
117
117
|
|
|
118
|
+
// Usage-attribution seam (用量归因): forwards the child loop's REAL
|
|
119
|
+
// provider-reported token usage to the spawner (the ~4-chars/token
|
|
120
|
+
// estimate kept in _tokenCount below is only a budget heuristic and never
|
|
121
|
+
// leaves this context). Wired by spawn_sub_agent / isolated run_skill so
|
|
122
|
+
// the parent loop can re-yield attributed `token-usage` events.
|
|
123
|
+
this._onUsage =
|
|
124
|
+
typeof options.onUsage === "function" ? options.onUsage : null;
|
|
125
|
+
|
|
118
126
|
// Optional abort signal for cancellation
|
|
119
127
|
this._signal = options.signal || null;
|
|
120
128
|
|
|
@@ -295,6 +303,21 @@ export class SubAgentContext {
|
|
|
295
303
|
for await (const event of gen) {
|
|
296
304
|
this._iterationCount++;
|
|
297
305
|
|
|
306
|
+
if (event.type === "token-usage" && this._onUsage) {
|
|
307
|
+
// Forward real usage to the spawner. A nested child's event already
|
|
308
|
+
// carries its own attribution frame — preserve it (deepest wins).
|
|
309
|
+
try {
|
|
310
|
+
this._onUsage({
|
|
311
|
+
provider: event.provider || null,
|
|
312
|
+
model: event.model || null,
|
|
313
|
+
usage: event.usage || null,
|
|
314
|
+
attribution: event.attribution || null,
|
|
315
|
+
});
|
|
316
|
+
} catch (_e) {
|
|
317
|
+
// Usage forwarding is best-effort — never break the child loop
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
298
321
|
if (event.type === "tool-executing") {
|
|
299
322
|
this._toolsUsed.push(event.tool);
|
|
300
323
|
}
|