chainlesschain 0.166.38 → 0.166.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -1
- package/scripts/governed-learning-local-attestor-service.mjs +222 -0
- package/scripts/governed-learning-local-attestor-trust-approval-service.mjs +338 -0
- package/scripts/governed-learning-local-attestor-trust-operations-service.mjs +575 -0
- package/scripts/governed-learning-windows-secure-pipe-broker.ps1 +375 -0
- package/src/assets/web-panel/assets/{AIOps-DBbcVPqB.js → AIOps-BK9J9OWp.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-D5vETPOk.js → ActionButton-LPNZQqBA.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-WVhas3Fw.js → Analytics-Bc4GSjWD.js} +2 -2
- package/src/assets/web-panel/assets/{AppLayout-CSTRI93Q.js → AppLayout-DvOI0V4E.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BZT8FOoE.js → Artifacts-Dk84hXbN.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CT2-Tsby.js → Audit-q1LFnus7.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BWA5LNBe.js → BackgroundAgents-CwalUYLs.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-B-zEbldA.js → Backup-DklgvW1G.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BAEwtdNT.js → BaseInput-BUwoeDOX.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BT1-y6t1.js → Chat-DbHcDB_8.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BVijMHeO.js → ChatBubbleRenderer-vEtAN7ar.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-B8IJYZsD.js → Checkbox-BhshLHuh.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DEt453nL.js → Codegen-CrqH-uBK.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DWuVSmZv.js → Col-CTHhv3KN.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CcoNuU33.js → Community-BXTvtMJe.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BKtuIYWA.js → Compact-BpvJtxF1.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-bHzxGq3P.js → Compliance-CpMouPia.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BY2Kb15t.js → Cowork-C7yp3_hW.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-DC-j0jvp.js → Cron-C-XxPYai.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CzEuAHQz.js → Crosschain-CMdyqfrL.js} +1 -1
- package/src/assets/web-panel/assets/{DID-7QUNq6Fz.js → DID-kuaHK2dq.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CT6RiEFl.js → Dashboard-DH2-ms5o.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CW8IPY7r.js → Dropdown-DXLZ0jjH.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Zt8WOLuN.js → EmailListRenderer-DK86nfd5.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-B6aymxi7.js → FamilyGuardDashboard-CRKmGOug.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BiuFrRq0.js → Federation-DKK3wIGA.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DaiOAkHa.js → FormItemContext-CUGNKN_D.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-D1KbDpXs.js → GenericCardRenderer-CA0GwYSK.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BILl0huA.js → Git-CFm46B43.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CLyhrPrh.js → Governance-CfOa3K-_.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DyNhiIpK.js → Inference-C4C6jHDC.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Bor_ye4m.js → KnowledgeGraph-D5IhrCDs.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-ZDqbu8kg.js → Logs-BNeyeUIr.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-XsLyxgz8.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-DbDi29dH.js → Marketplace-0pLshxdU.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DfU8dWbV.js → McpTools-DK4FG-4k.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-DeAz-2-6.js → Memory-CQfkhP-b.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-ws3TJXal.js → MobileBridge-pbinAwCm.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CGwVfeTv.js → MobileProjects-CWqK_5p8.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BtJjJJpl.js → Mtc-B-OQ9yid.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-BNZwipXs.js → MtcAudit-Cp6iZgrT.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-9mSOrKWA.js → Multisig-D9cQONHI.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-gz1lEDED.js → NLProgramming-BUY0rZvc.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BeufuOVX.js → Notes-CsXIIMCf.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-CbFyi9jZ.js → NotificationSettings-C6qIk1ej.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-Cz3qay2q.js +1 -0
- package/src/assets/web-panel/assets/{Organization-DKBKNViH.js → Organization-Cs0gsc4U.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CvPfKE1x.js → Overflow-C3ZfbqPx.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DjL2q8og.js → P2P-D1lxB22Z.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-Cv9PLMWJ.js → PdhVaultBrowser-SNHvZvv_.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BUoNho3w.js → Permissions-CFSk6KJV.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-C4Iu2Pic.js → PersonalDataHub-puvpUUGe.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-BiDrIlwr.js → Pipeline-BMqYweJm.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BnvU6vGp.js → Privacy-C0sXA71u.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-DDzoyhnH.js → ProjectInit-ClaKClvs.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CV6b43H0.js → ProjectSettings-CtHJp6_9.js} +2 -2
- package/src/assets/web-panel/assets/Projects-HuPL4QZa.js +1 -0
- package/src/assets/web-panel/assets/{Providers-DaeuFo-x.js → Providers-crByRu10.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-C03Bll1h.js → QrScannerModal-BKO9i7Sy.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Cn9nLaen.js → QuickAsk-1IdXt4pm.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BXfkC8Ts.js → Recommend-DiQwZD6r.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DNj6D_LI.js → RemoteSession-DesjH6lx.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-DDDIwiUI.js → Reputation-b-nY3pul.js} +1 -1
- package/src/assets/web-panel/assets/{Row-JukNm-id.js → Row-Bt7nCF5s.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-B1AhzL2z.js → RssFeed-CcTg4JEQ.js} +2 -2
- package/src/assets/web-panel/assets/{Search-B5y6_DVm.js → Search-C2uI3GFe.js} +1 -1
- package/src/assets/web-panel/assets/{Security-C2pvv32x.js → Security-3NrvV4g1.js} +3 -3
- package/src/assets/web-panel/assets/{Services-DBka7ppY.js → Services-B1cKHgYr.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DfPwNTSh.js → Skeleton-BTZdEKX3.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-Cs4ntp-l.js → Skills-Bi_Zy8Ru.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CrUJ0guM.js → Sla-CR2gW1OA.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BFbokLV1.js → SpeechSettings-Bphe-fh1.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CSnh1o3D.js → SyncSettings-C64DsCjZ.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CQZppIPo.js → Tasks-D18Px4aF.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BqLeHq7Z.js → Templates-DGfS0ZAF.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CkzPA-ri.js → Tenant-D6ank4rT.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-D5IRhnu6.js → Terminal-MBMZ_5Gz.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-ICdiYzgz.js → TimelineRenderer-C_u6JjZi.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-89CaZBwe.js → Tokens-CqmhScSK.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Di251qR1.js → Trigger-D1B9cX1b.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-M4sC3Mv6.js → Trust-D_P3Mfbl.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-BL7EUWxj.js → UkeySign-CUASyjWb.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BV5Se5il.js → VideoEditing-eGLhjeJX.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-IoY13rov.js → Wallet-Dba_6QCL.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DKFPq0uV.js → WebAuthn-CiAEtYZZ.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-oizkYeQD.js → WorkflowEditor-D-zW3rph.js} +1 -1
- package/src/assets/web-panel/assets/{chat-Du6ZthE5.js → chat-DEzJInHX.js} +1 -1
- package/src/assets/web-panel/assets/{colors-I2ie73HS.js → colors-DM6Ke3hD.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-C-02XOOx.js → compact-item-CAMIx_cM.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DgP09zg2.js → createContext-BrbtMPOW.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DQGZAYxC.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-kWDasRib.js → hasIn-tnV_CKFU.js} +1 -1
- package/src/assets/web-panel/assets/{index-M9mzJo6V.js → index-9o6JlqCH.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cx5dAdFu.js → index-A3azg5vi.js} +1 -1
- package/src/assets/web-panel/assets/{index-AtAiEmjM.js → index-B5glieXV.js} +1 -1
- package/src/assets/web-panel/assets/{index-H_31JkaZ.js → index-B6KWb2WQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BSlTGxUJ.js → index-BIkQL-F7.js} +1 -1
- package/src/assets/web-panel/assets/{index-OYyn8GoU.js → index-BJ8Yd5W8.js} +1 -1
- package/src/assets/web-panel/assets/{index-5Ll5Fdqb.js → index-BZVDnMvs.js} +1 -1
- package/src/assets/web-panel/assets/{index-mF8UmKqp.js → index-B_aGo7Y_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BUvpjPMv.js → index-BbdSgz4e.js} +1 -1
- package/src/assets/web-panel/assets/{index-CkP2DW3a.js → index-BeC4Jmxn.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbHEQTU6.js → index-BfGYDWyS.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKJ-d5F1.js → index-Br1t2LsA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CHSghc3j.js → index-BuSXesCq.js} +1 -1
- package/src/assets/web-panel/assets/{index-CjuJ1FYZ.js → index-BzuFmNOf.js} +1 -1
- package/src/assets/web-panel/assets/index-C9a56Oco.js +1 -0
- package/src/assets/web-panel/assets/index-CU5eDYYp.js +1 -0
- package/src/assets/web-panel/assets/{index-CtbMRqD-.js → index-CVJ67rg0.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZ6bWk4x.js → index-CVij36sN.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ryflob2W.js → index-CaCQEvVe.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYxia8nl.js → index-Cx3S7Z4l.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpOQeTac.js → index-D1SsqpBQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Na5QA1LE.js → index-D2X5hC5X.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5LV04FO.js → index-D4-jekkQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9HwtJX5.js → index-D57Rt85L.js} +1 -1
- package/src/assets/web-panel/assets/{index-LLQQqj9B.js → index-DBYM7wpW.js} +1 -1
- package/src/assets/web-panel/assets/{index-D0EQSoEb.js → index-DH6MvJcX.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3D5NSjS.js → index-DI1yJrlv.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgogPjKJ.js → index-DJPjCj-L.js} +1 -1
- package/src/assets/web-panel/assets/{index-I4A_y2Ee.js → index-MxrGcqPa.js} +1 -1
- package/src/assets/web-panel/assets/{index-RwcHDSqP.js → index-Oi0LTcjV.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cokjvq67.js → index-QhkpDqBl.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDM6OO4D.js → index-TiClDP9o.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZcdP3id.js → index-cJQlyKYg.js} +1 -1
- package/src/assets/web-panel/assets/{index-DcVj7YJB.js → index-gOfw5W--.js} +1 -1
- package/src/assets/web-panel/assets/{index-HH3Zccc0.js → index-mtzwU2IE.js} +1 -1
- package/src/assets/web-panel/assets/{index-BkcCllZ7.js → index-mxqufmW1.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bpz5RnQy.js → index-nDxVFSLd.js} +3 -3
- package/src/assets/web-panel/assets/{index-CQCdk4dn.js → index-xqyMxX6r.js} +1 -1
- package/src/assets/web-panel/assets/{index-uHI8QHu4.js → index-yi_liTJn.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BPHGo-UX.js → initDefaultProps-CVHDph1O.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BBr8JvWc.js → motion-CElqp9xA.js} +1 -1
- package/src/assets/web-panel/assets/{move-CdKWToz7.js → move-XZw1bQmy.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-B8tkkKBs.js → mtc-parser-SGviFxRK.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DN4aP33H.js → omit-BGKRrIHI.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CoHRkRJq.js → pickAttrs-BuJYHAWJ.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DpGGGAPa.js → placementArrow-TVa4r_EM.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BabRsZo5.js → responsiveObserve-DVPWQMuO.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DJjyrwqK.js → slide-BeOL-UpA.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BaRVkO5S.js → statusUtils-DNYqZCQQ.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-HcMYUjTR.js → styleChecker-DRx9GRig.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-c3IBzp2l.js → useFlexGapSupport-Daqz3PDA.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DD7igwyF.js → useFs-C6A7nr7V.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-GEF0hhnd.js → usePersonalDataHub-D5hwRSvC.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-D51u7zqF.js → vnode-CHXMdIU3.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-tXG23Lc9.js → zoom-sl0JxyZz.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +1 -1
- package/src/commands/evolution-attestor-trust.js +113 -0
- package/src/commands/evolution.js +2 -0
- package/src/commands/learning.js +34 -5
- package/src/data/changelog.json +26 -0
- package/src/lib/evolution/evolution-artifact-ports.js +21 -0
- package/src/lib/evolution/evolution-deployment-loader.js +56 -0
- package/src/lib/evolution/evolution-immutable-ledger-segment-store.js +812 -0
- package/src/lib/evolution/evolution-ledger-file-manifest-catalog.js +218 -0
- package/src/lib/evolution/evolution-ledger-manifest-catalog.js +472 -0
- package/src/lib/evolution/evolution-ledger-manifest-chain.js +997 -0
- package/src/lib/evolution/evolution-ledger-manifest-head-store.js +408 -0
- package/src/lib/evolution/evolution-ledger-manifest-witness-adapter.js +554 -0
- package/src/lib/evolution/evolution-ledger-v2-manifest-backend.js +460 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-ipc-endpoint.js +94 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-approval-client.js +485 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-ipc-capability.js +200 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-ledger.js +1222 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-operations-cli-host.js +802 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-operations-client.js +445 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-operations.js +1082 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-operator-registry.js +1453 -0
- package/src/lib/evolution/governed-skill-synthesis-candidate-evaluator.js +147 -0
- package/src/lib/evolution/governed-skill-synthesis-cli-host.js +115 -0
- package/src/lib/evolution/governed-skill-synthesis-evaluation-ledger-adapter.js +715 -0
- package/src/lib/evolution/governed-skill-synthesis-external-attestor.js +499 -0
- package/src/lib/evolution/governed-skill-synthesis-model-evaluator.js +514 -0
- package/src/lib/evolution/governed-skill-synthesis-process-attestor-worker.mjs +208 -0
- package/src/lib/evolution/governed-skill-synthesis-process-attestor.js +557 -0
- package/src/lib/evolution/governed-skill-synthesis-process-grader-worker.mjs +143 -0
- package/src/lib/evolution/governed-skill-synthesis-process-grader.js +444 -0
- package/src/lib/evolution/governed-skill-synthesis-provider-chat.js +220 -0
- package/src/lib/evolution/governed-skill-synthesis-windows-secure-pipe-host.js +236 -0
- package/src/lib/hook-audit-store.js +68 -2
- package/src/lib/hooks-v2-runtime.js +52 -26
- package/src/lib/learning/skill-synthesizer.js +66 -5
- package/src/lib/remote-read-loop-guard.js +232 -37
- package/src/lib/task-progress-tracker.js +7 -4
- package/src/runtime/agent-core.js +16 -5
- package/src/runtime/coding-agent-shell-policy.cjs +10 -17
- package/src/assets/web-panel/assets/MarkdownRenderer-DnSfkf98.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-CFbhBT44.js +0 -1
- package/src/assets/web-panel/assets/Projects-B0k1907g.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CxKkOIjh.js +0 -1
- package/src/assets/web-panel/assets/index-b5a6l3Uu.js +0 -1
- package/src/assets/web-panel/assets/index-xt-BOyp_.js +0 -1
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { types as utilTypes } from "node:util";
|
|
6
|
+
|
|
7
|
+
import executionBroker, {
|
|
8
|
+
SANDBOX_BOUNDARIES,
|
|
9
|
+
} from "../process-execution-broker/index.js";
|
|
10
|
+
import { BUILT_IN_PROVIDERS } from "../llm-providers.js";
|
|
11
|
+
|
|
12
|
+
export const GOVERNED_SKILL_SYNTHESIS_PROCESS_GRADER_SCHEMA =
|
|
13
|
+
"chainlesschain.governed-skill-synthesis-process-grader/v2";
|
|
14
|
+
|
|
15
|
+
const WORKER = fileURLToPath(
|
|
16
|
+
new URL(
|
|
17
|
+
"./governed-skill-synthesis-process-grader-worker.mjs",
|
|
18
|
+
import.meta.url,
|
|
19
|
+
),
|
|
20
|
+
);
|
|
21
|
+
const CREDENTIAL_RESOLVER = fileURLToPath(
|
|
22
|
+
new URL(
|
|
23
|
+
"../process-execution-broker/credential-transport.js",
|
|
24
|
+
import.meta.url,
|
|
25
|
+
),
|
|
26
|
+
);
|
|
27
|
+
const PROCESS_GRADERS = new WeakMap();
|
|
28
|
+
const OPTION_KEYS = new Set([
|
|
29
|
+
"apiKey",
|
|
30
|
+
"baseUrl",
|
|
31
|
+
"maxTokens",
|
|
32
|
+
"memoryLimitMb",
|
|
33
|
+
"model",
|
|
34
|
+
"provider",
|
|
35
|
+
"timeoutMs",
|
|
36
|
+
]);
|
|
37
|
+
const MAX_MESSAGES = 8;
|
|
38
|
+
const MAX_PROMPT_BYTES = 64 * 1024;
|
|
39
|
+
const MAX_OUTPUT_BYTES = 96 * 1024;
|
|
40
|
+
const REQUIRED_SANDBOX_BOUNDARIES = Object.freeze([
|
|
41
|
+
SANDBOX_BOUNDARIES.PRIVILEGE_REDUCTION,
|
|
42
|
+
SANDBOX_BOUNDARIES.PROCESS_TREE,
|
|
43
|
+
SANDBOX_BOUNDARIES.RESOURCE_LIMITS,
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
function sha256(bytes) {
|
|
47
|
+
return `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function plainRecord(value, label, allowedKeys) {
|
|
51
|
+
if (
|
|
52
|
+
!value ||
|
|
53
|
+
typeof value !== "object" ||
|
|
54
|
+
Array.isArray(value) ||
|
|
55
|
+
utilTypes.isProxy(value) ||
|
|
56
|
+
Object.getPrototypeOf(value) !== Object.prototype
|
|
57
|
+
) {
|
|
58
|
+
throw new TypeError(`${label} must be a plain object`);
|
|
59
|
+
}
|
|
60
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
61
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
62
|
+
if (
|
|
63
|
+
typeof key !== "string" ||
|
|
64
|
+
!allowedKeys.has(key) ||
|
|
65
|
+
!descriptor ||
|
|
66
|
+
!("value" in descriptor) ||
|
|
67
|
+
!descriptor.enumerable
|
|
68
|
+
) {
|
|
69
|
+
throw new TypeError(`${label} contains unsupported fields`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function boundedString(value, label, maximum) {
|
|
76
|
+
if (
|
|
77
|
+
typeof value !== "string" ||
|
|
78
|
+
value.length === 0 ||
|
|
79
|
+
value.length > maximum ||
|
|
80
|
+
value.trim() !== value ||
|
|
81
|
+
value.includes("\0")
|
|
82
|
+
) {
|
|
83
|
+
throw new TypeError(`${label} must be a non-empty bounded string`);
|
|
84
|
+
}
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function boundedText(value, label, maximum) {
|
|
89
|
+
if (
|
|
90
|
+
typeof value !== "string" ||
|
|
91
|
+
value.trim().length === 0 ||
|
|
92
|
+
value.length > maximum ||
|
|
93
|
+
value.includes("\0")
|
|
94
|
+
) {
|
|
95
|
+
throw new TypeError(`${label} must be non-empty bounded text`);
|
|
96
|
+
}
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function boundedInteger(value, label, minimum, maximum) {
|
|
101
|
+
if (!Number.isSafeInteger(value) || value < minimum || value > maximum) {
|
|
102
|
+
throw new TypeError(`${label} must be from ${minimum} to ${maximum}`);
|
|
103
|
+
}
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function normalizeBaseUrl(provider, value) {
|
|
108
|
+
const expected = BUILT_IN_PROVIDERS[provider]?.baseUrl;
|
|
109
|
+
if (!expected) throw new TypeError("process grader provider is unsupported");
|
|
110
|
+
let actual;
|
|
111
|
+
try {
|
|
112
|
+
actual = new URL(value || expected);
|
|
113
|
+
} catch {
|
|
114
|
+
throw new TypeError("process grader baseUrl is invalid");
|
|
115
|
+
}
|
|
116
|
+
if (
|
|
117
|
+
actual.protocol !== "https:" ||
|
|
118
|
+
actual.username ||
|
|
119
|
+
actual.password ||
|
|
120
|
+
actual.search ||
|
|
121
|
+
actual.hash ||
|
|
122
|
+
actual.href.replace(/\/$/u, "") !==
|
|
123
|
+
new URL(expected).href.replace(/\/$/u, "")
|
|
124
|
+
) {
|
|
125
|
+
throw new TypeError(
|
|
126
|
+
"process grader baseUrl must match the credential-free built-in endpoint",
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
return actual.href.replace(/\/$/u, "");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function normalizeMessages(value) {
|
|
133
|
+
if (
|
|
134
|
+
!Array.isArray(value) ||
|
|
135
|
+
utilTypes.isProxy(value) ||
|
|
136
|
+
value.length === 0 ||
|
|
137
|
+
value.length > MAX_MESSAGES
|
|
138
|
+
) {
|
|
139
|
+
throw new TypeError("process grader messages are invalid");
|
|
140
|
+
}
|
|
141
|
+
let bytes = 0;
|
|
142
|
+
const result = value.map((message, index) => {
|
|
143
|
+
plainRecord(
|
|
144
|
+
message,
|
|
145
|
+
`process grader message ${index}`,
|
|
146
|
+
new Set(["content", "role"]),
|
|
147
|
+
);
|
|
148
|
+
if (!["assistant", "system", "user"].includes(message.role)) {
|
|
149
|
+
throw new TypeError(`process grader message ${index} role is invalid`);
|
|
150
|
+
}
|
|
151
|
+
const content = boundedText(
|
|
152
|
+
message.content,
|
|
153
|
+
`process grader message ${index} content`,
|
|
154
|
+
MAX_PROMPT_BYTES,
|
|
155
|
+
);
|
|
156
|
+
bytes += Buffer.byteLength(content, "utf8");
|
|
157
|
+
return { role: message.role, content };
|
|
158
|
+
});
|
|
159
|
+
if (bytes > MAX_PROMPT_BYTES) {
|
|
160
|
+
throw new TypeError("process grader prompt exceeds 65536 bytes");
|
|
161
|
+
}
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function artifactSnapshot(target, label, maximumBytes) {
|
|
166
|
+
const stat = fs.lstatSync(target);
|
|
167
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1) {
|
|
168
|
+
throw new Error(`${label} is not a single-link regular file`);
|
|
169
|
+
}
|
|
170
|
+
const physical = fs.realpathSync.native(target);
|
|
171
|
+
const bytes = fs.readFileSync(physical);
|
|
172
|
+
if (bytes.length === 0 || bytes.length > maximumBytes) {
|
|
173
|
+
throw new Error(`${label} size is invalid`);
|
|
174
|
+
}
|
|
175
|
+
return Object.freeze({
|
|
176
|
+
physical,
|
|
177
|
+
digest: sha256(bytes),
|
|
178
|
+
size: bytes.length,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function executionSnapshot() {
|
|
183
|
+
return Object.freeze({
|
|
184
|
+
worker: artifactSnapshot(WORKER, "process grader worker", 128 * 1024),
|
|
185
|
+
credentialResolver: artifactSnapshot(
|
|
186
|
+
CREDENTIAL_RESOLVER,
|
|
187
|
+
"process grader credential resolver",
|
|
188
|
+
128 * 1024,
|
|
189
|
+
),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function executionSnapshotMatches(left, right) {
|
|
194
|
+
return ["worker", "credentialResolver"].every(
|
|
195
|
+
(name) =>
|
|
196
|
+
left[name].physical === right[name].physical &&
|
|
197
|
+
left[name].digest === right[name].digest &&
|
|
198
|
+
left[name].size === right[name].size,
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function minimalProcessEnvironment() {
|
|
203
|
+
if (process.platform !== "win32") return Object.freeze({});
|
|
204
|
+
const environment = {};
|
|
205
|
+
for (const key of ["SystemRoot", "WINDIR", "TEMP", "TMP"]) {
|
|
206
|
+
const value = process.env[key];
|
|
207
|
+
if (
|
|
208
|
+
typeof value === "string" &&
|
|
209
|
+
value.length > 0 &&
|
|
210
|
+
value.length <= 32 * 1024 &&
|
|
211
|
+
!value.includes("\0")
|
|
212
|
+
) {
|
|
213
|
+
environment[key] = value;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (!environment.SystemRoot && !environment.WINDIR) {
|
|
217
|
+
throw new Error("Windows process grader requires a system root");
|
|
218
|
+
}
|
|
219
|
+
return Object.freeze(environment);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function runProcess({
|
|
223
|
+
apiKey,
|
|
224
|
+
baseUrl,
|
|
225
|
+
input,
|
|
226
|
+
snapshot,
|
|
227
|
+
timeoutMs,
|
|
228
|
+
memoryLimitMb,
|
|
229
|
+
}) {
|
|
230
|
+
return new Promise((resolve, reject) => {
|
|
231
|
+
const child = executionBroker.spawn(
|
|
232
|
+
process.execPath,
|
|
233
|
+
[
|
|
234
|
+
`--max-old-space-size=${memoryLimitMb}`,
|
|
235
|
+
...(process.platform === "win32"
|
|
236
|
+
? []
|
|
237
|
+
: [
|
|
238
|
+
"--experimental-permission",
|
|
239
|
+
`--allow-fs-read=${snapshot.worker.physical}`,
|
|
240
|
+
`--allow-fs-read=${snapshot.credentialResolver.physical}`,
|
|
241
|
+
]),
|
|
242
|
+
snapshot.worker.physical,
|
|
243
|
+
],
|
|
244
|
+
{
|
|
245
|
+
cwd: path.dirname(snapshot.worker.physical),
|
|
246
|
+
env: {
|
|
247
|
+
...minimalProcessEnvironment(),
|
|
248
|
+
VOLCENGINE_API_KEY: apiKey,
|
|
249
|
+
},
|
|
250
|
+
credentialTargetHost: new URL(baseUrl).hostname,
|
|
251
|
+
credentialTtlMs: Math.min(timeoutMs + 5_000, 125_000),
|
|
252
|
+
credentialMaxUses: 1,
|
|
253
|
+
policy: "allow",
|
|
254
|
+
requirePersistentAudit: true,
|
|
255
|
+
sandboxPolicy: {
|
|
256
|
+
profile: "network-only",
|
|
257
|
+
requiredBoundaries: REQUIRED_SANDBOX_BOUNDARIES,
|
|
258
|
+
},
|
|
259
|
+
shell: false,
|
|
260
|
+
windowsHide: true,
|
|
261
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
262
|
+
origin: "governed-skill-synthesis-process-grader",
|
|
263
|
+
reason:
|
|
264
|
+
"Run the bounded learning synthesis grader in a killable process",
|
|
265
|
+
},
|
|
266
|
+
);
|
|
267
|
+
let stdout = "";
|
|
268
|
+
let stderr = "";
|
|
269
|
+
let settled = false;
|
|
270
|
+
let terminalError = null;
|
|
271
|
+
const finish = (callback, value) => {
|
|
272
|
+
if (settled) return;
|
|
273
|
+
settled = true;
|
|
274
|
+
clearTimeout(timer);
|
|
275
|
+
callback(value);
|
|
276
|
+
};
|
|
277
|
+
const timer = setTimeout(() => {
|
|
278
|
+
terminalError = new Error(
|
|
279
|
+
`learning synthesis process grader timed out after ${timeoutMs}ms`,
|
|
280
|
+
);
|
|
281
|
+
terminalError.code = "LEARNING_SYNTHESIS_PROCESS_GRADER_TIMEOUT";
|
|
282
|
+
child.kill("SIGKILL");
|
|
283
|
+
}, timeoutMs);
|
|
284
|
+
timer.unref?.();
|
|
285
|
+
child.stdout.on("data", (chunk) => {
|
|
286
|
+
stdout += chunk.toString("utf8");
|
|
287
|
+
if (Buffer.byteLength(stdout, "utf8") > MAX_OUTPUT_BYTES) {
|
|
288
|
+
terminalError = new Error("process grader stdout exceeded its bound");
|
|
289
|
+
child.kill("SIGKILL");
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
child.stderr.on("data", (chunk) => {
|
|
293
|
+
stderr += chunk.toString("utf8");
|
|
294
|
+
if (Buffer.byteLength(stderr, "utf8") > MAX_OUTPUT_BYTES) {
|
|
295
|
+
terminalError = new Error("process grader stderr exceeded its bound");
|
|
296
|
+
child.kill("SIGKILL");
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
child.once("error", (error) => finish(reject, error));
|
|
300
|
+
child.once("close", (code, signal) => {
|
|
301
|
+
if (terminalError) return finish(reject, terminalError);
|
|
302
|
+
if (code !== 0) {
|
|
303
|
+
return finish(
|
|
304
|
+
reject,
|
|
305
|
+
new Error(
|
|
306
|
+
`learning synthesis process grader exited ${code ?? "null"}/${signal ?? "none"}: ${stderr.slice(0, 256)}`,
|
|
307
|
+
),
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
const lines = stdout.trimEnd().split("\n");
|
|
312
|
+
if (lines.length !== 1) throw new Error("multiple output records");
|
|
313
|
+
const message = JSON.parse(lines[0]);
|
|
314
|
+
plainRecord(
|
|
315
|
+
message,
|
|
316
|
+
"process grader output",
|
|
317
|
+
new Set(["content", "ok"]),
|
|
318
|
+
);
|
|
319
|
+
if (message.ok !== true) throw new Error("grader output was not ok");
|
|
320
|
+
const content = boundedText(
|
|
321
|
+
message.content,
|
|
322
|
+
"process grader output content",
|
|
323
|
+
64 * 1024,
|
|
324
|
+
);
|
|
325
|
+
finish(resolve, content);
|
|
326
|
+
} catch (cause) {
|
|
327
|
+
finish(
|
|
328
|
+
reject,
|
|
329
|
+
new Error("learning synthesis process grader output is invalid", {
|
|
330
|
+
cause,
|
|
331
|
+
}),
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
child.stdin.once("error", (error) => {
|
|
336
|
+
terminalError ??= error;
|
|
337
|
+
});
|
|
338
|
+
child.stdin.end(JSON.stringify(input));
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export function createGovernedSkillSynthesisProcessGrader(options = {}) {
|
|
343
|
+
plainRecord(options, "process grader options", OPTION_KEYS);
|
|
344
|
+
const provider = boundedString(
|
|
345
|
+
options.provider,
|
|
346
|
+
"process grader provider",
|
|
347
|
+
64,
|
|
348
|
+
);
|
|
349
|
+
if (provider !== "volcengine") {
|
|
350
|
+
throw new TypeError("process grader currently requires volcengine");
|
|
351
|
+
}
|
|
352
|
+
const model = boundedString(
|
|
353
|
+
options.model || BUILT_IN_PROVIDERS[provider].models[0],
|
|
354
|
+
"process grader model",
|
|
355
|
+
256,
|
|
356
|
+
);
|
|
357
|
+
const apiKey = boundedString(
|
|
358
|
+
options.apiKey,
|
|
359
|
+
"process grader credential",
|
|
360
|
+
16 * 1024,
|
|
361
|
+
);
|
|
362
|
+
const baseUrl = normalizeBaseUrl(provider, options.baseUrl);
|
|
363
|
+
const timeoutMs = boundedInteger(
|
|
364
|
+
options.timeoutMs ?? 30_000,
|
|
365
|
+
"process grader timeoutMs",
|
|
366
|
+
1_000,
|
|
367
|
+
120_000,
|
|
368
|
+
);
|
|
369
|
+
const maxTokens = boundedInteger(
|
|
370
|
+
options.maxTokens ?? 2_048,
|
|
371
|
+
"process grader maxTokens",
|
|
372
|
+
128,
|
|
373
|
+
4_096,
|
|
374
|
+
);
|
|
375
|
+
const memoryLimitMb = boundedInteger(
|
|
376
|
+
options.memoryLimitMb ?? 128,
|
|
377
|
+
"process grader memoryLimitMb",
|
|
378
|
+
32,
|
|
379
|
+
512,
|
|
380
|
+
);
|
|
381
|
+
const credentialTargetHost = new URL(baseUrl).hostname;
|
|
382
|
+
const credentialTtlMs = Math.min(timeoutMs + 5_000, 125_000);
|
|
383
|
+
const snapshot = executionSnapshot();
|
|
384
|
+
const descriptor = Object.freeze({
|
|
385
|
+
schema: GOVERNED_SKILL_SYNTHESIS_PROCESS_GRADER_SCHEMA,
|
|
386
|
+
isolation: "process",
|
|
387
|
+
provider,
|
|
388
|
+
model,
|
|
389
|
+
workerArtifactDigest: snapshot.worker.digest,
|
|
390
|
+
credentialResolverArtifactDigest: snapshot.credentialResolver.digest,
|
|
391
|
+
inheritedEnvironment: false,
|
|
392
|
+
credentialDelivery: "single-use-broker-reference",
|
|
393
|
+
credentialTargetHost,
|
|
394
|
+
credentialMaxUses: 1,
|
|
395
|
+
credentialTtlMs,
|
|
396
|
+
hardDeadlineEnforced: true,
|
|
397
|
+
sandboxProfile: "network-only",
|
|
398
|
+
requiredSandboxBoundaries: REQUIRED_SANDBOX_BOUNDARIES,
|
|
399
|
+
persistentProcessAuditRequired: true,
|
|
400
|
+
});
|
|
401
|
+
const port = async (messages) => {
|
|
402
|
+
const current = executionSnapshot();
|
|
403
|
+
if (!executionSnapshotMatches(current, snapshot)) {
|
|
404
|
+
throw new Error(
|
|
405
|
+
"process grader worker or credential resolver changed after construction",
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
const content = await runProcess({
|
|
409
|
+
snapshot,
|
|
410
|
+
timeoutMs,
|
|
411
|
+
memoryLimitMb,
|
|
412
|
+
apiKey,
|
|
413
|
+
baseUrl,
|
|
414
|
+
input: {
|
|
415
|
+
schema: "chainlesschain.skill-synthesis-process-grader-request/v2",
|
|
416
|
+
provider,
|
|
417
|
+
model,
|
|
418
|
+
baseUrl,
|
|
419
|
+
maxTokens,
|
|
420
|
+
timeoutMs,
|
|
421
|
+
messages: normalizeMessages(messages),
|
|
422
|
+
},
|
|
423
|
+
});
|
|
424
|
+
const after = executionSnapshot();
|
|
425
|
+
if (!executionSnapshotMatches(after, snapshot)) {
|
|
426
|
+
throw new Error(
|
|
427
|
+
"process grader worker or credential resolver changed during execution",
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
return content;
|
|
431
|
+
};
|
|
432
|
+
Object.freeze(port);
|
|
433
|
+
PROCESS_GRADERS.set(port, descriptor);
|
|
434
|
+
return port;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
export function isGovernedSkillSynthesisProcessGrader(value) {
|
|
438
|
+
return PROCESS_GRADERS.has(value);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
export function getGovernedSkillSynthesisProcessGraderDescriptor(value) {
|
|
442
|
+
const descriptor = PROCESS_GRADERS.get(value);
|
|
443
|
+
return descriptor ? Object.freeze(structuredClone(descriptor)) : null;
|
|
444
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { types as utilTypes } from "node:util";
|
|
2
|
+
|
|
3
|
+
import { createChatFn } from "../cowork-adapter.js";
|
|
4
|
+
import { BUILT_IN_PROVIDERS } from "../llm-providers.js";
|
|
5
|
+
|
|
6
|
+
const PORTS = new WeakSet();
|
|
7
|
+
const OPTION_KEYS = new Set([
|
|
8
|
+
"apiKey",
|
|
9
|
+
"baseUrl",
|
|
10
|
+
"maxTokens",
|
|
11
|
+
"model",
|
|
12
|
+
"provider",
|
|
13
|
+
"timeoutMs",
|
|
14
|
+
]);
|
|
15
|
+
const MESSAGE_ROLES = new Set(["assistant", "system", "user"]);
|
|
16
|
+
const MAX_MESSAGES = 8;
|
|
17
|
+
const MAX_PROMPT_BYTES = 64 * 1024;
|
|
18
|
+
|
|
19
|
+
function plainDataRecord(value, label, allowedKeys) {
|
|
20
|
+
if (
|
|
21
|
+
!value ||
|
|
22
|
+
typeof value !== "object" ||
|
|
23
|
+
Array.isArray(value) ||
|
|
24
|
+
utilTypes.isProxy(value) ||
|
|
25
|
+
(Object.getPrototypeOf(value) !== Object.prototype &&
|
|
26
|
+
Object.getPrototypeOf(value) !== null)
|
|
27
|
+
) {
|
|
28
|
+
throw new TypeError(`${label} must be a plain object`);
|
|
29
|
+
}
|
|
30
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
31
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
32
|
+
if (
|
|
33
|
+
typeof key !== "string" ||
|
|
34
|
+
!allowedKeys.has(key) ||
|
|
35
|
+
!descriptor ||
|
|
36
|
+
!("value" in descriptor) ||
|
|
37
|
+
!descriptor.enumerable
|
|
38
|
+
) {
|
|
39
|
+
throw new TypeError(`${label} contains unsupported fields`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function boundedString(value, label, maximum) {
|
|
46
|
+
if (
|
|
47
|
+
typeof value !== "string" ||
|
|
48
|
+
value.length === 0 ||
|
|
49
|
+
value.length > maximum ||
|
|
50
|
+
value.trim() !== value ||
|
|
51
|
+
value.includes("\0")
|
|
52
|
+
) {
|
|
53
|
+
throw new TypeError(`${label} must be a non-empty bounded string`);
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function boundedContent(value, label, maximum) {
|
|
59
|
+
if (
|
|
60
|
+
typeof value !== "string" ||
|
|
61
|
+
value.trim().length === 0 ||
|
|
62
|
+
value.length > maximum ||
|
|
63
|
+
value.includes("\0")
|
|
64
|
+
) {
|
|
65
|
+
throw new TypeError(`${label} must be non-empty bounded text`);
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function boundedInteger(value, label, minimum, maximum) {
|
|
71
|
+
if (!Number.isSafeInteger(value) || value < minimum || value > maximum) {
|
|
72
|
+
throw new TypeError(
|
|
73
|
+
`${label} must be an integer from ${minimum} to ${maximum}`,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function normalizeBaseUrl(provider, value) {
|
|
80
|
+
const providerDefinition = BUILT_IN_PROVIDERS[provider];
|
|
81
|
+
const baseUrl = value || providerDefinition.baseUrl;
|
|
82
|
+
let parsed;
|
|
83
|
+
try {
|
|
84
|
+
parsed = new URL(baseUrl);
|
|
85
|
+
} catch {
|
|
86
|
+
throw new TypeError("learning synthesis provider baseUrl is invalid");
|
|
87
|
+
}
|
|
88
|
+
if (
|
|
89
|
+
parsed.protocol !== "https:" ||
|
|
90
|
+
parsed.username ||
|
|
91
|
+
parsed.password ||
|
|
92
|
+
parsed.search ||
|
|
93
|
+
parsed.hash
|
|
94
|
+
) {
|
|
95
|
+
throw new TypeError(
|
|
96
|
+
"learning synthesis cloud provider baseUrl must be credential-free HTTPS",
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
const expected = new URL(providerDefinition.baseUrl);
|
|
100
|
+
const normalized = parsed.href.replace(/\/$/u, "");
|
|
101
|
+
const expectedNormalized = expected.href.replace(/\/$/u, "");
|
|
102
|
+
if (normalized !== expectedNormalized) {
|
|
103
|
+
throw new TypeError(
|
|
104
|
+
"learning synthesis provider baseUrl must match the built-in provider endpoint",
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
return normalized;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function normalizeMessages(messages) {
|
|
111
|
+
if (
|
|
112
|
+
!Array.isArray(messages) ||
|
|
113
|
+
utilTypes.isProxy(messages) ||
|
|
114
|
+
messages.length === 0 ||
|
|
115
|
+
messages.length > MAX_MESSAGES
|
|
116
|
+
) {
|
|
117
|
+
throw new TypeError(
|
|
118
|
+
`learning synthesis messages must contain 1 to ${MAX_MESSAGES} entries`,
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
let bytes = 0;
|
|
122
|
+
const normalized = messages.map((message, index) => {
|
|
123
|
+
plainDataRecord(
|
|
124
|
+
message,
|
|
125
|
+
`learning synthesis message ${index}`,
|
|
126
|
+
new Set(["content", "role"]),
|
|
127
|
+
);
|
|
128
|
+
if (!MESSAGE_ROLES.has(message.role)) {
|
|
129
|
+
throw new TypeError(
|
|
130
|
+
`learning synthesis message ${index} role is invalid`,
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
const content = boundedContent(
|
|
134
|
+
message.content,
|
|
135
|
+
`learning synthesis message ${index} content`,
|
|
136
|
+
MAX_PROMPT_BYTES,
|
|
137
|
+
);
|
|
138
|
+
bytes += Buffer.byteLength(content, "utf8");
|
|
139
|
+
return Object.freeze({ role: message.role, content });
|
|
140
|
+
});
|
|
141
|
+
if (bytes > MAX_PROMPT_BYTES) {
|
|
142
|
+
throw new TypeError(
|
|
143
|
+
`learning synthesis prompt exceeds ${MAX_PROMPT_BYTES} bytes`,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
return Object.freeze(normalized);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Create the narrow provider egress used by a signed learning deployment.
|
|
151
|
+
* Credentials stay in the closure and are never exposed on the returned port.
|
|
152
|
+
*/
|
|
153
|
+
export function createGovernedSkillSynthesisProviderChat(options = {}) {
|
|
154
|
+
plainDataRecord(options, "learning synthesis provider options", OPTION_KEYS);
|
|
155
|
+
const provider = boundedString(
|
|
156
|
+
options.provider,
|
|
157
|
+
"learning synthesis provider",
|
|
158
|
+
64,
|
|
159
|
+
);
|
|
160
|
+
if (provider === "ollama" || !Object.hasOwn(BUILT_IN_PROVIDERS, provider)) {
|
|
161
|
+
throw new TypeError(
|
|
162
|
+
"learning synthesis provider must be a supported cloud provider",
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
const model = boundedString(
|
|
166
|
+
options.model || BUILT_IN_PROVIDERS[provider].models[0],
|
|
167
|
+
"learning synthesis model",
|
|
168
|
+
256,
|
|
169
|
+
);
|
|
170
|
+
const apiKey = boundedString(
|
|
171
|
+
options.apiKey,
|
|
172
|
+
"learning synthesis provider credential",
|
|
173
|
+
16 * 1024,
|
|
174
|
+
);
|
|
175
|
+
const baseUrl = normalizeBaseUrl(provider, options.baseUrl);
|
|
176
|
+
const timeoutMs = boundedInteger(
|
|
177
|
+
options.timeoutMs ?? 30_000,
|
|
178
|
+
"learning synthesis provider timeoutMs",
|
|
179
|
+
1_000,
|
|
180
|
+
120_000,
|
|
181
|
+
);
|
|
182
|
+
const maxTokens = boundedInteger(
|
|
183
|
+
options.maxTokens ?? 2_048,
|
|
184
|
+
"learning synthesis provider maxTokens",
|
|
185
|
+
128,
|
|
186
|
+
4_096,
|
|
187
|
+
);
|
|
188
|
+
const chat = createChatFn({ provider, model, baseUrl, apiKey });
|
|
189
|
+
|
|
190
|
+
const port = async (messages) => {
|
|
191
|
+
const controller = new AbortController();
|
|
192
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
193
|
+
timer.unref?.();
|
|
194
|
+
try {
|
|
195
|
+
return await chat(normalizeMessages(messages), {
|
|
196
|
+
maxTokens,
|
|
197
|
+
signal: controller.signal,
|
|
198
|
+
});
|
|
199
|
+
} catch (error) {
|
|
200
|
+
if (controller.signal.aborted) {
|
|
201
|
+
const timeout = new Error(
|
|
202
|
+
`learning synthesis provider timed out after ${timeoutMs}ms`,
|
|
203
|
+
{ cause: error },
|
|
204
|
+
);
|
|
205
|
+
timeout.code = "LEARNING_SYNTHESIS_PROVIDER_TIMEOUT";
|
|
206
|
+
throw timeout;
|
|
207
|
+
}
|
|
208
|
+
throw error;
|
|
209
|
+
} finally {
|
|
210
|
+
clearTimeout(timer);
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
Object.freeze(port);
|
|
214
|
+
PORTS.add(port);
|
|
215
|
+
return port;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function isGovernedSkillSynthesisProviderChat(value) {
|
|
219
|
+
return PORTS.has(value);
|
|
220
|
+
}
|