chainlesschain 0.166.46 → 0.166.48
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/README.md +6 -4
- package/package.json +4 -2
- package/src/assets/web-panel/assets/{AIOps-Cp8KiMmv.js → AIOps-BLGEffkh.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-B4d9BGsm.js → ActionButton-Cz1z2VGD.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Cf9yXTkv.js → Analytics-C3j9cf6q.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-40UkmxtP.js → AppLayout-BR9ERuCA.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-Ckkb4oOA.js → Artifacts-CozJCm4y.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-Dnf569k5.js → Audit-DC5g9Ra2.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-CA6bLem4.js → BackgroundAgents-B1zrQ0dW.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-ChQU0I_Q.js → Backup-ChVnfjpm.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BHeZXnNN.js → BaseInput-8_vLQsLf.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-DcFVYB2E.js → Chat-Dct9bm6L.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-BvoSsCKh.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-2PDbejv2.js → Checkbox-DZQIsCIC.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DJBn1RAu.js → Codegen-CdzHxmnq.js} +1 -1
- package/src/assets/web-panel/assets/{Col-CPRq7n6y.js → Col-DdAN8LeW.js} +1 -1
- package/src/assets/web-panel/assets/{Community-axvINFMi.js → Community-CNgjT9MA.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-_OX4Qbe0.js → Compact-BtQiX6G-.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DWAkvzRL.js → Compliance-OGX5ma3j.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CUIJ25oj.js → Cowork-CgugQnGM.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-nR0m7H3_.js → Cron-Bpg7cPFD.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CgTLXzh_.js → Crosschain-D1hsuswf.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BllzRB6Q.js → DID-miDRsMBw.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-C9f0IIBN.js → Dashboard-CGcl8htP.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BkahetiO.js → Dropdown-BFaxTdVE.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-rartVC-k.js → EmailListRenderer-BQdGLZIO.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-BqpG3XHV.js → EvolutionSettings-bMvgBk6r.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DgUdFvw1.js → FamilyGuardDashboard-c1WVC_--.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-oFpIQU6g.js → Federation-DyAcFrQY.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BUH5xlyP.js → FormItemContext-CfwpfD2B.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-ilRa-ueg.js → GenericCardRenderer-DkJcbBpS.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DlHHSF8j.js → Git-DgYIrPJh.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-yQiiXIWe.js → Governance-BF1tYPJ6.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BUDRVGOP.js → Inference-BFkwRIrU.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BaGyIoN1.js → KnowledgeGraph-DpCoqhBa.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-C1cO6zE0.js → Logs-DU2qAJmD.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-_z_Iaoes.js → MarkdownRenderer-QWv7UJLq.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-CM8cGL0K.js → Marketplace-Dz9NUrfo.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CDqAMU0U.js → McpTools-B67I3d5v.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-CfB0-Ofv.js → Memory-crkElJSy.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BL18ytvB.js → MobileBridge-BO20VbdX.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-PIyyxbuJ.js → MobileProjects-Ba-3gZZd.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BTTrFCol.js → Mtc-BAHZM084.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-JHZn037c.js → MtcAudit-CL3DzajL.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-CMf9NEdB.js → Multisig-BSWWzvWH.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Dhk3qaus.js → NLProgramming-fnxqXM_3.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-6F8EarNN.js → Notes-qUZPIQXT.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-gxdaVEit.js → NotificationSettings-x9Xrixqu.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-gVgXQWdc.js → OrderTableRenderer-BtMtQUt7.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-CzvHcDNO.js → Organization-C946Hzna.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Dclx30Vv.js → Overflow-BYf8KIts.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CM0Wm9vZ.js → P2P-Cbqf5dnv.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-rmxp0cuF.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-B_oATenG.js → Permissions-CZBw45EW.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-CptiVBh5.js → PersonalDataHub-BKwUAt43.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-DkHzgyyI.js → Pipeline-DmFD2QW4.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DzZvwcKh.js → Privacy-KpuwWvt5.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CzkCs-5G.js → ProjectInit-Bt8UheX6.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BB8dcxRD.js → ProjectSettings-2ZeAn9CP.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-B7PW9CFY.js → Projects-zBuet8Zs.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-Tfx-ti1V.js → Providers-DcEAnw6L.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-EvWlNhfX.js → QrScannerModal-qF7liYG9.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CUspgbNC.js → QuickAsk-qiESlVBJ.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-COY2g77J.js → Recommend-Bk-cQyi9.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BzMBU6E6.js → RemoteSession-CwrekErS.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-RtYRF4YP.js → Reputation-Bmw_UQtW.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Bva3l9Lc.js → Row-CPdqZIUX.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BhjzLvW3.js → RssFeed-D_W-xxvS.js} +2 -2
- package/src/assets/web-panel/assets/{Search-BYzT2PTR.js → Search-Hu0oDFj_.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Bcl4-KTv.js → Security-DeRxUwmq.js} +3 -3
- package/src/assets/web-panel/assets/{Services-BRRa4A0f.js → Services-CsNmHFkf.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DYQ016qy.js → Skeleton-gv_Vz0tN.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CAUKL9JA.js → Skills-Dgg-_rCB.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BTyUqfuD.js → Sla-Bpu-bsEJ.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CUjMihrs.js → SpeechSettings-CrhleHuF.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CvfOSupr.js → SyncSettings-JHjUN6I9.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-EvjNXrWH.js → Tasks-DKRWKkl9.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-wPAp0EoM.js → Templates-leiWntLq.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CP0D-q9Q.js → Tenant--1bYulvn.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-CQ0f2iFg.js → Terminal-C0y6FvSS.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-D3JrGSPb.js → TimelineRenderer-CQK4PVv4.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-yXf2PPp9.js → Tokens-DbIvF-DV.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DfmMOoZ2.js → Trigger-CkXJ2vuq.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BTCyMgf1.js → Trust-B02WXJPw.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DKCwIBHi.js → UkeySign-VPMkfzmw.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CQpDSzLO.js → VideoEditing-C5ezUnah.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CyFrzC3K.js → Wallet-CYfvYRrY.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-D6Nr_1kd.js → WebAuthn-DtKl-kpr.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-CgR9tNrB.js → WorkflowEditor-DACITF-u.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CRG_IeyP.js → chat-qnygfnLi.js} +1 -1
- package/src/assets/web-panel/assets/{colors-MdE3TStI.js → colors-D4mISLBD.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-B0LRuiNV.js → compact-item-BBPfxYGL.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-B_V5fjcX.js → createContext-Byx4ndHp.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DBy6gsuI.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DSL-c_hr.js → hasIn-CGjLkkn3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DE7bSYmW.js → index-B8UpadHC.js} +1 -1
- package/src/assets/web-panel/assets/{index-BD0w-888.js → index-B9jH-h4X.js} +1 -1
- package/src/assets/web-panel/assets/{index-BbZZ7P_c.js → index-BN7_TSgU.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIDCNwy6.js → index-BNe2lCk6.js} +1 -1
- package/src/assets/web-panel/assets/{index-CkN53KiJ.js → index-B_fHPZ8E.js} +1 -1
- package/src/assets/web-panel/assets/index-BfEDXk_E.js +1 -0
- package/src/assets/web-panel/assets/{index-BsAEd-Do.js → index-BklGH3YI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CS3bOhV7.js → index-BmKYaaGP.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3iW-mhn.js → index-BxQF1wCU.js} +1 -1
- package/src/assets/web-panel/assets/{index-SmQfEHjp.js → index-ByA1NyFP.js} +1 -1
- package/src/assets/web-panel/assets/{index-0200QxC4.js → index-BzeBBAl5.js} +1 -1
- package/src/assets/web-panel/assets/{index-c8OqO3rq.js → index-C3abGsSW.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-aKWR2v.js → index-C9tcHs46.js} +1 -1
- package/src/assets/web-panel/assets/{index-BNhWoD6d.js → index-CD5Btq6p.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVDi4rS9.js → index-CFMWjuav.js} +1 -1
- package/src/assets/web-panel/assets/{index-CEOAZm5j.js → index-CMj8qmpX.js} +1 -1
- package/src/assets/web-panel/assets/{index-C67dPW0L.js → index-CVUJjQAT.js} +1 -1
- package/src/assets/web-panel/assets/{index-D3pJBTvo.js → index-CWhI8G14.js} +1 -1
- package/src/assets/web-panel/assets/{index-DtOTppk8.js → index-CZjNamSU.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRRY44XP.js → index-CmHE-lY_.js} +1 -1
- package/src/assets/web-panel/assets/{index-Tg3yl8wc.js → index-CoA8WsVr.js} +1 -1
- package/src/assets/web-panel/assets/{index-CXMeisJK.js → index-Cpg3AWRy.js} +1 -1
- package/src/assets/web-panel/assets/index-CrxUwNM8.js +1 -0
- package/src/assets/web-panel/assets/{index-Bq8-2Ibv.js → index-CsVuQsY1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHp1nSur.js → index-CydHMjwc.js} +1 -1
- package/src/assets/web-panel/assets/{index-CPYshcic.js → index-DH6iC5b2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBwBZwio.js → index-DZXhKAk9.js} +1 -1
- package/src/assets/web-panel/assets/{index-Didyuq2Z.js → index-D_g9mA1N.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdHMc9LQ.js → index-DboTeuPF.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5dqieYX.js → index-DfgpKd64.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdplnAS9.js → index-Dmfe0L2Z.js} +1 -1
- package/src/assets/web-panel/assets/{index-KaSejHjf.js → index-Dzni_5Qw.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpwGsAA-.js → index-J5JkStvY.js} +1 -1
- package/src/assets/web-panel/assets/{index-OBhlHSMN.js → index-Ne8UGllV.js} +3 -3
- package/src/assets/web-panel/assets/{index-CZICtYJ0.js → index-O09jXbir.js} +1 -1
- package/src/assets/web-panel/assets/{index-DVgTf7CZ.js → index-Y7el_3WS.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQAsL19t.js → index-c_tBkIlU.js} +1 -1
- package/src/assets/web-panel/assets/{index-BMm8tO2X.js → index-lKJWAmd4.js} +1 -1
- package/src/assets/web-panel/assets/{index-CNytQuFq.js → index-xzRKTy0R.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-P8SBN6Di.js → initDefaultProps-XuhfEIhB.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BubbjUT_.js → motion-Cbxh6AxO.js} +1 -1
- package/src/assets/web-panel/assets/{move-Chcykv0I.js → move-C7IEnFly.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DyiYuGDu.js → mtc-parser-lLADx4LL.js} +1 -1
- package/src/assets/web-panel/assets/{omit-Rdwb_Neb.js → omit-mIbic_k-.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CCr0MYHl.js → pickAttrs-_xIYEqu3.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-B1ZXz3bb.js → placementArrow-ClB-E0ny.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BGEdwej6.js → responsiveObserve-D36Bg2ut.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CpnsUMaT.js → slide-CUuO08Bl.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-C7x-TVp_.js → statusUtils-BKahwLbv.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CC5k_791.js → styleChecker-2pT-T8vy.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-BpZFKsJW.js → useFlexGapSupport-DyH5g7Rg.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CVq5HySy.js → useFs-CTOauB3X.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BGkdLryu.js → usePersonalDataHub-B02JYIMe.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-uLtOUEK-.js → vnode-Do22wQrc.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BfVC9iUs.js → zoom-BfnL7rit.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +3 -3
- package/src/commands/agent.js +8 -0
- package/src/commands/background-session.js +31 -3
- package/src/commands/chat.js +5 -1
- package/src/commands/eval.js +86 -28
- package/src/commands/llm.js +104 -1
- package/src/commands/plugin.js +161 -1
- package/src/commands/sandbox.js +121 -2
- package/src/commands/serve.js +11 -2
- package/src/commands/skill.js +29 -0
- package/src/data/changelog.json +26 -0
- package/src/gateways/ws/session-protocol.js +13 -0
- package/src/gateways/ws/ws-agent-handler.js +17 -0
- package/src/gateways/ws/ws-server.js +3 -0
- package/src/gateways/ws/ws-session-state.js +131 -0
- package/src/generated/cc-agent-protocol.schema.json +48 -1
- package/src/lazy-dispatch.js +8 -1
- package/src/lib/agent-sandbox.js +337 -53
- package/src/lib/app-server/cli-agent-kernel-adapter.js +28 -0
- package/src/lib/app-server/server.js +93 -0
- package/src/lib/background-agent-keeper-client.js +2 -0
- package/src/lib/background-agent-keeper-protocol.js +7 -0
- package/src/lib/background-agent-list-index.js +222 -0
- package/src/lib/background-agent-supervisor.js +232 -47
- package/src/lib/codex-app-server-adapter.js +82 -27
- package/src/lib/context-memory-kernel/durable-memory-port.js +31 -8
- package/src/lib/context-memory-kernel/provider-context.js +118 -19
- package/src/lib/deferred-question-context.js +278 -0
- package/src/lib/eval/evidence.js +202 -64
- package/src/lib/eval/plugin-suite.js +1181 -0
- package/src/lib/eval/runner.js +10 -3
- package/src/lib/evolution/agent-evolution-runtime-composition.js +236 -1
- package/src/lib/evolution/agent-model-projection.js +97 -1
- package/src/lib/evolution/evidence-backed-wiki-maintainer.js +154 -1
- package/src/lib/evolution/evolution-artifact-ports.js +6 -0
- package/src/lib/evolution/evolution-deployment-loader.js +87 -3
- package/src/lib/evolution/evolution-eval-gate.js +8 -0
- package/src/lib/evolution/evolution-eval-runtime-composition.js +255 -0
- package/src/lib/evolution/evolution-evidence-artifact-adapter.js +58 -2
- package/src/lib/evolution/evolution-ledger-file-backend.js +23 -2
- package/src/lib/evolution/evolution-ledger-manifest-chain.js +223 -7
- package/src/lib/evolution/evolution-ledger-v2-journal.js +525 -0
- package/src/lib/evolution/evolution-ledger-v2-manifest-backend.js +46 -2
- package/src/lib/evolution/evolution-ledger.js +57 -1
- package/src/lib/evolution/evolution-run-ledger-adapter.js +93 -0
- package/src/lib/evolution/evolution-run-wiki-evidence-resolver.js +259 -0
- package/src/lib/evolution/governed-hub-llm.js +238 -5
- package/src/lib/evolution/governed-hub-resolver.js +82 -4
- package/src/lib/evolution/governed-hub-skill.js +11 -5
- package/src/lib/evolution/governed-skill-synthesis-provider-chat.js +10 -1
- package/src/lib/evolution/skill-runtime-revalidation-ledger-adapter.js +254 -0
- package/src/lib/evolution/skill-runtime-revalidation.js +530 -0
- package/src/lib/evolution/skill-target-matrix-eval.js +4 -4
- package/src/lib/evolution/wiki-evidence-commit-guard.js +366 -0
- package/src/lib/evolution/wiki-informed-skill-proposer.js +13 -1
- package/src/lib/goal-context.js +14 -5
- package/src/lib/interaction-adapter.js +166 -1
- package/src/lib/model-capabilities.js +271 -0
- package/src/lib/model-context-catalog.js +105 -0
- package/src/lib/model-context-window.js +4 -49
- package/src/lib/openai-responses.js +428 -0
- package/src/lib/plugin-runtime/scopes.js +7 -1
- package/src/lib/remote-read-loop-guard.js +2 -2
- package/src/lib/runtime-usage-ledger.js +16 -0
- package/src/lib/session-host-snapshot.js +16 -0
- package/src/lib/skill-loader.js +12 -0
- package/src/lib/with-file-lock.js +3 -1
- package/src/repl/agent-repl.js +5 -1
- package/src/runtime/agent-core.js +348 -23
- package/src/runtime/agent-runtime.js +7 -0
- package/src/runtime/coding-agent-contract-shared.cjs +13 -1
- package/src/runtime/headless-runner.js +4 -1
- package/src/runtime/headless-stream.js +283 -45
- package/src/runtime/runtime-factory.js +26 -2
- package/src/workers/background-agent-keeper.js +23 -13
- package/src/workers/background-agent-worker.js +27 -13
- package/src/assets/web-panel/assets/ChatBubbleRenderer-Bi2SY9E_.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-fYmQzmTA.js +0 -7
- package/src/assets/web-panel/assets/devWarning-BtFLt3qI.js +0 -1
- package/src/assets/web-panel/assets/index-BhuWQHeG.js +0 -1
- package/src/assets/web-panel/assets/index-D-4tFek3.js +0 -1
package/src/lib/agent-sandbox.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** OS-isolated shell execution for the coding agent. */
|
|
2
2
|
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { proxyEnv } from "./sandbox-egress-proxy.js";
|
|
5
6
|
import executionBroker from "./process-execution-broker/index.js";
|
|
@@ -10,8 +11,15 @@ export const AGENT_SANDBOX_MODES = Object.freeze([
|
|
|
10
11
|
"workspace-write",
|
|
11
12
|
"strict",
|
|
12
13
|
]);
|
|
14
|
+
export const AGENT_SANDBOX_CAPABILITY_SCHEMA =
|
|
15
|
+
"chainlesschain.agent-sandbox-capabilities/v1";
|
|
13
16
|
export const _deps = {
|
|
14
17
|
spawnSync: (...args) => executionBroker.spawnSync(...args),
|
|
18
|
+
host: () => ({
|
|
19
|
+
platform: process.platform,
|
|
20
|
+
release: os.release(),
|
|
21
|
+
arch: process.arch,
|
|
22
|
+
}),
|
|
15
23
|
};
|
|
16
24
|
|
|
17
25
|
function stringList(value) {
|
|
@@ -322,46 +330,298 @@ export function enforceSandboxFailClosed(sandbox, reason = "safe") {
|
|
|
322
330
|
};
|
|
323
331
|
}
|
|
324
332
|
|
|
333
|
+
function capability(id, details = {}) {
|
|
334
|
+
return { id, ...details };
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function addUniqueCapability(target, entry) {
|
|
338
|
+
if (!target.some((candidate) => candidate.id === entry.id)) {
|
|
339
|
+
target.push(entry);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Describe the exact legacy agent-shell sandbox request without claiming that
|
|
345
|
+
* a command has run. `enforceable` is backend capability; `applied` is only
|
|
346
|
+
* populated after a child was successfully started through that backend.
|
|
347
|
+
*/
|
|
348
|
+
export function assessAgentSandboxCapabilities(sandbox, options = {}) {
|
|
349
|
+
const host = options.host || {
|
|
350
|
+
platform: process.platform,
|
|
351
|
+
release: os.release(),
|
|
352
|
+
arch: process.arch,
|
|
353
|
+
};
|
|
354
|
+
const execution = options.execution || null;
|
|
355
|
+
const availability = options.availability || null;
|
|
356
|
+
const requested = [];
|
|
357
|
+
const enforceable = [];
|
|
358
|
+
const unsupported = [];
|
|
359
|
+
|
|
360
|
+
if (!sandbox) {
|
|
361
|
+
return {
|
|
362
|
+
schema: AGENT_SANDBOX_CAPABILITY_SCHEMA,
|
|
363
|
+
host: {
|
|
364
|
+
platform: String(host.platform),
|
|
365
|
+
release: String(host.release),
|
|
366
|
+
arch: String(host.arch),
|
|
367
|
+
},
|
|
368
|
+
backend: {
|
|
369
|
+
engine: null,
|
|
370
|
+
isolationLevel: "policy-only",
|
|
371
|
+
availabilityChecked: false,
|
|
372
|
+
available: null,
|
|
373
|
+
reason: null,
|
|
374
|
+
},
|
|
375
|
+
status: "disabled",
|
|
376
|
+
execution: {
|
|
377
|
+
observed: false,
|
|
378
|
+
attempted: false,
|
|
379
|
+
started: false,
|
|
380
|
+
},
|
|
381
|
+
requested,
|
|
382
|
+
enforceable,
|
|
383
|
+
applied: [],
|
|
384
|
+
unsupported,
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const engine = String(sandbox.engine || "");
|
|
389
|
+
const policy = sandbox.policy || normalizeSandboxPolicy({}, sandbox.cwd);
|
|
390
|
+
const supportedEngine = engine === "docker" || engine === "bubblewrap";
|
|
391
|
+
const supportedPlatform =
|
|
392
|
+
engine !== "bubblewrap" || host.platform === "linux";
|
|
393
|
+
const isolationCapability =
|
|
394
|
+
engine === "docker"
|
|
395
|
+
? "isolation.container"
|
|
396
|
+
: engine === "bubblewrap"
|
|
397
|
+
? "isolation.linux-namespace"
|
|
398
|
+
: "isolation.unknown";
|
|
399
|
+
const networkCapability = sandbox.network
|
|
400
|
+
? "network.unrestricted"
|
|
401
|
+
: "network.none";
|
|
402
|
+
|
|
403
|
+
addUniqueCapability(requested, capability(isolationCapability));
|
|
404
|
+
addUniqueCapability(requested, capability("filesystem.workspace-read-write"));
|
|
405
|
+
addUniqueCapability(requested, capability(networkCapability));
|
|
406
|
+
|
|
407
|
+
const filesystemRequests = [
|
|
408
|
+
["filesystem.additional-read", policy.allowRead],
|
|
409
|
+
["filesystem.deny-read", policy.denyRead],
|
|
410
|
+
["filesystem.additional-write", policy.allowWrite],
|
|
411
|
+
["filesystem.deny-write", policy.denyWrite],
|
|
412
|
+
];
|
|
413
|
+
for (const [id, values] of filesystemRequests) {
|
|
414
|
+
if (values?.length) {
|
|
415
|
+
addUniqueCapability(
|
|
416
|
+
requested,
|
|
417
|
+
capability(id, { entries: values.length }),
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
const domainRuleCount =
|
|
422
|
+
(policy.allowedDomains?.length || 0) + (policy.deniedDomains?.length || 0);
|
|
423
|
+
if (domainRuleCount > 0) {
|
|
424
|
+
addUniqueCapability(
|
|
425
|
+
requested,
|
|
426
|
+
capability("network.domain-policy", { entries: domainRuleCount }),
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (!supportedEngine) {
|
|
431
|
+
unsupported.push(
|
|
432
|
+
capability("backend.engine", {
|
|
433
|
+
reason: "unsupported_engine",
|
|
434
|
+
message: `Unsupported agent sandbox engine: ${engine || "<empty>"}`,
|
|
435
|
+
remediation: "Use engine=docker or engine=bubblewrap.",
|
|
436
|
+
}),
|
|
437
|
+
);
|
|
438
|
+
} else if (!supportedPlatform) {
|
|
439
|
+
unsupported.push(
|
|
440
|
+
capability("backend.platform", {
|
|
441
|
+
reason: "bubblewrap_requires_linux",
|
|
442
|
+
message: `bubblewrap is only supported on Linux; host platform is ${host.platform}`,
|
|
443
|
+
remediation: "Use Docker on this host or run bubblewrap on Linux.",
|
|
444
|
+
}),
|
|
445
|
+
);
|
|
446
|
+
} else {
|
|
447
|
+
addUniqueCapability(
|
|
448
|
+
enforceable,
|
|
449
|
+
capability(isolationCapability, {
|
|
450
|
+
enforcement:
|
|
451
|
+
engine === "docker" ? "docker-container" : "bubblewrap-namespaces",
|
|
452
|
+
}),
|
|
453
|
+
);
|
|
454
|
+
addUniqueCapability(
|
|
455
|
+
enforceable,
|
|
456
|
+
capability("filesystem.workspace-read-write", {
|
|
457
|
+
enforcement:
|
|
458
|
+
engine === "docker" ? "docker-bind-mount" : "bubblewrap-bind-mount",
|
|
459
|
+
}),
|
|
460
|
+
);
|
|
461
|
+
addUniqueCapability(
|
|
462
|
+
enforceable,
|
|
463
|
+
capability(networkCapability, {
|
|
464
|
+
enforcement:
|
|
465
|
+
engine === "docker"
|
|
466
|
+
? sandbox.network
|
|
467
|
+
? "docker-default-network"
|
|
468
|
+
: "docker-network-none"
|
|
469
|
+
: sandbox.network
|
|
470
|
+
? "bubblewrap-share-net"
|
|
471
|
+
: "bubblewrap-unshared-network-namespace",
|
|
472
|
+
}),
|
|
473
|
+
);
|
|
474
|
+
|
|
475
|
+
for (const [id, values] of filesystemRequests) {
|
|
476
|
+
if (!values?.length) continue;
|
|
477
|
+
if (engine === "docker") {
|
|
478
|
+
unsupported.push(
|
|
479
|
+
capability(id, {
|
|
480
|
+
reason: "docker_fine_grained_filesystem_unsupported",
|
|
481
|
+
message:
|
|
482
|
+
"The Docker sandbox backend cannot enforce fine-grained filesystem policy; use engine=bubblewrap",
|
|
483
|
+
remediation:
|
|
484
|
+
"Use engine=bubblewrap on Linux or remove the fine-grained rule.",
|
|
485
|
+
}),
|
|
486
|
+
);
|
|
487
|
+
} else if (id === "filesystem.additional-read") {
|
|
488
|
+
unsupported.push(
|
|
489
|
+
capability(id, {
|
|
490
|
+
reason: "bubblewrap_additional_read_not_isolated",
|
|
491
|
+
message:
|
|
492
|
+
"The bubblewrap agent-shell backend exposes the host root read-only and cannot make allowRead an exclusive read boundary",
|
|
493
|
+
remediation:
|
|
494
|
+
"Remove allowRead or use the attested ProcessExecutionBroker sandbox for a supported execution contract.",
|
|
495
|
+
}),
|
|
496
|
+
);
|
|
497
|
+
} else {
|
|
498
|
+
addUniqueCapability(
|
|
499
|
+
enforceable,
|
|
500
|
+
capability(id, {
|
|
501
|
+
entries: values.length,
|
|
502
|
+
enforcement: `bubblewrap-${id.replace("filesystem.", "")}-mount`,
|
|
503
|
+
}),
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (domainRuleCount > 0) {
|
|
509
|
+
unsupported.push(
|
|
510
|
+
capability("network.domain-policy", {
|
|
511
|
+
reason: "domain_policy_has_no_non_bypassable_backend",
|
|
512
|
+
message:
|
|
513
|
+
"Domain-restricted sandbox networking has no non-bypassable backend enforcement; refusing unrestricted network access",
|
|
514
|
+
remediation:
|
|
515
|
+
"Disable sandbox networking or use a separately attested dependency-fetch service.",
|
|
516
|
+
}),
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const executionObserved = execution !== null;
|
|
522
|
+
const executionAttempted = execution?.attempted === true;
|
|
523
|
+
const executionStarted = execution?.started === true;
|
|
524
|
+
const availabilityChecked = availability !== null || executionStarted;
|
|
525
|
+
const available = executionStarted
|
|
526
|
+
? true
|
|
527
|
+
: availability === null
|
|
528
|
+
? null
|
|
529
|
+
: availability.available === true;
|
|
530
|
+
const availabilityReason = executionStarted
|
|
531
|
+
? null
|
|
532
|
+
: availability?.reason || null;
|
|
533
|
+
let status = "ready";
|
|
534
|
+
if (unsupported.length > 0) status = "unsupported";
|
|
535
|
+
else if (executionStarted) status = "applied";
|
|
536
|
+
else if (executionAttempted) status = "failed-to-start";
|
|
537
|
+
else if (availabilityChecked && !available) status = "unavailable";
|
|
538
|
+
|
|
539
|
+
return {
|
|
540
|
+
schema: AGENT_SANDBOX_CAPABILITY_SCHEMA,
|
|
541
|
+
host: {
|
|
542
|
+
platform: String(host.platform),
|
|
543
|
+
release: String(host.release),
|
|
544
|
+
arch: String(host.arch),
|
|
545
|
+
},
|
|
546
|
+
backend: {
|
|
547
|
+
engine,
|
|
548
|
+
isolationLevel: isolationLevel(sandbox),
|
|
549
|
+
availabilityChecked,
|
|
550
|
+
available,
|
|
551
|
+
reason: availabilityReason,
|
|
552
|
+
},
|
|
553
|
+
status,
|
|
554
|
+
execution: {
|
|
555
|
+
observed: executionObserved,
|
|
556
|
+
attempted: executionAttempted,
|
|
557
|
+
started: executionStarted,
|
|
558
|
+
},
|
|
559
|
+
requested,
|
|
560
|
+
enforceable,
|
|
561
|
+
applied: executionStarted ? enforceable.map((entry) => ({ ...entry })) : [],
|
|
562
|
+
unsupported,
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
export function assertSandboxCapabilities(sandbox, options = {}) {
|
|
567
|
+
const report = assessAgentSandboxCapabilities(sandbox, options);
|
|
568
|
+
if (report.unsupported.length === 0) return report;
|
|
569
|
+
const error = new Error(
|
|
570
|
+
`Unsupported sandbox capability request: ${report.unsupported
|
|
571
|
+
.map((entry) => `${entry.id} (${entry.message})`)
|
|
572
|
+
.join("; ")}`,
|
|
573
|
+
);
|
|
574
|
+
error.code = "CONFIG_SANDBOX_CAPABILITY_UNSUPPORTED";
|
|
575
|
+
error.capabilityReport = report;
|
|
576
|
+
throw error;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
function attachSandboxCapabilityReport(
|
|
580
|
+
result,
|
|
581
|
+
sandbox,
|
|
582
|
+
execution,
|
|
583
|
+
availability,
|
|
584
|
+
host,
|
|
585
|
+
) {
|
|
586
|
+
return {
|
|
587
|
+
...result,
|
|
588
|
+
sandboxCapabilities: assessAgentSandboxCapabilities(sandbox, {
|
|
589
|
+
execution,
|
|
590
|
+
availability,
|
|
591
|
+
host,
|
|
592
|
+
}),
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
|
|
325
596
|
export function executeSandboxedShell(command, sandbox, options = {}) {
|
|
326
597
|
if (!sandbox || !["docker", "bubblewrap"].includes(sandbox.engine)) {
|
|
327
598
|
throw new Error("A supported agent sandbox configuration is required");
|
|
328
599
|
}
|
|
329
600
|
const hostCwd = path.resolve(options.cwd || sandbox.cwd);
|
|
330
601
|
const policy = sandbox.policy || normalizeSandboxPolicy({}, hostCwd);
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
if (
|
|
337
|
-
(policy.allowedDomains.length || policy.deniedDomains.length) &&
|
|
338
|
-
sandbox.network
|
|
339
|
-
) {
|
|
602
|
+
const capabilityHost = _deps.host();
|
|
603
|
+
const capabilityReport = assessAgentSandboxCapabilities(sandbox, {
|
|
604
|
+
host: capabilityHost,
|
|
605
|
+
});
|
|
606
|
+
if (capabilityReport.unsupported.length > 0) {
|
|
340
607
|
return {
|
|
341
608
|
stdout: "",
|
|
342
|
-
stderr:
|
|
343
|
-
|
|
609
|
+
stderr: capabilityReport.unsupported
|
|
610
|
+
.map((entry) => entry.message)
|
|
611
|
+
.join("; "),
|
|
344
612
|
exitCode: 1,
|
|
345
613
|
failedToStart: true,
|
|
614
|
+
sandboxCapabilities: capabilityReport,
|
|
346
615
|
};
|
|
347
616
|
}
|
|
617
|
+
// Proxy environment variables are advisory: a child can clear them or open a
|
|
618
|
+
// raw socket. Until a backend can enforce egress below the process layer,
|
|
619
|
+
// domain-restricted networking must fail closed instead of granting the
|
|
620
|
+
// sandbox an unrestricted network namespace.
|
|
621
|
+
const egress = options.egressProxy || null;
|
|
348
622
|
if (sandbox.engine === "bubblewrap") {
|
|
349
623
|
return executeBubblewrapShell(command, sandbox, options, hostCwd, policy);
|
|
350
624
|
}
|
|
351
|
-
if (
|
|
352
|
-
policy.allowRead.length ||
|
|
353
|
-
policy.denyRead.length ||
|
|
354
|
-
policy.allowWrite.length ||
|
|
355
|
-
policy.denyWrite.length
|
|
356
|
-
) {
|
|
357
|
-
return {
|
|
358
|
-
stdout: "",
|
|
359
|
-
stderr:
|
|
360
|
-
"The Docker sandbox backend cannot enforce fine-grained filesystem policy; use engine=bubblewrap",
|
|
361
|
-
exitCode: 1,
|
|
362
|
-
failedToStart: true,
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
625
|
const args = ["run", "--rm", "--init"];
|
|
366
626
|
if (!sandbox.network) args.push("--network", "none");
|
|
367
627
|
args.push("--mount", `type=bind,source=${hostCwd},target=/workspace`);
|
|
@@ -397,22 +657,34 @@ export function executeSandboxedShell(command, sandbox, options = {}) {
|
|
|
397
657
|
auditContext: options.auditContext,
|
|
398
658
|
});
|
|
399
659
|
if (result.error) {
|
|
400
|
-
return
|
|
660
|
+
return attachSandboxCapabilityReport(
|
|
661
|
+
{
|
|
662
|
+
stdout: result.stdout || "",
|
|
663
|
+
stderr:
|
|
664
|
+
result.error.code === "ENOENT"
|
|
665
|
+
? "Docker is not installed"
|
|
666
|
+
: result.error.message,
|
|
667
|
+
exitCode: typeof result.status === "number" ? result.status : 1,
|
|
668
|
+
failedToStart: true,
|
|
669
|
+
},
|
|
670
|
+
sandbox,
|
|
671
|
+
{ attempted: true, started: false },
|
|
672
|
+
{ available: false, reason: result.error.message },
|
|
673
|
+
capabilityHost,
|
|
674
|
+
);
|
|
675
|
+
}
|
|
676
|
+
return attachSandboxCapabilityReport(
|
|
677
|
+
{
|
|
401
678
|
stdout: result.stdout || "",
|
|
402
|
-
stderr:
|
|
403
|
-
result.error.code === "ENOENT"
|
|
404
|
-
? "Docker is not installed"
|
|
405
|
-
: result.error.message,
|
|
679
|
+
stderr: result.stderr || "",
|
|
406
680
|
exitCode: typeof result.status === "number" ? result.status : 1,
|
|
407
|
-
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
signal: result.signal || null,
|
|
415
|
-
};
|
|
681
|
+
signal: result.signal || null,
|
|
682
|
+
},
|
|
683
|
+
sandbox,
|
|
684
|
+
{ attempted: true, started: true },
|
|
685
|
+
{ available: true, reason: null },
|
|
686
|
+
capabilityHost,
|
|
687
|
+
);
|
|
416
688
|
}
|
|
417
689
|
|
|
418
690
|
function executeBubblewrapShell(command, sandbox, options, hostCwd, policy) {
|
|
@@ -469,22 +741,34 @@ function executeBubblewrapShell(command, sandbox, options, hostCwd, policy) {
|
|
|
469
741
|
auditContext: options.auditContext,
|
|
470
742
|
});
|
|
471
743
|
if (result.error) {
|
|
472
|
-
return
|
|
744
|
+
return attachSandboxCapabilityReport(
|
|
745
|
+
{
|
|
746
|
+
stdout: result.stdout || "",
|
|
747
|
+
stderr:
|
|
748
|
+
result.error.code === "ENOENT"
|
|
749
|
+
? "bubblewrap is not installed"
|
|
750
|
+
: result.error.message,
|
|
751
|
+
exitCode: typeof result.status === "number" ? result.status : 1,
|
|
752
|
+
failedToStart: true,
|
|
753
|
+
},
|
|
754
|
+
sandbox,
|
|
755
|
+
{ attempted: true, started: false },
|
|
756
|
+
{ available: false, reason: result.error.message },
|
|
757
|
+
_deps.host(),
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
return attachSandboxCapabilityReport(
|
|
761
|
+
{
|
|
473
762
|
stdout: result.stdout || "",
|
|
474
|
-
stderr:
|
|
475
|
-
result.error.code === "ENOENT"
|
|
476
|
-
? "bubblewrap is not installed"
|
|
477
|
-
: result.error.message,
|
|
763
|
+
stderr: result.stderr || "",
|
|
478
764
|
exitCode: typeof result.status === "number" ? result.status : 1,
|
|
479
|
-
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
signal: result.signal || null,
|
|
487
|
-
};
|
|
765
|
+
signal: result.signal || null,
|
|
766
|
+
},
|
|
767
|
+
sandbox,
|
|
768
|
+
{ attempted: true, started: true },
|
|
769
|
+
{ available: true, reason: null },
|
|
770
|
+
_deps.host(),
|
|
771
|
+
);
|
|
488
772
|
}
|
|
489
773
|
|
|
490
774
|
/**
|
|
@@ -2,6 +2,7 @@ import { PassThrough } from "node:stream";
|
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import {
|
|
4
4
|
assertSandboxAvailable,
|
|
5
|
+
assertSandboxCapabilities,
|
|
5
6
|
normalizeAgentSandboxMode,
|
|
6
7
|
} from "../agent-sandbox.js";
|
|
7
8
|
|
|
@@ -127,6 +128,7 @@ export class CliAgentKernelAdapter {
|
|
|
127
128
|
},
|
|
128
129
|
},
|
|
129
130
|
);
|
|
131
|
+
assertSandboxCapabilities(sandbox);
|
|
130
132
|
assertSandboxAvailable(sandbox);
|
|
131
133
|
|
|
132
134
|
const input = new PassThrough();
|
|
@@ -166,6 +168,26 @@ export class CliAgentKernelAdapter {
|
|
|
166
168
|
binding: event.binding,
|
|
167
169
|
});
|
|
168
170
|
}
|
|
171
|
+
if (event.type === "question_request") {
|
|
172
|
+
const answerQuestion = async () => {
|
|
173
|
+
let answer = null;
|
|
174
|
+
try {
|
|
175
|
+
answer = await current.requestQuestion(event);
|
|
176
|
+
} catch {
|
|
177
|
+
// A missing/rejecting host is cancellation, never implicit consent.
|
|
178
|
+
}
|
|
179
|
+
writeLine(input, {
|
|
180
|
+
type: "answer",
|
|
181
|
+
id: event.id,
|
|
182
|
+
answer,
|
|
183
|
+
binding: event.binding,
|
|
184
|
+
});
|
|
185
|
+
};
|
|
186
|
+
// The Headless runtime owns blocking semantics and its timeout. Keep
|
|
187
|
+
// the transport event chain free so a timed-out question can emit
|
|
188
|
+
// question_resolved/result even while a slow host request is pending.
|
|
189
|
+
void answerQuestion().catch(() => {});
|
|
190
|
+
}
|
|
169
191
|
if (event.type === "result") {
|
|
170
192
|
session.current = null;
|
|
171
193
|
current.resolve(event);
|
|
@@ -194,6 +216,7 @@ export class CliAgentKernelAdapter {
|
|
|
194
216
|
permissionMode,
|
|
195
217
|
sandbox,
|
|
196
218
|
interactiveApprovals: true,
|
|
219
|
+
interactiveQuestions: turnOptions.interactiveQuestions === true,
|
|
197
220
|
includePartialMessages: true,
|
|
198
221
|
ephemeral: false,
|
|
199
222
|
evolutionIngress:
|
|
@@ -263,6 +286,7 @@ export class CliAgentKernelAdapter {
|
|
|
263
286
|
options = {},
|
|
264
287
|
emit,
|
|
265
288
|
requestApproval,
|
|
289
|
+
requestQuestion,
|
|
266
290
|
}) {
|
|
267
291
|
const session = await this._session(threadId, options);
|
|
268
292
|
if (session.current) {
|
|
@@ -283,6 +307,10 @@ export class CliAgentKernelAdapter {
|
|
|
283
307
|
turnId,
|
|
284
308
|
emit,
|
|
285
309
|
requestApproval,
|
|
310
|
+
requestQuestion:
|
|
311
|
+
typeof requestQuestion === "function"
|
|
312
|
+
? requestQuestion
|
|
313
|
+
: async () => null,
|
|
286
314
|
resolve,
|
|
287
315
|
reject,
|
|
288
316
|
};
|
|
@@ -10,6 +10,7 @@ import { AppServerGraphRuntime } from "./graph-runtime.js";
|
|
|
10
10
|
import { captureAgentSkillOutcomeIndex } from "../evolution/agent-evolution-runtime-composition-brand.js";
|
|
11
11
|
import { captureSkillVectorAuthority } from "../skill-vector-authority.js";
|
|
12
12
|
import { captureSkillRetrievalRevocationReader } from "../evolution/skill-retrieval-revocation-authority.js";
|
|
13
|
+
import { sameInteractionBinding } from "../interaction-binding.js";
|
|
13
14
|
import { compileGraphDefinition } from "../graph-kernel/compiler.js";
|
|
14
15
|
import { createCliContextMemoryRuntime } from "../context-memory-kernel/runtime.js";
|
|
15
16
|
import { isEvolutionWorkbenchCliHost } from "../evolution/evolution-workbench-cli-host.js";
|
|
@@ -882,6 +883,10 @@ export class CcAppServer {
|
|
|
882
883
|
turnOptions.skillRetrievalRevocationReader =
|
|
883
884
|
skillRetrievalRevocationReader;
|
|
884
885
|
}
|
|
886
|
+
if (this.negotiated) {
|
|
887
|
+
turnOptions.interactiveQuestions =
|
|
888
|
+
this.negotiated.features.includes("deferred_questions");
|
|
889
|
+
}
|
|
885
890
|
const result = await this.kernel.startTurn({
|
|
886
891
|
threadId,
|
|
887
892
|
turnId: attempt.id,
|
|
@@ -896,6 +901,7 @@ export class CcAppServer {
|
|
|
896
901
|
event,
|
|
897
902
|
}),
|
|
898
903
|
requestApproval: (event) => this._requestApproval(turn, event),
|
|
904
|
+
requestQuestion: (event) => this._requestQuestion(turn, event),
|
|
899
905
|
});
|
|
900
906
|
const failed = result?.is_error === true || result?.subtype === "error";
|
|
901
907
|
const output = typeof result?.result === "string" ? result.result : "";
|
|
@@ -1137,6 +1143,8 @@ export class CcAppServer {
|
|
|
1137
1143
|
turnOptions.skillRetrievalRevocationReader =
|
|
1138
1144
|
this.skillRetrievalRevocationReader;
|
|
1139
1145
|
}
|
|
1146
|
+
turnOptions.interactiveQuestions =
|
|
1147
|
+
this.negotiated?.features.includes("deferred_questions") === true;
|
|
1140
1148
|
const result = await this.kernel.startTurn({
|
|
1141
1149
|
threadId: turn.threadId,
|
|
1142
1150
|
turnId: turn.id,
|
|
@@ -1144,6 +1152,7 @@ export class CcAppServer {
|
|
|
1144
1152
|
options: turnOptions,
|
|
1145
1153
|
emit: (event) => this._emitKernelEvent(turn, event),
|
|
1146
1154
|
requestApproval: (event) => this._requestApproval(turn, event),
|
|
1155
|
+
requestQuestion: (event) => this._requestQuestion(turn, event),
|
|
1147
1156
|
});
|
|
1148
1157
|
if (turn.interruptRequested) {
|
|
1149
1158
|
await this._completeTurn(turn, "interrupted", result);
|
|
@@ -1321,6 +1330,48 @@ export class CcAppServer {
|
|
|
1321
1330
|
);
|
|
1322
1331
|
return;
|
|
1323
1332
|
}
|
|
1333
|
+
if (event?.type === "question_request") {
|
|
1334
|
+
if (!this.negotiated?.features.includes("deferred_questions")) return;
|
|
1335
|
+
const blocking = event.blocking !== false && event.mode !== "deferred";
|
|
1336
|
+
if (blocking) turn.status = "waiting_input";
|
|
1337
|
+
turn.revision += 1;
|
|
1338
|
+
await this._notify(
|
|
1339
|
+
"question/requested",
|
|
1340
|
+
{ request: this._questionRequest(turn, event) },
|
|
1341
|
+
{
|
|
1342
|
+
threadId: turn.threadId,
|
|
1343
|
+
turnId: turn.id,
|
|
1344
|
+
itemId: `${turn.id}:question:${safeId(event.id, "question")}`,
|
|
1345
|
+
traceId,
|
|
1346
|
+
idempotencyKey: `question-requested:${turn.id}:${event.id}`,
|
|
1347
|
+
},
|
|
1348
|
+
);
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
if (event?.type === "question_resolved") {
|
|
1352
|
+
if (!this.negotiated?.features.includes("deferred_questions")) return;
|
|
1353
|
+
if (event.blocking !== false && event.mode !== "deferred") {
|
|
1354
|
+
turn.status = "running";
|
|
1355
|
+
}
|
|
1356
|
+
turn.revision += 1;
|
|
1357
|
+
await this._notify(
|
|
1358
|
+
"question/resolved",
|
|
1359
|
+
{
|
|
1360
|
+
threadId: turn.threadId,
|
|
1361
|
+
turnId: turn.id,
|
|
1362
|
+
questionId: safeId(event.id, `${turn.id}:question`),
|
|
1363
|
+
mode: event.mode === "deferred" ? "deferred" : "blocking",
|
|
1364
|
+
via: event.via || "unknown",
|
|
1365
|
+
},
|
|
1366
|
+
{
|
|
1367
|
+
threadId: turn.threadId,
|
|
1368
|
+
turnId: turn.id,
|
|
1369
|
+
traceId,
|
|
1370
|
+
idempotencyKey: `question-resolved:${turn.id}:${event.id}:${event.via}`,
|
|
1371
|
+
},
|
|
1372
|
+
);
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1324
1375
|
if (event?.type === "plan_update") {
|
|
1325
1376
|
await this._notify(
|
|
1326
1377
|
"item/completed",
|
|
@@ -1394,6 +1445,48 @@ export class CcAppServer {
|
|
|
1394
1445
|
return result;
|
|
1395
1446
|
}
|
|
1396
1447
|
|
|
1448
|
+
_questionRequest(turn, event) {
|
|
1449
|
+
const id = safeId(event.id, `${turn.id}:question`);
|
|
1450
|
+
return {
|
|
1451
|
+
id,
|
|
1452
|
+
threadId: turn.threadId,
|
|
1453
|
+
turnId: turn.id,
|
|
1454
|
+
binding: event.binding || null,
|
|
1455
|
+
question: String(event.question || "").slice(0, 16_384),
|
|
1456
|
+
options: Array.isArray(event.options)
|
|
1457
|
+
? event.options.slice(0, 128)
|
|
1458
|
+
: null,
|
|
1459
|
+
multiSelect: event.multiSelect === true,
|
|
1460
|
+
mode: event.mode === "deferred" ? "deferred" : "blocking",
|
|
1461
|
+
blocking: event.blocking !== false && event.mode !== "deferred",
|
|
1462
|
+
purpose: event.purpose || "decision",
|
|
1463
|
+
contextRevision: Number.isSafeInteger(event.context_revision)
|
|
1464
|
+
? event.context_revision
|
|
1465
|
+
: null,
|
|
1466
|
+
expiresAt: new Date(this.now() + this.requestTimeoutMs).toISOString(),
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
async _requestQuestion(turn, event) {
|
|
1471
|
+
if (!this.negotiated?.features.includes("deferred_questions")) return null;
|
|
1472
|
+
const request = this._questionRequest(turn, event);
|
|
1473
|
+
const result = requireObject(
|
|
1474
|
+
await this._requestClient("question/answer", { request }),
|
|
1475
|
+
"question answer",
|
|
1476
|
+
);
|
|
1477
|
+
if (
|
|
1478
|
+
result.questionId !== request.id ||
|
|
1479
|
+
!request.binding ||
|
|
1480
|
+
!sameInteractionBinding(request.binding, result.binding)
|
|
1481
|
+
) {
|
|
1482
|
+
throw new JsonRpcError(
|
|
1483
|
+
JSON_RPC_ERROR.INVALID_PARAMS,
|
|
1484
|
+
"client returned an invalid or stale question answer",
|
|
1485
|
+
);
|
|
1486
|
+
}
|
|
1487
|
+
return Object.hasOwn(result, "answer") ? result.answer : null;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1397
1490
|
async _requestHumanTask({ task }) {
|
|
1398
1491
|
const result = await this._requestClient("humanTask/decide", { task });
|
|
1399
1492
|
const response = requireObject(result, "humanTask decision");
|
|
@@ -4,6 +4,7 @@ import { createNdjsonReader } from "./background-session-transport.js";
|
|
|
4
4
|
import {
|
|
5
5
|
BACKGROUND_AGENT_KEEPER_ARM,
|
|
6
6
|
BACKGROUND_AGENT_KEEPER_ARMED,
|
|
7
|
+
BACKGROUND_AGENT_KEEPER_ARM_TIMEOUT_MS,
|
|
7
8
|
BACKGROUND_AGENT_KEEPER_HELLO,
|
|
8
9
|
BACKGROUND_AGENT_KEEPER_HEARTBEAT,
|
|
9
10
|
BACKGROUND_AGENT_KEEPER_HEARTBEAT_INTERVAL_MS,
|
|
@@ -244,6 +245,7 @@ export async function connectBackgroundAgentKeeper(options = {}) {
|
|
|
244
245
|
BACKGROUND_AGENT_KEEPER_ARM,
|
|
245
246
|
BACKGROUND_AGENT_KEEPER_ARMED,
|
|
246
247
|
normalized,
|
|
248
|
+
BACKGROUND_AGENT_KEEPER_ARM_TIMEOUT_MS,
|
|
247
249
|
);
|
|
248
250
|
activeTurn = normalized;
|
|
249
251
|
return normalized;
|
|
@@ -50,6 +50,13 @@ export const BACKGROUND_AGENT_KEEPER_IDENTITY_PROBE_TIMEOUT_MS =
|
|
|
50
50
|
export const BACKGROUND_AGENT_KEEPER_STATE_LOCK_TIMEOUT_MS = 5_000;
|
|
51
51
|
export const BACKGROUND_AGENT_KEEPER_PERSIST_RETRY_TIMEOUT_MS =
|
|
52
52
|
3 * BACKGROUND_AGENT_KEEPER_STATE_LOCK_TIMEOUT_MS;
|
|
53
|
+
// ARM durably binds a newly spawned turn. It can contend with a strict state
|
|
54
|
+
// lock and, on Windows, an incumbent identity probe. Keep this deadline
|
|
55
|
+
// independent from short HELLO requests and long destructive RETIRE cleanup.
|
|
56
|
+
export const BACKGROUND_AGENT_KEEPER_ARM_TIMEOUT_MS =
|
|
57
|
+
BACKGROUND_AGENT_KEEPER_IDENTITY_PROBE_TIMEOUT_MS +
|
|
58
|
+
BACKGROUND_AGENT_KEEPER_STATE_LOCK_TIMEOUT_MS +
|
|
59
|
+
10_000;
|
|
53
60
|
// A 20-Agent macOS formal run can leave successfully SIGKILLed process groups
|
|
54
61
|
// observable for several seconds while launchd reaps their orphaned leaders.
|
|
55
62
|
// Two seconds made that bounded kernel/reaper delay look like an escaped tree.
|