chainlesschain 0.166.103 → 0.166.104
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 +1 -1
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
- package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-BLrXpdnP.js → AIOps-Bah3HREy.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-C0xy9uFy.js → ActionButton-DY2aeZMc.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-C6EephQP.js → Analytics-BFly8Xaa.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-ZCXdOD9y.js → AppLayout-dp0Zz-JM.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-D4MfZ-pl.js → Artifacts-DcIg09ai.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BQ8c3bBu.js → Audit-DkN-lsjZ.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BOA7_ljM.js → BackgroundAgents-BjzgusLx.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-60uiQjGT.js → Backup-CU8S6qu9.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BDvEbGs_.js → BaseInput-B1pC2gjL.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-B3IkAuFQ.js → Chat-B6xFp6gD.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DxNCLZ_X.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-njGbfJWq.js → Checkbox-QHw7Vc4U.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CF7DtdxC.js → Codegen-gdecsfjg.js} +1 -1
- package/src/assets/web-panel/assets/{Col-C_3Zix40.js → Col-B0_JmAmc.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CzU-ZC2d.js → Community-DRCcP5xR.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BgeqsPRh.js → Compact-DZtoGzhX.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-6l7cwiqp.js → Compliance-BfNTvEnT.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-D4s905fI.js → Cowork-CDXTLm84.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-CGTYSxRS.js → Cron-Big35CbN.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BnSo-Yt3.js → Crosschain-C8ArrAVr.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Dm4vk2X1.js → DID-D_77BI2O.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-D7H-PZ_N.js → Dashboard-D2SxTzEp.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-COslkgxn.js → Dropdown-mR1-b9ud.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CJWEetmk.js → EmailListRenderer-DPl7TE1c.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-BbzebAWe.js → EvolutionSettings-BxRYLRSH.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BsoTOXwk.js → FamilyGuardDashboard-rnGtXJ5Z.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-Ck5kM_5H.js → Federation-BpxenYK8.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-gShxCqtF.js → FormItemContext-Cz1kDf6l.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DarN1G-z.js → GenericCardRenderer-CGV3KN6U.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CJfpLyP5.js → Git-CIRP4UTx.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CVcJmpQz.js → Governance-DX4r8Vmt.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-ComU_ig8.js → Inference-DQKk02Hl.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-35hprFJy.js → KnowledgeGraph-DdD6J-By.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BQDqBTz0.js → Logs-DA2w-1_m.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-BpdGAVCC.js → MarkdownRenderer-C9aSGETh.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-B9O9OKnn.js → Marketplace-BsJ6_6KW.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-VMKxA4Wc.js → McpTools-_6k30z6u.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-CcBbf3Bc.js → Memory-C0_dYY0A.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-D7myz46N.js → MobileBridge-CCTnVqiC.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-Da5KBXyx.js → MobileProjects-RZdxDSwC.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-x3NPZfuL.js → Mtc-D4Ys8lvX.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-CwnzptEC.js → MtcAudit-BKTC--a2.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-CCAxf4Ye.js → Multisig-CGR1qOe1.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CptHKz-Q.js → NLProgramming-hKKD4qWb.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-0uEp4DCJ.js → Notes-pCn7Ec40.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-DthvrOLd.js → NotificationSettings-B9eEJXEs.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-CmJuhaT2.js +1 -0
- package/src/assets/web-panel/assets/{Organization-BWf2tmQQ.js → Organization-CcQbrnwW.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BbvAtEth.js → Overflow-HmD4Mn72.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-zBo6enit.js → P2P-B7LIgx5H.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-D_LMQ4A4.js → PdhVaultBrowser-CXiHnBfX.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-C1ucb2ck.js → Permissions-CQRI3y_l.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-Bz64RddJ.js → PersonalDataHub-1EeHmsy5.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-DXJt3y3_.js → Pipeline-BFyoIdn8.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DiZ8b_ut.js → Privacy-BxWthXMF.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-DfLKKrJ4.js → ProjectInit-DfigBilu.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Ct6kJuIY.js → ProjectSettings-CFmIcVc-.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BBUMlZ3m.js → Projects-CR7H59v3.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DYVQPHvc.js → Providers-2ulom-76.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-23Il7iPp.js → QrScannerModal-BwhO07b_.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-WgOZKrv1.js → QuickAsk-_Wg34OwF.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CRIka6xT.js → Recommend-D_jq6Svg.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DOy3GjVZ.js → RemoteSession-BlzvEfsa.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-BXyi6xeR.js → Reputation-9CTXHfL4.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CoMxuIcR.js → Row-DlCYCN-t.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-87hPkoM6.js → RssFeed-BvlInFCH.js} +3 -3
- package/src/assets/web-panel/assets/{Search-B1EqFCO4.js → Search-CfaUzKuL.js} +1 -1
- package/src/assets/web-panel/assets/{Security-HcC41eGs.js → Security-bAWgLyve.js} +3 -3
- package/src/assets/web-panel/assets/{Services-BqLwmvCM.js → Services-C4LOGACW.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CIMmjW4r.js → Skeleton-Dd0Uwh3_.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CgurezJU.js → Skills-ZYF1kYCU.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CJuRuqPE.js → Sla-DpsmIaEo.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BUwsbd1o.js → SpeechSettings-BBXoJ4yc.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-qo04TOX-.js → SyncSettings-SOnROi2Y.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-HFA_ZlDk.js +1 -0
- package/src/assets/web-panel/assets/{Templates-D1PTczPW.js → Templates-fsK-RCEc.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-Bi0FkEPR.js → Tenant-CuqYxamb.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DfSt3bIF.js → Terminal-GKlI2R5F.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-B7bIVs4R.js → TimelineRenderer-DMDMHLeY.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-B6w5XrMb.js → Tokens-BoV60rh3.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-XXVSDWiF.js → Trigger-CE344-Ws.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DYvlgcK-.js → Trust-DENwgkVc.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-XyYwJMBM.js → UkeySign-FrcM7yfm.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-C47WbtHH.js → VideoEditing-DAY9WaC2.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CYfqTj_C.js → Wallet-BuUR5i82.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-3AduFn1l.js → WebAuthn-nfSQuq85.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-DHYEHjMJ.js → WorkflowEditor-DHhPOp9l.js} +1 -1
- package/src/assets/web-panel/assets/{chat-AeehErSw.js → chat-C4nsLzYy.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DKXJ8paX.js → colors-BwXH0Wjn.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BOlCiomD.js → compact-item-uApFG30S.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BAP6U85b.js → createContext-BpyYs4fe.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-Bk6HGn3N.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BLmeL1Xe.js → hasIn-MXCLi00p.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdNSmvog.js → index-1LxX2IwJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dv8-g1pY.js → index-61CBBrHE.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClpwxOXo.js → index-B0P1Z_oa.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgtaOzMo.js → index-B7jojVc7.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRcJlKSa.js → index-BEGMfaOo.js} +1 -1
- package/src/assets/web-panel/assets/{index-wyKpTsGM.js → index-BOhjapd5.js} +1 -1
- package/src/assets/web-panel/assets/{index-BuUwKmEI.js → index-BaBwXpAp.js} +1 -1
- package/src/assets/web-panel/assets/index-Bb1LPYdi.js +1 -0
- package/src/assets/web-panel/assets/{index-Co7pjF53.js → index-Btv--Nnt.js} +1 -1
- package/src/assets/web-panel/assets/index-C-FsTuFG.js +1 -0
- package/src/assets/web-panel/assets/{index-CFKzWIo8.js → index-CF0bUOP4.js} +1 -1
- package/src/assets/web-panel/assets/{index-CaHhfpBi.js → index-CNjUPfJP.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZMbXl5lo.js → index-CRmNdEk_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTnp4Nt3.js → index-C_oOpXhP.js} +1 -1
- package/src/assets/web-panel/assets/{index-OLKhib9T.js → index-ChUTKrOq.js} +1 -1
- package/src/assets/web-panel/assets/{index-T28naovw.js → index-CiIpIYhs.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bpx54vfs.js → index-CwVvk2i7.js} +1 -1
- package/src/assets/web-panel/assets/{index-BAS2QqLn.js → index-D3_tj06B.js} +1 -1
- package/src/assets/web-panel/assets/{index-CRa4pAaM.js → index-DE4W4vLO.js} +3 -3
- package/src/assets/web-panel/assets/{index-BSOenF5s.js → index-DLxKx5_J.js} +1 -1
- package/src/assets/web-panel/assets/{index-DE7cbDDe.js → index-DTXi_gQh.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWYqOI1A.js → index-Daco83me.js} +1 -1
- package/src/assets/web-panel/assets/{index-DQLQuwpA.js → index-DffWVpZv.js} +1 -1
- package/src/assets/web-panel/assets/{index-CiqeF0Pf.js → index-Dkncxel3.js} +1 -1
- package/src/assets/web-panel/assets/{index-IlzfIRNh.js → index-Dn12gJJU.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bn54FU3i.js → index-Dt-nq2eF.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bt-FCVzh.js → index-Du01X9N9.js} +1 -1
- package/src/assets/web-panel/assets/{index-EKNODw4P.js → index-DucLR6YX.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5AKY6bJ.js → index-Gz2rGWef.js} +1 -1
- package/src/assets/web-panel/assets/{index-C8qi53Ki.js → index-IvgszJ3C.js} +1 -1
- package/src/assets/web-panel/assets/{index-urPvyUVk.js → index-S80LLjdx.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bs2O3f81.js → index-WKbnwbKa.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpZqbc4w.js → index-XHBXtvqp.js} +1 -1
- package/src/assets/web-panel/assets/{index-De2fPxdb.js → index-nn22NSDK.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0IjlB9m.js → index-pCIAE2yS.js} +1 -1
- package/src/assets/web-panel/assets/{index-PEe9OWEQ.js → index-pRpMLhMt.js} +1 -1
- package/src/assets/web-panel/assets/{index-FPXLIXoy.js → index-pgHGBAoF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BhcpWl5z.js → index-ugIUt5TL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsQ38fVY.js → index-xLGf7f9K.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CDWa1rnn.js → initDefaultProps-C58CkKEo.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CX2Cnsd5.js → motion-BLWPO2NV.js} +1 -1
- package/src/assets/web-panel/assets/{move-Bfe1NcEF.js → move-BgrFMwYp.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DbdqleHE.js → mtc-parser-Cq2AuGzl.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CE2K7NVv.js → omit-Bb-9L7if.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-y_bZgxWG.js → pickAttrs-vLmOxYr1.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BOHR4zwr.js → placementArrow-BNySU_dJ.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-B8Jwq05-.js → responsiveObserve-xnbwagnm.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BD7RJ3Kn.js → slide-BccbY5Cn.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BuxDJeDx.js → statusUtils-DOp9d2-w.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DgYQ2Q0o.js → styleChecker-Bu1w6ho9.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DAHF0Fwi.js → useFlexGapSupport-ZsUOrVdL.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-D4kDyLFp.js → useFs-C0zpzKtO.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BHtSxW4A.js → usePersonalDataHub-DO1OdgXK.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CHKtdqW0.js → vnode-jTIRyhR5.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CIZAMma9.js → zoom-DKvS7-Qs.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +56 -20
- package/src/commands/batch.js +17 -12
- package/src/commands/eval.js +24 -8
- package/src/data/changelog.json +13 -0
- package/src/harness/mcp-client.js +187 -26
- package/src/lib/background-session-transport.js +21 -5
- package/src/lib/decision-layer/runtime.js +180 -10
- package/src/lib/direct-model-usage.js +34 -0
- package/src/lib/evolution/agent-evolution-ingress.js +63 -7
- package/src/lib/evolution/evolution-evidence-artifact-adapter.js +10 -0
- package/src/lib/evolution/evolution-evidence-projector.js +46 -7
- package/src/lib/evolution/skill-decision-projection.js +211 -0
- package/src/lib/evolution/skill-retrieval-revocation-authority.js +17 -2
- package/src/lib/skill-loader.js +16 -0
- package/src/repl/agent-repl.js +86 -7
- package/src/runtime/agent-core.js +111 -13
- package/src/runtime/headless-runner.js +212 -22
- package/src/runtime/headless-stream.js +189 -25
- package/src/runtime/mcp-config.js +26 -17
- package/src/runtime/mcp-tool-search.js +44 -14
- package/src/assets/web-panel/assets/ChatBubbleRenderer-n6BVStHf.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-CxXuPzZg.js +0 -1
- package/src/assets/web-panel/assets/Tasks-QEFENVsp.js +0 -1
- package/src/assets/web-panel/assets/devWarning-rGldFhxo.js +0 -1
- package/src/assets/web-panel/assets/index-Cw-lfvvV.js +0 -1
- package/src/assets/web-panel/assets/index-QBXRSyoZ.js +0 -1
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { types } from "node:util";
|
|
2
|
+
import { createSkillDecisionRequest } from "../decision-layer/contracts.js";
|
|
3
|
+
|
|
4
|
+
const MAX_BYTES = 256 * 1024;
|
|
5
|
+
|
|
6
|
+
function canonical(value) {
|
|
7
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
8
|
+
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
9
|
+
return `{${Object.keys(value)
|
|
10
|
+
.sort()
|
|
11
|
+
.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`)
|
|
12
|
+
.join(",")}}`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Capture descriptors before any authority await. Never evaluate source getters
|
|
16
|
+
// or allow caller mutation to change committed evidence or outbound bytes.
|
|
17
|
+
function snapshot(value) {
|
|
18
|
+
let nodes = 0;
|
|
19
|
+
let bytes = 0;
|
|
20
|
+
const seen = new Set();
|
|
21
|
+
const visit = (entry, depth) => {
|
|
22
|
+
if (++nodes > 4096 || depth > 16)
|
|
23
|
+
throw new TypeError("Skill decision input exceeds its structural budget");
|
|
24
|
+
if (typeof entry === "string") {
|
|
25
|
+
bytes += Buffer.byteLength(entry, "utf8");
|
|
26
|
+
if (bytes > MAX_BYTES)
|
|
27
|
+
throw new TypeError("Skill decision input exceeds its byte budget");
|
|
28
|
+
return entry;
|
|
29
|
+
}
|
|
30
|
+
if (
|
|
31
|
+
entry === null ||
|
|
32
|
+
typeof entry === "boolean" ||
|
|
33
|
+
(typeof entry === "number" && Number.isFinite(entry))
|
|
34
|
+
)
|
|
35
|
+
return entry;
|
|
36
|
+
if (
|
|
37
|
+
!entry ||
|
|
38
|
+
typeof entry !== "object" ||
|
|
39
|
+
types.isProxy(entry) ||
|
|
40
|
+
seen.has(entry)
|
|
41
|
+
)
|
|
42
|
+
throw new TypeError(
|
|
43
|
+
"Skill decision input must be acyclic plain JSON data",
|
|
44
|
+
);
|
|
45
|
+
const array = Array.isArray(entry);
|
|
46
|
+
if (
|
|
47
|
+
!array &&
|
|
48
|
+
![Object.prototype, null].includes(Object.getPrototypeOf(entry))
|
|
49
|
+
)
|
|
50
|
+
throw new TypeError("Skill decision input must use plain objects");
|
|
51
|
+
const keys = Reflect.ownKeys(entry).filter(
|
|
52
|
+
(key) => !(array && key === "length"),
|
|
53
|
+
);
|
|
54
|
+
if (
|
|
55
|
+
array &&
|
|
56
|
+
(keys.length !== entry.length ||
|
|
57
|
+
keys.some((key, index) => key !== String(index)))
|
|
58
|
+
)
|
|
59
|
+
throw new TypeError("Skill decision arrays must be dense data");
|
|
60
|
+
seen.add(entry);
|
|
61
|
+
const output = array ? [] : Object.create(null);
|
|
62
|
+
for (const key of keys) {
|
|
63
|
+
const property = Object.getOwnPropertyDescriptor(entry, key);
|
|
64
|
+
if (
|
|
65
|
+
typeof key !== "string" ||
|
|
66
|
+
!property?.enumerable ||
|
|
67
|
+
!("value" in property)
|
|
68
|
+
)
|
|
69
|
+
throw new TypeError(
|
|
70
|
+
"Skill decision input cannot contain accessors or symbols",
|
|
71
|
+
);
|
|
72
|
+
bytes += Buffer.byteLength(key, "utf8");
|
|
73
|
+
if (bytes > MAX_BYTES)
|
|
74
|
+
throw new TypeError("Skill decision input exceeds its byte budget");
|
|
75
|
+
Object.defineProperty(output, key, {
|
|
76
|
+
value: visit(property.value, depth + 1),
|
|
77
|
+
enumerable: true,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
seen.delete(entry);
|
|
81
|
+
return Object.freeze(output);
|
|
82
|
+
};
|
|
83
|
+
const result = visit(value, 0);
|
|
84
|
+
if (Buffer.byteLength(JSON.stringify(result), "utf8") > MAX_BYTES)
|
|
85
|
+
throw new TypeError("Skill decision input exceeds its byte budget");
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function exact(value, keys) {
|
|
90
|
+
if (
|
|
91
|
+
!value ||
|
|
92
|
+
typeof value !== "object" ||
|
|
93
|
+
Array.isArray(value) ||
|
|
94
|
+
Object.keys(value).sort().join("\0") !== [...keys].sort().join("\0")
|
|
95
|
+
)
|
|
96
|
+
throw new TypeError("Skill decision has an unsupported protocol shape");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function text(value) {
|
|
100
|
+
if (typeof value !== "string" || !value.length)
|
|
101
|
+
throw new TypeError("Skill decision requires nonempty text");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function snapshotSkillDecisionPayload(value) {
|
|
105
|
+
const payload = snapshot(value);
|
|
106
|
+
exact(payload, ["state", "questions"]);
|
|
107
|
+
exact(payload.state, ["task", "candidates"]);
|
|
108
|
+
text(payload.state.task);
|
|
109
|
+
const candidates = payload.state.candidates;
|
|
110
|
+
if (
|
|
111
|
+
!Array.isArray(candidates) ||
|
|
112
|
+
candidates.length < 1 ||
|
|
113
|
+
candidates.length > 8
|
|
114
|
+
)
|
|
115
|
+
throw new TypeError("Skill decision requires bounded candidates");
|
|
116
|
+
candidates.forEach((candidate, index) => {
|
|
117
|
+
exact(candidate, [
|
|
118
|
+
"candidateId",
|
|
119
|
+
"name",
|
|
120
|
+
"description",
|
|
121
|
+
"category",
|
|
122
|
+
"tags",
|
|
123
|
+
]);
|
|
124
|
+
if (candidate.candidateId !== `c${index + 1}`)
|
|
125
|
+
throw new TypeError("Skill decision candidate identity changed");
|
|
126
|
+
for (const key of ["name", "description", "category"]) text(candidate[key]);
|
|
127
|
+
if (!Array.isArray(candidate.tags) || candidate.tags.length > 32)
|
|
128
|
+
throw new TypeError("Skill decision tags are unbounded");
|
|
129
|
+
candidate.tags.forEach(text);
|
|
130
|
+
});
|
|
131
|
+
const ids = candidates.map(({ candidateId }) => candidateId);
|
|
132
|
+
exact(payload.questions, [
|
|
133
|
+
"needs_skill",
|
|
134
|
+
"best_skill",
|
|
135
|
+
...ids.map((id) => `fits_${id}`),
|
|
136
|
+
]);
|
|
137
|
+
for (const key of ["needs_skill", ...ids.map((id) => `fits_${id}`)]) {
|
|
138
|
+
exact(payload.questions[key], ["type", "instructions"]);
|
|
139
|
+
if (payload.questions[key].type !== "noul")
|
|
140
|
+
throw new TypeError("Skill decision question type changed");
|
|
141
|
+
text(payload.questions[key].instructions);
|
|
142
|
+
}
|
|
143
|
+
const choice = payload.questions.best_skill;
|
|
144
|
+
exact(choice, ["type", "instructions", "criteria"]);
|
|
145
|
+
if (choice.type !== "choice")
|
|
146
|
+
throw new TypeError("Skill decision question type changed");
|
|
147
|
+
text(choice.instructions);
|
|
148
|
+
exact(choice.criteria, [...ids, "none"]);
|
|
149
|
+
Object.values(choice.criteria).forEach(text);
|
|
150
|
+
return payload;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function snapshotSkillDecisionRequest(value) {
|
|
154
|
+
const request = snapshot(value);
|
|
155
|
+
const rebuilt = createSkillDecisionRequest({
|
|
156
|
+
decisionId: request.decisionId,
|
|
157
|
+
...request.binding,
|
|
158
|
+
query: request.payload?.state?.task,
|
|
159
|
+
candidates: request.candidates,
|
|
160
|
+
});
|
|
161
|
+
if (canonical(request) !== canonical(rebuilt))
|
|
162
|
+
throw new TypeError("Skill decision request identity or contract changed");
|
|
163
|
+
snapshotSkillDecisionPayload(request.payload);
|
|
164
|
+
return request;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function textPath(path) {
|
|
168
|
+
return (
|
|
169
|
+
/^state\.task$/u.test(path) ||
|
|
170
|
+
/^state\.candidates\.\d+\.(?:name|description|category|tags\.\d+)$/u.test(
|
|
171
|
+
path,
|
|
172
|
+
) ||
|
|
173
|
+
/^questions\.best_skill\.criteria\.c[1-8]$/u.test(path)
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function buildSkillDecisionPayload(original, projection) {
|
|
178
|
+
if (
|
|
179
|
+
projection.visibility !== "model-visible" ||
|
|
180
|
+
projection.truncated ||
|
|
181
|
+
(projection.redactionSummary?.byType?.["content-truncation"] ?? 0) > 0
|
|
182
|
+
)
|
|
183
|
+
throw new Error("Skill decision projection is opaque or truncated");
|
|
184
|
+
const captured = snapshotSkillDecisionPayload(original);
|
|
185
|
+
const projected = snapshotSkillDecisionPayload(projection.content);
|
|
186
|
+
const compare = (before, after, path = "") => {
|
|
187
|
+
if (
|
|
188
|
+
typeof before === "string" &&
|
|
189
|
+
typeof after === "string" &&
|
|
190
|
+
textPath(path)
|
|
191
|
+
)
|
|
192
|
+
return;
|
|
193
|
+
if (before === null || typeof before !== "object") {
|
|
194
|
+
if (before !== after)
|
|
195
|
+
throw new Error("Skill decision projection changed protocol metadata");
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (
|
|
199
|
+
!after ||
|
|
200
|
+
typeof after !== "object" ||
|
|
201
|
+
Array.isArray(before) !== Array.isArray(after) ||
|
|
202
|
+
Object.keys(before).sort().join("\0") !==
|
|
203
|
+
Object.keys(after).sort().join("\0")
|
|
204
|
+
)
|
|
205
|
+
throw new Error("Skill decision projection changed protocol structure");
|
|
206
|
+
for (const key of Object.keys(before))
|
|
207
|
+
compare(before[key], after[key], path ? `${path}.${key}` : key);
|
|
208
|
+
};
|
|
209
|
+
compare(captured, projected);
|
|
210
|
+
return projected;
|
|
211
|
+
}
|
|
@@ -239,9 +239,19 @@ export async function openSkillRetrievalRevocationAuthority({
|
|
|
239
239
|
) {
|
|
240
240
|
throw new Error("Retrieval revocation load is not authoritative");
|
|
241
241
|
}
|
|
242
|
-
|
|
242
|
+
const loadedState = loaded.found
|
|
243
243
|
? verifySkillRetrievalRevocationState(loaded.state, tenantId)
|
|
244
244
|
: null;
|
|
245
|
+
if (
|
|
246
|
+
state !== null &&
|
|
247
|
+
(loadedState === null ||
|
|
248
|
+
loadedState.revision < state.revision ||
|
|
249
|
+
(loadedState.revision === state.revision &&
|
|
250
|
+
loadedState.stateDigest !== state.stateDigest))
|
|
251
|
+
) {
|
|
252
|
+
throw new Error("Retrieval revocation state regressed");
|
|
253
|
+
}
|
|
254
|
+
state = loadedState;
|
|
245
255
|
return state;
|
|
246
256
|
}
|
|
247
257
|
|
|
@@ -265,6 +275,10 @@ export async function openSkillRetrievalRevocationAuthority({
|
|
|
265
275
|
receiptDigest: entry?.propagationRequestDigest ?? null,
|
|
266
276
|
});
|
|
267
277
|
},
|
|
278
|
+
async refresh() {
|
|
279
|
+
const current = await reload();
|
|
280
|
+
return current?.stateDigest ?? null;
|
|
281
|
+
},
|
|
268
282
|
async invalidateRetrieval(input) {
|
|
269
283
|
const request = normalizeRequest(input, tenantId);
|
|
270
284
|
const contentDigest = request.dependency.digest;
|
|
@@ -351,7 +365,8 @@ export function captureSkillRetrievalRevocationReader(reader) {
|
|
|
351
365
|
if (
|
|
352
366
|
!readerBrand.has(reader) ||
|
|
353
367
|
reader.schema !== SKILL_RETRIEVAL_REVOCATION_READER_SCHEMA ||
|
|
354
|
-
typeof reader.inspect !== "function"
|
|
368
|
+
typeof reader.inspect !== "function" ||
|
|
369
|
+
typeof reader.refresh !== "function"
|
|
355
370
|
) {
|
|
356
371
|
throw new TypeError(
|
|
357
372
|
"A branded Skill retrieval revocation reader is required",
|
package/src/lib/skill-loader.js
CHANGED
|
@@ -392,6 +392,7 @@ export class CLISkillLoader {
|
|
|
392
392
|
throw new TypeError("reauthorizeSkill must be a function or null");
|
|
393
393
|
}
|
|
394
394
|
this._cache = null;
|
|
395
|
+
this._lastLoadOptions = null;
|
|
395
396
|
bindSkillRuntimeAdmission(this, skillRuntimeAdmission, {
|
|
396
397
|
required: skillRuntimeAdmissionRequired,
|
|
397
398
|
});
|
|
@@ -1264,6 +1265,12 @@ export class CLISkillLoader {
|
|
|
1264
1265
|
*/
|
|
1265
1266
|
loadAll(options = {}) {
|
|
1266
1267
|
this._cacheStats.descriptorScans += 1;
|
|
1268
|
+
// Preserve explicit layer policy for a later freshness scan. In particular,
|
|
1269
|
+
// refreshing an opt-in decision must not re-enable a disabled skill layer.
|
|
1270
|
+
this._lastLoadOptions = {
|
|
1271
|
+
...options,
|
|
1272
|
+
...(options.env ? { env: { ...options.env } } : {}),
|
|
1273
|
+
};
|
|
1267
1274
|
// `cc agent --bare` (CC_SKILLS=0): no skill layer loads at all — cache the
|
|
1268
1275
|
// empty result so getResolvedSkills stays cheap on every call.
|
|
1269
1276
|
if (allSkillsDisabled(options)) {
|
|
@@ -1336,6 +1343,14 @@ export class CLISkillLoader {
|
|
|
1336
1343
|
return this.loadAll();
|
|
1337
1344
|
}
|
|
1338
1345
|
|
|
1346
|
+
/** Rescan the same layers under the options used for the current cache. */
|
|
1347
|
+
refreshResolvedSkills() {
|
|
1348
|
+
// A failed scan must not leave a previous descriptor set available as if
|
|
1349
|
+
// it were current on the next lookup.
|
|
1350
|
+
this._cache = null;
|
|
1351
|
+
return this.loadAll(this._lastLoadOptions ?? {});
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1339
1354
|
/**
|
|
1340
1355
|
* Get auto-activated persona skills
|
|
1341
1356
|
* @returns {object[]} skills with category "persona" and activation "auto"
|
|
@@ -1367,6 +1382,7 @@ export class CLISkillLoader {
|
|
|
1367
1382
|
*/
|
|
1368
1383
|
clearCache() {
|
|
1369
1384
|
this._cache = null;
|
|
1385
|
+
this._lastLoadOptions = null;
|
|
1370
1386
|
this._bodyCache.clear();
|
|
1371
1387
|
this._cacheStats = {
|
|
1372
1388
|
descriptorScans: 0,
|
package/src/repl/agent-repl.js
CHANGED
|
@@ -86,7 +86,9 @@ import {
|
|
|
86
86
|
} from "../lib/session-host-snapshot.js";
|
|
87
87
|
import { acquireSessionHostLease } from "../lib/session-host-lease.js";
|
|
88
88
|
import {
|
|
89
|
+
normalizeSessionBudgetRootConfig,
|
|
89
90
|
openProductionSessionBudgetRoot,
|
|
91
|
+
readProductionSessionBudget,
|
|
90
92
|
sessionBudgetAdmissionError,
|
|
91
93
|
} from "../lib/session-budget-production-root.js";
|
|
92
94
|
import {
|
|
@@ -2265,9 +2267,25 @@ export function prepareReplJsonlResumeCandidate(sessionId, dependencies = {}) {
|
|
|
2265
2267
|
error.code = "CC_REPL_SESSION_AUTHORITY_MISMATCH";
|
|
2266
2268
|
throw error;
|
|
2267
2269
|
}
|
|
2270
|
+
const declaredBudget = dataDescriptorValue(
|
|
2271
|
+
stateDescriptors,
|
|
2272
|
+
"sessionBudgetRoot",
|
|
2273
|
+
"REPL session host resume state",
|
|
2274
|
+
{ required: false },
|
|
2275
|
+
);
|
|
2276
|
+
const sessionBudgetRoot =
|
|
2277
|
+
declaredBudget == null
|
|
2278
|
+
? null
|
|
2279
|
+
: normalizeSessionBudgetRootConfig(
|
|
2280
|
+
snapshotReplMessageValue(
|
|
2281
|
+
declaredBudget,
|
|
2282
|
+
"REPL session budget declaration",
|
|
2283
|
+
),
|
|
2284
|
+
);
|
|
2268
2285
|
return brandedFrozenCandidate(REPL_JSONL_RESUME_CANDIDATES, {
|
|
2269
2286
|
ok: true,
|
|
2270
2287
|
sessionId,
|
|
2288
|
+
sessionBudgetRoot,
|
|
2271
2289
|
rebuiltMessages,
|
|
2272
2290
|
replayMessages: normalizedReplay.replayMessages,
|
|
2273
2291
|
canonicalSystemMessages: normalizedReplay.canonicalSystemMessages,
|
|
@@ -2786,8 +2804,60 @@ export async function runReplStartupBoundary(options, startupDependencies) {
|
|
|
2786
2804
|
) {
|
|
2787
2805
|
leaseScope.lease = acquireHostLease(leaseSessionId, { hostKind: "repl" });
|
|
2788
2806
|
}
|
|
2789
|
-
|
|
2790
|
-
|
|
2807
|
+
const injectedBudgetReader = dependencyDataFunction(
|
|
2808
|
+
startupDependencies,
|
|
2809
|
+
"readProductionSessionBudget",
|
|
2810
|
+
null,
|
|
2811
|
+
);
|
|
2812
|
+
const sidecar =
|
|
2813
|
+
leaseSessionId &&
|
|
2814
|
+
(process.platform === "linux" || injectedBudgetReader !== null)
|
|
2815
|
+
? synchronousReplRecoveryValue(
|
|
2816
|
+
(injectedBudgetReader || readProductionSessionBudget)(leaseSessionId),
|
|
2817
|
+
"REPL budget sidecar",
|
|
2818
|
+
)
|
|
2819
|
+
: null;
|
|
2820
|
+
let effectiveBudgetConfig = options.sessionBudgetRoot;
|
|
2821
|
+
const declaredBudgetConfig = startupCandidate?.sessionBudgetRoot;
|
|
2822
|
+
const requestedBudgetConfig = options.sessionBudgetRoot?.enabled
|
|
2823
|
+
? normalizeSessionBudgetRootConfig(options.sessionBudgetRoot)
|
|
2824
|
+
: null;
|
|
2825
|
+
if (startupCandidate?.ok === true) {
|
|
2826
|
+
if (declaredBudgetConfig?.enabled) {
|
|
2827
|
+
if (!sidecar) {
|
|
2828
|
+
throw Object.assign(
|
|
2829
|
+
new Error("budgeted REPL session is missing its budget sidecar"),
|
|
2830
|
+
{ code: "CC_SESSION_BUDGET_SIDECAR_REQUIRED" },
|
|
2831
|
+
);
|
|
2832
|
+
}
|
|
2833
|
+
if (
|
|
2834
|
+
requestedBudgetConfig &&
|
|
2835
|
+
JSON.stringify(requestedBudgetConfig) !==
|
|
2836
|
+
JSON.stringify(declaredBudgetConfig)
|
|
2837
|
+
) {
|
|
2838
|
+
throw Object.assign(
|
|
2839
|
+
new Error("REPL budget does not match its JSONL declaration"),
|
|
2840
|
+
{ code: "CC_SESSION_BUDGET_CONFIG_MISMATCH" },
|
|
2841
|
+
);
|
|
2842
|
+
}
|
|
2843
|
+
effectiveBudgetConfig = declaredBudgetConfig;
|
|
2844
|
+
} else if (requestedBudgetConfig || sidecar) {
|
|
2845
|
+
throw Object.assign(
|
|
2846
|
+
new Error("existing REPL session has no canonical budget declaration"),
|
|
2847
|
+
{ code: "CC_SESSION_BUDGET_JSONL_REQUIRED" },
|
|
2848
|
+
);
|
|
2849
|
+
}
|
|
2850
|
+
} else if (sidecar) {
|
|
2851
|
+
throw Object.assign(
|
|
2852
|
+
new Error("budget sidecar has no canonical REPL session"),
|
|
2853
|
+
{ code: "CC_SESSION_BUDGET_JSONL_REQUIRED" },
|
|
2854
|
+
);
|
|
2855
|
+
}
|
|
2856
|
+
let workspaceOptions = {
|
|
2857
|
+
...options,
|
|
2858
|
+
sessionBudgetRoot: effectiveBudgetConfig,
|
|
2859
|
+
};
|
|
2860
|
+
if (effectiveBudgetConfig?.enabled === true) {
|
|
2791
2861
|
if (!leaseSessionId || !leaseScope?.lease) {
|
|
2792
2862
|
throw Object.assign(
|
|
2793
2863
|
new Error(
|
|
@@ -2813,10 +2883,10 @@ export async function runReplStartupBoundary(options, startupDependencies) {
|
|
|
2813
2883
|
"CC_REPL_STARTUP_DEPENDENCY_INVALID",
|
|
2814
2884
|
);
|
|
2815
2885
|
}
|
|
2816
|
-
const root = openBudgetRoot(leaseSessionId,
|
|
2886
|
+
const root = openBudgetRoot(leaseSessionId, effectiveBudgetConfig, {
|
|
2817
2887
|
persist: true,
|
|
2818
2888
|
signal: combineReplSignals(options.signal, leaseScope.lease.signal),
|
|
2819
|
-
table:
|
|
2889
|
+
table: effectiveBudgetConfig.table,
|
|
2820
2890
|
});
|
|
2821
2891
|
if (
|
|
2822
2892
|
root?.enabled !== true ||
|
|
@@ -2850,7 +2920,7 @@ export async function runReplStartupBoundary(options, startupDependencies) {
|
|
|
2850
2920
|
throw admissionError;
|
|
2851
2921
|
}
|
|
2852
2922
|
budgetScope.root = root;
|
|
2853
|
-
workspaceOptions = { ...
|
|
2923
|
+
workspaceOptions = { ...workspaceOptions, ...root.options };
|
|
2854
2924
|
}
|
|
2855
2925
|
const trustedWorkspaceRoot = readCwd();
|
|
2856
2926
|
return enterWorkspace(trustedWorkspaceRoot, () =>
|
|
@@ -2867,11 +2937,17 @@ export function startReplJsonlSession(
|
|
|
2867
2937
|
options = {},
|
|
2868
2938
|
) {
|
|
2869
2939
|
const requireDurable =
|
|
2870
|
-
observabilityScope != null ||
|
|
2940
|
+
observabilityScope != null ||
|
|
2941
|
+
options.requireDurable === true ||
|
|
2942
|
+
options.sessionBudgetRoot?.enabled === true;
|
|
2871
2943
|
try {
|
|
2944
|
+
const budgetDeclaration = options.sessionBudgetRoot?.enabled
|
|
2945
|
+
? normalizeSessionBudgetRootConfig(options.sessionBudgetRoot)
|
|
2946
|
+
: null;
|
|
2872
2947
|
const sessionId = startSession(requestedId, {
|
|
2873
2948
|
...meta,
|
|
2874
2949
|
...(observabilityScope != null ? { observabilityScope } : {}),
|
|
2950
|
+
...(budgetDeclaration ? { sessionBudgetRoot: budgetDeclaration } : {}),
|
|
2875
2951
|
});
|
|
2876
2952
|
if (requireDurable && (typeof sessionId !== "string" || !sessionId)) {
|
|
2877
2953
|
throw new Error("JSONL session creation returned no durable session id");
|
|
@@ -3966,7 +4042,10 @@ async function startAgentReplInWorkspaceOwned(
|
|
|
3966
4042
|
options.sessionId || null,
|
|
3967
4043
|
meta,
|
|
3968
4044
|
options.observabilityScope,
|
|
3969
|
-
{
|
|
4045
|
+
{
|
|
4046
|
+
requireDurable: Boolean(_sessionBudget),
|
|
4047
|
+
sessionBudgetRoot: options.sessionBudgetRoot,
|
|
4048
|
+
},
|
|
3970
4049
|
);
|
|
3971
4050
|
if (
|
|
3972
4051
|
sessionId &&
|
|
@@ -9289,24 +9289,122 @@ async function executeToolInner(
|
|
|
9289
9289
|
? null
|
|
9290
9290
|
: captureSkillDecisionRuntime(skillDecisionRuntime);
|
|
9291
9291
|
if (decisionRuntime !== null && routing.candidates.length > 0) {
|
|
9292
|
-
const
|
|
9293
|
-
|
|
9294
|
-
|
|
9295
|
-
|
|
9292
|
+
const decisionInputsFor = (result, descriptors) => {
|
|
9293
|
+
const descriptorsByDigest = new Map(
|
|
9294
|
+
descriptors.map((skill) => [
|
|
9295
|
+
skill.executionIdentity?.contentDigest,
|
|
9296
|
+
skill,
|
|
9297
|
+
]),
|
|
9298
|
+
);
|
|
9299
|
+
return result.candidates.slice(0, 5).map((candidate) => {
|
|
9300
|
+
const descriptor = descriptorsByDigest.get(candidate.digest);
|
|
9296
9301
|
return {
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9302
|
+
candidate: {
|
|
9303
|
+
id: candidate.id,
|
|
9304
|
+
displayName: candidate.displayName,
|
|
9305
|
+
description: descriptor?.description || candidate.displayName,
|
|
9306
|
+
category: candidate.category,
|
|
9307
|
+
digest: candidate.digest,
|
|
9308
|
+
tags: Array.isArray(descriptor?.tags)
|
|
9309
|
+
? [...descriptor.tags]
|
|
9310
|
+
: [],
|
|
9311
|
+
},
|
|
9312
|
+
// Scope and compatibility are local routing inputs. They never
|
|
9313
|
+
// leave the process, but changes invalidate the old advice.
|
|
9314
|
+
identity: {
|
|
9315
|
+
namespace: candidate.namespace,
|
|
9316
|
+
version: candidate.version,
|
|
9317
|
+
paths: descriptor?.paths ?? null,
|
|
9318
|
+
os: descriptor?.os ?? null,
|
|
9319
|
+
capabilities: descriptor?.capabilities ?? null,
|
|
9320
|
+
},
|
|
9303
9321
|
};
|
|
9304
|
-
})
|
|
9322
|
+
});
|
|
9323
|
+
};
|
|
9324
|
+
const decisionInputs = decisionInputsFor(routing, skills);
|
|
9325
|
+
const snapshotFor = (result, inputs) =>
|
|
9326
|
+
JSON.stringify({
|
|
9327
|
+
candidates: inputs,
|
|
9328
|
+
selectedDigest: result.selected?.digest ?? null,
|
|
9329
|
+
conflicts: result.conflicts,
|
|
9330
|
+
});
|
|
9331
|
+
const decisionSnapshot = snapshotFor(routing, decisionInputs);
|
|
9332
|
+
const contextRevision = `routing-${createHash("sha256")
|
|
9333
|
+
.update(
|
|
9334
|
+
JSON.stringify({
|
|
9335
|
+
query: args.query,
|
|
9336
|
+
category: args.category ?? null,
|
|
9337
|
+
cwd,
|
|
9338
|
+
turnId: turnId || toolCallId || "list-skills",
|
|
9339
|
+
toolCallId: toolCallId ?? null,
|
|
9340
|
+
decisionSnapshot,
|
|
9341
|
+
}),
|
|
9342
|
+
)
|
|
9343
|
+
.digest("hex")}`;
|
|
9344
|
+
const decision = await decisionRuntime.suggest({
|
|
9345
|
+
query: args.query,
|
|
9346
|
+
candidates: decisionInputs.map(({ candidate }) => candidate),
|
|
9305
9347
|
turnId: turnId || toolCallId || "list-skills",
|
|
9306
|
-
contextRevision
|
|
9348
|
+
contextRevision,
|
|
9307
9349
|
signal,
|
|
9308
9350
|
});
|
|
9309
|
-
|
|
9351
|
+
signal?.throwIfAborted();
|
|
9352
|
+
// The provider result belongs to the captured candidate set. Recheck
|
|
9353
|
+
// the persisted revocations and live loader before exposing advice.
|
|
9354
|
+
await skillRetrievalRevocationReader?.refresh();
|
|
9355
|
+
signal?.throwIfAborted();
|
|
9356
|
+
const refreshedSkills =
|
|
9357
|
+
typeof skillLoader.refreshResolvedSkills === "function"
|
|
9358
|
+
? await skillLoader.refreshResolvedSkills()
|
|
9359
|
+
: skillLoader.getResolvedSkills();
|
|
9360
|
+
signal?.throwIfAborted();
|
|
9361
|
+
let currentSkills = await filterSkillsByCwd(
|
|
9362
|
+
refreshedSkills.filter(skillAllowed),
|
|
9363
|
+
cwd,
|
|
9364
|
+
);
|
|
9365
|
+
if (args.category) {
|
|
9366
|
+
currentSkills = currentSkills.filter(
|
|
9367
|
+
(s) => s.category.toLowerCase() === args.category.toLowerCase(),
|
|
9368
|
+
);
|
|
9369
|
+
}
|
|
9370
|
+
// The vector index can change while the decision provider is in
|
|
9371
|
+
// flight. Score the refreshed corpus again before comparing routing.
|
|
9372
|
+
vector =
|
|
9373
|
+
vectorAuthority === null
|
|
9374
|
+
? null
|
|
9375
|
+
: await vectorAuthority.score({
|
|
9376
|
+
query: args.query,
|
|
9377
|
+
skills: currentSkills,
|
|
9378
|
+
});
|
|
9379
|
+
signal?.throwIfAborted();
|
|
9380
|
+
const currentRouting = routeSkillDescriptors({
|
|
9381
|
+
skills: currentSkills,
|
|
9382
|
+
query: args.query,
|
|
9383
|
+
target: { os: process.platform },
|
|
9384
|
+
vectorScores: vector?.scores ?? null,
|
|
9385
|
+
outcomeMetrics: outcomeAuthority.metrics,
|
|
9386
|
+
revocationReader: skillRetrievalRevocationReader ?? null,
|
|
9387
|
+
topK: Math.min(64, Math.max(1, currentSkills.length)),
|
|
9388
|
+
});
|
|
9389
|
+
const currentByDigest = new Map(
|
|
9390
|
+
currentSkills.map((skill) => [
|
|
9391
|
+
skill.executionIdentity?.contentDigest,
|
|
9392
|
+
skill,
|
|
9393
|
+
]),
|
|
9394
|
+
);
|
|
9395
|
+
const currentDecisionSnapshot = snapshotFor(
|
|
9396
|
+
currentRouting,
|
|
9397
|
+
decisionInputsFor(currentRouting, currentSkills),
|
|
9398
|
+
);
|
|
9399
|
+
routing = currentRouting;
|
|
9400
|
+
skills = routing.candidates
|
|
9401
|
+
.map(({ digest }) => currentByDigest.get(digest))
|
|
9402
|
+
.filter(Boolean);
|
|
9403
|
+
signal?.throwIfAborted();
|
|
9404
|
+
if (
|
|
9405
|
+
decision.visible &&
|
|
9406
|
+
currentDecisionSnapshot === decisionSnapshot
|
|
9407
|
+
) {
|
|
9310
9408
|
routing = Object.freeze({
|
|
9311
9409
|
...routing,
|
|
9312
9410
|
decisionSuggestion: Object.freeze({
|