chainlesschain 0.162.186 → 0.162.188
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-DTXiO-TB.js → AIOps-Brr1LVcE.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BbmDW-Pz.js → ActionButton-DQU74DKG.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CSfgXJuD.js → Analytics-CYp9178y.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BS0FFLb7.js → AppLayout-DW4SCYsW.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-B19WFPK2.js → Artifacts-CYlD_ed1.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CQhZBi7n.js → Audit-CWl1rZOi.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BOLZCpGH.js → BackgroundAgents-BOR-LPsa.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-Dz3R_ePD.js → Backup-DLpG7j1X.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CYfgMpax.js → BaseInput-B35K9wdr.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-5CymMr1j.js → Chat-CwUJb9gB.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-B2A_TJtl.js → ChatBubbleRenderer-1v6aMS1m.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-CDXHVYcu.js → Checkbox-pi3-tPNW.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-uq9Z9oiS.js → Codegen-FyNF35eL.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BuW1K_65.js → Col-tGt_JDEr.js} +1 -1
- package/src/assets/web-panel/assets/{Community-Bbg-PvRY.js → Community-CC7LonQX.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-co0pPPTw.js → Compact-BGXrHHjE.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-B-pFAv7z.js → Compliance-DSW0TBZ8.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-54ZQS4gC.js → Cowork-Bhk7rbvE.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-B1BF2Seq.js → Cron-DxyiQ2NZ.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-Dey6qQTj.js → Crosschain-B2ZkxHok.js} +1 -1
- package/src/assets/web-panel/assets/{DID-ltERvfAj.js → DID-yOJV99eJ.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DuWxOcqN.js → Dashboard-CKsttz7D.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CrZ8ekTo.js → Dropdown-CVFldXSL.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-fIyHXhUS.js → EmailListRenderer-Bufv638J.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BtRyrRPm.js → FamilyGuardDashboard-4ncjoIjL.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-EUC6Wydj.js → Federation-DsknEDoX.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BOpka2G-.js → FormItemContext-Cqe5jWXA.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BXtrrYHn.js → GenericCardRenderer-NAJaFKxc.js} +1 -1
- package/src/assets/web-panel/assets/{Git-8WMb7PiR.js → Git-CszKQpnl.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DNWOeDTV.js → Governance-BXGodXi6.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Bne9b_Lb.js → Inference-CkoYuG2c.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Cp-6Us9b.js → KnowledgeGraph-DFlEr_T0.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-Ck-uSPAx.js → Logs-CVaENddA.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-7iWGwZ-r.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Vdq7brrJ.js → Marketplace-CDlLT0fw.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-ggLnw4hY.js → McpTools-DdwOyszN.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-BKIjNVCU.js → Memory-DKQnkKuG.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BElCY25a.js → MobileBridge-DGseqlzJ.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DpLgovdH.js → MobileProjects-COBbEOlj.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-bNdrF_Zh.js → Mtc-O61Vwyli.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-Dw8w1Cqk.js → MtcAudit-Dw2SyasS.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-CfGKvlqc.js → Multisig-hSu_l8kf.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-D6OJf7YN.js → NLProgramming-CX1Epurr.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-B3n_LzIS.js → Notes-R9xX8o8_.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-Uu1V_ICM.js → NotificationSettings-jtSNLCuK.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-aGyWwWcp.js → OrderTableRenderer-BU2Yqq5H.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-qjFFmuwK.js → Organization-Pu2WO-U3.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-J4ZgnwZz.js → Overflow-BjnqUyFp.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-YEZF-uVH.js → P2P-jjkvz44c.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-yqx7fwqk.js → PdhVaultBrowser-69ca_WeR.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-DdEjlZ02.js → Permissions-D4yDpivd.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-DbAPYvns.js → PersonalDataHub-0qsL6iH1.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-Bxlk_ZJU.js → Pipeline-Cx7Ybrk2.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CpE-05tz.js → Privacy-PbfR_M_V.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-DWlhcGHT.js → ProjectInit-CyV6Gsub.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BnH6BiTQ.js → ProjectSettings-C7KZ2Wdk.js} +2 -2
- package/src/assets/web-panel/assets/Projects-DQDjO-yK.js +1 -0
- package/src/assets/web-panel/assets/{Providers-Bdz_sTyb.js → Providers-DyFVBBMX.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BHh2b3pH.js → QrScannerModal-CzB1BC9_.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-D84M09pe.js → QuickAsk-Bk636mC1.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Czc30K6M.js → Recommend-DoWxHIT3.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-q_TU5qxt.js → RemoteSession-oOVIv9wq.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-CnTce4WM.js → Reputation-BucoReGG.js} +1 -1
- package/src/assets/web-panel/assets/{Row-C60UFLay.js → Row-DzmOdJU7.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BOUFEu9_.js → RssFeed-C1tK7KGU.js} +3 -3
- package/src/assets/web-panel/assets/{Search-D4__blE-.js → Search-CSnInOqk.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BoOm7_JK.js → Security-dlejr15l.js} +3 -3
- package/src/assets/web-panel/assets/{Services-AvzrW6HA.js → Services-BioPZuNh.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BZlrHozi.js → Skeleton-DWMibwpC.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CKaMLuk0.js → Skills-BAAnx1B2.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DYCNJF8h.js → Sla-jWNp4hNO.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-y5kqKha-.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-B6tW8dVO.js → SyncSettings-B9GNsc3e.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-oNC_2NVz.js → Tasks-BDBYKRen.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-DvLPvvjL.js → Templates-DRiE5eaN.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BDt9UBn_.js → Tenant-BGlAvExF.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-ddCUnH-X.js → Terminal-B8uzrbNY.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-CA4sDL47.js → TimelineRenderer-Df48iveY.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-By03hnVs.js → Tokens-CcmHndN6.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Dz2mH-ZU.js → Trigger-DPkWxmQ2.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DShSWHeJ.js → Trust-DTb5a5AV.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-JN8lP3gt.js → UkeySign-CBmg5vch.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BgPy4gV3.js → VideoEditing-B0mZrz4O.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CQGEsXw_.js → Wallet-Bxs7_mpd.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-D8xR-ds_.js → WebAuthn-C8x3cMxU.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-Df61_p1p.js → WorkflowEditor-DPrNznrP.js} +1 -1
- package/src/assets/web-panel/assets/{chat-fdPby427.js → chat-D3bYWu7S.js} +1 -1
- package/src/assets/web-panel/assets/{colors-Dimqhufo.js → colors-DY-PwMu4.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DHayKcqZ.js → compact-item-LDk10Kw6.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-hZUhypRH.js → createContext-C-2MZnFq.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-B4dXIJqD.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-Dw7zC_dV.js → hasIn-BQIBjcnB.js} +1 -1
- package/src/assets/web-panel/assets/{index-y5LHQ5Ck.js → index-7xKu7Fns.js} +1 -1
- package/src/assets/web-panel/assets/{index-CBQK-LEF.js → index-8JC9BJa1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BuMSdwno.js → index-B5pgtZnY.js} +1 -1
- package/src/assets/web-panel/assets/{index-BM5BNqp9.js → index-BI4KgcYC.js} +1 -1
- package/src/assets/web-panel/assets/{index-BwnUluxu.js → index-BN-xdSWZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7jQEwB6.js → index-BRI3ngNg.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIxxvaGN.js → index-BX2b9Orc.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1yMYKi-.js → index-BdXnYMCZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CuaVa8tX.js → index-BrnRO9yE.js} +1 -1
- package/src/assets/web-panel/assets/index-C-C7DaG6.js +1 -0
- package/src/assets/web-panel/assets/{index-CIOE8tt6.js → index-C3GNvExG.js} +1 -1
- package/src/assets/web-panel/assets/{index-C8XXPz2n.js → index-C7FC8cP2.js} +1 -1
- package/src/assets/web-panel/assets/{index-cEnkyHtX.js → index-COG61sRv.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJP7TjWm.js → index-CQVb2dWp.js} +1 -1
- package/src/assets/web-panel/assets/{index-CvKHpaao.js → index-CY4KnaO9.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxoPzPHy.js → index-CaslYch6.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSlda4-6.js → index-CbR6ROOa.js} +1 -1
- package/src/assets/web-panel/assets/{index-CPZ3U5iH.js → index-CiTvBAr-.js} +1 -1
- package/src/assets/web-panel/assets/{index-j0pxzOu7.js → index-Cx6D_dx2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DzJXkoZs.js → index-Cz4b6Z_7.js} +1 -1
- package/src/assets/web-panel/assets/{index-BVHdkz8F.js → index-D3Oq-DLL.js} +17 -17
- package/src/assets/web-panel/assets/{index-ulvBurtw.js → index-D4K1weKc.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyEhrvpm.js → index-DSvo_bp0.js} +1 -1
- package/src/assets/web-panel/assets/{index-DC2R4zvM.js → index-DTIZpPtG.js} +1 -1
- package/src/assets/web-panel/assets/{index-CsCo_A0I.js → index-DY2FIrmz.js} +1 -1
- package/src/assets/web-panel/assets/{index-CTiVrnpR.js → index-DYyLJPlF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHJUptSx.js → index-Dd2Km97U.js} +1 -1
- package/src/assets/web-panel/assets/{index-CcpDboUd.js → index-Dh-tkpKQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DnwDYBnG.js → index-DhRt9cYJ.js} +1 -1
- package/src/assets/web-panel/assets/index-DkfWzWtd.js +1 -0
- package/src/assets/web-panel/assets/{index--DVpUpz3.js → index-DlRYqt3S.js} +1 -1
- package/src/assets/web-panel/assets/{index-DVM_KgzF.js → index-HasPt4-h.js} +1 -1
- package/src/assets/web-panel/assets/{index-DX1DwDFI.js → index-KFZO_lcx.js} +1 -1
- package/src/assets/web-panel/assets/{index-lPjBQJCy.js → index-L3smcoQX.js} +1 -1
- package/src/assets/web-panel/assets/{index-Urt2R5aE.js → index-L6qixyLc.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYdNwhkv.js → index-VCh5zNJo.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bhmpp3cm.js → index-_HRO_cIu.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAjvkQ4K.js → index-k7C_oDCO.js} +1 -1
- package/src/assets/web-panel/assets/{index-JE6Udz2r.js → index-lmm9p-jm.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-B4pR3px5.js → initDefaultProps-zQPSHf2C.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CE7dWPPs.js → motion-CKCStGVk.js} +1 -1
- package/src/assets/web-panel/assets/{move-Hw8cUObc.js → move-BufVDGYF.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CvRjE4Fa.js → mtc-parser-DcaFxy5D.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CkFeLVre.js → omit-EScpkGdo.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-5ZMqmbbb.js → pickAttrs-72hG_qfT.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BZ4oeZ0q.js → placementArrow-CMFWiH20.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-lwoiX_Us.js → responsiveObserve-DKQHS41p.js} +1 -1
- package/src/assets/web-panel/assets/{slide-D_as37l8.js → slide-QVAFHTIQ.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BsA-4Bs7.js → statusUtils-DIz38e2G.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BVar4sLQ.js → styleChecker-zK5cyLby.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-j1IwVpGd.js → useFlexGapSupport-DhZngk62.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-7Q9bEnUp.js → useFs-BvV2cvkg.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BBwTIRMd.js → usePersonalDataHub-CRmxb9l3.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-C7Dk-M8w.js → vnode-CgQIbobP.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-D3UHaTFB.js → zoom-D4XrrO0R.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/auto-mode.js +47 -0
- package/src/commands/team.js +1805 -473
- package/src/data/auto-mode-safety-eval-v1.json +3294 -0
- package/src/data/changelog.json +26 -0
- package/src/harness/worktree-isolator.js +671 -79
- package/src/lib/agent-team/task-lease.js +378 -78
- package/src/lib/agent-team/team-agent-stream.js +488 -0
- package/src/lib/agent-team/team-budget.js +216 -20
- package/src/lib/agent-team/team-mailbox.js +389 -15
- package/src/lib/agent-team/team-run-state-lock.js +209 -0
- package/src/lib/agent-team/team-runner.js +547 -63
- package/src/lib/agent-team/team-scope-lock.js +409 -0
- package/src/lib/agent-team/team-task-contract.js +277 -0
- package/src/lib/agent-team/team-worktree.js +1171 -62
- package/src/lib/agent-worktree.js +19 -20
- package/src/lib/auto-mode-safety-classifier.js +2034 -0
- package/src/lib/auto-mode-safety-eval.js +1022 -0
- package/src/lib/collaboration-run-store.js +983 -68
- package/src/lib/with-file-lock.js +190 -24
- package/src/lib/worktree-isolator.js +3 -0
- package/src/lib/worktree-sparse.js +23 -0
- package/src/runtime/headless-stream.js +6 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-DxjsdAXw.js +0 -1
- package/src/assets/web-panel/assets/Projects-CHw2fXDB.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-BvCSU6d2.js +0 -1
- package/src/assets/web-panel/assets/devWarning-ePxoBp92.js +0 -1
- package/src/assets/web-panel/assets/index-BTBDdCoo.js +0 -1
- package/src/assets/web-panel/assets/index-CfOGx8Ns.js +0 -1
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Incremental parser for a real teammate's `cc agent --output-format
|
|
3
|
+
* stream-json` stdout.
|
|
4
|
+
*
|
|
5
|
+
* The parser deliberately retains only billing metadata. Prompt, assistant and
|
|
6
|
+
* terminal result bodies are parsed only as part of the current NDJSON line and
|
|
7
|
+
* are never copied into parser state or returned to callers.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { TextDecoder } from "node:util";
|
|
11
|
+
|
|
12
|
+
export const DEFAULT_TEAM_AGENT_MAX_LINE_BYTES = 1024 * 1024;
|
|
13
|
+
export const DEFAULT_TEAM_AGENT_MAX_TOTAL_BYTES = 32 * 1024 * 1024;
|
|
14
|
+
|
|
15
|
+
const USAGE_KEYS = Object.freeze([
|
|
16
|
+
"input_tokens",
|
|
17
|
+
"output_tokens",
|
|
18
|
+
"cache_read_input_tokens",
|
|
19
|
+
"cache_creation_input_tokens",
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
function emptyUsage() {
|
|
23
|
+
return {
|
|
24
|
+
input_tokens: 0,
|
|
25
|
+
output_tokens: 0,
|
|
26
|
+
cache_read_input_tokens: 0,
|
|
27
|
+
cache_creation_input_tokens: 0,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function cloneUsage(usage) {
|
|
32
|
+
return usage ? { ...usage } : null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function cloneUsageRecords(records) {
|
|
36
|
+
return Array.isArray(records)
|
|
37
|
+
? records.map((record) => ({
|
|
38
|
+
provider: record.provider,
|
|
39
|
+
model: record.model,
|
|
40
|
+
usage: cloneUsage(record.usage),
|
|
41
|
+
}))
|
|
42
|
+
: [];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function positiveInteger(value, name) {
|
|
46
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
47
|
+
throw new TypeError(`${name} must be a positive safe integer`);
|
|
48
|
+
}
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function asBuffer(chunk) {
|
|
53
|
+
if (typeof chunk === "string") return Buffer.from(chunk, "utf8");
|
|
54
|
+
if (Buffer.isBuffer(chunk)) return chunk;
|
|
55
|
+
if (chunk instanceof Uint8Array) {
|
|
56
|
+
return Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength);
|
|
57
|
+
}
|
|
58
|
+
throw new TypeError(
|
|
59
|
+
"TeamAgentStreamParser.push expects a string or Uint8Array",
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export class TeamAgentStreamError extends Error {
|
|
64
|
+
constructor(code, message, details = {}) {
|
|
65
|
+
super(message);
|
|
66
|
+
this.name = "TeamAgentStreamError";
|
|
67
|
+
this.code = code;
|
|
68
|
+
for (const [key, value] of Object.entries(details)) {
|
|
69
|
+
if (value != null) this[key] = value;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @typedef {object} TeamAgentStreamSummary
|
|
76
|
+
* @property {string|null} provider
|
|
77
|
+
* @property {string|null} model
|
|
78
|
+
* @property {object|null} usage
|
|
79
|
+
* @property {Array<object>} usageRecords
|
|
80
|
+
* @property {boolean} terminalResult
|
|
81
|
+
*/
|
|
82
|
+
|
|
83
|
+
export class TeamAgentStreamParser {
|
|
84
|
+
#maxLineBytes;
|
|
85
|
+
#maxTotalBytes;
|
|
86
|
+
#totalBytes = 0;
|
|
87
|
+
#lineBytes = 0;
|
|
88
|
+
#lineChunks = [];
|
|
89
|
+
#lineNumber = 0;
|
|
90
|
+
#provider = null;
|
|
91
|
+
#model = null;
|
|
92
|
+
#usage = emptyUsage();
|
|
93
|
+
#lastResultUsage = null;
|
|
94
|
+
#lastResultProvider = null;
|
|
95
|
+
#lastResultModel = null;
|
|
96
|
+
#tokenUsageEvents = 0;
|
|
97
|
+
#usageByIdentity = new Map();
|
|
98
|
+
#sawTerminalResult = false;
|
|
99
|
+
#finished = false;
|
|
100
|
+
#failed = null;
|
|
101
|
+
#finalSummary = null;
|
|
102
|
+
|
|
103
|
+
constructor({
|
|
104
|
+
maxLineBytes = DEFAULT_TEAM_AGENT_MAX_LINE_BYTES,
|
|
105
|
+
maxTotalBytes = DEFAULT_TEAM_AGENT_MAX_TOTAL_BYTES,
|
|
106
|
+
} = {}) {
|
|
107
|
+
this.#maxLineBytes = positiveInteger(maxLineBytes, "maxLineBytes");
|
|
108
|
+
this.#maxTotalBytes = positiveInteger(maxTotalBytes, "maxTotalBytes");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Consume one stdout chunk. Chunks may end anywhere, including in the middle
|
|
113
|
+
* of an NDJSON line or a multi-byte UTF-8 character.
|
|
114
|
+
*
|
|
115
|
+
* @returns {this}
|
|
116
|
+
*/
|
|
117
|
+
push(chunk) {
|
|
118
|
+
this.#assertWritable();
|
|
119
|
+
const bytes = asBuffer(chunk);
|
|
120
|
+
if (bytes.length === 0) return this;
|
|
121
|
+
|
|
122
|
+
const nextTotal = this.#totalBytes + bytes.length;
|
|
123
|
+
if (!Number.isSafeInteger(nextTotal) || nextTotal > this.#maxTotalBytes) {
|
|
124
|
+
this.#fail(
|
|
125
|
+
new TeamAgentStreamError(
|
|
126
|
+
"TEAM_AGENT_STREAM_TOTAL_LIMIT",
|
|
127
|
+
`Teammate stream exceeded the ${this.#maxTotalBytes}-byte total limit`,
|
|
128
|
+
{
|
|
129
|
+
limit: this.#maxTotalBytes,
|
|
130
|
+
actual: nextTotal,
|
|
131
|
+
},
|
|
132
|
+
),
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
this.#totalBytes = nextTotal;
|
|
136
|
+
|
|
137
|
+
let start = 0;
|
|
138
|
+
for (let i = 0; i < bytes.length; i += 1) {
|
|
139
|
+
if (bytes[i] !== 0x0a) continue;
|
|
140
|
+
this.#appendLineBytes(bytes.subarray(start, i));
|
|
141
|
+
this.#consumePendingLine();
|
|
142
|
+
start = i + 1;
|
|
143
|
+
}
|
|
144
|
+
this.#appendLineBytes(bytes.subarray(start));
|
|
145
|
+
return this;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Finish the stream, consuming a final line even when it has no trailing LF.
|
|
150
|
+
* Repeated calls are idempotent.
|
|
151
|
+
*
|
|
152
|
+
* `token_usage` events win over the terminal result aggregate to prevent
|
|
153
|
+
* double counting. The last `result.usage` is used only when no token-usage
|
|
154
|
+
* event was observed.
|
|
155
|
+
*
|
|
156
|
+
* @returns {TeamAgentStreamSummary}
|
|
157
|
+
*/
|
|
158
|
+
finish(chunk) {
|
|
159
|
+
if (chunk !== undefined) this.push(chunk);
|
|
160
|
+
if (this.#failed) throw this.#failed;
|
|
161
|
+
if (this.#finished) return this.#copySummary();
|
|
162
|
+
|
|
163
|
+
if (this.#lineBytes > 0) this.#consumePendingLine();
|
|
164
|
+
this.#finished = true;
|
|
165
|
+
this.#finalSummary = Object.freeze({
|
|
166
|
+
provider: this.#provider,
|
|
167
|
+
model: this.#model,
|
|
168
|
+
usage: Object.freeze(
|
|
169
|
+
cloneUsage(
|
|
170
|
+
this.#tokenUsageEvents > 0 ? this.#usage : this.#lastResultUsage,
|
|
171
|
+
),
|
|
172
|
+
),
|
|
173
|
+
usageRecords: Object.freeze(
|
|
174
|
+
this.#usageRecords().map((record) =>
|
|
175
|
+
Object.freeze({
|
|
176
|
+
...record,
|
|
177
|
+
usage: Object.freeze(record.usage),
|
|
178
|
+
}),
|
|
179
|
+
),
|
|
180
|
+
),
|
|
181
|
+
terminalResult: this.#sawTerminalResult,
|
|
182
|
+
});
|
|
183
|
+
return this.#copySummary();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Return the billing metadata observed so far without finishing the stream.
|
|
188
|
+
* This is intentionally limited to provider/model/usage so callers can
|
|
189
|
+
* enforce a live per-agent token ceiling without retaining assistant text.
|
|
190
|
+
*/
|
|
191
|
+
status() {
|
|
192
|
+
if (this.#failed) throw this.#failed;
|
|
193
|
+
if (this.#finished) return this.#copySummary();
|
|
194
|
+
return this.#copyLiveSummary();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Return already-observed billing data even after a later malformed line
|
|
199
|
+
* poisoned the protocol parser. This never exposes prompt/result content and
|
|
200
|
+
* lets callers bill work consumed before a stream failure.
|
|
201
|
+
*/
|
|
202
|
+
partialStatus() {
|
|
203
|
+
if (this.#finished) return this.#copySummary();
|
|
204
|
+
return this.#copyLiveSummary();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
#copyLiveSummary() {
|
|
208
|
+
return {
|
|
209
|
+
provider: this.#provider,
|
|
210
|
+
model: this.#model,
|
|
211
|
+
usage:
|
|
212
|
+
this.#tokenUsageEvents > 0
|
|
213
|
+
? cloneUsage(this.#usage)
|
|
214
|
+
: cloneUsage(this.#lastResultUsage),
|
|
215
|
+
usageRecords: this.#usageRecords(),
|
|
216
|
+
terminalResult: this.#sawTerminalResult,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
#assertWritable() {
|
|
221
|
+
if (this.#failed) throw this.#failed;
|
|
222
|
+
if (this.#finished) {
|
|
223
|
+
throw new TeamAgentStreamError(
|
|
224
|
+
"TEAM_AGENT_STREAM_FINISHED",
|
|
225
|
+
"Cannot push data after the teammate stream has finished",
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
#appendLineBytes(bytes) {
|
|
231
|
+
if (bytes.length === 0) return;
|
|
232
|
+
const nextLineBytes = this.#lineBytes + bytes.length;
|
|
233
|
+
if (
|
|
234
|
+
!Number.isSafeInteger(nextLineBytes) ||
|
|
235
|
+
nextLineBytes > this.#maxLineBytes
|
|
236
|
+
) {
|
|
237
|
+
this.#fail(
|
|
238
|
+
new TeamAgentStreamError(
|
|
239
|
+
"TEAM_AGENT_STREAM_LINE_LIMIT",
|
|
240
|
+
`Teammate stream line exceeded the ${this.#maxLineBytes}-byte limit`,
|
|
241
|
+
{
|
|
242
|
+
line: this.#lineNumber + 1,
|
|
243
|
+
limit: this.#maxLineBytes,
|
|
244
|
+
actual: nextLineBytes,
|
|
245
|
+
},
|
|
246
|
+
),
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Copy partial input: stdout buffers are caller-owned and may be reused.
|
|
251
|
+
this.#lineChunks.push(Buffer.from(bytes));
|
|
252
|
+
this.#lineBytes = nextLineBytes;
|
|
253
|
+
|
|
254
|
+
// Bound array/object overhead as well as payload bytes when a producer
|
|
255
|
+
// supplies a very large number of tiny chunks for one line.
|
|
256
|
+
if (this.#lineChunks.length >= 64) {
|
|
257
|
+
this.#lineChunks = [Buffer.concat(this.#lineChunks, this.#lineBytes)];
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
#consumePendingLine() {
|
|
262
|
+
this.#lineNumber += 1;
|
|
263
|
+
let raw =
|
|
264
|
+
this.#lineChunks.length === 0
|
|
265
|
+
? Buffer.alloc(0)
|
|
266
|
+
: Buffer.concat(this.#lineChunks, this.#lineBytes);
|
|
267
|
+
this.#lineChunks = [];
|
|
268
|
+
this.#lineBytes = 0;
|
|
269
|
+
|
|
270
|
+
if (raw.length > 0 && raw[raw.length - 1] === 0x0d) {
|
|
271
|
+
raw = raw.subarray(0, raw.length - 1);
|
|
272
|
+
}
|
|
273
|
+
if (raw.length === 0) return;
|
|
274
|
+
|
|
275
|
+
let line;
|
|
276
|
+
try {
|
|
277
|
+
line = new TextDecoder("utf-8", { fatal: true }).decode(raw);
|
|
278
|
+
} catch {
|
|
279
|
+
this.#fail(
|
|
280
|
+
new TeamAgentStreamError(
|
|
281
|
+
"TEAM_AGENT_STREAM_INVALID_UTF8",
|
|
282
|
+
`Invalid UTF-8 in teammate stream at line ${this.#lineNumber}`,
|
|
283
|
+
{ line: this.#lineNumber },
|
|
284
|
+
),
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
raw = null;
|
|
288
|
+
|
|
289
|
+
if (this.#lineNumber === 1 && line.charCodeAt(0) === 0xfeff) {
|
|
290
|
+
line = line.slice(1);
|
|
291
|
+
}
|
|
292
|
+
if (line.trim() === "") return;
|
|
293
|
+
|
|
294
|
+
let event;
|
|
295
|
+
try {
|
|
296
|
+
event = JSON.parse(line);
|
|
297
|
+
} catch {
|
|
298
|
+
// Never include JSON.parse's engine-specific message: recent runtimes
|
|
299
|
+
// may quote the source text, which can contain a prompt or result body.
|
|
300
|
+
this.#fail(
|
|
301
|
+
new TeamAgentStreamError(
|
|
302
|
+
"TEAM_AGENT_STREAM_INVALID_JSON",
|
|
303
|
+
`Invalid JSON in teammate stream at line ${this.#lineNumber}`,
|
|
304
|
+
{ line: this.#lineNumber },
|
|
305
|
+
),
|
|
306
|
+
);
|
|
307
|
+
} finally {
|
|
308
|
+
line = null;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (!event || typeof event !== "object" || Array.isArray(event)) return;
|
|
312
|
+
|
|
313
|
+
if (event.type === "system" && event.subtype === "init") {
|
|
314
|
+
if (this.#provider == null && typeof event.provider === "string") {
|
|
315
|
+
this.#provider = event.provider;
|
|
316
|
+
}
|
|
317
|
+
if (this.#model == null && typeof event.model === "string") {
|
|
318
|
+
this.#model = event.model;
|
|
319
|
+
}
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (event.type === "token_usage") {
|
|
324
|
+
const usage = this.#normalizeUsage(event.usage);
|
|
325
|
+
const provider =
|
|
326
|
+
typeof event.provider === "string" ? event.provider : this.#provider;
|
|
327
|
+
const model = typeof event.model === "string" ? event.model : this.#model;
|
|
328
|
+
for (const key of USAGE_KEYS) {
|
|
329
|
+
const next = this.#usage[key] + usage[key];
|
|
330
|
+
if (!Number.isSafeInteger(next)) {
|
|
331
|
+
this.#fail(
|
|
332
|
+
new TeamAgentStreamError(
|
|
333
|
+
"TEAM_AGENT_STREAM_INVALID_USAGE",
|
|
334
|
+
`Unsafe ${key} total in teammate stream at line ${this.#lineNumber}`,
|
|
335
|
+
{ line: this.#lineNumber, field: key },
|
|
336
|
+
),
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
this.#usage[key] = next;
|
|
340
|
+
}
|
|
341
|
+
this.#recordUsage(provider, model, usage);
|
|
342
|
+
this.#tokenUsageEvents += 1;
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (event.type === "result") {
|
|
347
|
+
this.#sawTerminalResult = true;
|
|
348
|
+
this.#lastResultProvider =
|
|
349
|
+
typeof event.provider === "string" ? event.provider : this.#provider;
|
|
350
|
+
this.#lastResultModel =
|
|
351
|
+
typeof event.model === "string" ? event.model : this.#model;
|
|
352
|
+
this.#lastResultUsage =
|
|
353
|
+
event.usage == null ? null : this.#normalizeUsage(event.usage);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
#recordUsage(provider, model, usage) {
|
|
358
|
+
const normalizedProvider =
|
|
359
|
+
typeof provider === "string" && provider ? provider : null;
|
|
360
|
+
const normalizedModel = typeof model === "string" && model ? model : null;
|
|
361
|
+
const identity = `${normalizedProvider || ""}\0${normalizedModel || ""}`;
|
|
362
|
+
let record = this.#usageByIdentity.get(identity);
|
|
363
|
+
if (!record) {
|
|
364
|
+
if (this.#usageByIdentity.size >= 64) {
|
|
365
|
+
this.#fail(
|
|
366
|
+
new TeamAgentStreamError(
|
|
367
|
+
"TEAM_AGENT_STREAM_USAGE_IDENTITY_LIMIT",
|
|
368
|
+
"Teammate stream exceeded the 64-model billing identity limit",
|
|
369
|
+
{ limit: 64 },
|
|
370
|
+
),
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
record = {
|
|
374
|
+
provider: normalizedProvider,
|
|
375
|
+
model: normalizedModel,
|
|
376
|
+
usage: emptyUsage(),
|
|
377
|
+
};
|
|
378
|
+
this.#usageByIdentity.set(identity, record);
|
|
379
|
+
}
|
|
380
|
+
for (const key of USAGE_KEYS) {
|
|
381
|
+
const next = record.usage[key] + usage[key];
|
|
382
|
+
if (!Number.isSafeInteger(next)) {
|
|
383
|
+
this.#fail(
|
|
384
|
+
new TeamAgentStreamError(
|
|
385
|
+
"TEAM_AGENT_STREAM_INVALID_USAGE",
|
|
386
|
+
`Unsafe ${key} identity total in teammate stream`,
|
|
387
|
+
{ field: key },
|
|
388
|
+
),
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
record.usage[key] = next;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
#usageRecords() {
|
|
396
|
+
if (this.#tokenUsageEvents > 0) {
|
|
397
|
+
return [...this.#usageByIdentity.values()].map((record) => ({
|
|
398
|
+
provider: record.provider,
|
|
399
|
+
model: record.model,
|
|
400
|
+
usage: cloneUsage(record.usage),
|
|
401
|
+
}));
|
|
402
|
+
}
|
|
403
|
+
if (!this.#lastResultUsage) return [];
|
|
404
|
+
return [
|
|
405
|
+
{
|
|
406
|
+
provider: this.#lastResultProvider ?? this.#provider,
|
|
407
|
+
model: this.#lastResultModel ?? this.#model,
|
|
408
|
+
usage: cloneUsage(this.#lastResultUsage),
|
|
409
|
+
},
|
|
410
|
+
];
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
#normalizeUsage(raw) {
|
|
414
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
415
|
+
this.#fail(
|
|
416
|
+
new TeamAgentStreamError(
|
|
417
|
+
"TEAM_AGENT_STREAM_INVALID_USAGE",
|
|
418
|
+
`Invalid usage object in teammate stream at line ${this.#lineNumber}`,
|
|
419
|
+
{ line: this.#lineNumber },
|
|
420
|
+
),
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const usage = emptyUsage();
|
|
425
|
+
for (const key of USAGE_KEYS) {
|
|
426
|
+
const rawValue = raw[key];
|
|
427
|
+
if (rawValue == null) continue;
|
|
428
|
+
if (
|
|
429
|
+
(typeof rawValue !== "number" && typeof rawValue !== "string") ||
|
|
430
|
+
rawValue === ""
|
|
431
|
+
) {
|
|
432
|
+
this.#invalidUsageField(key);
|
|
433
|
+
}
|
|
434
|
+
const value = Number(rawValue);
|
|
435
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
436
|
+
this.#invalidUsageField(key);
|
|
437
|
+
}
|
|
438
|
+
usage[key] = value;
|
|
439
|
+
}
|
|
440
|
+
return usage;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
#invalidUsageField(field) {
|
|
444
|
+
this.#fail(
|
|
445
|
+
new TeamAgentStreamError(
|
|
446
|
+
"TEAM_AGENT_STREAM_INVALID_USAGE",
|
|
447
|
+
`Invalid ${field} in teammate stream at line ${this.#lineNumber}`,
|
|
448
|
+
{ line: this.#lineNumber, field },
|
|
449
|
+
),
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
#copySummary() {
|
|
454
|
+
return {
|
|
455
|
+
provider: this.#finalSummary.provider,
|
|
456
|
+
model: this.#finalSummary.model,
|
|
457
|
+
usage: cloneUsage(this.#finalSummary.usage),
|
|
458
|
+
usageRecords: cloneUsageRecords(this.#finalSummary.usageRecords),
|
|
459
|
+
terminalResult: this.#finalSummary.terminalResult,
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
#fail(error) {
|
|
464
|
+
this.#lineChunks = [];
|
|
465
|
+
this.#lineBytes = 0;
|
|
466
|
+
this.#failed = error;
|
|
467
|
+
throw error;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Parse a complete string/buffer or a synchronous iterable of chunks.
|
|
473
|
+
*
|
|
474
|
+
* @returns {TeamAgentStreamSummary}
|
|
475
|
+
*/
|
|
476
|
+
export function parseTeamAgentStream(input, options = {}) {
|
|
477
|
+
const parser = new TeamAgentStreamParser(options);
|
|
478
|
+
if (
|
|
479
|
+
typeof input === "string" ||
|
|
480
|
+
Buffer.isBuffer(input) ||
|
|
481
|
+
input instanceof Uint8Array
|
|
482
|
+
) {
|
|
483
|
+
parser.push(input);
|
|
484
|
+
} else if (input != null) {
|
|
485
|
+
for (const chunk of input) parser.push(chunk);
|
|
486
|
+
}
|
|
487
|
+
return parser.finish();
|
|
488
|
+
}
|