chainlesschain 0.162.180 → 0.162.181
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 +6 -3
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-D_TIL54O.js → AIOps-cq0dwbnf.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-eQwy9r-f.js → ActionButton-CvcgGl3w.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-D2eNuDgT.js → Analytics-hM2-jFqg.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CFhwOFsf.js → AppLayout-B9_Gsd_g.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-CJUMw6PB.js → Artifacts-B7bu52Og.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CDB9V58o.js → Audit-DThfDgqB.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-TBppYFjN.js → BackgroundAgents-DjlFiD4v.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CYEOUpzJ.js → Backup-CK9xJKnG.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-C88fFT2u.js → BaseInput-DEiSU8K8.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-mkr1vC3N.js → Chat-CpT96czj.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-C7bofJuA.js → ChatBubbleRenderer-BKPPNmZI.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-CVU4xqti.js → Checkbox-C1GfDnO0.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-rrNcByz3.js → Codegen-3DAKgiLx.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Cqu-zCvh.js → Col-74cOwZU1.js} +1 -1
- package/src/assets/web-panel/assets/{Community-RGRlSgXV.js → Community-tn9Kkz9j.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DBm6epOK.js → Compact-BcoXH7m4.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BgKw5iaW.js → Compliance-DIPGUBgi.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BqQcNO3Z.js → Cowork-doD5_91c.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-DO5gTFNb.js → Cron-C-IDvubz.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-B8hbJNuN.js → Crosschain-CdcCoBdj.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B08bFJ2C.js → DID-DdH5aMMA.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-xNdy_ifo.js → Dashboard-DHLA4mm0.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-D-KIZgWL.js → Dropdown-dEeCt7Md.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DKCvsaGo.js → EmailListRenderer-BMaecFv9.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-D_cfqama.js → FamilyGuardDashboard-DUaUukTN.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-B-UqQD68.js → Federation-CMBE0_rp.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BWWvWuJW.js → FormItemContext-PG-JDbXq.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CPchx6N7.js → GenericCardRenderer-Bcb0p88m.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Vx4co9Ff.js → Git-Bgv15myB.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-D4x0pp_m.js → Governance-DB8YTArI.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-T3KvwPYR.js → Inference-BQMwCWaS.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Ddv3KUv3.js → KnowledgeGraph-B1_ZziiB.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DfH-Dkae.js → Logs-DovEEnt_.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-DHW3PbCq.js → MarkdownRenderer-D201OL4T.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-tjgb0R3D.js → Marketplace-BlCXSpyB.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DHAk5nYX.js → McpTools-CsCR09Wj.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-A2Yx7thM.js → Memory-CBVRLKno.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BEmTVfN5.js → MobileBridge-C9OIafgA.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DuFHUgE4.js → MobileProjects-D_zoJ8Xs.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BDSll0OZ.js → Mtc-vE-HdvLj.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-CuBvluaS.js → MtcAudit-CPLaekCd.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-BmXAA-Sb.js → Multisig-C_UP9C2o.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-ci2stZAe.js → NLProgramming-2nODJcU1.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-D-1RpqnS.js → Notes-BhE-SJGu.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-C0GyitIT.js → NotificationSettings-D21q7BNU.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-U2bN-hj5.js → OrderTableRenderer-0b62GYOD.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BNZgpPci.js → Organization-CEqmw_sb.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CDidKmUN.js → Overflow-MW-gMDO_.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BnreBaXq.js → P2P-CY0hjI_G.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DwJUxO9j.js → PdhVaultBrowser-BbWh7Man.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BQGgJPH0.js → Permissions-ChqEA_4Q.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-k_fSkCwL.js → PersonalDataHub-B3YrbYfD.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-WGqKMqau.js → Pipeline-B8WBhhlW.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DtHj9Ymq.js → Privacy-Cmb0PXNx.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B3wH2SFC.js → ProjectInit-hF6zW3Nz.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Cd0cgcA1.js → ProjectSettings-BFSVfpW0.js} +2 -2
- package/src/assets/web-panel/assets/Projects-DAWkVFkc.js +1 -0
- package/src/assets/web-panel/assets/{Providers-DTpxEXur.js → Providers-B8yux8Dx.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-B2v6gR-C.js → QrScannerModal-N76cQluO.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-D3Nr9xXR.js → QuickAsk-ClvZ0KYR.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-C9inoMky.js → Recommend-B-GfgBpT.js} +1 -1
- package/src/assets/web-panel/assets/RemoteSession-mlglCdQi.js +5 -0
- package/src/assets/web-panel/assets/{Reputation-41KFG646.js → Reputation-DJIZzQeG.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DqAaqqCv.js → Row-COzxu_bb.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CMDpCDKc.js → RssFeed-CoYsJQuE.js} +3 -3
- package/src/assets/web-panel/assets/{Search-B6mtegNL.js → Search-DC77Mq9S.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BaePFVZ8.js → Security-Loy2EdMO.js} +3 -3
- package/src/assets/web-panel/assets/{Services-DeG3Qscl.js → Services-GUD07Eu0.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-D_QP7F90.js → Skeleton-DWzkptYU.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DLGyUgIA.js → Skills-CEDn1r-Z.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BN2pxW1Q.js → Sla-ub_k4pXh.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BWsZPd8B.js → SpeechSettings-D7HLX9CA.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-VOZRPODW.js → SyncSettings-DbwOvl6m.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-CBQzoAu5.js +1 -0
- package/src/assets/web-panel/assets/{Templates-eJSob-q0.js → Templates-BNVeIhud.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-Bdwk8Rwy.js → Tenant-PS9AzhXU.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-CsMLKIoV.js → Terminal-Cgb4eLB_.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-D5qkbPKT.js → TimelineRenderer-CrmXMOkg.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DKgwn8hI.js → Tokens-DD-VDHw1.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-HlEHniGM.js → Trigger-BsoN_n-n.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CdPcsBpN.js → Trust-n8LmN4ZV.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-vAdXd-vG.js → UkeySign-C9_7MImA.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-9hHBYFnH.js → VideoEditing-DyBteNgn.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Dxh5d1yR.js → Wallet-BS5ixeXI.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-BsFmLHkp.js → WebAuthn-spc4UImU.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-Cn0OIwLn.js → WorkflowEditor-D7iVvaBO.js} +1 -1
- package/src/assets/web-panel/assets/chat-6CmBkHrL.js +1 -0
- package/src/assets/web-panel/assets/{colors-Du9jzLN0.js → colors-BGoCLkxI.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DhEscfzw.js → compact-item-fYZBetMO.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CwzEfF3i.js → createContext-BeM-1UVj.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BzPwHnw8.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DT_GSE6J.js → hasIn-CE7ZuEnV.js} +1 -1
- package/src/assets/web-panel/assets/{index-53z1YUxX.js → index--lap6cf7.js} +1 -1
- package/src/assets/web-panel/assets/{index-NA2oBLSB.js → index-ATcSr_2O.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWL3SYN3.js → index-B2U-ObMq.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-QkW1fp.js → index-B3CDgvNW.js} +1 -1
- package/src/assets/web-panel/assets/{index-BF-ZCVGE.js → index-B4wiTEOM.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4kZoXNr.js → index-B8BsdNV_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DnVVYKCE.js → index-BEVm0lCS.js} +10 -10
- package/src/assets/web-panel/assets/{index-DfRDyY1q.js → index-BNZDILcO.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8s5FxJY.js → index-BU_2qiDk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnHhFnwt.js → index-BV551878.js} +1 -1
- package/src/assets/web-panel/assets/{index-DhXay17G.js → index-BfPL-m46.js} +1 -1
- package/src/assets/web-panel/assets/{index-B6QDWRLk.js → index-BowH1eLQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DN60VBn5.js → index-BsMfoaeo.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cnok8mhZ.js → index-BunaQCa0.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dny_ZnAO.js → index-C0v6YKKO.js} +1 -1
- package/src/assets/web-panel/assets/{index-D8gt0j7r.js → index-C4SJVjs4.js} +1 -1
- package/src/assets/web-panel/assets/{index-Mobw3PHs.js → index-C9Y3k0HI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAVW0cWM.js → index-CIpVrf5P.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyEhUJcu.js → index-CRLjEP1H.js} +1 -1
- package/src/assets/web-panel/assets/{index-DzjzrOli.js → index-CRnUE8Cb.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5IytTND.js → index-Cip8emOQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQWENaZf.js → index-CpIGIB85.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQWxDOvM.js → index-D1r9tT3J.js} +1 -1
- package/src/assets/web-panel/assets/{index-BrkJ7JPm.js → index-DT3zPSVX.js} +1 -1
- package/src/assets/web-panel/assets/index-DacrAdc-.js +1 -0
- package/src/assets/web-panel/assets/{index-BFD0cEna.js → index-De0quFDw.js} +1 -1
- package/src/assets/web-panel/assets/{index-v5HLYCVa.js → index-DoXk5KJ8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DtRwLhee.js → index-DsvfrESp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BgSR2WMG.js → index-Dw1PyYPm.js} +1 -1
- package/src/assets/web-panel/assets/index-EHzNJozo.js +1 -0
- package/src/assets/web-panel/assets/{index-CGvgnfl9.js → index-MtOuq2i6.js} +1 -1
- package/src/assets/web-panel/assets/{index-1LoutPJd.js → index-Puq6Luf1.js} +1 -1
- package/src/assets/web-panel/assets/{index-tND8-TDU.js → index-QIpnpZgz.js} +1 -1
- package/src/assets/web-panel/assets/{index-D3llLkYM.js → index-RMZ8a7Yt.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4SN3by5.js → index-WUrJ6S1j.js} +1 -1
- package/src/assets/web-panel/assets/{index-VeHs6qH0.js → index-YjcumOZ4.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cc9aPkv-.js → index-lJBjB1QX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIYTjbv_.js → index-ukg99D1V.js} +1 -1
- package/src/assets/web-panel/assets/{index-gFjYdstW.js → index-zb7rVOhV.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Cvt59c10.js → initDefaultProps-CYHMs1ag.js} +1 -1
- package/src/assets/web-panel/assets/{motion-D15pPEzl.js → motion-DDB2Ffk5.js} +1 -1
- package/src/assets/web-panel/assets/{move-N55KeXJ7.js → move-Bg3cD-dX.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CyFO1bYP.js → mtc-parser-B5nedjTS.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B5IXfxU2.js → omit-BHyuUILu.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CpVqsulV.js → pickAttrs-C9YQnEN9.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-ME36sMF3.js → placementArrow-DBUFYUe7.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BXAIR1r-.js → responsiveObserve-nBs2Obnk.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BkOX3-Dp.js → slide-DkCEaXNU.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Cy4Aklpt.js → statusUtils-aqE1Wi6U.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-gUd2T206.js → styleChecker-CN5bhfHB.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CaVD4o99.js → useFlexGapSupport-B_oX_kvJ.js} +1 -1
- package/src/assets/web-panel/assets/{useFs--pFGl0KD.js → useFs-rCuXHeme.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-D45iP86i.js → usePersonalDataHub-DZR9Abyd.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BayoChH_.js → vnode-ConCYQlX.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CpP38poi.js → zoom-CUdDxG5M.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +4 -1
- package/src/commands/background-session.js +2 -1
- package/src/commands/context.js +69 -2
- package/src/data/changelog.json +13 -0
- package/src/gateways/ws/background-agent-protocol.js +38 -0
- package/src/gateways/ws/message-dispatcher.js +1 -0
- package/src/gateways/ws/remote-session-protocol.js +65 -6
- package/src/gateways/ws/ws-server.js +8 -1
- package/src/harness/feature-flags.js +15 -8
- package/src/harness/mcp-client.js +618 -43
- package/src/lazy-dispatch.js +30 -1
- package/src/lib/agent-authority.js +22 -0
- package/src/lib/agent-core.js +2 -0
- package/src/lib/agent-sandbox.js +161 -0
- package/src/lib/agent-team/team-runner.js +22 -0
- package/src/lib/artifact-store.js +35 -0
- package/src/lib/async-hook-supervisor.cjs +13 -2
- package/src/lib/audit-mtc.js +3 -2
- package/src/lib/background-agent-supervisor.js +104 -3
- package/src/lib/background-interaction-journal.js +407 -0
- package/src/lib/background-interaction-resolver.js +23 -34
- package/src/lib/background-session-transport.js +12 -2
- package/src/lib/capability-manifest.js +41 -3
- package/src/lib/capability-negotiation.js +1 -1
- package/src/lib/channels/channel-manager.js +33 -0
- package/src/lib/channels/telegram-channel.js +23 -5
- package/src/lib/channels/webhook-channel.js +38 -15
- package/src/lib/chrome-connector.js +169 -23
- package/src/lib/config-manager.js +23 -9
- package/src/lib/context-breakdown.js +31 -0
- package/src/lib/cowork-cron.js +274 -32
- package/src/lib/cross-chain-mtc.js +3 -2
- package/src/lib/durable-security-store.js +124 -0
- package/src/lib/event-runtime-host.js +67 -6
- package/src/lib/event-runtime-store.js +163 -0
- package/src/lib/goal-store.js +32 -12
- package/src/lib/headless-manifest.js +2 -1
- package/src/lib/hook-environment.cjs +58 -0
- package/src/lib/hook-manager.js +12 -5
- package/src/lib/hook-runner.cjs +122 -28
- package/src/lib/hook-runner.js +1 -0
- package/src/lib/hooks-v2-producers.js +36 -0
- package/src/lib/hooks-v2-runtime.js +329 -52
- package/src/lib/interaction-adapter.js +60 -19
- package/src/lib/interaction-binding.js +64 -0
- package/src/lib/json-schema-output.js +439 -14
- package/src/lib/json-schema-validate.js +514 -883
- package/src/lib/lan-pairing-tokens.js +115 -57
- package/src/lib/lsp/__tests__/lsp-client.test.js +32 -0
- package/src/lib/lsp/__tests__/lsp-manager.test.js +25 -0
- package/src/lib/lsp/lsp-client.js +4 -0
- package/src/lib/lsp/lsp-manager.js +3 -0
- package/src/lib/lsp/lsp-server-registry.js +18 -0
- package/src/lib/mcp-client.js +1 -0
- package/src/lib/mcp-oauth.js +35 -21
- package/src/lib/packer/pkg-config-generator.js +1 -0
- package/src/lib/permission-decision.js +99 -0
- package/src/lib/plugin-monitor-supervisor.js +3 -0
- package/src/lib/plugin-runtime/capabilities.js +50 -0
- package/src/lib/plugin-runtime/capability-consent.js +42 -35
- package/src/lib/plugin-runtime/hooks.js +36 -9
- package/src/lib/plugin-runtime/install.js +23 -7
- package/src/lib/plugin-runtime/lsp.js +4 -0
- package/src/lib/plugin-runtime/manifest.js +50 -2
- package/src/lib/plugin-runtime/mcp.js +30 -5
- package/src/lib/plugin-runtime/monitors.js +11 -0
- package/src/lib/plugin-runtime/plugin-options.js +94 -38
- package/src/lib/plugin-runtime/policy.js +29 -2
- package/src/lib/plugin-runtime/sandbox-policy.js +84 -0
- package/src/lib/plugin-runtime/scopes.js +7 -3
- package/src/lib/plugin-runtime/trust.js +36 -31
- package/src/lib/process-execution-broker/credential-agent.js +114 -16
- package/src/lib/process-execution-broker/credential-transport-worker.js +312 -0
- package/src/lib/process-execution-broker/credential-transport.js +378 -0
- package/src/lib/process-execution-broker/index.js +408 -19
- package/src/lib/process-execution-broker/platform-sandbox.js +561 -21
- package/src/lib/process-execution-broker/windows-sandbox.ps1 +999 -0
- package/src/lib/project-mcp-trust.js +21 -26
- package/src/lib/protocol-replay.js +19 -12
- package/src/lib/settings-hooks.cjs +13 -0
- package/src/lib/skill-loader.js +83 -10
- package/src/lib/sync-credentials.js +5 -4
- package/src/lib/turn-binding.js +8 -6
- package/src/repl/agent-repl.js +113 -28
- package/src/repl/repl-turn-binding.js +5 -2
- package/src/runtime/agent-core.js +331 -26
- package/src/runtime/coding-agent-contract-shared.cjs +3 -3
- package/src/runtime/headless-runner.js +101 -4
- package/src/runtime/headless-stream.js +209 -23
- package/src/runtime/mcp-config.js +29 -17
- package/src/runtime/policies/agent-policy.js +2 -0
- package/src/workers/background-agent-worker.js +128 -13
- package/src/assets/web-panel/assets/Projects-BbgmyQnS.js +0 -1
- package/src/assets/web-panel/assets/RemoteSession-Bqk3EYSu.js +0 -4
- package/src/assets/web-panel/assets/Tasks-3bDAUz8K.js +0 -1
- package/src/assets/web-panel/assets/chat-CJ19O6Dh.js +0 -1
- package/src/assets/web-panel/assets/devWarning-BBMFnsja.js +0 -1
- package/src/assets/web-panel/assets/index-Do8JMV4N.js +0 -1
- package/src/assets/web-panel/assets/index-UYAJ6iNM.js +0 -1
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable pending/settlement journal for background human interactions.
|
|
3
|
+
*
|
|
4
|
+
* Each mutation appends a full snapshot to the session's tamper-evident JSONL
|
|
5
|
+
* transcript. The worker persists a terminal settlement before delivering it
|
|
6
|
+
* to the suspended child, so retries can be classified as the same idempotent
|
|
7
|
+
* answer or a conflicting second settlement even after a process restart.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { createHash } from "node:crypto";
|
|
11
|
+
import {
|
|
12
|
+
appendEvent as storeAppendEvent,
|
|
13
|
+
readEvents as storeReadEvents,
|
|
14
|
+
} from "../harness/jsonl-session-store.js";
|
|
15
|
+
import {
|
|
16
|
+
normalizeInteractionBinding,
|
|
17
|
+
sameInteractionBinding,
|
|
18
|
+
} from "./interaction-binding.js";
|
|
19
|
+
|
|
20
|
+
export const BACKGROUND_INTERACTION_JOURNAL_EVENT =
|
|
21
|
+
"background_interaction_journal";
|
|
22
|
+
export const BACKGROUND_INTERACTION_JOURNAL_VERSION = 1;
|
|
23
|
+
export const MAX_BACKGROUND_INTERACTION_RECORDS = 256;
|
|
24
|
+
|
|
25
|
+
const TERMINAL_STATUSES = new Set(["resolved", "rejected", "cancelled"]);
|
|
26
|
+
|
|
27
|
+
export const _deps = {
|
|
28
|
+
appendEvent: storeAppendEvent,
|
|
29
|
+
readEvents: storeReadEvents,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function journalError(message, code, details = {}) {
|
|
33
|
+
const error = new Error(message);
|
|
34
|
+
error.code = code;
|
|
35
|
+
Object.assign(error, details);
|
|
36
|
+
return error;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function cloneJson(value) {
|
|
40
|
+
if (value === undefined) return null;
|
|
41
|
+
return JSON.parse(JSON.stringify(value));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function canonicalize(value) {
|
|
45
|
+
if (value === undefined) return "__undefined__";
|
|
46
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
47
|
+
if (Array.isArray(value)) {
|
|
48
|
+
return `[${value.map((entry) => canonicalize(entry)).join(",")}]`;
|
|
49
|
+
}
|
|
50
|
+
return `{${Object.keys(value)
|
|
51
|
+
.sort()
|
|
52
|
+
.map((key) => `${JSON.stringify(key)}:${canonicalize(value[key])}`)
|
|
53
|
+
.join(",")}}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function fingerprint(value) {
|
|
57
|
+
return createHash("sha256").update(canonicalize(value)).digest("hex");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function normalizeError(error, fallbackCode = "INTERACTION_REJECTED") {
|
|
61
|
+
if (!error) return null;
|
|
62
|
+
if (typeof error === "string") {
|
|
63
|
+
return { code: fallbackCode, message: error };
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
code: String(error.code || fallbackCode),
|
|
67
|
+
message: String(error.message || error),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function normalizeSettlement(outcome = {}) {
|
|
72
|
+
const status = String(outcome.status || "");
|
|
73
|
+
if (!TERMINAL_STATUSES.has(status)) {
|
|
74
|
+
throw journalError(
|
|
75
|
+
`Invalid background interaction settlement status: ${status || "<missing>"}`,
|
|
76
|
+
"INTERACTION_SETTLEMENT_INVALID",
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
status,
|
|
81
|
+
answer: status === "resolved" ? cloneJson(outcome.answer) : null,
|
|
82
|
+
error:
|
|
83
|
+
status === "resolved"
|
|
84
|
+
? null
|
|
85
|
+
: normalizeError(
|
|
86
|
+
outcome.error,
|
|
87
|
+
status === "cancelled"
|
|
88
|
+
? "INTERACTION_CANCELLED"
|
|
89
|
+
: "INTERACTION_REJECTED",
|
|
90
|
+
),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export class BackgroundInteractionJournal {
|
|
95
|
+
constructor(options = {}) {
|
|
96
|
+
this.backgroundAgentId = String(options.backgroundAgentId || "");
|
|
97
|
+
if (!this.backgroundAgentId) {
|
|
98
|
+
throw journalError(
|
|
99
|
+
"backgroundAgentId is required for the interaction journal",
|
|
100
|
+
"INTERACTION_JOURNAL_INVALID",
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
this._now = options.now || Date.now;
|
|
104
|
+
this.records = [];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
static fromJSON(snapshot, options = {}) {
|
|
108
|
+
if (
|
|
109
|
+
!snapshot ||
|
|
110
|
+
snapshot.version !== BACKGROUND_INTERACTION_JOURNAL_VERSION ||
|
|
111
|
+
typeof snapshot.backgroundAgentId !== "string" ||
|
|
112
|
+
!Array.isArray(snapshot.records)
|
|
113
|
+
) {
|
|
114
|
+
throw journalError(
|
|
115
|
+
"Invalid background interaction journal snapshot",
|
|
116
|
+
"INTERACTION_JOURNAL_CORRUPT",
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
const journal = new BackgroundInteractionJournal({
|
|
120
|
+
backgroundAgentId: snapshot.backgroundAgentId,
|
|
121
|
+
now: options.now,
|
|
122
|
+
});
|
|
123
|
+
journal.records = snapshot.records.map((record) => ({
|
|
124
|
+
requestId: String(record.requestId || ""),
|
|
125
|
+
binding: normalizeInteractionBinding(record.binding),
|
|
126
|
+
payload: cloneJson(record.payload || {}),
|
|
127
|
+
payloadFingerprint: String(record.payloadFingerprint || ""),
|
|
128
|
+
status: String(record.status || "pending"),
|
|
129
|
+
createdAt: Number(record.createdAt) || 0,
|
|
130
|
+
settledAt: record.settledAt == null ? null : Number(record.settledAt),
|
|
131
|
+
settlement: record.settlement ? cloneJson(record.settlement) : null,
|
|
132
|
+
settlementFingerprint: record.settlementFingerprint
|
|
133
|
+
? String(record.settlementFingerprint)
|
|
134
|
+
: null,
|
|
135
|
+
}));
|
|
136
|
+
return journal;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
toJSON() {
|
|
140
|
+
return {
|
|
141
|
+
version: BACKGROUND_INTERACTION_JOURNAL_VERSION,
|
|
142
|
+
backgroundAgentId: this.backgroundAgentId,
|
|
143
|
+
records: cloneJson(this.records),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
get(requestId) {
|
|
148
|
+
return (
|
|
149
|
+
this.records.find((record) => record.requestId === String(requestId)) ||
|
|
150
|
+
null
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
pending() {
|
|
155
|
+
return this.records.filter((record) => record.status === "pending");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
recordPending({ requestId, binding, payload = {}, createdAt } = {}) {
|
|
159
|
+
const id = String(requestId || "");
|
|
160
|
+
const normalizedBinding = normalizeInteractionBinding(binding);
|
|
161
|
+
if (!id || normalizedBinding.sequence === null) {
|
|
162
|
+
throw journalError(
|
|
163
|
+
"A requestId and complete interaction binding are required",
|
|
164
|
+
"INTERACTION_REQUEST_INVALID",
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
const safePayload = cloneJson(payload);
|
|
168
|
+
const payloadFingerprint = fingerprint(safePayload);
|
|
169
|
+
const existing = this.get(id);
|
|
170
|
+
if (existing) {
|
|
171
|
+
if (
|
|
172
|
+
sameInteractionBinding(existing.binding, normalizedBinding) &&
|
|
173
|
+
existing.payloadFingerprint === payloadFingerprint
|
|
174
|
+
) {
|
|
175
|
+
return { applied: false, record: cloneJson(existing) };
|
|
176
|
+
}
|
|
177
|
+
throw journalError(
|
|
178
|
+
`Interaction request ${id} was replayed with different binding or payload`,
|
|
179
|
+
"INTERACTION_REQUEST_CONFLICT",
|
|
180
|
+
{ requestId: id },
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const record = {
|
|
185
|
+
requestId: id,
|
|
186
|
+
binding: normalizedBinding,
|
|
187
|
+
payload: safePayload,
|
|
188
|
+
payloadFingerprint,
|
|
189
|
+
status: "pending",
|
|
190
|
+
createdAt: Number(createdAt) || this._now(),
|
|
191
|
+
settledAt: null,
|
|
192
|
+
settlement: null,
|
|
193
|
+
settlementFingerprint: null,
|
|
194
|
+
};
|
|
195
|
+
this.records.push(record);
|
|
196
|
+
this._prune();
|
|
197
|
+
return { applied: true, record: cloneJson(record) };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
settle(requestId, binding, outcome = {}) {
|
|
201
|
+
const id = String(requestId || "");
|
|
202
|
+
const record = this.get(id);
|
|
203
|
+
if (!record) {
|
|
204
|
+
throw journalError(
|
|
205
|
+
`Unknown background interaction request: ${id || "<missing>"}`,
|
|
206
|
+
"INTERACTION_REQUEST_UNKNOWN",
|
|
207
|
+
{ requestId: id },
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
if (!sameInteractionBinding(record.binding, binding)) {
|
|
211
|
+
throw journalError(
|
|
212
|
+
`Interaction response binding does not match request ${id}`,
|
|
213
|
+
"INTERACTION_BINDING_MISMATCH",
|
|
214
|
+
{ requestId: id },
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
const settlement = normalizeSettlement(outcome);
|
|
218
|
+
const settlementFingerprint = fingerprint(settlement);
|
|
219
|
+
if (record.status !== "pending") {
|
|
220
|
+
if (record.settlementFingerprint === settlementFingerprint) {
|
|
221
|
+
return { applied: false, record: cloneJson(record) };
|
|
222
|
+
}
|
|
223
|
+
throw journalError(
|
|
224
|
+
`Interaction request ${id} is already settled`,
|
|
225
|
+
"INTERACTION_ALREADY_SETTLED",
|
|
226
|
+
{ requestId: id, status: record.status },
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
record.status = settlement.status;
|
|
231
|
+
record.settledAt = this._now();
|
|
232
|
+
record.settlement = settlement;
|
|
233
|
+
record.settlementFingerprint = settlementFingerprint;
|
|
234
|
+
return { applied: true, record: cloneJson(record) };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
rejectPending(error = {}) {
|
|
238
|
+
const rejected = [];
|
|
239
|
+
for (const record of this.pending()) {
|
|
240
|
+
const result = this.settle(record.requestId, record.binding, {
|
|
241
|
+
status: "rejected",
|
|
242
|
+
error,
|
|
243
|
+
});
|
|
244
|
+
rejected.push(result.record);
|
|
245
|
+
}
|
|
246
|
+
return rejected;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
_prune() {
|
|
250
|
+
while (this.records.length > MAX_BACKGROUND_INTERACTION_RECORDS) {
|
|
251
|
+
const terminalIndex = this.records.findIndex((record) =>
|
|
252
|
+
TERMINAL_STATUSES.has(record.status),
|
|
253
|
+
);
|
|
254
|
+
if (terminalIndex === -1) {
|
|
255
|
+
throw journalError(
|
|
256
|
+
`Background interaction journal exceeded ${MAX_BACKGROUND_INTERACTION_RECORDS} pending requests`,
|
|
257
|
+
"INTERACTION_PENDING_LIMIT",
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
this.records.splice(terminalIndex, 1);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export class BackgroundInteractionPersistenceError extends Error {
|
|
266
|
+
constructor(operation, sessionId, cause) {
|
|
267
|
+
const detail =
|
|
268
|
+
cause?.message || String(cause || "unknown persistence error");
|
|
269
|
+
super(
|
|
270
|
+
`Background interaction journal ${operation} failed for ${sessionId}: ${detail}`,
|
|
271
|
+
{ cause },
|
|
272
|
+
);
|
|
273
|
+
this.name = "BackgroundInteractionPersistenceError";
|
|
274
|
+
this.code =
|
|
275
|
+
operation === "read"
|
|
276
|
+
? "INTERACTION_JOURNAL_READ_FAILED"
|
|
277
|
+
: "INTERACTION_JOURNAL_PERSIST_FAILED";
|
|
278
|
+
this.operation = operation;
|
|
279
|
+
this.sessionId = sessionId;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export function persistBackgroundInteractionJournal(
|
|
284
|
+
sessionId,
|
|
285
|
+
journal,
|
|
286
|
+
options = {},
|
|
287
|
+
) {
|
|
288
|
+
const failIfUnavailable = options.failIfUnavailable !== false;
|
|
289
|
+
try {
|
|
290
|
+
if (!sessionId || !(journal instanceof BackgroundInteractionJournal)) {
|
|
291
|
+
throw new TypeError("sessionId and interaction journal are required");
|
|
292
|
+
}
|
|
293
|
+
_deps.appendEvent(
|
|
294
|
+
sessionId,
|
|
295
|
+
BACKGROUND_INTERACTION_JOURNAL_EVENT,
|
|
296
|
+
journal.toJSON(),
|
|
297
|
+
);
|
|
298
|
+
return true;
|
|
299
|
+
} catch (error) {
|
|
300
|
+
if (!failIfUnavailable) return false;
|
|
301
|
+
throw new BackgroundInteractionPersistenceError(
|
|
302
|
+
"write",
|
|
303
|
+
sessionId || "<missing-session>",
|
|
304
|
+
error,
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export function loadBackgroundInteractionJournal(
|
|
310
|
+
sessionId,
|
|
311
|
+
backgroundAgentId,
|
|
312
|
+
options = {},
|
|
313
|
+
) {
|
|
314
|
+
const failIfUnavailable = options.failIfUnavailable !== false;
|
|
315
|
+
try {
|
|
316
|
+
if (!sessionId || !backgroundAgentId) {
|
|
317
|
+
throw new TypeError("sessionId and backgroundAgentId are required");
|
|
318
|
+
}
|
|
319
|
+
const events = _deps.readEvents(sessionId) || [];
|
|
320
|
+
for (let index = events.length - 1; index >= 0; index--) {
|
|
321
|
+
const event = events[index];
|
|
322
|
+
if (
|
|
323
|
+
event?.type === BACKGROUND_INTERACTION_JOURNAL_EVENT &&
|
|
324
|
+
event.data?.backgroundAgentId === backgroundAgentId
|
|
325
|
+
) {
|
|
326
|
+
return BackgroundInteractionJournal.fromJSON(event.data, options);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return new BackgroundInteractionJournal({
|
|
330
|
+
backgroundAgentId,
|
|
331
|
+
now: options.now,
|
|
332
|
+
});
|
|
333
|
+
} catch (error) {
|
|
334
|
+
if (!failIfUnavailable) {
|
|
335
|
+
return new BackgroundInteractionJournal({
|
|
336
|
+
backgroundAgentId,
|
|
337
|
+
now: options.now,
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
throw new BackgroundInteractionPersistenceError(
|
|
341
|
+
"read",
|
|
342
|
+
sessionId || "<missing-session>",
|
|
343
|
+
error,
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Clone-mutate-persist transaction. The live journal is not changed when the
|
|
350
|
+
* append fails, so a caller may safely retry the same settlement.
|
|
351
|
+
*/
|
|
352
|
+
export function updateBackgroundInteractionJournal(
|
|
353
|
+
sessionId,
|
|
354
|
+
journal,
|
|
355
|
+
mutate,
|
|
356
|
+
options = {},
|
|
357
|
+
) {
|
|
358
|
+
const draft = BackgroundInteractionJournal.fromJSON(journal.toJSON(), {
|
|
359
|
+
now: options.now || journal._now,
|
|
360
|
+
});
|
|
361
|
+
const result = mutate(draft);
|
|
362
|
+
if (!options.persistIf || options.persistIf(result) !== false) {
|
|
363
|
+
persistBackgroundInteractionJournal(sessionId, draft, options);
|
|
364
|
+
}
|
|
365
|
+
return { journal: draft, result };
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Recovery entry point used when a worker is observed lost or starts again.
|
|
370
|
+
* An optional state-file fallback lets pre-journal pendingQuestion records be
|
|
371
|
+
* imported once and deterministically rejected.
|
|
372
|
+
*/
|
|
373
|
+
export function rejectPendingBackgroundInteractions(
|
|
374
|
+
sessionId,
|
|
375
|
+
backgroundAgentId,
|
|
376
|
+
options = {},
|
|
377
|
+
) {
|
|
378
|
+
let journal = loadBackgroundInteractionJournal(
|
|
379
|
+
sessionId,
|
|
380
|
+
backgroundAgentId,
|
|
381
|
+
options,
|
|
382
|
+
);
|
|
383
|
+
const fallback = options.fallbackRequest;
|
|
384
|
+
const hasFallback =
|
|
385
|
+
fallback?.requestId &&
|
|
386
|
+
normalizeInteractionBinding(fallback.binding).sequence !== null &&
|
|
387
|
+
!journal.get(fallback.requestId);
|
|
388
|
+
if (!journal.pending().length && !hasFallback) {
|
|
389
|
+
return { journal, rejected: [], changed: false };
|
|
390
|
+
}
|
|
391
|
+
const mutation = updateBackgroundInteractionJournal(
|
|
392
|
+
sessionId,
|
|
393
|
+
journal,
|
|
394
|
+
(draft) => {
|
|
395
|
+
if (hasFallback) draft.recordPending(fallback);
|
|
396
|
+
return draft.rejectPending({
|
|
397
|
+
code: options.code || "INTERACTION_WORKER_LOST",
|
|
398
|
+
message:
|
|
399
|
+
options.message ||
|
|
400
|
+
"The background worker exited before the interaction settled",
|
|
401
|
+
});
|
|
402
|
+
},
|
|
403
|
+
options,
|
|
404
|
+
);
|
|
405
|
+
journal = mutation.journal;
|
|
406
|
+
return { journal, rejected: mutation.result, changed: true };
|
|
407
|
+
}
|
|
@@ -13,6 +13,16 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { randomUUID } from "node:crypto";
|
|
16
|
+
import {
|
|
17
|
+
hasCompleteInteractionBinding,
|
|
18
|
+
normalizeInteractionBinding,
|
|
19
|
+
sameInteractionBinding,
|
|
20
|
+
} from "./interaction-binding.js";
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
normalizeInteractionBinding,
|
|
24
|
+
sameInteractionBinding,
|
|
25
|
+
} from "./interaction-binding.js";
|
|
16
26
|
|
|
17
27
|
export const BACKGROUND_INTERACTION_PROTOCOL_VERSION = 1;
|
|
18
28
|
export const DEFAULT_BACKGROUND_INTERACTION_TIMEOUT_MS = 60_000;
|
|
@@ -30,31 +40,6 @@ function asNullableString(value) {
|
|
|
30
40
|
return String(value);
|
|
31
41
|
}
|
|
32
42
|
|
|
33
|
-
function normalizeBinding(binding = {}) {
|
|
34
|
-
return {
|
|
35
|
-
backgroundAgentId: asNullableString(binding.backgroundAgentId),
|
|
36
|
-
sessionId: asNullableString(binding.sessionId),
|
|
37
|
-
turnId: asNullableString(binding.turnId),
|
|
38
|
-
toolUseId: asNullableString(binding.toolUseId),
|
|
39
|
-
sequence:
|
|
40
|
-
Number.isSafeInteger(binding.sequence) && binding.sequence > 0
|
|
41
|
-
? binding.sequence
|
|
42
|
-
: null,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function sameBinding(left, right) {
|
|
47
|
-
const a = normalizeBinding(left);
|
|
48
|
-
const b = normalizeBinding(right);
|
|
49
|
-
return (
|
|
50
|
-
a.backgroundAgentId === b.backgroundAgentId &&
|
|
51
|
-
a.sessionId === b.sessionId &&
|
|
52
|
-
a.turnId === b.turnId &&
|
|
53
|
-
a.toolUseId === b.toolUseId &&
|
|
54
|
-
a.sequence === b.sequence
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
43
|
function validRequest(message) {
|
|
59
44
|
return (
|
|
60
45
|
message &&
|
|
@@ -65,12 +50,16 @@ function validRequest(message) {
|
|
|
65
50
|
message.requestId.length <= 256 &&
|
|
66
51
|
message.payload &&
|
|
67
52
|
typeof message.payload === "object" &&
|
|
68
|
-
|
|
53
|
+
hasCompleteInteractionBinding(message.binding)
|
|
69
54
|
);
|
|
70
55
|
}
|
|
71
56
|
|
|
72
57
|
function sendIpc(target, message, onError = () => {}) {
|
|
73
|
-
if (
|
|
58
|
+
if (
|
|
59
|
+
!target ||
|
|
60
|
+
typeof target.send !== "function" ||
|
|
61
|
+
target.connected === false
|
|
62
|
+
)
|
|
74
63
|
return false;
|
|
75
64
|
try {
|
|
76
65
|
target.send(message, (error) => {
|
|
@@ -138,7 +127,8 @@ export function createBackgroundInteractionClient(options = {}) {
|
|
|
138
127
|
return;
|
|
139
128
|
}
|
|
140
129
|
const entry = pending.get(message.requestId);
|
|
141
|
-
if (!entry || !
|
|
130
|
+
if (!entry || !sameInteractionBinding(entry.binding, message.binding))
|
|
131
|
+
return;
|
|
142
132
|
|
|
143
133
|
if (message.status === "resolved") {
|
|
144
134
|
settle(entry, entry.resolve, message.answer);
|
|
@@ -170,7 +160,7 @@ export function createBackgroundInteractionClient(options = {}) {
|
|
|
170
160
|
|
|
171
161
|
sequence += 1;
|
|
172
162
|
const requestId = `${backgroundAgentId}:${idFactory()}`;
|
|
173
|
-
const binding =
|
|
163
|
+
const binding = normalizeInteractionBinding({
|
|
174
164
|
backgroundAgentId,
|
|
175
165
|
sessionId: payload.sessionId ?? sessionId,
|
|
176
166
|
turnId: payload.turnId ?? turnId,
|
|
@@ -301,7 +291,7 @@ export function attachInteractionRequestHandler(
|
|
|
301
291
|
protocolVersion: BACKGROUND_INTERACTION_PROTOCOL_VERSION,
|
|
302
292
|
requestId:
|
|
303
293
|
typeof message?.requestId === "string" ? message.requestId : "",
|
|
304
|
-
binding:
|
|
294
|
+
binding: normalizeInteractionBinding(message?.binding),
|
|
305
295
|
status: "rejected",
|
|
306
296
|
error: { code, message: detail },
|
|
307
297
|
};
|
|
@@ -315,7 +305,7 @@ export function attachInteractionRequestHandler(
|
|
|
315
305
|
message.protocolVersion === BACKGROUND_INTERACTION_PROTOCOL_VERSION
|
|
316
306
|
) {
|
|
317
307
|
const active = inflight.get(message.requestId);
|
|
318
|
-
if (active &&
|
|
308
|
+
if (active && sameInteractionBinding(active.binding, message.binding)) {
|
|
319
309
|
inflight.delete(message.requestId);
|
|
320
310
|
active.controller.abort(message.reason || "cancelled");
|
|
321
311
|
}
|
|
@@ -331,12 +321,11 @@ export function attachInteractionRequestHandler(
|
|
|
331
321
|
return;
|
|
332
322
|
}
|
|
333
323
|
|
|
334
|
-
const binding =
|
|
324
|
+
const binding = normalizeInteractionBinding(message.binding);
|
|
335
325
|
const expectedAgentId = asNullableString(options.backgroundAgentId);
|
|
336
326
|
const expectedSessionId = asNullableString(options.sessionId);
|
|
337
327
|
if (
|
|
338
|
-
(expectedAgentId &&
|
|
339
|
-
binding.backgroundAgentId !== expectedAgentId) ||
|
|
328
|
+
(expectedAgentId && binding.backgroundAgentId !== expectedAgentId) ||
|
|
340
329
|
(expectedSessionId && binding.sessionId !== expectedSessionId)
|
|
341
330
|
) {
|
|
342
331
|
rejectRequest(
|
|
@@ -198,7 +198,8 @@ export function startBackgroundSessionServer(opts) {
|
|
|
198
198
|
case "interaction_response": {
|
|
199
199
|
try {
|
|
200
200
|
// Support both field names: requestId (client) and intId (wire legacy)
|
|
201
|
-
const { requestId, intId, answer, result, error } =
|
|
201
|
+
const { requestId, intId, binding, answer, result, error } =
|
|
202
|
+
message;
|
|
202
203
|
const resolvedId = requestId || intId;
|
|
203
204
|
if (!resolvedId) {
|
|
204
205
|
writeMessage(socket, {
|
|
@@ -208,14 +209,23 @@ export function startBackgroundSessionServer(opts) {
|
|
|
208
209
|
return;
|
|
209
210
|
}
|
|
210
211
|
// Single-object callback matching worker expectation: { requestId, answer, error }
|
|
211
|
-
onInteractionResponse?.({
|
|
212
|
+
const settlement = onInteractionResponse?.({
|
|
212
213
|
requestId: resolvedId,
|
|
214
|
+
binding,
|
|
213
215
|
answer: answer ?? result,
|
|
214
216
|
error,
|
|
215
217
|
});
|
|
216
218
|
writeMessage(socket, {
|
|
217
219
|
type: "received",
|
|
218
220
|
requestId: resolvedId,
|
|
221
|
+
accepted:
|
|
222
|
+
typeof settlement === "object"
|
|
223
|
+
? settlement.accepted === true
|
|
224
|
+
: settlement === true,
|
|
225
|
+
duplicate:
|
|
226
|
+
typeof settlement === "object"
|
|
227
|
+
? settlement.duplicate === true
|
|
228
|
+
: false,
|
|
219
229
|
});
|
|
220
230
|
} catch (err) {
|
|
221
231
|
writeMessage(socket, {
|
|
@@ -49,6 +49,14 @@ export const CAPABILITY_MANIFEST = Object.freeze({
|
|
|
49
49
|
description:
|
|
50
50
|
'tool_use / tool_result lines carry a pairing `id` ("tu-<n>")',
|
|
51
51
|
}),
|
|
52
|
+
Object.freeze({
|
|
53
|
+
key: "permission_decision",
|
|
54
|
+
field: "permission_decision",
|
|
55
|
+
companionFields: Object.freeze(["permission_decision_id"]),
|
|
56
|
+
minVersion: 1,
|
|
57
|
+
description:
|
|
58
|
+
"gated tool_result lines may carry a redacted permission decision and its correlation id",
|
|
59
|
+
}),
|
|
52
60
|
Object.freeze({
|
|
53
61
|
key: "trace_id",
|
|
54
62
|
field: "trace_id",
|
|
@@ -135,6 +143,24 @@ export function toFieldGate(m = CAPABILITY_MANIFEST) {
|
|
|
135
143
|
return out;
|
|
136
144
|
}
|
|
137
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Every negotiable line field → the primary gate field that controls it.
|
|
148
|
+
* Companion fields are kept under the same logical feature so negotiation can
|
|
149
|
+
* never emit a decision without its id (or an orphan id without its decision).
|
|
150
|
+
* @returns {Record<string, string>}
|
|
151
|
+
*/
|
|
152
|
+
export function toGateableFieldGate(m = CAPABILITY_MANIFEST) {
|
|
153
|
+
const out = {};
|
|
154
|
+
for (const f of wireFeaturesOf(m)) {
|
|
155
|
+
if (!f?.field) continue;
|
|
156
|
+
out[f.field] = f.field;
|
|
157
|
+
for (const companion of f.companionFields || []) {
|
|
158
|
+
if (companion) out[companion] = f.field;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
163
|
+
|
|
138
164
|
/**
|
|
139
165
|
* The server negotiation offer shape consumed by
|
|
140
166
|
* capability-negotiation.js `negotiateProtocol(server, …)`.
|
|
@@ -199,7 +225,12 @@ export function capabilityDigest(m = CAPABILITY_MANIFEST) {
|
|
|
199
225
|
protocolVersion: Number(mm.protocolVersion) || 1,
|
|
200
226
|
minProtocolVersion: Number(mm.minProtocolVersion) || 1,
|
|
201
227
|
wire: wireFeaturesOf(mm)
|
|
202
|
-
.map((f) => [
|
|
228
|
+
.map((f) => [
|
|
229
|
+
f.key,
|
|
230
|
+
f.field,
|
|
231
|
+
[...(f.companionFields || [])].sort(),
|
|
232
|
+
Number(f.minVersion) || 1,
|
|
233
|
+
])
|
|
203
234
|
.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0)),
|
|
204
235
|
runtime: [...(mm.runtimeFeatures || [])].sort(),
|
|
205
236
|
mcp: [...(mm.mcpFeatures || [])].sort(),
|
|
@@ -224,7 +255,7 @@ export function renderBehaviorMatrix(m = CAPABILITY_MANIFEST) {
|
|
|
224
255
|
return wireFeaturesOf(m).map((f) => ({
|
|
225
256
|
feature: f.key,
|
|
226
257
|
minVersion: Number(f.minVersion) || 1,
|
|
227
|
-
field: f.field,
|
|
258
|
+
field: [f.field, ...(f.companionFields || [])].join(", "),
|
|
228
259
|
negotiable: true,
|
|
229
260
|
description: String(f.description || ""),
|
|
230
261
|
}));
|
|
@@ -280,6 +311,7 @@ export function diffCapabilities(prev, next = CAPABILITY_MANIFEST) {
|
|
|
280
311
|
for (const f of wireFeaturesOf(m)) {
|
|
281
312
|
out.set(f.key, {
|
|
282
313
|
field: f.field,
|
|
314
|
+
companionFields: [...(f.companionFields || [])].sort(),
|
|
283
315
|
minVersion: Number(f.minVersion) || 1,
|
|
284
316
|
});
|
|
285
317
|
}
|
|
@@ -294,7 +326,13 @@ export function diffCapabilities(prev, next = CAPABILITY_MANIFEST) {
|
|
|
294
326
|
const changedWireFeatures = [];
|
|
295
327
|
for (const [key, nv] of n) {
|
|
296
328
|
const pv = p.get(key);
|
|
297
|
-
if (
|
|
329
|
+
if (
|
|
330
|
+
pv &&
|
|
331
|
+
(pv.field !== nv.field ||
|
|
332
|
+
pv.minVersion !== nv.minVersion ||
|
|
333
|
+
JSON.stringify(pv.companionFields) !==
|
|
334
|
+
JSON.stringify(nv.companionFields))
|
|
335
|
+
) {
|
|
298
336
|
changedWireFeatures.push({ feature: key, from: pv, to: nv });
|
|
299
337
|
}
|
|
300
338
|
}
|
|
@@ -210,7 +210,7 @@ const FEATURE_TO_FIELD = toFieldGate();
|
|
|
210
210
|
* baseline). Mutates `gate` in place and returns it.
|
|
211
211
|
*
|
|
212
212
|
* @param {{features:string[], ok:boolean}} result
|
|
213
|
-
* @param {{seq?:boolean, trace_id?:boolean, tool_use_id?:boolean}} gate
|
|
213
|
+
* @param {{seq?:boolean, trace_id?:boolean, tool_use_id?:boolean, permission_decision?:boolean}} gate
|
|
214
214
|
*/
|
|
215
215
|
export function applyNegotiationToGate(result, gate = {}) {
|
|
216
216
|
if (!result || result.ok === false) return gate;
|