chainlesschain 0.166.34 → 0.166.37
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 +2 -2
- package/src/assets/web-panel/assets/{AIOps-D8PJmSrh.js → AIOps-B_Nt1Qe4.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DG6DqHA3.js → ActionButton-CHQbie4X.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DiLleeWs.js → Analytics-Bm9364Lw.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DxYkhlHK.js → AppLayout-DTwlIh2v.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-BAW3Kdsi.js → Artifacts-OibP0qB4.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DBr4uY6E.js → Audit-B8Fwavkg.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-Dw0r-bHX.js → BackgroundAgents-p1Vb2K2B.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-AyhwYsio.js → Backup-BI3QT-wI.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Cj8qJotr.js → BaseInput-BW_VRWWu.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-DcvimQ0u.js → Chat-CUEhDQfq.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer--joJ1e2f.js → ChatBubbleRenderer-C5UVXdVE.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-C2mlU77l.js → Checkbox-URYsaaxv.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CAfc3YaV.js → Codegen-DJAwC80a.js} +1 -1
- package/src/assets/web-panel/assets/{Col-CIxoxtJI.js → Col-DfRKFzc9.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DvufZoRg.js → Community-GOkGHuly.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-55JTa99J.js → Compact-CIMs13NC.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BllWog6P.js → Compliance-BE-TQIxV.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-ThsFGc5p.js → Cowork-CYmbJiWw.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-CZjl5Ig2.js → Cron-Be3OIWyM.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-DIAKAoQT.js → Crosschain-2xB2HS2D.js} +1 -1
- package/src/assets/web-panel/assets/{DID-ayygwEil.js → DID-B_lJO2yF.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-C3Xjm2UO.js → Dashboard-DnVWqUER.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-C1S3zf-j.js → Dropdown-C7ZJvHVa.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DRvriU-H.js → EmailListRenderer-DLevT-0F.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-iSX2bmsD.js → FamilyGuardDashboard-BwhQ5BRU.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-Dk0Stkv-.js → Federation-BkGI-Xkq.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DasXSGff.js → FormItemContext-BgIIbMd7.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-Dv9XGlxI.js → GenericCardRenderer-qL-qN8Nb.js} +1 -1
- package/src/assets/web-panel/assets/{Git-B5PgXL3Z.js → Git-BTzgrC4U.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-B78x11e_.js → Governance-p28vdCN4.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-b7CX1RqW.js → Inference-Cqephrur.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph--MgBzMVp.js → KnowledgeGraph-C3v5Q4Zp.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CYCiGmVc.js → Logs-T6f0w32w.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-yrl10SWw.js → MarkdownRenderer-Dj5XPm3S.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-CsbwQ0eM.js → Marketplace-ClDsvHDH.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-0GBWHVra.js → McpTools-C4P-_snx.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-fAywmAYr.js → Memory-BZZfG6y6.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BeNEyy3s.js → MobileBridge-DpIv_BLs.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-Buz3NIQg.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-CqRhJB70.js → Mtc-HS2PJB79.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-BEyGZflc.js → MtcAudit-UmBrcU27.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-luz3EBT2.js → Multisig-C00sXiZf.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Dkbvp8IX.js → NLProgramming-Dj1ng_ph.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Cf9I2K8j.js → Notes-C4LEVKlk.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-BTfuzynL.js → NotificationSettings-BWXwnekv.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-CZHfK8Nn.js +1 -0
- package/src/assets/web-panel/assets/{Organization-BbG3-vDy.js → Organization-CFEtFPrV.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CMtFKEIQ.js → Overflow-DSz4MJK1.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-6SAEb_lU.js → P2P-DyTEytwG.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-B5QNGLVx.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-ClZxZKZl.js → Permissions-wEC_X7x4.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BYkyoZDT.js → PersonalDataHub-If5GZlGZ.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-B28ZgADI.js → Pipeline-LB4gqqmX.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BxtZywbB.js → Privacy-QVLhoxcN.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-DPqoRnxK.js → ProjectInit-FaAbTYTo.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-QjKvMkau.js → ProjectSettings-DhMeNA21.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-Cp0Z8ZG0.js → Projects-5L4lkWAZ.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-CrS-rbyb.js → Providers-DhZFp8fO.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-xTrhbVAU.js → QrScannerModal-BZuJ7_xi.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DFOqJoq-.js → QuickAsk-TXddPYYb.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DXlKqu2-.js → Recommend-DDuXIKYt.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BLLaZH8K.js → RemoteSession-CDrTXImv.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-CUgAdJ11.js → Reputation-B2xKaKzt.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DzOO3wP-.js → Row-DzAjWAOX.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-B6GrRvh8.js → RssFeed-CKH38BLF.js} +3 -3
- package/src/assets/web-panel/assets/{Search-Cj3zKLb3.js → Search-CuPqJYoQ.js} +1 -1
- package/src/assets/web-panel/assets/{Security-LnktzidI.js → Security-DmAd2hxz.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BQ6sIc2K.js → Services-Bt3nljnY.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CCSV3Jbw.js → Skeleton-CP7RH093.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CpoQ4SNk.js → Skills-DKNeMBTx.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DbAbgRPq.js → Sla-CbpM8Nrd.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-C4cJ_hoD.js → SpeechSettings-DTk-vTzF.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BKFzjN9Z.js → SyncSettings-DKiplwmc.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-z-lOm8fx.js +1 -0
- package/src/assets/web-panel/assets/{Templates-DTEQfFAQ.js → Templates-Rb-Q0DGX.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-wToJWKXB.js → Tenant-C2sqDUnR.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-1s3c7kmF.js → Terminal-DcyzskEE.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BcfsYW3u.js → TimelineRenderer-lg0Eam7N.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Byez6FY0.js → Tokens-D9USIMIA.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Cq8mZO88.js → Trigger-BQpaQJ5k.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DUrMmEwR.js → Trust-C-Mik04s.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CVHwXrVU.js → UkeySign-DrnZ_o56.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CDKbTRUS.js → VideoEditing-BDOsoZi0.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BqnEBIOy.js → Wallet-Ct_bleI7.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CeTMpj7_.js → WebAuthn-B6b6FDao.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-F6OgjV3C.js → WorkflowEditor-ZUJMaIHr.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CMHUCwq3.js → chat-BII20OJy.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DzVM_fpJ.js → colors-DEsJRV3n.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-Hhmg51yT.js → compact-item-DoDYAzN9.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-SwHt7x3Q.js → createContext-o_nofnVW.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-0tgDCszN.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-HGNKkn9A.js → hasIn-CAsABTHC.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cc-d6f0F.js → index-B0ApxOMw.js} +1 -1
- package/src/assets/web-panel/assets/{index-E-bI8HpV.js → index-B4SfcwZA.js} +1 -1
- package/src/assets/web-panel/assets/{index-BJqNTF1S.js → index-B9Z75LfA.js} +1 -1
- package/src/assets/web-panel/assets/{index-DgoefbLs.js → index-B9hYHPhs.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDtzUt75.js → index-BDRh3v44.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_HgLPC5.js → index-BcYbQoY7.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1QJxiOL.js → index-Bmwo5wQG.js} +1 -1
- package/src/assets/web-panel/assets/{index-ChLHLBkF.js → index-Bn2ZPUXO.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5dcWBqg.js → index-BnbnmRqg.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bq9MMKno.js → index-Bqyg3PME.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ba2Kszdy.js → index-BrIIJ2s-.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDt4wSl6.js → index-BxT8yTwS.js} +1 -1
- package/src/assets/web-panel/assets/{index-COOcGOyK.js → index-Bycj011d.js} +1 -1
- package/src/assets/web-panel/assets/{index-DQT5thlV.js → index-BzMA6Ra3.js} +1 -1
- package/src/assets/web-panel/assets/{index-F7Grz3-G.js → index-C1YDdyQ1.js} +1 -1
- package/src/assets/web-panel/assets/{index-jrRtmiUh.js → index-CE2J04dA.js} +1 -1
- package/src/assets/web-panel/assets/index-CFF8XEFE.js +1 -0
- package/src/assets/web-panel/assets/{index-BDE-WiE5.js → index-CQE-WMEU.js} +1 -1
- package/src/assets/web-panel/assets/{index-B6YQN5_R.js → index-CVQSl1uY.js} +1 -1
- package/src/assets/web-panel/assets/{index-BlHB5eax.js → index-CeJSTcXw.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-YkiVyL.js → index-CeWJqXNX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRikmONJ.js → index-Cf3sFEoE.js} +1 -1
- package/src/assets/web-panel/assets/{index-MDdTkUpA.js → index-D5Fd4tdL.js} +1 -1
- package/src/assets/web-panel/assets/{index-CMG_2fK2.js → index-DDQzBK3l.js} +1 -1
- package/src/assets/web-panel/assets/{index-Co4RcBua.js → index-DQmX_-hk.js} +1 -1
- package/src/assets/web-panel/assets/{index--iOqM_AI.js → index-DRAA2McB.js} +1 -1
- package/src/assets/web-panel/assets/{index-pwLuJGFh.js → index-DU2Rpx1m.js} +1 -1
- package/src/assets/web-panel/assets/index-DVUEISry.js +1 -0
- package/src/assets/web-panel/assets/{index-AQcDW8bB.js → index-DWZNYecl.js} +3 -3
- package/src/assets/web-panel/assets/{index-oz0Xxs8D.js → index-D_CMB_wC.js} +1 -1
- package/src/assets/web-panel/assets/{index-aKV4Py_2.js → index-Dbb34cAr.js} +1 -1
- package/src/assets/web-panel/assets/{index-BstLYy9q.js → index-DciLb_Ww.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyZUrnje.js → index-Dgt1mKby.js} +1 -1
- package/src/assets/web-panel/assets/{index-sYkFp9A4.js → index-Dhnau6uw.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDhCx17_.js → index-DrsAF-Ar.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dcg7nQDe.js → index-DsoFTdA2.js} +1 -1
- package/src/assets/web-panel/assets/{index-CWkWh48N.js → index-TSwbtCYG.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cnm4zroJ.js → index-kIyLNyoF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmPYmoY3.js → index-tCeNfxv4.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-C_2QM45F.js → initDefaultProps-CNjeeoKE.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DkxY04tR.js → motion-CBT8IZDm.js} +1 -1
- package/src/assets/web-panel/assets/{move-D0CJlA7D.js → move-h1MOxjqv.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DjP38YUD.js → mtc-parser-C_3pqNmn.js} +1 -1
- package/src/assets/web-panel/assets/{omit-C9CJDaGT.js → omit-CMUnPFDk.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-D5Wq2fa8.js → pickAttrs-p8_c1xq0.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DJ6Dixs7.js → placementArrow-D6O67r23.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DMmM0Dee.js → responsiveObserve-DquhepAK.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DipmpYA-.js → slide-CZ-m6gmS.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DSqw6_nU.js → statusUtils-k9ejZFtd.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-t828MYjI.js → styleChecker-NX6_137R.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-COsSNzDQ.js → useFlexGapSupport-bCqR70lP.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-Bq5IEzv_.js → useFs-2l0vSqyY.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CUKM0HdW.js → usePersonalDataHub-1yccm4O7.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-l-JwAt2M.js → vnode-CxQzajDo.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-D7xkW-gD.js → zoom-CrTKwFyb.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/hub.js +21 -6
- package/src/commands/llm.js +4 -3
- package/src/commands/stream.js +28 -7
- package/src/commands/ui.js +10 -2
- package/src/data/changelog.json +39 -0
- package/src/gateways/ws/chat-intent-protocol.js +4 -1
- package/src/gateways/ws/llm-chat-protocol.js +29 -3
- package/src/gateways/ws/message-dispatcher.js +3 -1
- package/src/gateways/ws/personal-data-hub-protocol.js +24 -10
- package/src/gateways/ws/session-core-protocol.js +23 -6
- package/src/gateways/ws/session-protocol.js +1 -0
- package/src/lib/__tests__/provider-stream.test.js +6 -8
- package/src/lib/chat-core.js +67 -9
- package/src/lib/chat-intent-service.js +138 -39
- package/src/lib/evolution/evolution-artifact-ports.js +40 -3
- package/src/lib/evolution/evolution-deployment-loader.js +7 -1
- package/src/lib/evolution/evolution-file-identity.js +50 -0
- package/src/lib/evolution/evolution-file-witness.js +206 -91
- package/src/lib/evolution/evolution-ledger-file-backend.js +4 -0
- package/src/lib/evolution/evolution-ledger.js +37 -5
- package/src/lib/evolution/evolution-witness-segments.js +330 -0
- package/src/lib/evolution/governed-hub-llm.js +56 -0
- package/src/lib/evolution/governed-hub-resolver.js +65 -0
- package/src/lib/evolution/governed-hub-skill.js +36 -0
- package/src/lib/evolution/governed-model-turn.js +88 -0
- package/src/lib/evolution/progressive-canary-external-watchdog.js +6 -4
- package/src/lib/evolution/skill-candidate-registry.js +45 -11
- package/src/lib/evolution/skill-release-registry.js +46 -12
- package/src/lib/llm-connection-probe.js +21 -4
- package/src/lib/personal-data-hub-wiring.js +49 -0
- package/src/lib/provider-stream.js +94 -45
- package/src/lib/ws-chat-handler.js +19 -2
- package/src/assets/web-panel/assets/MobileProjects-Zt1cpErd.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-DBmCtl2H.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-CWG2OLvh.js +0 -7
- package/src/assets/web-panel/assets/Tasks-Cf4bl7NS.js +0 -1
- package/src/assets/web-panel/assets/devWarning-5q_Y0E88.js +0 -1
- package/src/assets/web-panel/assets/index-dl9TJMh5.js +0 -1
- package/src/assets/web-panel/assets/index-x0DDgUaT.js +0 -1
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { ensurePrivateDirectory } from "../secure-fs.js";
|
|
3
|
+
|
|
4
|
+
export const EVOLUTION_SEGMENTED_WITNESS_SCHEMA =
|
|
5
|
+
"chainlesschain.evolution-file-witness-store/v2";
|
|
6
|
+
const SEGMENT_SCHEMA = "chainlesschain.evolution-file-witness-segment/v1";
|
|
7
|
+
export const EVOLUTION_WITNESS_SEGMENT_RECORDS = 256;
|
|
8
|
+
const MAX_RECORDS = 262_144;
|
|
9
|
+
const MAX_SEGMENTS = MAX_RECORDS / EVOLUTION_WITNESS_SEGMENT_RECORDS;
|
|
10
|
+
const MAX_CACHE_BYTES = 16 * 1024 * 1024;
|
|
11
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
12
|
+
const HEAD_KEYS = new Set([
|
|
13
|
+
"schema",
|
|
14
|
+
"current",
|
|
15
|
+
"segments",
|
|
16
|
+
"history",
|
|
17
|
+
"discardedAnchors",
|
|
18
|
+
]);
|
|
19
|
+
const SEGMENT_KEYS = new Set(["schema", "history", "discardedAnchors"]);
|
|
20
|
+
|
|
21
|
+
function exact(value, keys, label) {
|
|
22
|
+
if (
|
|
23
|
+
!value ||
|
|
24
|
+
typeof value !== "object" ||
|
|
25
|
+
Array.isArray(value) ||
|
|
26
|
+
Object.keys(value).length !== keys.size ||
|
|
27
|
+
Object.keys(value).some((key) => !keys.has(key))
|
|
28
|
+
) {
|
|
29
|
+
throw new Error(`${label} fields are invalid`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function matchesDiscard(entry, snapshot) {
|
|
34
|
+
return (
|
|
35
|
+
snapshot &&
|
|
36
|
+
(entry.anchorDigest === snapshot.anchorDigest ||
|
|
37
|
+
entry.headDigest === snapshot.headDigest ||
|
|
38
|
+
entry.segmentDigest === snapshot.segmentDigest)
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Internal storage adapter. Record signatures and trust policy stay with the witness. */
|
|
43
|
+
export function createEvolutionWitnessSegments({
|
|
44
|
+
filePath,
|
|
45
|
+
fsImpl,
|
|
46
|
+
readBytes,
|
|
47
|
+
writeBytes,
|
|
48
|
+
confirmDurable,
|
|
49
|
+
validateStore,
|
|
50
|
+
legacySchema,
|
|
51
|
+
canonical,
|
|
52
|
+
hash,
|
|
53
|
+
encodeRecord,
|
|
54
|
+
maximumHistoryBytes,
|
|
55
|
+
}) {
|
|
56
|
+
const segmentDirectory = `${filePath}.segments-v2`;
|
|
57
|
+
const secureOptions = { deps: { fs: fsImpl }, failIfUnavailable: true };
|
|
58
|
+
const metadata = new WeakMap();
|
|
59
|
+
const cache = new Map();
|
|
60
|
+
let cacheBytes = 0;
|
|
61
|
+
|
|
62
|
+
const segmentPath = (digest) => {
|
|
63
|
+
if (!DIGEST.test(digest || ""))
|
|
64
|
+
throw new Error("witness segment digest is invalid");
|
|
65
|
+
return path.join(segmentDirectory, `${digest.slice(7)}.json`);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const assertDirectory = () => {
|
|
69
|
+
ensurePrivateDirectory(segmentDirectory, secureOptions);
|
|
70
|
+
const observed = fsImpl.lstatSync(segmentDirectory);
|
|
71
|
+
if (!observed.isDirectory() || observed.isSymbolicLink()) {
|
|
72
|
+
throw new Error("witness segment directory is invalid");
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const validateSegment = (segment, previous, trustEpoch) => {
|
|
77
|
+
exact(segment, SEGMENT_KEYS, "witness segment");
|
|
78
|
+
if (
|
|
79
|
+
segment.schema !== SEGMENT_SCHEMA ||
|
|
80
|
+
!Array.isArray(segment.history) ||
|
|
81
|
+
segment.history.length !== EVOLUTION_WITNESS_SEGMENT_RECORDS
|
|
82
|
+
) {
|
|
83
|
+
throw new Error("witness segment length or schema is invalid");
|
|
84
|
+
}
|
|
85
|
+
validateStore(
|
|
86
|
+
{
|
|
87
|
+
schema: legacySchema,
|
|
88
|
+
current: segment.history.at(-1),
|
|
89
|
+
history: segment.history,
|
|
90
|
+
discardedAnchors: segment.discardedAnchors,
|
|
91
|
+
},
|
|
92
|
+
trustEpoch,
|
|
93
|
+
previous,
|
|
94
|
+
);
|
|
95
|
+
return segment;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const observe = (records, discardedAnchors, observations) => {
|
|
99
|
+
for (const query of observations.discards) {
|
|
100
|
+
if (
|
|
101
|
+
discardedAnchors.some((entry) => matchesDiscard(entry, query.snapshot))
|
|
102
|
+
) {
|
|
103
|
+
query.matched = true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
for (const query of observations.records) {
|
|
107
|
+
const firstGeneration = records[0].generation;
|
|
108
|
+
const index = query.checkpoint.generation - firstGeneration;
|
|
109
|
+
if (Number.isSafeInteger(index) && index >= 0 && index < records.length) {
|
|
110
|
+
const record = records[index];
|
|
111
|
+
if (record.witnessDigest === query.checkpoint.witnessDigest)
|
|
112
|
+
query.record = record;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const remember = (digest, segment, trustEpoch) => {
|
|
118
|
+
if (trustEpoch === null) return;
|
|
119
|
+
// A cached decision belongs only to bytes rehashed on this read and a
|
|
120
|
+
// current verifier epoch. Copy through a small encoding so no parser
|
|
121
|
+
// substring can retain a whole source segment.
|
|
122
|
+
const encoded = canonical({
|
|
123
|
+
first: segment.history[0],
|
|
124
|
+
last: segment.history.at(-1),
|
|
125
|
+
discardedAnchors: segment.discardedAnchors,
|
|
126
|
+
});
|
|
127
|
+
const bytes = 6 * encoded.length;
|
|
128
|
+
const existing = cache.get(digest);
|
|
129
|
+
if (existing) cacheBytes -= existing.bytes;
|
|
130
|
+
cache.delete(digest);
|
|
131
|
+
if (cache.size >= MAX_SEGMENTS || cacheBytes + bytes > MAX_CACHE_BYTES)
|
|
132
|
+
return;
|
|
133
|
+
cache.set(digest, { ...JSON.parse(encoded), trustEpoch, bytes });
|
|
134
|
+
cacheBytes += bytes;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const load = (head, trustEpoch, options = {}) => {
|
|
138
|
+
exact(head, HEAD_KEYS, "segmented witness store");
|
|
139
|
+
if (
|
|
140
|
+
head.schema !== EVOLUTION_SEGMENTED_WITNESS_SCHEMA ||
|
|
141
|
+
!Array.isArray(head.segments) ||
|
|
142
|
+
head.segments.length < 1 ||
|
|
143
|
+
head.segments.length >= MAX_SEGMENTS ||
|
|
144
|
+
!Array.isArray(head.history) ||
|
|
145
|
+
head.history.length < 1 ||
|
|
146
|
+
head.history.length > EVOLUTION_WITNESS_SEGMENT_RECORDS ||
|
|
147
|
+
head.segments.length * EVOLUTION_WITNESS_SEGMENT_RECORDS +
|
|
148
|
+
head.history.length >
|
|
149
|
+
MAX_RECORDS
|
|
150
|
+
) {
|
|
151
|
+
throw new Error("segmented witness store capacity or schema is invalid");
|
|
152
|
+
}
|
|
153
|
+
assertDirectory();
|
|
154
|
+
const seen = new Set();
|
|
155
|
+
const observations = {
|
|
156
|
+
discards: (options.discards || [])
|
|
157
|
+
.filter(Boolean)
|
|
158
|
+
.map((snapshot) => ({ snapshot, matched: false })),
|
|
159
|
+
records: (options.records || []).map((checkpoint) => ({
|
|
160
|
+
checkpoint,
|
|
161
|
+
record: null,
|
|
162
|
+
})),
|
|
163
|
+
};
|
|
164
|
+
let previous = null;
|
|
165
|
+
let storedBytes = options.headBytes;
|
|
166
|
+
if (
|
|
167
|
+
!Number.isSafeInteger(storedBytes) ||
|
|
168
|
+
storedBytes < 1 ||
|
|
169
|
+
storedBytes > maximumHistoryBytes
|
|
170
|
+
) {
|
|
171
|
+
throw new Error("witness history exceeds its configured maximum size");
|
|
172
|
+
}
|
|
173
|
+
for (const digest of head.segments) {
|
|
174
|
+
if (seen.has(digest)) throw new Error("witness segment is repeated");
|
|
175
|
+
seen.add(digest);
|
|
176
|
+
const bytes = readBytes(
|
|
177
|
+
segmentPath(digest),
|
|
178
|
+
maximumHistoryBytes - storedBytes,
|
|
179
|
+
);
|
|
180
|
+
storedBytes += bytes.length;
|
|
181
|
+
if (hash(bytes) !== digest)
|
|
182
|
+
throw new Error("witness segment bytes changed");
|
|
183
|
+
const cached = cache.get(digest);
|
|
184
|
+
const canReuse =
|
|
185
|
+
cached && trustEpoch !== null && cached.trustEpoch === trustEpoch;
|
|
186
|
+
const needsRecord = observations.records.some(
|
|
187
|
+
({ checkpoint }) =>
|
|
188
|
+
canReuse &&
|
|
189
|
+
checkpoint.generation >= cached.first.generation &&
|
|
190
|
+
checkpoint.generation <= cached.last.generation,
|
|
191
|
+
);
|
|
192
|
+
if (canReuse) {
|
|
193
|
+
if (
|
|
194
|
+
(!previous && cached.first.generation !== 0) ||
|
|
195
|
+
(previous &&
|
|
196
|
+
(cached.first.generation !== previous.generation + 1 ||
|
|
197
|
+
cached.first.previousWitnessDigest !== previous.witnessDigest))
|
|
198
|
+
) {
|
|
199
|
+
throw new Error("witness segment history is not contiguous");
|
|
200
|
+
}
|
|
201
|
+
for (const query of observations.discards) {
|
|
202
|
+
if (
|
|
203
|
+
cached.discardedAnchors.some((entry) =>
|
|
204
|
+
matchesDiscard(entry, query.snapshot),
|
|
205
|
+
)
|
|
206
|
+
) {
|
|
207
|
+
query.matched = true;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (needsRecord) {
|
|
211
|
+
const parsed = JSON.parse(
|
|
212
|
+
new TextDecoder("utf-8", { fatal: true }).decode(bytes),
|
|
213
|
+
);
|
|
214
|
+
observe(parsed.history, parsed.discardedAnchors, observations);
|
|
215
|
+
}
|
|
216
|
+
previous = cached.last;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
const parsed = JSON.parse(
|
|
220
|
+
new TextDecoder("utf-8", { fatal: true }).decode(bytes),
|
|
221
|
+
);
|
|
222
|
+
const segment = validateSegment(parsed, previous, trustEpoch);
|
|
223
|
+
observe(segment.history, segment.discardedAnchors, observations);
|
|
224
|
+
remember(digest, segment, trustEpoch);
|
|
225
|
+
previous = segment.history.at(-1);
|
|
226
|
+
}
|
|
227
|
+
const store = validateStore(
|
|
228
|
+
{
|
|
229
|
+
schema: legacySchema,
|
|
230
|
+
current: head.current,
|
|
231
|
+
history: head.history,
|
|
232
|
+
discardedAnchors: head.discardedAnchors,
|
|
233
|
+
},
|
|
234
|
+
trustEpoch,
|
|
235
|
+
previous,
|
|
236
|
+
);
|
|
237
|
+
observe(store.history, store.discardedAnchors, observations);
|
|
238
|
+
metadata.set(store, {
|
|
239
|
+
segments: [...head.segments],
|
|
240
|
+
observations,
|
|
241
|
+
tailPreviousDiscardDigest: previous.discardAccumulatorDigest,
|
|
242
|
+
segmentBytes: storedBytes - options.headBytes,
|
|
243
|
+
});
|
|
244
|
+
return store;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const publish = (store) => {
|
|
248
|
+
const existing = metadata.get(store);
|
|
249
|
+
const segments = [...(existing?.segments || [])];
|
|
250
|
+
if (
|
|
251
|
+
segments.length * EVOLUTION_WITNESS_SEGMENT_RECORDS +
|
|
252
|
+
store.history.length >
|
|
253
|
+
MAX_RECORDS
|
|
254
|
+
) {
|
|
255
|
+
throw new Error("witness history exceeds its configured record capacity");
|
|
256
|
+
}
|
|
257
|
+
assertDirectory();
|
|
258
|
+
let history = store.history;
|
|
259
|
+
let discardedAnchors = store.discardedAnchors;
|
|
260
|
+
let segmentBytes = existing?.segmentBytes ?? 0;
|
|
261
|
+
let accumulator =
|
|
262
|
+
existing?.tailPreviousDiscardDigest ??
|
|
263
|
+
history[0].discardAccumulatorDigest;
|
|
264
|
+
while (history.length > EVOLUTION_WITNESS_SEGMENT_RECORDS) {
|
|
265
|
+
const records = history.slice(0, EVOLUTION_WITNESS_SEGMENT_RECORDS);
|
|
266
|
+
let discardCount = 0;
|
|
267
|
+
// The first record's predecessor may belong to the preceding segment.
|
|
268
|
+
// The caller carries the exact predecessor accumulator when loading.
|
|
269
|
+
for (const record of records) {
|
|
270
|
+
if (record.discardAccumulatorDigest !== accumulator) discardCount++;
|
|
271
|
+
accumulator = record.discardAccumulatorDigest;
|
|
272
|
+
}
|
|
273
|
+
const part = {
|
|
274
|
+
schema: SEGMENT_SCHEMA,
|
|
275
|
+
history: records,
|
|
276
|
+
discardedAnchors: discardedAnchors.slice(0, discardCount),
|
|
277
|
+
};
|
|
278
|
+
const bytes = Buffer.from(`${canonical(part)}\n`, "utf8");
|
|
279
|
+
segmentBytes += bytes.length;
|
|
280
|
+
if (segmentBytes > maximumHistoryBytes) {
|
|
281
|
+
throw new Error("witness history exceeds its configured maximum size");
|
|
282
|
+
}
|
|
283
|
+
const digest = hash(bytes);
|
|
284
|
+
const destination = segmentPath(digest);
|
|
285
|
+
if (fsImpl.existsSync(destination)) {
|
|
286
|
+
if (!readBytes(destination).equals(bytes)) {
|
|
287
|
+
throw new Error(
|
|
288
|
+
"existing witness segment differs from its content address",
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
// A previous process may have stopped after rename and before fsync of
|
|
292
|
+
// the directory. Reuse requires that durability boundary again.
|
|
293
|
+
confirmDurable(destination, bytes);
|
|
294
|
+
} else {
|
|
295
|
+
// The witness CAS lock serializes publication. Only complete, fsynced
|
|
296
|
+
// bytes are renamed into this immutable content address before HEAD.
|
|
297
|
+
writeBytes(destination, bytes);
|
|
298
|
+
}
|
|
299
|
+
segments.push(digest);
|
|
300
|
+
history = history.slice(EVOLUTION_WITNESS_SEGMENT_RECORDS);
|
|
301
|
+
discardedAnchors = discardedAnchors.slice(discardCount);
|
|
302
|
+
}
|
|
303
|
+
const encoded = `{"current":${encodeRecord(store.current)},"discardedAnchors":${canonical(discardedAnchors)},"history":[${history.map(encodeRecord).join(",")}],"schema":${JSON.stringify(EVOLUTION_SEGMENTED_WITNESS_SCHEMA)},"segments":${canonical(segments)}}`;
|
|
304
|
+
const headBytes = Buffer.from(`${encoded}\n`, "utf8");
|
|
305
|
+
if (segmentBytes + headBytes.length > maximumHistoryBytes) {
|
|
306
|
+
throw new Error("witness history exceeds its configured maximum size");
|
|
307
|
+
}
|
|
308
|
+
writeBytes(filePath, headBytes);
|
|
309
|
+
return store.current;
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
load,
|
|
314
|
+
publish,
|
|
315
|
+
handles: (store) =>
|
|
316
|
+
metadata.has(store) ||
|
|
317
|
+
store.history.length > EVOLUTION_WITNESS_SEGMENT_RECORDS,
|
|
318
|
+
isSegmented: (store) => metadata.has(store),
|
|
319
|
+
isDiscarded: (store, snapshot) =>
|
|
320
|
+
metadata
|
|
321
|
+
.get(store)
|
|
322
|
+
?.observations.discards.find((query) => query.snapshot === snapshot)
|
|
323
|
+
?.matched === true,
|
|
324
|
+
lookup: (store, checkpoint) =>
|
|
325
|
+
metadata
|
|
326
|
+
.get(store)
|
|
327
|
+
?.observations.records.find((query) => query.checkpoint === checkpoint)
|
|
328
|
+
?.record ?? null,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { prepareGovernedModelTurn } from "./governed-model-turn.js";
|
|
2
|
+
|
|
3
|
+
// A scoped wrapper preserves the Hub's independent local/cloud consent check.
|
|
4
|
+
// Never replace llm on the process-wide cached Hub or its analysis engine.
|
|
5
|
+
export function createGovernedHubLlm(llm, factory) {
|
|
6
|
+
if (
|
|
7
|
+
!llm ||
|
|
8
|
+
typeof llm.chat !== "function" ||
|
|
9
|
+
typeof llm.isLocal !== "boolean"
|
|
10
|
+
) {
|
|
11
|
+
throw new TypeError(
|
|
12
|
+
"A Hub model client with declared locality is required",
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
if (typeof factory !== "function")
|
|
16
|
+
throw new TypeError("A Hub evolution factory is required");
|
|
17
|
+
const identity = { name: llm.name, isLocal: llm.isLocal, chat: llm.chat };
|
|
18
|
+
const assertIdentity = () => {
|
|
19
|
+
if (
|
|
20
|
+
llm.name !== identity.name ||
|
|
21
|
+
llm.isLocal !== identity.isLocal ||
|
|
22
|
+
llm.chat !== identity.chat
|
|
23
|
+
) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
"Hub model identity changed; reopen the analysis invocation",
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const chat = identity.chat.bind(llm);
|
|
30
|
+
return Object.freeze({
|
|
31
|
+
get name() {
|
|
32
|
+
assertIdentity();
|
|
33
|
+
return identity.name;
|
|
34
|
+
},
|
|
35
|
+
get isLocal() {
|
|
36
|
+
assertIdentity();
|
|
37
|
+
return identity.isLocal;
|
|
38
|
+
},
|
|
39
|
+
async chat(messages, options = {}) {
|
|
40
|
+
assertIdentity();
|
|
41
|
+
const turn = await prepareGovernedModelTurn(factory, {
|
|
42
|
+
mode: "hub-analysis",
|
|
43
|
+
messages,
|
|
44
|
+
signal: options.signal,
|
|
45
|
+
});
|
|
46
|
+
assertIdentity();
|
|
47
|
+
const response = await chat(turn.messages, options);
|
|
48
|
+
assertIdentity();
|
|
49
|
+
if (!response || typeof response.text !== "string") {
|
|
50
|
+
throw new Error("Hub model response must contain text");
|
|
51
|
+
}
|
|
52
|
+
await turn.complete(response.text);
|
|
53
|
+
return response;
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { prepareGovernedModelTurn } from "./governed-model-turn.js";
|
|
2
|
+
import { createGovernedHubLlm } from "./governed-hub-llm.js";
|
|
3
|
+
|
|
4
|
+
export function createGovernedHubResolver(ports, factory) {
|
|
5
|
+
if (typeof factory !== "function")
|
|
6
|
+
throw new TypeError("A resolver evolution factory is required");
|
|
7
|
+
const {
|
|
8
|
+
resolver,
|
|
9
|
+
llm,
|
|
10
|
+
embeddingStage,
|
|
11
|
+
EntityResolver,
|
|
12
|
+
EmbeddingStage,
|
|
13
|
+
LLMStage,
|
|
14
|
+
} = ports;
|
|
15
|
+
// Rebuild stages for each drain. Neither the shared resolver nor its embedding
|
|
16
|
+
// cache may acquire the authority of an individual WebSocket request.
|
|
17
|
+
const embedding =
|
|
18
|
+
embeddingStage &&
|
|
19
|
+
new EmbeddingStage({
|
|
20
|
+
vault: resolver.vault,
|
|
21
|
+
embedFn: async (profile) => {
|
|
22
|
+
const turn = await prepareGovernedModelTurn(factory, {
|
|
23
|
+
mode: "hub-embedding",
|
|
24
|
+
messages: [{ role: "user", content: profile }],
|
|
25
|
+
});
|
|
26
|
+
// Chat projection prepends host provenance. Embed only the projected
|
|
27
|
+
// profile: per-Run evidence IDs must not change semantic similarity.
|
|
28
|
+
const profileMessage = turn.messages[1];
|
|
29
|
+
if (
|
|
30
|
+
turn.messages.length !== 2 ||
|
|
31
|
+
turn.messages[0].role !== "system" ||
|
|
32
|
+
profileMessage?.role !== "user" ||
|
|
33
|
+
typeof profileMessage.content !== "string"
|
|
34
|
+
)
|
|
35
|
+
throw new Error(
|
|
36
|
+
"Projected embedding input must contain one text message",
|
|
37
|
+
);
|
|
38
|
+
const vector = await embeddingStage._embed(profileMessage.content);
|
|
39
|
+
if (
|
|
40
|
+
(!Array.isArray(vector) && !(vector instanceof Float32Array)) ||
|
|
41
|
+
vector.length === 0 ||
|
|
42
|
+
!Array.from(vector).every(Number.isFinite)
|
|
43
|
+
)
|
|
44
|
+
throw new Error(
|
|
45
|
+
"Embedding response must contain a nonempty finite vector",
|
|
46
|
+
);
|
|
47
|
+
await turn.complete(JSON.stringify(Array.from(vector)));
|
|
48
|
+
return vector;
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
const model =
|
|
52
|
+
resolver._llmStage &&
|
|
53
|
+
new LLMStage({
|
|
54
|
+
llm: createGovernedHubLlm(llm, factory),
|
|
55
|
+
acceptNonLocal: false,
|
|
56
|
+
});
|
|
57
|
+
return new EntityResolver({
|
|
58
|
+
vault: resolver.vault,
|
|
59
|
+
candidateLimit: resolver._candidateLimit,
|
|
60
|
+
embeddingHighThreshold: resolver._embeddingHighThreshold,
|
|
61
|
+
embeddingLowThreshold: resolver._embeddingLowThreshold,
|
|
62
|
+
embeddingStage: embedding ? embedding.asStageFn() : null,
|
|
63
|
+
llmStage: model ? model.asStageFn() : null,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createGovernedHubLlm } from "./governed-hub-llm.js";
|
|
2
|
+
|
|
3
|
+
// Analysis skills treat commentary failures as optional. A governed invocation
|
|
4
|
+
// must still surface a failed model turn after the SDK returns its report.
|
|
5
|
+
export async function runGovernedHubSkill(
|
|
6
|
+
hub,
|
|
7
|
+
factory,
|
|
8
|
+
runSkill,
|
|
9
|
+
name,
|
|
10
|
+
options,
|
|
11
|
+
) {
|
|
12
|
+
const model = createGovernedHubLlm(hub.llm, factory);
|
|
13
|
+
let failure;
|
|
14
|
+
let failed = false;
|
|
15
|
+
const llm = Object.freeze({
|
|
16
|
+
get name() {
|
|
17
|
+
return model.name;
|
|
18
|
+
},
|
|
19
|
+
get isLocal() {
|
|
20
|
+
return model.isLocal;
|
|
21
|
+
},
|
|
22
|
+
async chat(messages, chatOptions) {
|
|
23
|
+
if (failed) throw failure;
|
|
24
|
+
try {
|
|
25
|
+
return await model.chat(messages, chatOptions);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
failure = error;
|
|
28
|
+
failed = true;
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
const result = await runSkill({ vault: hub.vault, llm }, name, options);
|
|
34
|
+
if (failed) throw failure;
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { types } from "node:util";
|
|
3
|
+
import { captureAgentEvolutionRuntimeComposition } from "./agent-evolution-runtime-composition-brand.js";
|
|
4
|
+
import { captureAgentEvolutionIngress } from "./agent-evolution-ingress.js";
|
|
5
|
+
|
|
6
|
+
export function readEvolutionCompositionFactory(dependencies = {}) {
|
|
7
|
+
if (
|
|
8
|
+
!dependencies ||
|
|
9
|
+
typeof dependencies !== "object" ||
|
|
10
|
+
Array.isArray(dependencies) ||
|
|
11
|
+
types.isProxy(dependencies)
|
|
12
|
+
) {
|
|
13
|
+
throw new TypeError("Model turn dependencies must be a plain object");
|
|
14
|
+
}
|
|
15
|
+
const property = Object.getOwnPropertyDescriptor(
|
|
16
|
+
dependencies,
|
|
17
|
+
"evolutionCompositionFactory",
|
|
18
|
+
);
|
|
19
|
+
if (
|
|
20
|
+
property &&
|
|
21
|
+
(!Object.hasOwn(property, "value") || typeof property.value !== "function")
|
|
22
|
+
) {
|
|
23
|
+
throw new TypeError(
|
|
24
|
+
"evolutionCompositionFactory must be a function data property",
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
return property?.value ?? null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Only a host-owned factory can supply authority. Client messages supply input,
|
|
31
|
+
// never a run identifier or composition to borrow from another request.
|
|
32
|
+
export async function prepareGovernedModelTurn(
|
|
33
|
+
factory,
|
|
34
|
+
{ mode, messages, signal },
|
|
35
|
+
) {
|
|
36
|
+
signal?.throwIfAborted();
|
|
37
|
+
if (factory === null)
|
|
38
|
+
return {
|
|
39
|
+
governed: false,
|
|
40
|
+
messages,
|
|
41
|
+
complete: async () => {
|
|
42
|
+
signal?.throwIfAborted();
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
if (typeof factory !== "function")
|
|
46
|
+
throw new TypeError("Invalid evolution composition factory");
|
|
47
|
+
const runId = `${mode}-${randomUUID()}`;
|
|
48
|
+
const composition = captureAgentEvolutionRuntimeComposition(
|
|
49
|
+
await factory(
|
|
50
|
+
Object.freeze({ mode, runId, taskId: runId, cwd: process.cwd() }),
|
|
51
|
+
),
|
|
52
|
+
);
|
|
53
|
+
const ingress = captureAgentEvolutionIngress(composition.evolutionIngress);
|
|
54
|
+
if (
|
|
55
|
+
composition.runId !== runId ||
|
|
56
|
+
ingress.runId !== runId ||
|
|
57
|
+
composition.tenantId !== ingress.tenantId
|
|
58
|
+
) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
"Model evolution composition is not bound to the requested Run",
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
signal?.throwIfAborted();
|
|
64
|
+
await ingress.start();
|
|
65
|
+
await ingress.ingestUserPrompt({ messages, source: mode });
|
|
66
|
+
const prepared = await ingress.prepareModelRequest({ messages, tools: [] });
|
|
67
|
+
signal?.throwIfAborted();
|
|
68
|
+
return Object.freeze({
|
|
69
|
+
governed: true,
|
|
70
|
+
messages: prepared.messages,
|
|
71
|
+
async complete(content) {
|
|
72
|
+
signal?.throwIfAborted();
|
|
73
|
+
await ingress.ingestAgentEvent({ type: "response-complete", content });
|
|
74
|
+
signal?.throwIfAborted();
|
|
75
|
+
await ingress.complete();
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function* governModelTokenSource(source, turn, signal) {
|
|
81
|
+
let content = "";
|
|
82
|
+
for await (const delta of source) {
|
|
83
|
+
signal?.throwIfAborted();
|
|
84
|
+
content += delta;
|
|
85
|
+
yield delta;
|
|
86
|
+
}
|
|
87
|
+
await turn.complete(content);
|
|
88
|
+
}
|
|
@@ -218,6 +218,7 @@ export function createProgressiveCanaryHeartbeatAuthority({
|
|
|
218
218
|
const authority = Object.freeze({
|
|
219
219
|
planDigest: plan.planDigest,
|
|
220
220
|
async issue({ sequence, stage, activeStateDigest } = {}) {
|
|
221
|
+
const issuedAt = timestamp(Number(now()), "heartbeat clock");
|
|
221
222
|
const payload = {
|
|
222
223
|
schema: PROGRESSIVE_CANARY_HOST_HEARTBEAT_SCHEMA,
|
|
223
224
|
planDigest: plan.planDigest,
|
|
@@ -228,15 +229,16 @@ export function createProgressiveCanaryHeartbeatAuthority({
|
|
|
228
229
|
sequence: timestamp(sequence, "heartbeat sequence"),
|
|
229
230
|
stage: id(stage, "heartbeat stage"),
|
|
230
231
|
activeStateDigest: digest(activeStateDigest, "activeStateDigest"),
|
|
231
|
-
issuedAt
|
|
232
|
-
expiresAt:
|
|
232
|
+
issuedAt,
|
|
233
|
+
expiresAt: timestamp(
|
|
234
|
+
issuedAt + plan.leaseDurationMs,
|
|
235
|
+
"heartbeat expiry",
|
|
236
|
+
),
|
|
233
237
|
authorityId: plan.heartbeatAuthority.id,
|
|
234
238
|
authorityRevision: plan.heartbeatAuthority.revision,
|
|
235
239
|
handlerDigest: plan.heartbeatAuthority.handlerDigest,
|
|
236
240
|
publicKeySpkiDigest: plan.heartbeatAuthority.publicKeySpkiDigest,
|
|
237
241
|
};
|
|
238
|
-
if (payload.expiresAt !== payload.issuedAt + plan.leaseDurationMs)
|
|
239
|
-
throw new Error("heartbeat clock changed during issuance");
|
|
240
242
|
const signature = await attestor(Object.freeze(structuredClone(payload)));
|
|
241
243
|
const core = { ...payload, signature };
|
|
242
244
|
return verify(
|