chainlesschain 0.162.171 → 0.162.172
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/bin/chainlesschain.js +8 -0
- package/package.json +6 -1
- package/src/assets/web-panel/assets/{AIOps-Cf8yb18C.js → AIOps-oKCWU-LK.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CsFT6FMt.js → ActionButton-4CBfc5E4.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DQe_hXMA.js → Analytics-BEmR-k_b.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-Cl9Pp7jk.js → AppLayout-D6a4ZnrC.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-CBEzLVjF.js → Artifacts-BRWIHCPl.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BS2Un14C.js → Audit-CzGKlkTc.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DmcDH8OK.js → BackgroundAgents-CmMYN10o.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DvzjTkkn.js → Backup-CJ6e0ukD.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DnbpuyME.js → BaseInput-BpEvDrNt.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BJRRCm2P.js → Chat-wWuwwjKu.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-Bgpxyqd_.js → ChatBubbleRenderer-CJLyGo_u.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DFOrWmvm.js → Checkbox-C6pW60Br.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BIQ2kU6Q.js → Codegen-DF-nP22Y.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BI3R-N4I.js → Col-BuueEwZW.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CPiAwsHT.js → Community-DuE0Yzwr.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Bv4cslSK.js → Compact-BrHim8EB.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CSlDG1NZ.js → Compliance-DgAet8f_.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CFcRumXf.js → Cowork-B9wY05lx.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-DKYKMmOn.js → Cron-CvNBxfJX.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CxPMByp2.js → Crosschain-BnZRENa0.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DJqiYw1C.js → DID-DiqYLHTI.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-D2dLMxqy.js → Dashboard-t3SsRzZL.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BnJc384A.js → Dropdown-BCjMLam9.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DctFvm-J.js → EmailListRenderer-D2v9-IHJ.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-J_xg-Qop.js → FamilyGuardDashboard-_iQu35qa.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BckL07Uw.js → Federation-Bkty8VqB.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-B8s5ccSO.js → FormItemContext-DdPW81BY.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-hPMBK2No.js → GenericCardRenderer-DrNYM4Zj.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CfMpYLo7.js → Git-BjF-B2h0.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-Bt3OcrC7.js → Governance-DPhGdJ1v.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BlKc336N.js → Inference--PPksOVj.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-B6p7og2c.js → KnowledgeGraph-y5WdV_JV.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-uv5Re6YR.js → Logs-B6_x7zba.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-Bg8zSyF8.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-CfNbntHt.js → Marketplace-CHpfMu1A.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-YRXt74Yk.js → McpTools-qqjtX3Cf.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-BfQQs-Jd.js → Memory-hASSgxbw.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BuGC-4S2.js → MobileBridge-Dwh7Bhcf.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-Czieqw1m.js → MobileProjects-D09voh7W.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-DHWHOVCO.js → Mtc-9G1dXeId.js} +3 -3
- package/src/assets/web-panel/assets/{MtcAudit-DWSEbMW-.js → MtcAudit-CWtYXj6f.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DrhEv1vq.js → Multisig-bDI0EnDk.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-D8wKCu7E.js → NLProgramming-CTanRaBP.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-AFeqq0I_.js → Notes-BdQENJFv.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-D6qenYUo.js → NotificationSettings-JvnQdStO.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-CF0X4fyB.js → OrderTableRenderer-BMGL9RPJ.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DdfbNqf6.js → Organization-sBZnIb2D.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BFEvnLfd.js → Overflow-CzOhNGE6.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DtL6wbkz.js → P2P-D_D2yqda.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CQPriTud.js → PdhVaultBrowser-D5lKd_Kx.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-Bj25ANmR.js → Permissions-L5s-wENg.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BNj2Oux0.js → PersonalDataHub-iI49x6cH.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-Dyj8UEaG.js → Pipeline-DPHqyk09.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BBUrWRFz.js → Privacy-B-ZL9360.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BdX7uQn6.js → ProjectInit-f05YzsN2.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BghtW1zr.js → ProjectSettings-DZLKS6ex.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-9VTquZCz.js → Projects-ButF3DyM.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-D-0K_Eza.js → Providers-CFDSXnkR.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DDaN30_D.js → QrScannerModal-1N6Sdxdm.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DfHlifOj.js → QuickAsk-tEqRwRSR.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CgLIvYE2.js → Recommend-D4ZVHIwz.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DpOPrwE4.js → RemoteSession-Cqm32lhm.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-wMexlbCE.js → Reputation-BnjVsU_a.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D9aD_nrc.js → Row-DzpHyTuz.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-Drg7l6zu.js → RssFeed-Du5-ouwx.js} +3 -3
- package/src/assets/web-panel/assets/{Search-BKO1nrwN.js → Search-CYztyf2o.js} +1 -1
- package/src/assets/web-panel/assets/{Security-G3Kyk-TG.js → Security-C1hVxy8Z.js} +3 -3
- package/src/assets/web-panel/assets/{Services-xJReTOna.js → Services-BscEbAZ2.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-ldVDVTPG.js → Skeleton-B2sMLqKQ.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-emwNYV0j.js → Skills-CoHKax06.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CZYwGp1K.js → Sla-Bpie5KO6.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-BX63ijn5.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-Dcs5Hhj6.js → SyncSettings-Bf72so5A.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CerFAo26.js → Tasks-CVB2PZk4.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BdZUbOg3.js → Templates-q0qyclJx.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-B4c_7Bsw.js → Tenant-CW-W-i0k.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-D7QoPiXQ.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-tc6sp0TV.js → TimelineRenderer-BaRDAbyA.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Bw_vkMJq.js → Tokens-D6U4PRW8.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DkbJnpvz.js → Trigger-ClBDWdLo.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CIf9kqN1.js → Trust-C_M6rWPq.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-Cjwllnea.js → UkeySign-bXHx8s4C.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-kgfkY7AN.js → VideoEditing-BcIt_ieI.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CYWXt4u9.js → Wallet-Dd-4jcLs.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-QgPwyWCO.js → WebAuthn-B4F6yxQK.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-Co0lha18.js → WorkflowEditor-BEHkpfJq.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CI__Ox-r.js → chat-D7hhRpIO.js} +1 -1
- package/src/assets/web-panel/assets/{colors-Csv0eYYd.js → colors-AMRhrRzS.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-e53UCdHy.js → compact-item-BYpsOET5.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BMPGRDhV.js → createContext-CoUkR4LQ.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BRylvxzY.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-Dz68qIAq.js → hasIn-CJKJMKki.js} +1 -1
- package/src/assets/web-panel/assets/{index-BT3CV4Nh.js → index-8pmZHnQU.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyqcHiL1.js → index-BBJFiZ9Y.js} +1 -1
- package/src/assets/web-panel/assets/{index-HbhQRrM2.js → index-BP69Ul3S.js} +1 -1
- package/src/assets/web-panel/assets/{index-CoGSbW5J.js → index-BTFHYauX.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJqQL6so.js → index-BUJt2ar4.js} +1 -1
- package/src/assets/web-panel/assets/{index-CvLBQk_M.js → index-Bj30Aq6h.js} +1 -1
- package/src/assets/web-panel/assets/{index-ygfUVVFv.js → index-BlpuqGt5.js} +1 -1
- package/src/assets/web-panel/assets/index-Bzvxvzlk.js +1 -0
- package/src/assets/web-panel/assets/{index-CYUxs6J1.js → index-C19xZKIP.js} +1 -1
- package/src/assets/web-panel/assets/{index-B1s1B8Iy.js → index-C6bg22vc.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-NbcAbP.js → index-CH6XEWdj.js} +1 -1
- package/src/assets/web-panel/assets/{index-DctYrVMq.js → index-CK1Kknpl.js} +1 -1
- package/src/assets/web-panel/assets/{index-DVCd2aMX.js → index-CNyLbBGj.js} +1 -1
- package/src/assets/web-panel/assets/{index-t6f80uqL.js → index-COg__P6M.js} +22 -22
- package/src/assets/web-panel/assets/{index-5iicv5af.js → index-CRlJOWsf.js} +1 -1
- package/src/assets/web-panel/assets/{index-BW2dImbg.js → index-CScG8TAY.js} +1 -1
- package/src/assets/web-panel/assets/{index-K5E_wjut.js → index-CdL9cQIE.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dk9Gi8xd.js → index-Ck35u_0v.js} +1 -1
- package/src/assets/web-panel/assets/{index-_LmPlyeV.js → index-CkLZQtsh.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dtjm1K1a.js → index-DFoujkWD.js} +1 -1
- package/src/assets/web-panel/assets/{index--7tHEadk.js → index-DFwh0R9h.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5hLtxVz.js → index-DStN9E7o.js} +1 -1
- package/src/assets/web-panel/assets/{index-D0bg74e1.js → index-DcozYrXV.js} +1 -1
- package/src/assets/web-panel/assets/{index-wcCouSNq.js → index-De5mYp86.js} +1 -1
- package/src/assets/web-panel/assets/{index-CXuON9OG.js → index-DfEVOzNb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CNtZMPKV.js → index-Dfna8sKa.js} +1 -1
- package/src/assets/web-panel/assets/{index-B4lKPJy1.js → index-DjbMaBLf.js} +1 -1
- package/src/assets/web-panel/assets/index-Dl6H3dxS.js +1 -0
- package/src/assets/web-panel/assets/{index-C53o-MdJ.js → index-Dpl_SJuk.js} +1 -1
- package/src/assets/web-panel/assets/{index-53ljQo_x.js → index-DyF9uYzB.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpTzqJ0Z.js → index-HF3GvATm.js} +1 -1
- package/src/assets/web-panel/assets/{index-DCl4Xb4N.js → index-OJmXGn8n.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOpz2qS1.js → index-ZPdNPhUq.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHkDRNA5.js → index-djikyGz3.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyLUaP2i.js → index-gQWWnP3_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DnXm3Qsh.js → index-owVbLJnH.js} +1 -1
- package/src/assets/web-panel/assets/{index-ajz0E0pK.js → index-tWEDZHzj.js} +1 -1
- package/src/assets/web-panel/assets/{index-N9DkR1i7.js → index-ttTl376q.js} +1 -1
- package/src/assets/web-panel/assets/{index-CrsoSnQF.js → index-z5rYvstM.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DVCeQJrT.js → initDefaultProps-B_Uk-wzg.js} +1 -1
- package/src/assets/web-panel/assets/{motion-chBCR_8v.js → motion-ez7H8y8b.js} +1 -1
- package/src/assets/web-panel/assets/{move-BziPlrh6.js → move-CKWUhhhX.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-Cenk0OD7.js → mtc-parser-DkNl7ocj.js} +1 -1
- package/src/assets/web-panel/assets/{omit-D-AiRsei.js → omit-C0uA2ytw.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CHw3Fvqt.js → pickAttrs-CySaWMPl.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-g8I-rCad.js → placementArrow-BWL3-3xo.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BWffAr9k.js → responsiveObserve-BRy_wJog.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BmUQqhkb.js → slide-DmmvSaBD.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-B89gCO-y.js → statusUtils-C_7SYY0K.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-x1bnCF73.js → styleChecker-DYgBJGDh.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-B-k1_Ggw.js → useFlexGapSupport-nPkoZkT6.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-Bc3PUqQk.js → useFs-CzpsfP4_.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-D8qFDX1I.js → usePersonalDataHub-Bo2vvMWl.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-UaL5-WGg.js → vnode-D-hXAnHb.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-Dv7bsbLs.js → zoom-DW7seTGG.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/permissions.js +24 -1
- package/src/index.js +63 -845
- package/src/lib/agent-ipc-bus.js +331 -0
- package/src/lib/context-source-ledger.js +164 -0
- package/src/lib/execution-trace/index.js +10 -0
- package/src/lib/execution-trace/metrics-collector.js +218 -0
- package/src/lib/execution-trace/trace-context.js +182 -0
- package/src/lib/hook-manager.js +17 -0
- package/src/lib/hooks-v2-runtime.js +278 -0
- package/src/lib/metrics-collector.js +127 -0
- package/src/lib/observability/index.js +33 -0
- package/src/lib/observability/otlp-exporter.js +260 -0
- package/src/lib/otlp-exporter.js +45 -0
- package/src/lib/process-execution-broker/SPAWN_AUDIT_REPORT.md +117 -0
- package/src/lib/process-execution-broker/index.js +450 -0
- package/src/lib/process-execution-broker/patch-child-process.js +50 -0
- package/src/lib/process-execution-broker/spawn-audit.json +3814 -0
- package/src/lib/runtime-provenance-ledger.js +190 -0
- package/src/lib/session-hooks.js +41 -0
- package/src/program-base.js +4 -1
- package/src/repl/agent-repl.js +2 -0
- package/src/assets/web-panel/assets/MarkdownRenderer-CId5JWjX.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-CyaPrzOF.js +0 -1
- package/src/assets/web-panel/assets/Terminal-VVFLS3Ol.js +0 -3
- package/src/assets/web-panel/assets/devWarning-BIulobq7.js +0 -1
- package/src/assets/web-panel/assets/index-BGkiYnET.js +0 -1
- package/src/assets/web-panel/assets/index-Eyhrr_3u.js +0 -1
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent IPC Bus — M2: 后台Agent实时交互总线
|
|
3
|
+
* 对应文档 §2.2
|
|
4
|
+
*
|
|
5
|
+
* 解决后台agent运行期间不能提问/confirm/elicit的问题:
|
|
6
|
+
* - child agent 通过 IPC 发送 interaction_request
|
|
7
|
+
* - parent 路由给 UI/REPL/headless resolver
|
|
8
|
+
* - 结果通过 interaction_response 返回child
|
|
9
|
+
* - 支持超时、取消、默认值
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { EventEmitter } from "node:events";
|
|
13
|
+
import crypto from "node:crypto";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {Object} InteractionRequest
|
|
17
|
+
* @property {string} requestId
|
|
18
|
+
* @property {string} agentId - child agent id
|
|
19
|
+
* @property {string} sessionId
|
|
20
|
+
* @property {string} turnId
|
|
21
|
+
* @property {'permission_prompt'|'human_input'|'question'|'confirm'|'elicit'|'mcp_elicit'} type
|
|
22
|
+
* @property {string} prompt
|
|
23
|
+
* @property {string[]} [choices]
|
|
24
|
+
* @property {any} [defaultValue]
|
|
25
|
+
* @property {number} [timeoutMs]
|
|
26
|
+
* @property {Object} [metadata]
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
class AgentIPCBus extends EventEmitter {
|
|
30
|
+
constructor() {
|
|
31
|
+
super();
|
|
32
|
+
/** @type {Map<string, {req: InteractionRequest, resolve: Function, reject: Function, timer?: NodeJS.Timeout}>} */
|
|
33
|
+
this._pendingRequests = new Map();
|
|
34
|
+
/** @type {Map<string, Function>} resolvers by agentId */
|
|
35
|
+
this._agentResolvers = new Map();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Register an agent worker's send function so bus can route responses back
|
|
40
|
+
* @param {string} agentId
|
|
41
|
+
* @param {(msg: any) => void} sendToWorker
|
|
42
|
+
*/
|
|
43
|
+
registerAgent(agentId, sendToWorker) {
|
|
44
|
+
this._agentResolvers.set(agentId, sendToWorker);
|
|
45
|
+
this.emit("agent:registered", { agentId });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
unregisterAgent(agentId) {
|
|
49
|
+
this._agentResolvers.delete(agentId);
|
|
50
|
+
// Reject all pending for this agent
|
|
51
|
+
for (const [reqId, entry] of this._pendingRequests.entries()) {
|
|
52
|
+
if (entry.req.agentId === agentId) {
|
|
53
|
+
if (entry.timer) clearTimeout(entry.timer);
|
|
54
|
+
entry.reject(new Error(`Agent ${agentId} disconnected while waiting for response`));
|
|
55
|
+
this._pendingRequests.delete(reqId);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
this.emit("agent:unregistered", { agentId });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Child agent calls this to request human interaction
|
|
63
|
+
* @param {string} agentId
|
|
64
|
+
* @param {Partial<InteractionRequest>} req
|
|
65
|
+
* @returns {Promise<any>}
|
|
66
|
+
*/
|
|
67
|
+
requestInteraction(agentId, req) {
|
|
68
|
+
const requestId = crypto.randomUUID();
|
|
69
|
+
const fullReq = {
|
|
70
|
+
requestId,
|
|
71
|
+
agentId,
|
|
72
|
+
sessionId: req.sessionId,
|
|
73
|
+
turnId: req.turnId,
|
|
74
|
+
type: req.type || "question",
|
|
75
|
+
prompt: req.prompt,
|
|
76
|
+
choices: req.choices,
|
|
77
|
+
defaultValue: req.defaultValue,
|
|
78
|
+
timeoutMs: req.timeoutMs || 300000, // 5min default
|
|
79
|
+
metadata: req.metadata || {},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
const timer = setTimeout(() => {
|
|
84
|
+
this._pendingRequests.delete(requestId);
|
|
85
|
+
if (fullReq.defaultValue !== undefined) {
|
|
86
|
+
resolve(fullReq.defaultValue);
|
|
87
|
+
} else {
|
|
88
|
+
reject(new Error(`Interaction request ${requestId} timed out after ${fullReq.timeoutMs}ms`));
|
|
89
|
+
}
|
|
90
|
+
this.emit("request:timeout", fullReq);
|
|
91
|
+
}, fullReq.timeoutMs);
|
|
92
|
+
|
|
93
|
+
this._pendingRequests.set(requestId, { req: fullReq, resolve, reject, timer });
|
|
94
|
+
this.emit("request", fullReq);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Parent/UI calls this to respond to a pending request
|
|
100
|
+
* @param {string} requestId
|
|
101
|
+
* @param {any} response
|
|
102
|
+
*/
|
|
103
|
+
respond(requestId, response) {
|
|
104
|
+
const entry = this._pendingRequests.get(requestId);
|
|
105
|
+
if (!entry) return false;
|
|
106
|
+
if (entry.timer) clearTimeout(entry.timer);
|
|
107
|
+
this._pendingRequests.delete(requestId);
|
|
108
|
+
entry.resolve(response);
|
|
109
|
+
this.emit("request:resolved", { requestId, response });
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Reject/cancel a pending request
|
|
115
|
+
* @param {string} requestId
|
|
116
|
+
* @param {Error} [err]
|
|
117
|
+
*/
|
|
118
|
+
cancel(requestId, err) {
|
|
119
|
+
const entry = this._pendingRequests.get(requestId);
|
|
120
|
+
if (!entry) return false;
|
|
121
|
+
if (entry.timer) clearTimeout(entry.timer);
|
|
122
|
+
this._pendingRequests.delete(requestId);
|
|
123
|
+
entry.reject(err || new Error("Interaction cancelled by user"));
|
|
124
|
+
this.emit("request:cancelled", { requestId });
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Get pending interaction requests for UI */
|
|
129
|
+
getPendingRequests() {
|
|
130
|
+
return Array.from(this._pendingRequests.values()).map(e => e.req);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Number of pending requests */
|
|
134
|
+
get pendingCount() {
|
|
135
|
+
return this._pendingRequests.size;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Spawn a child agent process with standardized JSON-RPC over stdio protocol
|
|
140
|
+
* Aligned with Claude Code sub-agent spawn specification
|
|
141
|
+
* @param {string} command - Agent executable/script path
|
|
142
|
+
* @param {string[]} args - Command arguments
|
|
143
|
+
* @param {object} options - Spawn options
|
|
144
|
+
* @returns {Promise<{process: ChildProcess, agentId: string}>}
|
|
145
|
+
*/
|
|
146
|
+
async spawnAgentProcess(command, args = [], options = {}) {
|
|
147
|
+
const { spawn } = await import("node:child_process");
|
|
148
|
+
const agentId = options.agentId || crypto.randomUUID();
|
|
149
|
+
const heartbeatMs = options.heartbeatMs || 30000;
|
|
150
|
+
|
|
151
|
+
return new Promise((resolve, reject) => {
|
|
152
|
+
const child = spawn(command, args, {
|
|
153
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
154
|
+
env: {
|
|
155
|
+
...process.env,
|
|
156
|
+
CHAINLESSCHAIN_AGENT_ID: agentId,
|
|
157
|
+
CHAINLESSCHAIN_AGENT_MODE: "subagent",
|
|
158
|
+
CHAINLESSCHAIN_IPC_PROTOCOL: "jsonrpc-stdio-v1",
|
|
159
|
+
...options.env,
|
|
160
|
+
},
|
|
161
|
+
...options.spawnOptions,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
let buffer = "";
|
|
165
|
+
let initialized = false;
|
|
166
|
+
let heartbeatTimer = null;
|
|
167
|
+
|
|
168
|
+
// Handle stdout: line-delimited JSON-RPC
|
|
169
|
+
child.stdout.on("data", (chunk) => {
|
|
170
|
+
buffer += chunk.toString("utf8");
|
|
171
|
+
const lines = buffer.split("\n");
|
|
172
|
+
buffer = lines.pop() || ""; // Keep incomplete line in buffer
|
|
173
|
+
|
|
174
|
+
for (const line of lines) {
|
|
175
|
+
if (!line.trim()) continue;
|
|
176
|
+
try {
|
|
177
|
+
const msg = JSON.parse(line);
|
|
178
|
+
this._handleIncomingMessage(agentId, msg, child);
|
|
179
|
+
if (msg.method === "initialize" && !initialized) {
|
|
180
|
+
initialized = true;
|
|
181
|
+
this.registerAgent(agentId, (outMsg) => {
|
|
182
|
+
child.stdin.write(JSON.stringify(outMsg) + "\n");
|
|
183
|
+
});
|
|
184
|
+
// Send initialize response
|
|
185
|
+
child.stdin.write(JSON.stringify({
|
|
186
|
+
jsonrpc: "2.0",
|
|
187
|
+
id: msg.id,
|
|
188
|
+
result: {
|
|
189
|
+
protocolVersion: "1.0",
|
|
190
|
+
agentId,
|
|
191
|
+
capabilities: { interaction: true, tools: true },
|
|
192
|
+
},
|
|
193
|
+
}) + "\n");
|
|
194
|
+
// Setup heartbeat
|
|
195
|
+
heartbeatTimer = setInterval(() => {
|
|
196
|
+
if (child.exitCode !== null) {
|
|
197
|
+
clearInterval(heartbeatTimer);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
child.stdin.write(JSON.stringify({ jsonrpc: "2.0", method: "heartbeat" }) + "\n");
|
|
201
|
+
}, heartbeatMs);
|
|
202
|
+
resolve({ process: child, agentId });
|
|
203
|
+
}
|
|
204
|
+
} catch (e) {
|
|
205
|
+
this.emit("protocol:error", { agentId, error: e, raw: line });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Handle stderr: pass through to logger
|
|
211
|
+
child.stderr.on("data", (chunk) => {
|
|
212
|
+
this.emit("agent:stderr", { agentId, data: chunk.toString("utf8") });
|
|
213
|
+
if (options.captureStderr !== false) {
|
|
214
|
+
process.stderr.write(`[agent:${agentId}] ${chunk}`);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
child.on("error", (err) => {
|
|
219
|
+
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
220
|
+
if (!initialized) reject(err);
|
|
221
|
+
this.emit("agent:error", { agentId, error: err });
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
child.on("exit", (code, signal) => {
|
|
225
|
+
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
226
|
+
this.unregisterAgent(agentId);
|
|
227
|
+
this.emit("agent:exit", { agentId, code, signal });
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Timeout for initialization
|
|
231
|
+
setTimeout(() => {
|
|
232
|
+
if (!initialized) {
|
|
233
|
+
child.kill();
|
|
234
|
+
reject(new Error(`Agent ${agentId} initialization timed out`));
|
|
235
|
+
}
|
|
236
|
+
}, options.initTimeoutMs || 10000);
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Handle incoming JSON-RPC message from child agent
|
|
242
|
+
* @private
|
|
243
|
+
*/
|
|
244
|
+
_handleIncomingMessage(agentId, msg, child) {
|
|
245
|
+
if (!msg.jsonrpc || msg.jsonrpc !== "2.0") {
|
|
246
|
+
this.emit("protocol:warning", { agentId, msg, reason: "missing jsonrpc version" });
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Handle requests (method + id)
|
|
251
|
+
if (msg.method && msg.id) {
|
|
252
|
+
if (msg.method === "interaction_request") {
|
|
253
|
+
this.requestInteraction(agentId, msg.params).then((result) => {
|
|
254
|
+
child.stdin.write(JSON.stringify({
|
|
255
|
+
jsonrpc: "2.0",
|
|
256
|
+
id: msg.id,
|
|
257
|
+
result,
|
|
258
|
+
}) + "\n");
|
|
259
|
+
}).catch((err) => {
|
|
260
|
+
child.stdin.write(JSON.stringify({
|
|
261
|
+
jsonrpc: "2.0",
|
|
262
|
+
id: msg.id,
|
|
263
|
+
error: { code: -32000, message: err.message },
|
|
264
|
+
}) + "\n");
|
|
265
|
+
});
|
|
266
|
+
} else if (msg.method === "log") {
|
|
267
|
+
this.emit("agent:log", { agentId, params: msg.params });
|
|
268
|
+
// Acknowledge log
|
|
269
|
+
child.stdin.write(JSON.stringify({ jsonrpc: "2.0", id: msg.id, result: true }) + "\n");
|
|
270
|
+
} else {
|
|
271
|
+
this.emit("agent:request", { agentId, msg });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
// Handle notifications (method, no id)
|
|
275
|
+
else if (msg.method && !msg.id) {
|
|
276
|
+
if (msg.method === "heartbeat") {
|
|
277
|
+
this.emit("agent:heartbeat", { agentId });
|
|
278
|
+
} else if (msg.method === "progress") {
|
|
279
|
+
this.emit("agent:progress", { agentId, params: msg.params });
|
|
280
|
+
} else {
|
|
281
|
+
this.emit("agent:notification", { agentId, method: msg.method, params: msg.params });
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
// Handle responses (id + result/error)
|
|
285
|
+
else if (msg.id) {
|
|
286
|
+
this.emit("agent:response", { agentId, msg });
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Send a JSON-RPC request to a spawned agent via stdio
|
|
292
|
+
* @param {string} agentId
|
|
293
|
+
* @param {string} method
|
|
294
|
+
* @param {any} params
|
|
295
|
+
* @param {number} [timeoutMs=30000]
|
|
296
|
+
* @returns {Promise<any>}
|
|
297
|
+
*/
|
|
298
|
+
sendRequest(agentId, method, params = {}, timeoutMs = 30000) {
|
|
299
|
+
const sendToWorker = this._agentResolvers.get(agentId);
|
|
300
|
+
if (!sendToWorker) {
|
|
301
|
+
return Promise.reject(new Error(`Agent ${agentId} not registered`));
|
|
302
|
+
}
|
|
303
|
+
const id = crypto.randomUUID();
|
|
304
|
+
return new Promise((resolve, reject) => {
|
|
305
|
+
const timer = setTimeout(() => {
|
|
306
|
+
this.removeAllListeners(`response:${id}`);
|
|
307
|
+
reject(new Error(`Request ${method} to agent ${agentId} timed out`));
|
|
308
|
+
}, timeoutMs);
|
|
309
|
+
|
|
310
|
+
const onResponse = (respMsg) => {
|
|
311
|
+
if (respMsg.msg.id === id) {
|
|
312
|
+
clearTimeout(timer);
|
|
313
|
+
this.off("agent:response", onResponse);
|
|
314
|
+
if (respMsg.msg.error) {
|
|
315
|
+
reject(new Error(respMsg.msg.error.message));
|
|
316
|
+
} else {
|
|
317
|
+
resolve(respMsg.msg.result);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
this.on("agent:response", onResponse);
|
|
322
|
+
|
|
323
|
+
sendToWorker({ jsonrpc: "2.0", id, method, params });
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Singleton
|
|
329
|
+
const ipcBus = new AgentIPCBus();
|
|
330
|
+
export default ipcBus;
|
|
331
|
+
export { AgentIPCBus };
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Source Ledger — M4-1: 上下文来源归因系统
|
|
3
|
+
* 对应文档 §2.5
|
|
4
|
+
*
|
|
5
|
+
* 统一追踪每段上下文的来源、工具调用、权限模式、置信度,
|
|
6
|
+
* 让"AI 为什么此刻知道这件事"完全可追溯
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import crypto from "node:crypto";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {Object} ContextEntry
|
|
13
|
+
* @property {string} entryId
|
|
14
|
+
* @property {string} sessionId
|
|
15
|
+
* @property {string} turnId
|
|
16
|
+
* @property {string} sourceType - slash_command|mcp|tool|hook|skill|agent|file|memory|prompt|plugin
|
|
17
|
+
* @property {string} sourceId - tool name, mcp server name, hook id, etc.
|
|
18
|
+
* @property {'system'|'developer'|'plugin'|'user'|'agent'} permissionMode
|
|
19
|
+
* @property {number} confidence - 0-1
|
|
20
|
+
* @property {string} [summary]
|
|
21
|
+
* @property {any} [metadata]
|
|
22
|
+
* @property {number} tokenCount
|
|
23
|
+
* @property {Date} insertedAt
|
|
24
|
+
* @property {string[]} tags
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
class ContextSourceLedger {
|
|
28
|
+
constructor() {
|
|
29
|
+
/** @type {Map<string, ContextEntry>} */
|
|
30
|
+
this._entries = new Map();
|
|
31
|
+
/** @type {Map<string, ContextEntry[]>} turnIndex: turnId -> entries */
|
|
32
|
+
this._byTurn = new Map();
|
|
33
|
+
/** @type {Map<string, ContextEntry[]>} sessionIndex: sessionId -> entries */
|
|
34
|
+
this._bySession = new Map();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Record a context source entry
|
|
39
|
+
* @param {Partial<ContextEntry>} entry
|
|
40
|
+
* @returns {string} entryId
|
|
41
|
+
*/
|
|
42
|
+
record(entry) {
|
|
43
|
+
const entryId = entry.entryId || crypto.randomUUID();
|
|
44
|
+
const full = {
|
|
45
|
+
entryId,
|
|
46
|
+
sessionId: entry.sessionId || "unknown",
|
|
47
|
+
turnId: entry.turnId || "unknown",
|
|
48
|
+
sourceType: entry.sourceType || "unknown",
|
|
49
|
+
sourceId: entry.sourceId || "unknown",
|
|
50
|
+
permissionMode: entry.permissionMode || "agent",
|
|
51
|
+
confidence: entry.confidence ?? 0.8,
|
|
52
|
+
summary: entry.summary,
|
|
53
|
+
metadata: entry.metadata,
|
|
54
|
+
tokenCount: entry.tokenCount || 0,
|
|
55
|
+
insertedAt: new Date(),
|
|
56
|
+
tags: entry.tags || [],
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
this._entries.set(entryId, full);
|
|
60
|
+
|
|
61
|
+
// Index by turn
|
|
62
|
+
if (!this._byTurn.has(full.turnId)) this._byTurn.set(full.turnId, []);
|
|
63
|
+
this._byTurn.get(full.turnId).push(full);
|
|
64
|
+
|
|
65
|
+
// Index by session
|
|
66
|
+
if (!this._bySession.has(full.sessionId)) this._bySession.set(full.sessionId, []);
|
|
67
|
+
this._bySession.get(full.sessionId).push(full);
|
|
68
|
+
|
|
69
|
+
return entryId;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get all context entries for a given turn
|
|
74
|
+
* @param {string} turnId
|
|
75
|
+
* @returns {ContextEntry[]}
|
|
76
|
+
*/
|
|
77
|
+
getTurnContext(turnId) {
|
|
78
|
+
return this._byTurn.get(turnId) || [];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get all context entries for a session
|
|
83
|
+
* @param {string} sessionId
|
|
84
|
+
* @returns {ContextEntry[]}
|
|
85
|
+
*/
|
|
86
|
+
getSessionContext(sessionId) {
|
|
87
|
+
return this._bySession.get(sessionId) || [];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Generate context provenance summary for a turn
|
|
92
|
+
* Shows exactly where each piece of context came from
|
|
93
|
+
* @param {string} turnId
|
|
94
|
+
* @returns {Object} provenance report
|
|
95
|
+
*/
|
|
96
|
+
getTurnProvenance(turnId) {
|
|
97
|
+
const entries = this.getTurnContext(turnId);
|
|
98
|
+
const byType = {};
|
|
99
|
+
const byPermission = {};
|
|
100
|
+
const bySource = {};
|
|
101
|
+
let totalTokens = 0;
|
|
102
|
+
let avgConfidence = 0;
|
|
103
|
+
|
|
104
|
+
for (const e of entries) {
|
|
105
|
+
byType[e.sourceType] = (byType[e.sourceType] || 0) + 1;
|
|
106
|
+
byPermission[e.permissionMode] = (byPermission[e.permissionMode] || 0) + 1;
|
|
107
|
+
bySource[e.sourceId] = (bySource[e.sourceId] || 0) + 1;
|
|
108
|
+
totalTokens += e.tokenCount;
|
|
109
|
+
avgConfidence += e.confidence;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
avgConfidence = entries.length > 0 ? avgConfidence / entries.length : 0;
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
turnId,
|
|
116
|
+
totalEntries: entries.length,
|
|
117
|
+
totalTokens,
|
|
118
|
+
avgConfidence: Math.round(avgConfidence * 100) / 100,
|
|
119
|
+
byType,
|
|
120
|
+
byPermission,
|
|
121
|
+
bySource,
|
|
122
|
+
entries: entries.map(e => ({
|
|
123
|
+
sourceType: e.sourceType,
|
|
124
|
+
sourceId: e.sourceId,
|
|
125
|
+
permissionMode: e.permissionMode,
|
|
126
|
+
confidence: e.confidence,
|
|
127
|
+
tokenCount: e.tokenCount,
|
|
128
|
+
summary: e.summary,
|
|
129
|
+
tags: e.tags,
|
|
130
|
+
})),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Clear entries for a session
|
|
136
|
+
* @param {string} sessionId
|
|
137
|
+
*/
|
|
138
|
+
clearSession(sessionId) {
|
|
139
|
+
const entries = this._bySession.get(sessionId) || [];
|
|
140
|
+
for (const e of entries) {
|
|
141
|
+
this._entries.delete(e.entryId);
|
|
142
|
+
const turnEntries = this._byTurn.get(e.turnId);
|
|
143
|
+
if (turnEntries) {
|
|
144
|
+
const idx = turnEntries.findIndex(x => x.entryId === e.entryId);
|
|
145
|
+
if (idx >= 0) turnEntries.splice(idx, 1);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
this._bySession.delete(sessionId);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Get stats */
|
|
152
|
+
getStats() {
|
|
153
|
+
return {
|
|
154
|
+
totalEntries: this._entries.size,
|
|
155
|
+
sessionsTracked: this._bySession.size,
|
|
156
|
+
turnsTracked: this._byTurn.size,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Singleton
|
|
162
|
+
const ledger = new ContextSourceLedger();
|
|
163
|
+
export default ledger;
|
|
164
|
+
export { ContextSourceLedger };
|