chainlesschain 0.166.9 → 0.166.13
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 +33 -0
- package/bin/chainlesschain.js +5 -0
- package/package.json +5 -2
- package/src/assets/web-panel/assets/{AIOps-DJvpifGx.js → AIOps-BN25cNOD.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-D2UhuF_A.js → ActionButton-Da9IP-m5.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-C9ho9obu.js → Analytics-D7hkEvQm.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BvRCpFK3.js → AppLayout-CCV4Xnbc.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-jxrySvpk.js → Artifacts-CVSnVJeA.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-ovEw0ZYl.js → Audit-CuYdw5Ag.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-D7H5z6zS.js → BackgroundAgents-DZCnK-Tf.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BuXob8za.js → Backup-cV9FdpTy.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CtnszuQ2.js → BaseInput-BRnv6YSp.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-B_mYE8fJ.js → Chat-Bw5w87P4.js} +6 -6
- package/src/assets/web-panel/assets/ChatBubbleRenderer-C0GjtUAw.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-ierdtcJD.js → Checkbox-DaoTqcdt.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-3VKPJD_B.js → Codegen-B4dYcEIi.js} +1 -1
- package/src/assets/web-panel/assets/{Col-1EdMyf5P.js → Col-mAhuOeuD.js} +1 -1
- package/src/assets/web-panel/assets/{Community-D6H7UA8K.js → Community-BK6KEdBk.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BBAZvYIm.js → Compact-CCglmNu5.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CgsTrAoj.js → Compliance-Cm8S4of7.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-tnZgLoTE.js → Cowork-Dhs1QLMe.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-CPpZw2Nh.js → Cron-CLlhmXWk.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BymBcp5z.js → Crosschain-BnHVbaNs.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DKPxS_K1.js → DID-UzQP9-0O.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DvJhEmH9.js → Dashboard-CBdlPClz.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-b8iQyQIZ.js → Dropdown-axIRPdq1.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer--0-A-zKb.js → EmailListRenderer-DUalW5rx.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-C12iDN06.js → FamilyGuardDashboard-Bl4W9luY.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BRhaE2Z8.js → Federation-C1yP-uEu.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-C4dnq7yf.js → FormItemContext-Xh6Ig5q8.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CGAdbR5n.js → GenericCardRenderer-C2cz3bt2.js} +1 -1
- package/src/assets/web-panel/assets/{Git-4eA2fYzL.js → Git-C_z63ixg.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BJuY9Y-9.js → Governance-BYqB33_3.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DZ5Dy4up.js → Inference-CEULuArm.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BMTjRs4A.js → KnowledgeGraph-fgMsu-0H.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BKEeQEfJ.js → Logs-DO9Hdcec.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BkrK04xW.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Dhho4fEg.js → Marketplace-B8zyLiFe.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BW6xxSlU.js → McpTools-BLAN2mWW.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-mPqlpSkq.js → Memory-CrQcFM7u.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Cb9N_DQI.js → MobileBridge-DVnyiiU-.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BNs8tah_.js → MobileProjects-qjCME5OD.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CaxBt8tn.js → Mtc-4JE3C3It.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-DRPQbp3t.js → MtcAudit-CjBuak9I.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-CRm-d8bK.js → Multisig-BtPcYQcC.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BCCk3LPs.js → NLProgramming-Cx653_Ba.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Cv8SN8gN.js → Notes-CkuD3YzS.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-CggIvTh5.js → NotificationSettings-BgNgU7HH.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-BW3_bV12.js → OrderTableRenderer-BTC8W0a-.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BuRE-VCO.js → Organization-Dmd4Hjxz.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-DBrm1gju.js → Overflow-C_5DA-G0.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CWVnDYgS.js → P2P-uwslV4XC.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-8RKUIpte.js → PdhVaultBrowser-CuNgwVnX.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-tDUAxogW.js → Permissions-CJayVX9H.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-Dv2-CFis.js → PersonalDataHub-Cb05H5go.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-DM6kvFni.js → Pipeline-BZlGKapZ.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DzK-yL0d.js → Privacy-BIzZWYzd.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B5UrNpkj.js → ProjectInit-vEYYyQXQ.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CxJD43oW.js → ProjectSettings-MZqTy5CC.js} +2 -2
- package/src/assets/web-panel/assets/Projects-CRARUOl8.js +1 -0
- package/src/assets/web-panel/assets/{Providers-CYl4jRYK.js → Providers-80VAK8PX.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DeH2T0fH.js → QrScannerModal-CzRSoIwK.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Bw9k_kTk.js → QuickAsk-BpwQ2n4C.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Bl_jGwoi.js → Recommend-BC03TZ79.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-d6u01Kq0.js → RemoteSession-DE59-jaa.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-Ds_Dfr-k.js → Reputation-DOHmeWyA.js} +1 -1
- package/src/assets/web-panel/assets/{Row-BpQUQTNj.js → Row-hc5RZl1D.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BatpZBGt.js → RssFeed-Cv5uMP7E.js} +3 -3
- package/src/assets/web-panel/assets/{Search-D7hOObzi.js → Search-qohu7Ug0.js} +1 -1
- package/src/assets/web-panel/assets/{Security-dXQ4FKNt.js → Security-drCPFWV5.js} +4 -4
- package/src/assets/web-panel/assets/{Services-D8wInGPa.js → Services-BAEgUeRy.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DXQCoYpM.js → Skeleton-CkJkKBlo.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-D3oLRIVn.js → Skills-bMuKEpez.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BmP4-LnJ.js → Sla-DxWQVHRC.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DLj-xzro.js → SpeechSettings-BpS8idmV.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-8KKaaRMr.js → SyncSettings-BPBLlW5v.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-GyK42I7C.js → Tasks-C4SLEeUh.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-n1y_8UBG.js → Templates-r-wfU39U.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-B39nBph8.js → Tenant-C7vjRmLN.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DCQoOKXe.js → Terminal-DdzeFCV2.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BkhbDfXk.js → TimelineRenderer-CYyWN2KD.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BeHIIU8D.js → Tokens-D8A9osUg.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BHvWXVOb.js → Trigger-DBvrNlyS.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-y2WaOSto.js → Trust-DBVAGc7o.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DBFeJBzt.js → UkeySign-C1vQUCRJ.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BEOWitC-.js → VideoEditing-BKs4dah4.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BITedTe6.js → Wallet-ByIuj3lD.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DMwlJVin.js → WebAuthn-DYlAFCm9.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-CKfGFEu1.js → WorkflowEditor-Dwyadd0c.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DR6gnBGF.js → chat-Bm2f3s08.js} +1 -1
- package/src/assets/web-panel/assets/{colors-C_Hw5NCn.js → colors-C8ORSh7V.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-B8IPwsEu.js → compact-item-1iVlnsM-.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-D-u4JVnJ.js → createContext-CmqNyUSL.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-B69RCDDH.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CZubdS4D.js → hasIn-rUMaX3Ul.js} +1 -1
- package/src/assets/web-panel/assets/index-9biMQ-tw.js +1 -0
- package/src/assets/web-panel/assets/{index-C25rOz7O.js → index-B53c3diB.js} +1 -1
- package/src/assets/web-panel/assets/{index-CfniPP5p.js → index-B59OWAs7.js} +1 -1
- package/src/assets/web-panel/assets/{index-11ASqx-A.js → index-B8BrB0Ls.js} +1 -1
- package/src/assets/web-panel/assets/{index-auyNYjLo.js → index-BC32_0xT.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ctje8Vl3.js → index-BC8Wb6cy.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cg2bCeol.js → index-BCOhTILd.js} +1 -1
- package/src/assets/web-panel/assets/{index-D1w96gg9.js → index-BFniLMn9.js} +1 -1
- package/src/assets/web-panel/assets/{index-k1Xa5iw1.js → index-BIvM-uAX.js} +1 -1
- package/src/assets/web-panel/assets/{index-DuOU5apg.js → index-BK-RY0-7.js} +1 -1
- package/src/assets/web-panel/assets/{index-D47jt8ET.js → index-BQL9r73Y.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2VmtNaQ.js → index-BVtnizyC.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bizm87cX.js → index-Bf1PlIHp.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dt-w3xQ7.js → index-Bgw4Y2rU.js} +1 -1
- package/src/assets/web-panel/assets/{index-ffe7bvqP.js → index-BgwLNxmr.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cl5RpreD.js → index-C-J5-pGH.js} +1 -1
- package/src/assets/web-panel/assets/{index-idZKyADQ.js → index-C-ZIHi42.js} +1 -1
- package/src/assets/web-panel/assets/{index-LvjAKDSl.js → index-C3B1S-mW.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmRcgiYT.js → index-C5RfRciU.js} +1 -1
- package/src/assets/web-panel/assets/{index-rYBHSDcJ.js → index-CCEyz58d.js} +1 -1
- package/src/assets/web-panel/assets/index-COie87kl.js +1 -0
- package/src/assets/web-panel/assets/{index-DcFjRT-K.js → index-CTfEmKK0.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjRrqooR.js → index-CfiHyVyl.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpjHpRoq.js → index-CkFvuAex.js} +3 -3
- package/src/assets/web-panel/assets/{index-BzoFanEQ.js → index-D98FXb0w.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cbm8F0M2.js → index-DDHk911Q.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXS6wYJZ.js → index-DJxtPFOh.js} +1 -1
- package/src/assets/web-panel/assets/{index-DY6MHo9D.js → index-DVJ1uKf4.js} +1 -1
- package/src/assets/web-panel/assets/{index-CiXkhOkY.js → index-Dcck8QfW.js} +1 -1
- package/src/assets/web-panel/assets/{index-mYZJxGH6.js → index-DgUE51Pz.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqmLw8cs.js → index-Dsve5Gkv.js} +1 -1
- package/src/assets/web-panel/assets/{index-xoNssgz_.js → index-DvedhJeM.js} +1 -1
- package/src/assets/web-panel/assets/{index-DfnzrUxU.js → index-DwMdWKiF.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bi21Etg4.js → index-OcbzdRpT.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJ6pG79m.js → index-fPK6GFEg.js} +1 -1
- package/src/assets/web-panel/assets/{index-_nL79NT8.js → index-geQinnns.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTosx2Wu.js → index-pHWA7bmM.js} +1 -1
- package/src/assets/web-panel/assets/{index-cVqbas5C.js → index-reUHhuz8.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bv2132PO.js → index-tqTx5wXo.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-lcU_dT2r.js → initDefaultProps-CuA-cpkL.js} +1 -1
- package/src/assets/web-panel/assets/{motion-Dc7UNXZ1.js → motion-CimmE_9b.js} +1 -1
- package/src/assets/web-panel/assets/{move-Cll8ZXaL.js → move-DlGlrltz.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CAb_yLIM.js → mtc-parser-CK6BJQ07.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DurYMyTe.js → omit-BKjBfZfB.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BITQyOlw.js → pickAttrs-B2chVYw9.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Dg1rH91i.js → placementArrow-BW8aLJJ3.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-D_EWIeac.js → responsiveObserve-dXlPl66S.js} +1 -1
- package/src/assets/web-panel/assets/{slide-lK4d3zsh.js → slide-hSa89S4G.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Bflq-Git.js → statusUtils-DM6KLt-s.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Ccp0I-wt.js → styleChecker-C9MQAK15.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CYZbByYA.js → useFlexGapSupport-BpQDpP0z.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-B_x0nxFD.js → useFs-C7rtRViA.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DW55rL85.js → usePersonalDataHub-Dm15xafq.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Ca6MH3W8.js → vnode-mEiEytw4.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-NdHelOog.js → zoom-DzPxflhY.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +5 -5
- package/src/commands/agent.js +51 -20
- package/src/commands/compact.js +349 -3
- package/src/commands/context.js +72 -1
- package/src/commands/graph.js +26 -15
- package/src/commands/hmemory.js +21 -0
- package/src/commands/hook.js +256 -28
- package/src/commands/memory.js +209 -42
- package/src/commands/promcomp.js +17 -0
- package/src/commands/serve.js +94 -10
- package/src/commands/session.js +2 -3
- package/src/commands/team.js +7 -1
- package/src/data/changelog.json +41 -2
- package/src/gateways/ws/session-core-protocol.js +62 -3
- package/src/gateways/ws/session-protocol.js +123 -15
- package/src/gateways/ws/ws-agent-handler.js +157 -9
- package/src/gateways/ws/ws-session-gateway.js +204 -30
- package/src/generated/cc-agent-protocol.schema.json +2094 -4
- package/src/harness/prompt-compressor.js +5 -55
- package/src/lib/agent-sandbox.js +14 -4
- package/src/lib/agent-team/team-distributed-graph-bridge.js +3 -3
- package/src/lib/app-server/context-memory-notifications.js +54 -0
- package/src/lib/app-server/rollout-store-factory.js +115 -0
- package/src/lib/app-server/rollout-store.js +310 -23
- package/src/lib/app-server/server.js +184 -7
- package/src/lib/app-server/sqlite-rollout-store.js +59 -16
- package/src/lib/auto-mode-config.js +26 -0
- package/src/lib/causal-observability.js +13 -1
- package/src/lib/context-memory-kernel/authority.js +95 -0
- package/src/lib/context-memory-kernel/durable-memory-port.js +296 -0
- package/src/lib/context-memory-kernel/index.js +8 -0
- package/src/lib/context-memory-kernel/jsonl-session-context-port.js +232 -0
- package/src/lib/context-memory-kernel/live-compaction.js +375 -0
- package/src/lib/context-memory-kernel/memory-service.js +667 -0
- package/src/lib/context-memory-kernel/message-adapter.js +451 -0
- package/src/lib/context-memory-kernel/privacy-purge-port.js +244 -0
- package/src/lib/context-memory-kernel/provider-context.js +192 -0
- package/src/lib/context-memory-kernel/runtime.js +61 -0
- package/src/lib/direct-model-usage.js +22 -18
- package/src/lib/graph-kernel/cutover-authority-resolver.js +4 -5
- package/src/lib/graph-kernel/cutover-ledger.js +2 -2
- package/src/lib/graph-kernel/event-store.js +3 -5
- package/src/lib/graph-kernel/index.js +2 -0
- package/src/lib/graph-kernel/migration-saga.js +2 -2
- package/src/lib/graph-kernel/production-cutover-evidence.js +976 -0
- package/src/lib/graph-kernel/retirement-evidence.js +12 -4
- package/src/lib/hierarchical-memory.js +22 -0
- package/src/lib/hook-audit-store.js +170 -0
- package/src/lib/hook-event-bus.cjs +0 -0
- package/src/lib/hook-manager.js +25 -83
- package/src/lib/hook-runtime-adapters.js +233 -0
- package/src/lib/hook-runtime-contract.cjs +291 -0
- package/src/lib/hook-runtime-contract.js +21 -0
- package/src/lib/hook-trust.js +210 -0
- package/src/lib/hooks-v2-producers.js +52 -6
- package/src/lib/hooks-v2-runtime.js +443 -178
- package/src/lib/llm-pricing.js +10 -0
- package/src/lib/memory-manager.js +29 -4
- package/src/lib/model-context-window.js +52 -0
- package/src/lib/permanent-memory.js +17 -0
- package/src/lib/plan-mode.js +8 -4
- package/src/lib/process-execution-broker/index.js +208 -16
- package/src/lib/runtime-usage-ledger.js +20 -0
- package/src/lib/session-consolidator.js +59 -0
- package/src/lib/session-core-singletons.js +17 -4
- package/src/lib/session-hooks.js +29 -2
- package/src/lib/session-transcript-migration.js +188 -0
- package/src/lib/settings-hook-events.cjs +37 -401
- package/src/lib/settings-hook-events.js +210 -8
- package/src/lib/settings-hooks.cjs +42 -83
- package/src/lib/ws-session-manager.js +4 -1
- package/src/repl/agent-repl.js +186 -53
- package/src/runtime/agent-core.js +376 -350
- package/src/runtime/headless-runner.js +40 -33
- package/src/runtime/headless-stream.js +131 -30
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DaiA6CsX.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-B05DgASC.js +0 -1
- package/src/assets/web-panel/assets/Projects-Z2Orm8Ma.js +0 -1
- package/src/assets/web-panel/assets/devWarning-Cq6lSd_q.js +0 -1
- package/src/assets/web-panel/assets/index-BQ3213fz.js +0 -1
- package/src/assets/web-panel/assets/index-vJagfET2.js +0 -1
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import { BoundedAsyncQueue, QueueOverloadedError } from "./bounded-queue.js";
|
|
3
3
|
import { CliAgentKernelAdapter } from "./cli-agent-kernel-adapter.js";
|
|
4
|
-
import {
|
|
4
|
+
import { assertRolloutStore } from "./rollout-store.js";
|
|
5
|
+
import {
|
|
6
|
+
closeRolloutStore,
|
|
7
|
+
createRolloutStore,
|
|
8
|
+
} from "./rollout-store-factory.js";
|
|
5
9
|
import { AppServerGraphRuntime } from "./graph-runtime.js";
|
|
6
10
|
import { compileGraphDefinition } from "../graph-kernel/compiler.js";
|
|
11
|
+
import { createCliContextMemoryRuntime } from "../context-memory-kernel/runtime.js";
|
|
12
|
+
import {
|
|
13
|
+
contextPlanCreatedNotification,
|
|
14
|
+
memoryDeletionNotification,
|
|
15
|
+
memoryMutationNotification,
|
|
16
|
+
memoryRecalledNotification,
|
|
17
|
+
} from "./context-memory-notifications.js";
|
|
7
18
|
import {
|
|
8
19
|
APP_SERVER_MIN_PROTOCOL_VERSION,
|
|
9
20
|
APP_SERVER_PROTOCOL_VERSION,
|
|
@@ -19,7 +30,6 @@ import {
|
|
|
19
30
|
} from "./protocol.js";
|
|
20
31
|
|
|
21
32
|
const TERMINAL_TURN_STATUSES = new Set(["completed", "failed", "interrupted"]);
|
|
22
|
-
|
|
23
33
|
function stableValue(value) {
|
|
24
34
|
if (Array.isArray(value)) return value.map(stableValue);
|
|
25
35
|
if (!value || typeof value !== "object") return value;
|
|
@@ -96,13 +106,34 @@ function publicError(error) {
|
|
|
96
106
|
) {
|
|
97
107
|
return new JsonRpcError(JSON_RPC_ERROR.CONFLICT, error.message);
|
|
98
108
|
}
|
|
109
|
+
if (error?.code === "invalid_argument") {
|
|
110
|
+
return new JsonRpcError(
|
|
111
|
+
JSON_RPC_ERROR.INVALID_PARAMS,
|
|
112
|
+
error.message,
|
|
113
|
+
error.details || null,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
if (
|
|
117
|
+
[
|
|
118
|
+
"revision_conflict",
|
|
119
|
+
"legacy_writer_fenced",
|
|
120
|
+
"scope_denied",
|
|
121
|
+
"replica_tombstone_fenced",
|
|
122
|
+
].includes(error?.code)
|
|
123
|
+
) {
|
|
124
|
+
return new JsonRpcError(
|
|
125
|
+
JSON_RPC_ERROR.CONFLICT,
|
|
126
|
+
error.message,
|
|
127
|
+
error.details || null,
|
|
128
|
+
);
|
|
129
|
+
}
|
|
99
130
|
return error;
|
|
100
131
|
}
|
|
101
132
|
|
|
102
133
|
export class CcAppServer {
|
|
103
134
|
constructor({
|
|
104
135
|
send,
|
|
105
|
-
store =
|
|
136
|
+
store = null,
|
|
106
137
|
kernel = new CliAgentKernelAdapter(),
|
|
107
138
|
now = Date.now,
|
|
108
139
|
createId = randomUUID,
|
|
@@ -113,22 +144,31 @@ export class CcAppServer {
|
|
|
113
144
|
interruptSettlementMs = 30_000,
|
|
114
145
|
transport = "stdio",
|
|
115
146
|
graphRuntime = null,
|
|
147
|
+
contextMemoryRuntimeFactory = createCliContextMemoryRuntime,
|
|
116
148
|
} = {}) {
|
|
117
149
|
if (typeof send !== "function") {
|
|
118
150
|
throw new TypeError("CcAppServer requires a send(message) function");
|
|
119
151
|
}
|
|
152
|
+
const resolvedStore = assertRolloutStore(store || createRolloutStore(), {
|
|
153
|
+
requireList: true,
|
|
154
|
+
});
|
|
120
155
|
this.send = send;
|
|
121
|
-
this.store =
|
|
156
|
+
this.store = resolvedStore;
|
|
157
|
+
this._ownsStore = store == null;
|
|
122
158
|
this.kernel = kernel;
|
|
123
159
|
this.now = now;
|
|
124
160
|
this.createId = createId;
|
|
125
161
|
this.requestTimeoutMs = requestTimeoutMs;
|
|
126
162
|
this.interruptSettlementMs = interruptSettlementMs;
|
|
127
163
|
this.transport = transport === "websocket" ? "websocket" : "stdio";
|
|
164
|
+
if (typeof contextMemoryRuntimeFactory !== "function") {
|
|
165
|
+
throw new TypeError("contextMemoryRuntimeFactory must be a function");
|
|
166
|
+
}
|
|
167
|
+
this.contextMemoryRuntimeFactory = contextMemoryRuntimeFactory;
|
|
128
168
|
this.graphRuntime =
|
|
129
169
|
graphRuntime ||
|
|
130
170
|
new AppServerGraphRuntime({
|
|
131
|
-
rolloutStore:
|
|
171
|
+
rolloutStore: resolvedStore,
|
|
132
172
|
now,
|
|
133
173
|
createId,
|
|
134
174
|
executeNode: (context) => this._executeGraphNode(context),
|
|
@@ -299,6 +339,13 @@ export class CcAppServer {
|
|
|
299
339
|
"graph/history": () => this._graphHistory(message.params),
|
|
300
340
|
"graph/cancel": () => this._graphCancel(message.params),
|
|
301
341
|
"graph/reconcile": () => this._graphReconcile(message.params),
|
|
342
|
+
"context/plan": () => this._contextPlan(message.params),
|
|
343
|
+
"context/compact": () => this._contextCompact(message.params),
|
|
344
|
+
"memory/recall": () => this._memoryRecall(message.params),
|
|
345
|
+
"memory/propose": () => this._memoryPropose(message.params),
|
|
346
|
+
"memory/decide": () => this._memoryDecide(message.params),
|
|
347
|
+
"memory/delete": () => this._memoryDelete(message.params),
|
|
348
|
+
"memory/reconcile": () => this._memoryReconcile(message.params),
|
|
302
349
|
};
|
|
303
350
|
const handler = handlers[method];
|
|
304
351
|
if (!handler) {
|
|
@@ -353,6 +400,132 @@ export class CcAppServer {
|
|
|
353
400
|
});
|
|
354
401
|
}
|
|
355
402
|
|
|
403
|
+
_contextMemoryRuntime(options = {}) {
|
|
404
|
+
const runtime = this.contextMemoryRuntimeFactory(options);
|
|
405
|
+
if (!runtime?.kernel) {
|
|
406
|
+
throw new Error("Context/Memory runtime factory returned no kernel");
|
|
407
|
+
}
|
|
408
|
+
return runtime;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
async _contextPlan(rawParams) {
|
|
412
|
+
const params = requireObject(rawParams);
|
|
413
|
+
const runtime = this._contextMemoryRuntime({
|
|
414
|
+
scopeKey: `app-server:context:${params.sessionHead || "plan"}`,
|
|
415
|
+
});
|
|
416
|
+
try {
|
|
417
|
+
const plan = await runtime.kernel.planContext(params);
|
|
418
|
+
const notification = contextPlanCreatedNotification(plan);
|
|
419
|
+
await this._notify(notification.method, notification.params);
|
|
420
|
+
return plan;
|
|
421
|
+
} catch (error) {
|
|
422
|
+
await this._notify("context/event", {
|
|
423
|
+
type: "context.plan.rejected",
|
|
424
|
+
reason_code: safeId(error?.code, "context_plan_failed"),
|
|
425
|
+
});
|
|
426
|
+
throw error;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
async _contextCompact(rawParams) {
|
|
431
|
+
const params = requireObject(rawParams);
|
|
432
|
+
const sessionId = requiredString(params.sessionId, "sessionId");
|
|
433
|
+
const operationId = requiredString(params.operationId, "operationId");
|
|
434
|
+
const runtime = this._contextMemoryRuntime({ sessionId });
|
|
435
|
+
await this._notify("context/event", {
|
|
436
|
+
type: "context.compaction.started",
|
|
437
|
+
operation_id: operationId,
|
|
438
|
+
session_id: sessionId,
|
|
439
|
+
});
|
|
440
|
+
try {
|
|
441
|
+
const receipt = await runtime.kernel.compactContext(params);
|
|
442
|
+
const type =
|
|
443
|
+
receipt.status === "reconciliation_required"
|
|
444
|
+
? "context.compaction.reconciliation_required"
|
|
445
|
+
: ["committed", "degraded"].includes(receipt.status)
|
|
446
|
+
? "context.compaction.committed"
|
|
447
|
+
: "context.compaction.aborted";
|
|
448
|
+
await this._notify("context/event", {
|
|
449
|
+
type,
|
|
450
|
+
operation_id: operationId,
|
|
451
|
+
session_id: sessionId,
|
|
452
|
+
...(type === "context.compaction.aborted"
|
|
453
|
+
? { reason_code: safeId(receipt.status, "compaction_aborted") }
|
|
454
|
+
: { receipt }),
|
|
455
|
+
});
|
|
456
|
+
return receipt;
|
|
457
|
+
} catch (error) {
|
|
458
|
+
await this._notify("context/event", {
|
|
459
|
+
type: "context.compaction.aborted",
|
|
460
|
+
operation_id: operationId,
|
|
461
|
+
session_id: sessionId,
|
|
462
|
+
reason_code: safeId(error?.code, "compaction_failed"),
|
|
463
|
+
});
|
|
464
|
+
throw error;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
async _memoryRecall(rawParams) {
|
|
469
|
+
const params = requireObject(rawParams);
|
|
470
|
+
const runtime = this._contextMemoryRuntime({
|
|
471
|
+
scopeKey: "app-server:memory",
|
|
472
|
+
});
|
|
473
|
+
const result = await runtime.kernel.recallMemory(params);
|
|
474
|
+
const notification = memoryRecalledNotification(result);
|
|
475
|
+
await this._notify(notification.method, notification.params);
|
|
476
|
+
return result;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
async _memoryPropose(rawParams) {
|
|
480
|
+
const params = requireObject(rawParams);
|
|
481
|
+
const runtime = this._contextMemoryRuntime({
|
|
482
|
+
scopeKey: "app-server:memory",
|
|
483
|
+
});
|
|
484
|
+
const mutation = await runtime.kernel.proposeMemory(params);
|
|
485
|
+
await this._notifyMemoryMutation(mutation);
|
|
486
|
+
return mutation;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
async _memoryDecide(rawParams) {
|
|
490
|
+
const params = requireObject(rawParams);
|
|
491
|
+
const runtime = this._contextMemoryRuntime({
|
|
492
|
+
scopeKey: "app-server:memory",
|
|
493
|
+
});
|
|
494
|
+
const mutation = await runtime.kernel.decideMemory(params);
|
|
495
|
+
await this._notifyMemoryMutation(mutation);
|
|
496
|
+
return mutation;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
async _notifyMemoryMutation(mutation) {
|
|
500
|
+
const notification = memoryMutationNotification(mutation);
|
|
501
|
+
if (!notification) return;
|
|
502
|
+
await this._notify(notification.method, notification.params);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
async _memoryDelete(rawParams) {
|
|
506
|
+
const params = requireObject(rawParams);
|
|
507
|
+
const runtime = this._contextMemoryRuntime({
|
|
508
|
+
scopeKey: "app-server:memory",
|
|
509
|
+
});
|
|
510
|
+
const receipt = await runtime.kernel.deleteMemory(params);
|
|
511
|
+
const notification = memoryDeletionNotification(receipt);
|
|
512
|
+
await this._notify(notification.method, notification.params);
|
|
513
|
+
return receipt;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
async _memoryReconcile(rawParams) {
|
|
517
|
+
const params = requireObject(rawParams);
|
|
518
|
+
const operationId = requiredString(params.operationId, "operationId");
|
|
519
|
+
const runtime = this._contextMemoryRuntime({
|
|
520
|
+
scopeKey: "app-server:memory",
|
|
521
|
+
});
|
|
522
|
+
const result = await runtime.kernel.reconcile(operationId);
|
|
523
|
+
const notification = memoryDeletionNotification(result, operationId);
|
|
524
|
+
if (notification)
|
|
525
|
+
await this._notify(notification.method, notification.params);
|
|
526
|
+
return result;
|
|
527
|
+
}
|
|
528
|
+
|
|
356
529
|
_graphCompile(rawParams) {
|
|
357
530
|
const params = requireObject(rawParams);
|
|
358
531
|
const compiled = compileGraphDefinition(
|
|
@@ -1115,7 +1288,11 @@ export class CcAppServer {
|
|
|
1115
1288
|
);
|
|
1116
1289
|
}
|
|
1117
1290
|
this.pendingClientRequests.clear();
|
|
1118
|
-
|
|
1119
|
-
|
|
1291
|
+
try {
|
|
1292
|
+
await this.kernel.close?.();
|
|
1293
|
+
await Promise.all(this.workers);
|
|
1294
|
+
} finally {
|
|
1295
|
+
if (this._ownsStore) closeRolloutStore(this.store);
|
|
1296
|
+
}
|
|
1120
1297
|
}
|
|
1121
1298
|
}
|
|
@@ -6,17 +6,32 @@ import { createRequire } from "node:module";
|
|
|
6
6
|
import {
|
|
7
7
|
ROLLOUT_STORE_SCHEMA,
|
|
8
8
|
ROLLOUT_STORE_VERSION,
|
|
9
|
+
migrateRolloutStore,
|
|
9
10
|
_rolloutStoreInternals,
|
|
10
11
|
} from "./rollout-store.js";
|
|
11
12
|
|
|
12
|
-
const {
|
|
13
|
-
|
|
13
|
+
const {
|
|
14
|
+
assertExpectedHead,
|
|
15
|
+
buildRecord,
|
|
16
|
+
canonicalJson,
|
|
17
|
+
projectThread,
|
|
18
|
+
startPayload,
|
|
19
|
+
verifyRecords,
|
|
20
|
+
} = _rolloutStoreInternals;
|
|
14
21
|
|
|
15
22
|
let DatabaseSync = null;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
let sqliteProbed = false;
|
|
24
|
+
|
|
25
|
+
function loadDatabaseSync() {
|
|
26
|
+
if (!sqliteProbed) {
|
|
27
|
+
sqliteProbed = true;
|
|
28
|
+
try {
|
|
29
|
+
({ DatabaseSync } = createRequire(import.meta.url)("node:sqlite"));
|
|
30
|
+
} catch {
|
|
31
|
+
// node:sqlite is optional on the minimum supported Node 22.12 runtime.
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return DatabaseSync;
|
|
20
35
|
}
|
|
21
36
|
|
|
22
37
|
function sqliteError(code, message, cause = null) {
|
|
@@ -40,7 +55,7 @@ function recordThreadId(input) {
|
|
|
40
55
|
}
|
|
41
56
|
|
|
42
57
|
export function sqliteRolloutStoreAvailable() {
|
|
43
|
-
return typeof
|
|
58
|
+
return typeof loadDatabaseSync() === "function";
|
|
44
59
|
}
|
|
45
60
|
|
|
46
61
|
export class SqliteRolloutStore {
|
|
@@ -50,13 +65,14 @@ export class SqliteRolloutStore {
|
|
|
50
65
|
if (this.filename !== ":memory:") {
|
|
51
66
|
fs.mkdirSync(path.dirname(this.filename), { recursive: true });
|
|
52
67
|
}
|
|
53
|
-
|
|
68
|
+
const SqliteDatabase = database ? null : loadDatabaseSync();
|
|
69
|
+
if (!database && typeof SqliteDatabase !== "function") {
|
|
54
70
|
throw sqliteError(
|
|
55
71
|
"CC_ROLLOUT_SQLITE_UNAVAILABLE",
|
|
56
72
|
"SQLite rollout storage requires a Node runtime with node:sqlite",
|
|
57
73
|
);
|
|
58
74
|
}
|
|
59
|
-
this.db = database || new
|
|
75
|
+
this.db = database || new SqliteDatabase(this.filename);
|
|
60
76
|
this.db.exec("PRAGMA journal_mode = WAL");
|
|
61
77
|
this.db.exec("PRAGMA synchronous = FULL");
|
|
62
78
|
this.db.exec("PRAGMA foreign_keys = ON");
|
|
@@ -148,6 +164,7 @@ export class SqliteRolloutStore {
|
|
|
148
164
|
title = null,
|
|
149
165
|
parentThreadId = null,
|
|
150
166
|
metadata = {},
|
|
167
|
+
timestamp: startedAt = null,
|
|
151
168
|
} = {}) {
|
|
152
169
|
const id = recordThreadId(threadId);
|
|
153
170
|
return this._transaction(() => {
|
|
@@ -158,7 +175,8 @@ export class SqliteRolloutStore {
|
|
|
158
175
|
threadId: id,
|
|
159
176
|
eventType: "thread.started",
|
|
160
177
|
idempotencyKey: `thread:${id}`,
|
|
161
|
-
|
|
178
|
+
timestamp: startedAt || undefined,
|
|
179
|
+
payload: startPayload({ title, parentThreadId, metadata }),
|
|
162
180
|
},
|
|
163
181
|
null,
|
|
164
182
|
this.now,
|
|
@@ -199,6 +217,7 @@ export class SqliteRolloutStore {
|
|
|
199
217
|
}
|
|
200
218
|
return clone(duplicate);
|
|
201
219
|
}
|
|
220
|
+
assertExpectedHead(input, records);
|
|
202
221
|
const record = buildRecord(input, records.at(-1), this.now);
|
|
203
222
|
this.db
|
|
204
223
|
.prepare(
|
|
@@ -237,7 +256,7 @@ export class SqliteRolloutStore {
|
|
|
237
256
|
.map((threadId) => this.resume(threadId))
|
|
238
257
|
.filter((thread) => includeArchived || thread.status !== "archived")
|
|
239
258
|
.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt))
|
|
240
|
-
.slice(0, Math.max(1, Number(limit) || 100));
|
|
259
|
+
.slice(0, Math.max(1, Math.min(100_000, Number(limit) || 100)));
|
|
241
260
|
}
|
|
242
261
|
|
|
243
262
|
forkThread(sourceThreadId, { threadId = randomUUID(), title = null } = {}) {
|
|
@@ -261,6 +280,10 @@ export class SqliteRolloutStore {
|
|
|
261
280
|
return this.resume(target.id);
|
|
262
281
|
}
|
|
263
282
|
|
|
283
|
+
fork(sourceThreadId, options = {}) {
|
|
284
|
+
return this.forkThread(sourceThreadId, options);
|
|
285
|
+
}
|
|
286
|
+
|
|
264
287
|
checkpoint(threadId, payload = {}) {
|
|
265
288
|
return this.append({
|
|
266
289
|
threadId,
|
|
@@ -271,13 +294,19 @@ export class SqliteRolloutStore {
|
|
|
271
294
|
}
|
|
272
295
|
|
|
273
296
|
compact(threadId, options = {}) {
|
|
297
|
+
if (typeof options.summary !== "string" || !options.summary.trim()) {
|
|
298
|
+
throw sqliteError(
|
|
299
|
+
"CC_ROLLOUT_INVALID_ARGUMENT",
|
|
300
|
+
"compaction summary is required",
|
|
301
|
+
);
|
|
302
|
+
}
|
|
274
303
|
return this.append({
|
|
275
304
|
threadId,
|
|
276
305
|
eventType: "rollout.compacted",
|
|
277
306
|
idempotencyKey: options.idempotencyKey || null,
|
|
278
307
|
payload: {
|
|
279
|
-
summary:
|
|
280
|
-
retainedState: options.retainedState
|
|
308
|
+
summary: options.summary,
|
|
309
|
+
retainedState: options.retainedState ?? {},
|
|
281
310
|
},
|
|
282
311
|
});
|
|
283
312
|
}
|
|
@@ -292,11 +321,25 @@ export class SqliteRolloutStore {
|
|
|
292
321
|
return this.resume(threadId);
|
|
293
322
|
}
|
|
294
323
|
|
|
295
|
-
migrate({
|
|
324
|
+
migrate({
|
|
325
|
+
fromVersion = 1,
|
|
326
|
+
toVersion = 1,
|
|
327
|
+
dryRun = true,
|
|
328
|
+
targetStore = null,
|
|
329
|
+
threadIds = null,
|
|
330
|
+
} = {}) {
|
|
331
|
+
if (targetStore) {
|
|
332
|
+
return migrateRolloutStore({
|
|
333
|
+
sourceStore: this,
|
|
334
|
+
targetStore,
|
|
335
|
+
threadIds,
|
|
336
|
+
dryRun,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
296
339
|
if (Number(fromVersion) !== 1 || Number(toVersion) !== 1) {
|
|
297
340
|
throw sqliteError(
|
|
298
|
-
"
|
|
299
|
-
|
|
341
|
+
"CC_ROLLOUT_MIGRATION_UNSUPPORTED",
|
|
342
|
+
`rollout migration ${fromVersion} -> ${toVersion} is unsupported`,
|
|
300
343
|
);
|
|
301
344
|
}
|
|
302
345
|
return Object.freeze({
|
|
@@ -321,6 +321,12 @@ export function createAutoModeApprovalGate(inner, resolved, opts = {}) {
|
|
|
321
321
|
clearSessionPolicy(sessionId) {
|
|
322
322
|
return inner?.clearSessionPolicy?.(sessionId);
|
|
323
323
|
},
|
|
324
|
+
awaitPersistence() {
|
|
325
|
+
return inner?.awaitPersistence?.();
|
|
326
|
+
},
|
|
327
|
+
hasPolicyStore() {
|
|
328
|
+
return inner?.hasPolicyStore?.() === true;
|
|
329
|
+
},
|
|
324
330
|
setConfirmer(fn) {
|
|
325
331
|
confirm = typeof fn === "function" ? fn : null;
|
|
326
332
|
inner?.setConfirmer?.(fn);
|
|
@@ -360,6 +366,26 @@ export function createAutoModeApprovalGate(inner, resolved, opts = {}) {
|
|
|
360
366
|
return inner?.createAuthorizationBinder?.() || null;
|
|
361
367
|
},
|
|
362
368
|
async decide(ctx = {}) {
|
|
369
|
+
const shouldCheckPersistence =
|
|
370
|
+
typeof inner?.awaitPersistence === "function" &&
|
|
371
|
+
(typeof inner?.hasPolicyStore !== "function" ||
|
|
372
|
+
inner.hasPolicyStore() === true);
|
|
373
|
+
if (shouldCheckPersistence) {
|
|
374
|
+
try {
|
|
375
|
+
await inner.awaitPersistence();
|
|
376
|
+
} catch (error) {
|
|
377
|
+
return {
|
|
378
|
+
decision: "deny",
|
|
379
|
+
via: "policy-store-error",
|
|
380
|
+
base: "deny",
|
|
381
|
+
policy: "auto-mode",
|
|
382
|
+
riskLevel: RISK_LEVELS.includes(ctx.riskLevel)
|
|
383
|
+
? ctx.riskLevel
|
|
384
|
+
: "low",
|
|
385
|
+
error,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
}
|
|
363
389
|
if (!isActive()) return inner.decide(ctx);
|
|
364
390
|
const riskLevel = RISK_LEVELS.includes(ctx.riskLevel)
|
|
365
391
|
? ctx.riskLevel
|
|
@@ -532,6 +532,11 @@ function modelUsageBoundaryIdentity(data, field) {
|
|
|
532
532
|
),
|
|
533
533
|
model: boundedLabel(data.model, `${field} model`, MAX_MODEL_LENGTH),
|
|
534
534
|
source: normalizedUsageSource(data.source, `${field} source`),
|
|
535
|
+
operationId: boundedLabel(
|
|
536
|
+
data.operationId,
|
|
537
|
+
`${field} operationId`,
|
|
538
|
+
MAX_ID_LENGTH,
|
|
539
|
+
),
|
|
535
540
|
};
|
|
536
541
|
}
|
|
537
542
|
|
|
@@ -539,7 +544,8 @@ function sameModelUsageIdentity(left, right) {
|
|
|
539
544
|
return (
|
|
540
545
|
left.provider === right.provider &&
|
|
541
546
|
left.model === right.model &&
|
|
542
|
-
left.source === right.source
|
|
547
|
+
left.source === right.source &&
|
|
548
|
+
left.operationId === right.operationId
|
|
543
549
|
);
|
|
544
550
|
}
|
|
545
551
|
|
|
@@ -641,6 +647,11 @@ function strictUsage(event) {
|
|
|
641
647
|
}
|
|
642
648
|
return {
|
|
643
649
|
callId,
|
|
650
|
+
operationId: boundedLabel(
|
|
651
|
+
data.operationId,
|
|
652
|
+
"session usage operationId",
|
|
653
|
+
MAX_ID_LENGTH,
|
|
654
|
+
),
|
|
644
655
|
provider: usageIdentity(
|
|
645
656
|
data,
|
|
646
657
|
raw,
|
|
@@ -1047,6 +1058,7 @@ export function createVerifiedSessionObservabilityProjection(
|
|
|
1047
1058
|
provider: usage.provider,
|
|
1048
1059
|
model: usage.model,
|
|
1049
1060
|
source: usage.source,
|
|
1061
|
+
operationId: usage.operationId,
|
|
1050
1062
|
};
|
|
1051
1063
|
if (previous && !sameModelUsageIdentity(previous, identity)) {
|
|
1052
1064
|
throw new Error(
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
ContextMemoryAuthorityRegistry,
|
|
4
|
+
CUTOVER_STAGES,
|
|
5
|
+
} from "@chainlesschain/context-memory-kernel";
|
|
6
|
+
|
|
7
|
+
const STAGE_ENV = "CHAINLESSCHAIN_CONTEXT_MEMORY_CLI_STAGE";
|
|
8
|
+
const OPT_IN_ENV = "CHAINLESSCHAIN_CONTEXT_MEMORY_CLI_OPT_IN";
|
|
9
|
+
const CANARY_PERCENT_ENV = "CHAINLESSCHAIN_CONTEXT_MEMORY_CLI_CANARY_PERCENT";
|
|
10
|
+
|
|
11
|
+
function boundedPercent(value, fallback) {
|
|
12
|
+
const parsed = Number(value);
|
|
13
|
+
if (!Number.isFinite(parsed)) return fallback;
|
|
14
|
+
return Math.max(0, Math.min(100, parsed));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function cohortBucket(scopeKey) {
|
|
18
|
+
const digest = createHash("sha256").update(scopeKey).digest();
|
|
19
|
+
return digest.readUInt32BE(0) % 10_000;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function resolveCliContextMemoryCutover({
|
|
23
|
+
env = process.env,
|
|
24
|
+
scopeKey = "cli:global",
|
|
25
|
+
} = {}) {
|
|
26
|
+
const stage = env[STAGE_ENV] || "shadow";
|
|
27
|
+
if (!CUTOVER_STAGES.includes(stage)) {
|
|
28
|
+
const error = new Error(`Unsupported CLI Context/Memory stage: ${stage}`);
|
|
29
|
+
error.code = "CONTEXT_MEMORY_STAGE_INVALID";
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
let canonical = false;
|
|
33
|
+
let reason = stage;
|
|
34
|
+
if (stage === "internal_canary") {
|
|
35
|
+
const percent = boundedPercent(env[CANARY_PERCENT_ENV], 1);
|
|
36
|
+
canonical = cohortBucket(scopeKey) < percent * 100;
|
|
37
|
+
reason = canonical ? "internal_canary_selected" : "internal_canary_control";
|
|
38
|
+
} else if (stage === "opt_in_canary") {
|
|
39
|
+
canonical = env[OPT_IN_ENV] === "1";
|
|
40
|
+
reason = canonical ? "explicit_opt_in" : "not_opted_in";
|
|
41
|
+
} else if (
|
|
42
|
+
["canonical_default", "legacy_read_only", "retired"].includes(stage)
|
|
43
|
+
) {
|
|
44
|
+
canonical = true;
|
|
45
|
+
}
|
|
46
|
+
return Object.freeze({
|
|
47
|
+
stage,
|
|
48
|
+
scopeKey,
|
|
49
|
+
mode: canonical ? "canonical" : "legacy",
|
|
50
|
+
canonical,
|
|
51
|
+
shadow: stage === "shadow",
|
|
52
|
+
// A selected canonical cohort must never run a second legacy writer. This
|
|
53
|
+
// also covers canonical_default; legacy_read_only/retired only tighten the
|
|
54
|
+
// corresponding read capability.
|
|
55
|
+
legacyWritable: !canonical,
|
|
56
|
+
legacyReadable: stage !== "retired",
|
|
57
|
+
reason,
|
|
58
|
+
cohortBucket: cohortBucket(scopeKey),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function createCliAuthority({ decision, now = Date.now } = {}) {
|
|
63
|
+
if (!decision?.canonical) return { registry: null, writer: null };
|
|
64
|
+
const registry = new ContextMemoryAuthorityRegistry({ clock: now });
|
|
65
|
+
const writer = Object.freeze({
|
|
66
|
+
scopeKey: decision.scopeKey,
|
|
67
|
+
surface: "cli",
|
|
68
|
+
mode: "canonical",
|
|
69
|
+
writerId: "cli-context-memory-kernel",
|
|
70
|
+
generation: 1,
|
|
71
|
+
});
|
|
72
|
+
registry.bind({
|
|
73
|
+
...writer,
|
|
74
|
+
stage: decision.stage,
|
|
75
|
+
leaseExpiresAt: new Date(Number(now()) + 5 * 60_000).toISOString(),
|
|
76
|
+
});
|
|
77
|
+
registry.assertWriter(writer);
|
|
78
|
+
return { registry, writer };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function assertLegacyMutationAllowed(decision) {
|
|
82
|
+
if (decision?.legacyWritable) return;
|
|
83
|
+
const error = new Error(
|
|
84
|
+
`Legacy CLI Context/Memory mutations are fenced at ${decision?.stage || "unknown"}`,
|
|
85
|
+
);
|
|
86
|
+
error.code = "legacy_writer_fenced";
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export {
|
|
91
|
+
CANARY_PERCENT_ENV,
|
|
92
|
+
OPT_IN_ENV,
|
|
93
|
+
STAGE_ENV,
|
|
94
|
+
cohortBucket,
|
|
95
|
+
};
|