chainlesschain 0.166.97 → 0.166.98
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 +3 -3
- 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-BB9kKNVw.js → AIOps-DCIQFtF1.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DTg-lWE0.js → ActionButton-BxhHU3nE.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BWUZ0Tpc.js → Analytics-DdM_307O.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-Dj8WDnCf.js → AppLayout-C43-kSrh.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-x8NiiPTg.js → Artifacts-B2Vp2Am6.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-q7otRAqO.js → Audit-s-lYUfOp.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-f6qlO2au.js → BackgroundAgents-DTE7Kzio.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BbuX9qQS.js → Backup-9k1q4Mt6.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-amgV-Y0y.js → BaseInput-DlpUtK5R.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CZW3DW7j.js → Chat-CR9S8Rmb.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-Xtgfw3-c.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-DXHXC52i.js → Checkbox-DpFRu7Df.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DQh47r4e.js → Codegen-BIl72E4Y.js} +1 -1
- package/src/assets/web-panel/assets/{Col-lBOOXCD7.js → Col-91tl_err.js} +1 -1
- package/src/assets/web-panel/assets/{Community-BNFPnBu9.js → Community-CswahO9-.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-7MOWfBGb.js → Compact-D9pfHmaM.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-x0UA-rxk.js → Compliance-CXSZzAO9.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-C_eLfk_Q.js → Cowork-CuT9RWTn.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-BP2-_Fja.js → Cron-B71aJWDV.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-Dn-e1217.js → Crosschain-CcUuWyx8.js} +1 -1
- package/src/assets/web-panel/assets/{DID-D_jverif.js → DID-CtVVGOPL.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-BysweBms.js → Dashboard-CV7ZCYQq.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-osJi0Pci.js → Dropdown-DKHxwLgE.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-C72k1SKQ.js → EmailListRenderer-Bd03UIvv.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-CAtA1F9s.js → EvolutionSettings-CTrG03B_.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Bi0luzvO.js → FamilyGuardDashboard-DXS4bS6Q.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-CIwntDLI.js → Federation-BODG2Szj.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DRfwhPW-.js → FormItemContext-D32ccUqD.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-COJTzZ61.js → GenericCardRenderer-ClsyrKvF.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CwsR46lj.js → Git-DcM2yhbL.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-B1U-u9BN.js → Governance-BhUzM87n.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-vPsdYTS_.js → Inference-Dq1n0Ifg.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CVDRZM5h.js → KnowledgeGraph-dmmPwEks.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-YRslKbRL.js → Logs-CBSYrPmh.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-CRoDI77y.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-CtxYHchd.js → Marketplace-Cfw7XLck.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BkfCbpAk.js → McpTools-CNrZRy4n.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-COp-8Z20.js → Memory-BESjTxdd.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-7fX-n_xn.js → MobileBridge-Boyjo07i.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DUyTVgId.js → MobileProjects-BmxmpTWz.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CLXFZ5dV.js → Mtc-CBkrD0Fq.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-yJ4eP1wB.js → MtcAudit-BA7cAK8h.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-Cwb_qTh0.js → Multisig-m0RGzkKO.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CkuojSSJ.js → NLProgramming-D_TgzifU.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-ju-QtUhJ.js → Notes-Dr-Yr9LL.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-DjryXIC3.js → NotificationSettings-DGanpkqO.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-B4KNF8xr.js → OrderTableRenderer-D1FX50QY.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-6-EtcVaO.js → Organization-DRbPg-gs.js} +2 -2
- package/src/assets/web-panel/assets/{Overflow-BKja8nqr.js → Overflow-flEO37z6.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BX20f9uL.js → P2P-DqfqFbCW.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-C9zwOEUo.js → PdhVaultBrowser-Cmi5a5dW.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-YQjQVrfE.js → Permissions-DBVRlvBW.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-yZYclXxq.js → PersonalDataHub-gQqjPr9X.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-ChZCCXAI.js → Pipeline-6HlifUc9.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Ds7R-a0H.js → Privacy-bm_2-Zwg.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B3qz_xab.js → ProjectInit-BJW3isuq.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BlwNctdF.js → ProjectSettings-DD3yolz7.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BxtYpNl7.js → Projects-BF3GtWny.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-BE_1SS_-.js → Providers-CQA6WAK7.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CMQ25oLb.js → QrScannerModal-DOAwp5Xo.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DQRFLDeP.js → QuickAsk-qeFXsAZT.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-ChVra4Pk.js → Recommend-zDWXwZN8.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-9vPBIowJ.js → RemoteSession-toe6Ip06.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-MdbWbyQQ.js → Reputation-DRDi_Eqp.js} +1 -1
- package/src/assets/web-panel/assets/{Row-JLcBncLR.js → Row-Do2UbYkf.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CnMXnpFv.js → RssFeed-B57C6_Sa.js} +3 -3
- package/src/assets/web-panel/assets/{Search-Cf5ISVUe.js → Search-DfDyBpe9.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CywFo2EM.js → Security-CulNxeAM.js} +3 -3
- package/src/assets/web-panel/assets/{Services-CLYnSCG3.js → Services-COfAYvs4.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BtbhOlo1.js → Skeleton-0fn0T146.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DPeqcIo2.js → Skills-pPQgAhvJ.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BRb4SqDn.js → Sla-CIsRmePR.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-0Wuxts-7.js → SpeechSettings-Bn01d-8b.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BXtsOjXL.js → SyncSettings-Cx_Znk7L.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-D455Wfhx.js → Tasks-DvaskzpG.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-LGc4O0fj.js → Templates-DmHCEiDO.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DA--0GFz.js → Tenant-CqHyvnbW.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DQsA0xCq.js → Terminal-DTt3yqWL.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-VH8AuSLp.js → TimelineRenderer-BhkIxcR3.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-B8RyzFRN.js → Tokens-mhjYcBBP.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CA7lVVEf.js → Trigger-CdlMQfwX.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-wUoRRLg9.js → Trust-Bzovg_Gw.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-ByoT_alW.js → UkeySign-ph3EuYi7.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-D9fgAxJV.js → VideoEditing-Bo2B4VZE.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CRkTndvj.js → Wallet-BQTKsSUT.js} +2 -2
- package/src/assets/web-panel/assets/{WebAuthn-VwmHOxJK.js → WebAuthn-nJxsXNHV.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-Z0bPZc2O.js → WorkflowEditor-CjH8g2N7.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CfX_5qUm.js → chat-CkbNmnQD.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BK7mXUnR.js → colors-BY9JcObR.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-Uq755CeO.js → compact-item-Dzzq-d8n.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DWXq8Qnk.js → createContext-DiJxxdTx.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-D502_Z3w.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BXgy5JZA.js → hasIn-DaXPOw3D.js} +1 -1
- package/src/assets/web-panel/assets/{index-_I4nSJFc.js → index-6Z6Z4UwN.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4yvdQCj.js → index-7YVCjSqG.js} +1 -1
- package/src/assets/web-panel/assets/{index-D63nsr0a.js → index-B31oMRmK.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdwC1i3O.js → index-B4Sf1AMk.js} +1 -1
- package/src/assets/web-panel/assets/{index-CRLOeoFE.js → index-BGvIb1Sr.js} +1 -1
- package/src/assets/web-panel/assets/{index-JX7mXB5a.js → index-BHeHyLRM.js} +3 -3
- package/src/assets/web-panel/assets/{index-Ct41B4y4.js → index-BQvtlYUd.js} +1 -1
- package/src/assets/web-panel/assets/{index-VrR8eMCk.js → index-Bhsxh-rH.js} +1 -1
- package/src/assets/web-panel/assets/{index-C8e4SYX4.js → index-BlWg1bRA.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3VnhfYU.js → index-BqCHe05H.js} +1 -1
- package/src/assets/web-panel/assets/index-BrQ4nI4W.js +1 -0
- package/src/assets/web-panel/assets/{index-DSb7SKp5.js → index-BvgMt6Io.js} +1 -1
- package/src/assets/web-panel/assets/{index-Y77S-ZC0.js → index-BycyBM6g.js} +1 -1
- package/src/assets/web-panel/assets/index-C0_sewGO.js +1 -0
- package/src/assets/web-panel/assets/{index-CGy7b2rd.js → index-C6XSCXeb.js} +1 -1
- package/src/assets/web-panel/assets/{index-XdoslBhl.js → index-CAzfu6k5.js} +1 -1
- package/src/assets/web-panel/assets/{index-B09haI0M.js → index-CVblRqUN.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bt3tjvj-.js → index-CWLpEg34.js} +1 -1
- package/src/assets/web-panel/assets/{index-wYTro42F.js → index-C_OMH_FT.js} +1 -1
- package/src/assets/web-panel/assets/{index-H13lvPme.js → index-CbOOm8I8.js} +1 -1
- package/src/assets/web-panel/assets/{index-TDPkVyse.js → index-CnLO1_yN.js} +1 -1
- package/src/assets/web-panel/assets/{index-DuhlVXh4.js → index-CqOkm6kW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CfYb8FjC.js → index-DDnqjZa2.js} +1 -1
- package/src/assets/web-panel/assets/{index-VPLA-GO7.js → index-DObXhPhH.js} +1 -1
- package/src/assets/web-panel/assets/{index-CarQiRSA.js → index-DSqQyS9-.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ait-_UUh.js → index-DWT9-E5b.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-8lN1rG.js → index-D_Eoh740.js} +1 -1
- package/src/assets/web-panel/assets/{index-DiVH_NiY.js → index-DaylJfw6.js} +1 -1
- package/src/assets/web-panel/assets/{index-DbjUfyVq.js → index-DbmHmeP-.js} +1 -1
- package/src/assets/web-panel/assets/{index-LsBPnXHh.js → index-Djeh6rAb.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dg9P9EDV.js → index-Dl8U-0hn.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRQSkXde.js → index-EiaWq1TH.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZD1My0S.js → index-Igq-72Ep.js} +1 -1
- package/src/assets/web-panel/assets/{index-QXKuGlOS.js → index-Jmlk_lDX.js} +1 -1
- package/src/assets/web-panel/assets/{index-p3BlIre2.js → index-LRZSVBxC.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUR7dnMg.js → index-Uh9SjtgW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqJw5WsH.js → index-cu1J4avY.js} +1 -1
- package/src/assets/web-panel/assets/{index-9XsaovMH.js → index-dC2JACyJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BxSClhg5.js → index-i9eu2Kir.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DTuF67Yy.js → initDefaultProps-B0WuG3fa.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DZasLgsl.js → motion-1r5YB22w.js} +1 -1
- package/src/assets/web-panel/assets/{move-pPR4O1Du.js → move-CvtXWA_V.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-Dc7fidhm.js → mtc-parser-ChedmEE_.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CZ1IcubN.js → omit-DpEA3MP0.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BMtJilhr.js → pickAttrs-BWgrUZF6.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-D0EXaZA7.js → placementArrow-BWfo_VbI.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-HftdThc5.js → responsiveObserve-CRft03Vk.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CT1JEPWV.js → slide-l5LeXusH.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-rwE-IPZB.js → statusUtils-CCEC0JR-.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B2B8XHVq.js → styleChecker-Bw5Gw_2w.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-TXNvIFVa.js → useFlexGapSupport-BAuxWB7K.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BcWgJKvf.js → useFs-CxUP97Cw.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DWBDnOSR.js → usePersonalDataHub-BJDjT4Sy.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Cf_LjUuu.js → vnode-BcCsFzIs.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DM2Bfuyl.js → zoom-MLmG09h6.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/eval.js +79 -3
- package/src/commands/llm.js +40 -5
- package/src/data/changelog.json +13 -0
- package/src/lib/context-memory-kernel/message-adapter.js +41 -24
- package/src/lib/context-memory-kernel/segmented-memory-port.js +18 -0
- package/src/lib/eval/runner.js +22 -1
- package/src/lib/eval/verify01-contracts.js +106 -51
- package/src/lib/eval/verify01-execution.js +148 -166
- package/src/lib/eval/verify01-host-evidence.js +34 -2
- package/src/lib/eval/verify01-workspace.js +302 -0
- package/src/lib/execution-location-failure-site.js +18 -0
- package/src/lib/execution-location-target.js +10 -0
- package/src/lib/llm-connection-probe.js +147 -6
- package/src/lib/provider-http-error.js +30 -11
- package/src/lib/task-progress-tracker.js +1 -0
- package/src/runtime/agent-core.js +22 -0
- package/src/runtime/headless-runner.js +30 -20
- package/src/runtime/headless-stream.js +15 -10
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DgMYDmBW.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-CUBuc97a.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CbtBfs7a.js +0 -1
- package/src/assets/web-panel/assets/index-CicoHC0s.js +0 -1
- package/src/assets/web-panel/assets/index-DttyUwDx.js +0 -1
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/** Shared file boundaries and snapshots; no process broker or npm dependencies. */
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
import { evalDigest } from "./evidence.js";
|
|
6
|
+
const MAX_BYTES = 16 * 1024 * 1024;
|
|
7
|
+
export const MAX_SNAPSHOT_BYTES = 512 * 1024 * 1024;
|
|
8
|
+
const MAX_DIFF_BYTES = 32 * 1024 * 1024;
|
|
9
|
+
const EMPTY_DELIVERABLE_DIGEST = evalDigest(Buffer.alloc(0));
|
|
10
|
+
|
|
11
|
+
export function requireValue(condition, message) {
|
|
12
|
+
if (!condition) throw new Error(message);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function relativeFile(value) {
|
|
16
|
+
requireValue(
|
|
17
|
+
typeof value === "string" &&
|
|
18
|
+
value.length > 0 &&
|
|
19
|
+
!value.includes("\0") &&
|
|
20
|
+
!/[\\:*?<>|"]/u.test(value) &&
|
|
21
|
+
!value.startsWith("/") &&
|
|
22
|
+
value.split("/").every((part) => part && !/[. ]$/u.test(part)),
|
|
23
|
+
"review paths must be exact relative files",
|
|
24
|
+
);
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
export function readBytes(file) {
|
|
28
|
+
const descriptor = fs.openSync(file, "r");
|
|
29
|
+
try {
|
|
30
|
+
const before = fs.fstatSync(descriptor, { bigint: true });
|
|
31
|
+
requireValue(
|
|
32
|
+
before.isFile() && before.size <= BigInt(MAX_BYTES),
|
|
33
|
+
"input must be a regular file within 16 MiB",
|
|
34
|
+
);
|
|
35
|
+
const bytes = Buffer.alloc(Number(before.size) + 1);
|
|
36
|
+
let count = 0;
|
|
37
|
+
while (count < bytes.length) {
|
|
38
|
+
const size = fs.readSync(
|
|
39
|
+
descriptor,
|
|
40
|
+
bytes,
|
|
41
|
+
count,
|
|
42
|
+
bytes.length - count,
|
|
43
|
+
null,
|
|
44
|
+
);
|
|
45
|
+
if (!size) break;
|
|
46
|
+
count += size;
|
|
47
|
+
}
|
|
48
|
+
const after = fs.fstatSync(descriptor, { bigint: true });
|
|
49
|
+
requireValue(
|
|
50
|
+
count === Number(before.size) &&
|
|
51
|
+
["dev", "ino", "size", "mtimeNs", "ctimeNs"].every(
|
|
52
|
+
(key) => before[key] === after[key],
|
|
53
|
+
),
|
|
54
|
+
"input changed during read",
|
|
55
|
+
);
|
|
56
|
+
return bytes.subarray(0, count);
|
|
57
|
+
} finally {
|
|
58
|
+
fs.closeSync(descriptor);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function canonicalDirectory(directory) {
|
|
63
|
+
const absolute = path.resolve(directory);
|
|
64
|
+
const canonical = (fs.realpathSync.native || fs.realpathSync)(absolute);
|
|
65
|
+
const same =
|
|
66
|
+
process.platform === "win32"
|
|
67
|
+
? canonical.toLowerCase() === absolute.toLowerCase()
|
|
68
|
+
: canonical === absolute;
|
|
69
|
+
const stat = fs.lstatSync(absolute);
|
|
70
|
+
requireValue(
|
|
71
|
+
same && stat.isDirectory() && !stat.isSymbolicLink(),
|
|
72
|
+
"task directory must be canonical and unaliased",
|
|
73
|
+
);
|
|
74
|
+
return canonical;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Trusted preparation only: a seed contains no answer and never overwrites
|
|
78
|
+
* a project file. Existing source paths are not passed to this helper. */
|
|
79
|
+
export function seedVerify01Deliverables(directory, expectedFiles, budget) {
|
|
80
|
+
const root = canonicalDirectory(directory);
|
|
81
|
+
requireValue(
|
|
82
|
+
Array.isArray(expectedFiles) &&
|
|
83
|
+
expectedFiles.length > 0 &&
|
|
84
|
+
new Set(expectedFiles).size === expectedFiles.length,
|
|
85
|
+
"deliverable paths must be distinct",
|
|
86
|
+
);
|
|
87
|
+
expectedFiles.forEach(relativeFile);
|
|
88
|
+
const seeds = [];
|
|
89
|
+
for (const relative of expectedFiles) {
|
|
90
|
+
budget.remainingMs("deliverable-preparation");
|
|
91
|
+
let current = root;
|
|
92
|
+
for (const part of relative.split("/").slice(0, -1)) {
|
|
93
|
+
current = path.join(current, part);
|
|
94
|
+
within(root, current);
|
|
95
|
+
try {
|
|
96
|
+
fs.mkdirSync(current, { mode: 0o700 });
|
|
97
|
+
} catch (error) {
|
|
98
|
+
if (error.code !== "EEXIST") throw error;
|
|
99
|
+
}
|
|
100
|
+
canonicalDirectory(current);
|
|
101
|
+
}
|
|
102
|
+
const target = path.join(root, relative);
|
|
103
|
+
within(root, target);
|
|
104
|
+
const fd = fs.openSync(
|
|
105
|
+
target,
|
|
106
|
+
fs.constants.O_WRONLY |
|
|
107
|
+
fs.constants.O_CREAT |
|
|
108
|
+
fs.constants.O_EXCL |
|
|
109
|
+
(fs.constants.O_NOFOLLOW || 0),
|
|
110
|
+
0o600,
|
|
111
|
+
);
|
|
112
|
+
try {
|
|
113
|
+
const stat = fs.fstatSync(fd);
|
|
114
|
+
requireValue(
|
|
115
|
+
stat.isFile() && stat.nlink === 1 && stat.size === 0,
|
|
116
|
+
"seed must be an empty unaliased regular file",
|
|
117
|
+
);
|
|
118
|
+
regularPath(root, relative);
|
|
119
|
+
const named = fs.lstatSync(target);
|
|
120
|
+
requireValue(
|
|
121
|
+
named.dev === stat.dev && named.ino === stat.ino,
|
|
122
|
+
"seed path changed identity during preparation",
|
|
123
|
+
);
|
|
124
|
+
canonicalDirectory(path.dirname(target));
|
|
125
|
+
seeds.push(
|
|
126
|
+
Object.freeze({
|
|
127
|
+
path: relative,
|
|
128
|
+
before: null,
|
|
129
|
+
origin: "trusted-empty-deliverable-preparation",
|
|
130
|
+
digest: EMPTY_DELIVERABLE_DIGEST,
|
|
131
|
+
bytes: 0,
|
|
132
|
+
requestedMode: 0o600,
|
|
133
|
+
mode: stat.mode & 0o777,
|
|
134
|
+
preparedAt: new Date().toISOString(),
|
|
135
|
+
}),
|
|
136
|
+
);
|
|
137
|
+
} finally {
|
|
138
|
+
fs.closeSync(fd);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return Object.freeze(seeds);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function within(root, file) {
|
|
145
|
+
const relative = path.relative(root, file);
|
|
146
|
+
requireValue(
|
|
147
|
+
relative &&
|
|
148
|
+
relative !== ".." &&
|
|
149
|
+
!relative.startsWith(`..${path.sep}`) &&
|
|
150
|
+
!path.isAbsolute(relative),
|
|
151
|
+
"path escapes its declared root",
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function regularPath(root, relative) {
|
|
156
|
+
relativeFile(relative);
|
|
157
|
+
const file = path.join(root, relative);
|
|
158
|
+
within(root, file);
|
|
159
|
+
let current = root;
|
|
160
|
+
for (const segment of relative.split("/")) {
|
|
161
|
+
current = path.join(current, segment);
|
|
162
|
+
requireValue(
|
|
163
|
+
!fs.lstatSync(current).isSymbolicLink(),
|
|
164
|
+
"review/project paths must not traverse links",
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
requireValue(
|
|
168
|
+
fs.lstatSync(file).isFile(),
|
|
169
|
+
"review/project artifact must be a regular file",
|
|
170
|
+
);
|
|
171
|
+
return file;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function snapshotVerify01Workspace(directory, budget, stage) {
|
|
175
|
+
const files = new Map();
|
|
176
|
+
let total = 0;
|
|
177
|
+
let dependencyBytes = 0;
|
|
178
|
+
let dependencyFiles = 0;
|
|
179
|
+
const dependencyHash = createHash("sha256");
|
|
180
|
+
const buffer = Buffer.alloc(64 * 1024);
|
|
181
|
+
const visit = (current) => {
|
|
182
|
+
for (const entry of fs
|
|
183
|
+
.readdirSync(current, { withFileTypes: true })
|
|
184
|
+
.sort((a, b) => a.name.localeCompare(b.name, "en"))) {
|
|
185
|
+
budget.remainingMs(stage);
|
|
186
|
+
const full = path.join(current, entry.name);
|
|
187
|
+
const relative = path.relative(directory, full).split(path.sep).join("/");
|
|
188
|
+
if (entry.isDirectory()) visit(full);
|
|
189
|
+
else {
|
|
190
|
+
requireValue(
|
|
191
|
+
entry.isFile() || entry.isSymbolicLink(),
|
|
192
|
+
"task snapshot contains an unsupported filesystem object",
|
|
193
|
+
);
|
|
194
|
+
// Preserve link identities without following them into another root.
|
|
195
|
+
const dependency = relative.split("/").includes("node_modules");
|
|
196
|
+
if (dependency && entry.isSymbolicLink()) {
|
|
197
|
+
// A dependency linked outside the isolated workspace cannot be
|
|
198
|
+
// fingerprinted by this capture contract; never silently omit it.
|
|
199
|
+
within(directory, fs.realpathSync(full));
|
|
200
|
+
}
|
|
201
|
+
let bytes = entry.isSymbolicLink()
|
|
202
|
+
? Buffer.from(fs.readlinkSync(full))
|
|
203
|
+
: dependency
|
|
204
|
+
? null
|
|
205
|
+
: readBytes(full);
|
|
206
|
+
let digest, size;
|
|
207
|
+
if (dependency && bytes === null) {
|
|
208
|
+
const hash = createHash("sha256");
|
|
209
|
+
const fd = fs.openSync(full, "r");
|
|
210
|
+
size = 0;
|
|
211
|
+
try {
|
|
212
|
+
let count;
|
|
213
|
+
while (
|
|
214
|
+
(count = fs.readSync(fd, buffer, 0, buffer.length, null)) > 0
|
|
215
|
+
) {
|
|
216
|
+
budget.remainingMs(stage);
|
|
217
|
+
size += count;
|
|
218
|
+
requireValue(
|
|
219
|
+
dependencyBytes + size <= 16 * 1024 ** 3,
|
|
220
|
+
"dependency fingerprint exceeds 16 GiB",
|
|
221
|
+
);
|
|
222
|
+
hash.update(buffer.subarray(0, count));
|
|
223
|
+
}
|
|
224
|
+
} finally {
|
|
225
|
+
fs.closeSync(fd);
|
|
226
|
+
}
|
|
227
|
+
digest = `sha256:${hash.digest("hex")}`;
|
|
228
|
+
} else {
|
|
229
|
+
size = bytes.length;
|
|
230
|
+
digest = evalDigest(bytes);
|
|
231
|
+
}
|
|
232
|
+
if (dependency) {
|
|
233
|
+
dependencyBytes += size;
|
|
234
|
+
dependencyFiles++;
|
|
235
|
+
bytes = null;
|
|
236
|
+
} else total += size;
|
|
237
|
+
requireValue(
|
|
238
|
+
total <= MAX_SNAPSHOT_BYTES &&
|
|
239
|
+
files.size - dependencyFiles < 100000 &&
|
|
240
|
+
dependencyFiles <= 1000000,
|
|
241
|
+
"task snapshot exceeds its capture bound",
|
|
242
|
+
);
|
|
243
|
+
const value = {
|
|
244
|
+
type: entry.isSymbolicLink() ? "link" : "file",
|
|
245
|
+
mode: fs.lstatSync(full).mode & 0o777,
|
|
246
|
+
bytes,
|
|
247
|
+
size,
|
|
248
|
+
digest,
|
|
249
|
+
dependency,
|
|
250
|
+
};
|
|
251
|
+
files.set(relative, value);
|
|
252
|
+
if (dependency)
|
|
253
|
+
dependencyHash.update(
|
|
254
|
+
JSON.stringify([relative, value.type, value.mode, size, digest]) +
|
|
255
|
+
"\n",
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
visit(directory);
|
|
261
|
+
files.dependencyBoundary = {
|
|
262
|
+
contract:
|
|
263
|
+
"all node_modules files and link identities streamed with SHA-256; links never followed; dependency bodies omitted; every change rejected",
|
|
264
|
+
files: dependencyFiles,
|
|
265
|
+
bytes: dependencyBytes,
|
|
266
|
+
digest: `sha256:${dependencyHash.digest("hex")}`,
|
|
267
|
+
};
|
|
268
|
+
return files;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export function diffVerify01Workspace(before, after) {
|
|
272
|
+
const result = [];
|
|
273
|
+
let total = 0;
|
|
274
|
+
for (const file of [...new Set([...before.keys(), ...after.keys()])].sort()) {
|
|
275
|
+
const old = before.get(file),
|
|
276
|
+
next = after.get(file);
|
|
277
|
+
if (
|
|
278
|
+
old?.digest === next?.digest &&
|
|
279
|
+
old?.type === next?.type &&
|
|
280
|
+
old?.mode === next?.mode
|
|
281
|
+
)
|
|
282
|
+
continue;
|
|
283
|
+
total += (old?.bytes?.length || 0) + (next?.bytes?.length || 0);
|
|
284
|
+
requireValue(
|
|
285
|
+
total <= MAX_DIFF_BYTES,
|
|
286
|
+
"task diff exceeds 32 MiB; preserve workspace for independent inspection",
|
|
287
|
+
);
|
|
288
|
+
const describe = (value) =>
|
|
289
|
+
value
|
|
290
|
+
? {
|
|
291
|
+
type: value.type,
|
|
292
|
+
mode: value.mode,
|
|
293
|
+
digest: value.digest,
|
|
294
|
+
bytes: value.size,
|
|
295
|
+
dependency: value.dependency,
|
|
296
|
+
bytesBase64: value.bytes?.toString("base64") ?? null,
|
|
297
|
+
}
|
|
298
|
+
: null;
|
|
299
|
+
result.push({ path: file, before: describe(old), after: describe(next) });
|
|
300
|
+
}
|
|
301
|
+
return result;
|
|
302
|
+
}
|
|
@@ -27,6 +27,24 @@ export function readExecutionLocationStorageFailure(stderr) {
|
|
|
27
27
|
return match ? `${match[1]}${match[2] || ""}` : null;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
export function readExecutionLocationStorageLaunchFailure(stderr) {
|
|
31
|
+
const match = String(stderr || "")
|
|
32
|
+
.slice(0, MAX_DIAGNOSTIC_CHARS)
|
|
33
|
+
.match(
|
|
34
|
+
/\[windows-acl-launch:(inspect|repair|preflight):(spawn|timeout):(startup|initialize|traversal|lookup|repair-lock|repair-inspect|repair-write|verify):(EACCES|EPERM|ENOENT|ETIMEDOUT|EINVAL|ENOSYS|ENOMEM|EMFILE|ENFILE|ENOBUFS|EBUSY|UNKNOWN):(unknown|-?(?:0|[1-9][0-9]{0,4})):(spawnSync|spawn|unknown)\]/u,
|
|
35
|
+
);
|
|
36
|
+
if (!match) return null;
|
|
37
|
+
const [, operation, failureStage, progressStage, code, rawErrno, syscall] =
|
|
38
|
+
match;
|
|
39
|
+
const errno = rawErrno === "unknown" ? null : Number(rawErrno);
|
|
40
|
+
if (
|
|
41
|
+
(errno !== null && Math.abs(errno) > 65535) ||
|
|
42
|
+
(failureStage === "timeout") !== (code === "ETIMEDOUT")
|
|
43
|
+
)
|
|
44
|
+
return null;
|
|
45
|
+
return { operation, failureStage, progressStage, code, errno, syscall };
|
|
46
|
+
}
|
|
47
|
+
|
|
30
48
|
export function executionLocationFailureSite(error) {
|
|
31
49
|
const stack = String(error?.stack || "").slice(0, MAX_DIAGNOSTIC_CHARS);
|
|
32
50
|
for (const frame of stack.split(/\r?\n/u).slice(1)) {
|
|
@@ -7,6 +7,7 @@ import { TextDecoder } from "node:util";
|
|
|
7
7
|
import {
|
|
8
8
|
readExecutionLocationFailureSite,
|
|
9
9
|
readExecutionLocationStorageFailure,
|
|
10
|
+
readExecutionLocationStorageLaunchFailure,
|
|
10
11
|
} from "./execution-location-failure-site.js";
|
|
11
12
|
import {
|
|
12
13
|
EXECUTION_LOCATION_TARGET_ATTESTATION_SCHEMA,
|
|
@@ -1039,6 +1040,10 @@ function targetProcessFailure(result) {
|
|
|
1039
1040
|
error.failureCategory = failureCategory;
|
|
1040
1041
|
if (failureSite) error.failureSite = failureSite;
|
|
1041
1042
|
if (storageFailure) error.storageFailure = storageFailure;
|
|
1043
|
+
const storageLaunchFailure = readExecutionLocationStorageLaunchFailure(
|
|
1044
|
+
result.stderr,
|
|
1045
|
+
);
|
|
1046
|
+
if (storageLaunchFailure) error.storageLaunchFailure = storageLaunchFailure;
|
|
1042
1047
|
return error;
|
|
1043
1048
|
}
|
|
1044
1049
|
|
|
@@ -1108,6 +1113,11 @@ function runTargetCommand(profile, cliArgs, deps = {}, options = {}) {
|
|
|
1108
1113
|
error.failureCategory = failureCategory;
|
|
1109
1114
|
if (failureSite) error.failureSite = failureSite;
|
|
1110
1115
|
if (storageFailure) error.storageFailure = storageFailure;
|
|
1116
|
+
const storageLaunchFailure = readExecutionLocationStorageLaunchFailure(
|
|
1117
|
+
result?.stderr,
|
|
1118
|
+
);
|
|
1119
|
+
if (storageLaunchFailure)
|
|
1120
|
+
error.storageLaunchFailure = storageLaunchFailure;
|
|
1111
1121
|
throw error;
|
|
1112
1122
|
}
|
|
1113
1123
|
return options.interactive ? null : result.stdout;
|
|
@@ -1,13 +1,141 @@
|
|
|
1
1
|
import { formatProviderResponseError } from "./provider-http-error.js";
|
|
2
|
+
import { estimateCost } from "./llm-pricing.js";
|
|
2
3
|
|
|
3
4
|
// Reasoning models spend the same output allowance on thinking before the
|
|
4
5
|
// final answer. A 16-token probe can therefore receive HTTP 200 with only
|
|
5
6
|
// reasoning_content and finish_reason=length from an otherwise usable model.
|
|
6
7
|
const PROBE_OUTPUT_TOKENS = 1024;
|
|
8
|
+
export const LLM_PROBE_SCHEMA = "chainlesschain.llm-connection-probe/v1";
|
|
9
|
+
|
|
10
|
+
const count = (value) => Number.isSafeInteger(value) && value >= 0;
|
|
11
|
+
|
|
12
|
+
/** Preserve missing/malformed usage as unknown, including cached prompt tokens. */
|
|
13
|
+
export function normalizeLlmProbeUsage(provider, data) {
|
|
14
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) return null;
|
|
15
|
+
let usage;
|
|
16
|
+
if (provider === "ollama") {
|
|
17
|
+
usage = {
|
|
18
|
+
input_tokens: data.prompt_eval_count,
|
|
19
|
+
output_tokens: data.eval_count,
|
|
20
|
+
};
|
|
21
|
+
} else if (provider === "anthropic") {
|
|
22
|
+
usage = data.usage;
|
|
23
|
+
} else if (provider === "gemini") {
|
|
24
|
+
const raw = data.usageMetadata;
|
|
25
|
+
if (
|
|
26
|
+
!raw ||
|
|
27
|
+
!count(raw.candidatesTokenCount) ||
|
|
28
|
+
!count(raw.thoughtsTokenCount === undefined ? 0 : raw.thoughtsTokenCount)
|
|
29
|
+
)
|
|
30
|
+
return null;
|
|
31
|
+
const cached =
|
|
32
|
+
raw.cachedContentTokenCount === undefined
|
|
33
|
+
? 0
|
|
34
|
+
: raw.cachedContentTokenCount;
|
|
35
|
+
if (
|
|
36
|
+
!count(raw.promptTokenCount) ||
|
|
37
|
+
!count(cached) ||
|
|
38
|
+
cached > raw.promptTokenCount
|
|
39
|
+
)
|
|
40
|
+
return null;
|
|
41
|
+
usage = {
|
|
42
|
+
input_tokens: raw.promptTokenCount - cached,
|
|
43
|
+
output_tokens: raw.candidatesTokenCount + (raw.thoughtsTokenCount ?? 0),
|
|
44
|
+
cache_read_input_tokens: cached,
|
|
45
|
+
};
|
|
46
|
+
} else {
|
|
47
|
+
const raw = data.usage;
|
|
48
|
+
if (!raw || !count(raw.prompt_tokens) || !count(raw.completion_tokens))
|
|
49
|
+
return null;
|
|
50
|
+
const detailed = raw.prompt_tokens_details?.cached_tokens;
|
|
51
|
+
const legacy = raw.prompt_cache_hit_tokens;
|
|
52
|
+
const cached =
|
|
53
|
+
detailed === undefined ? (legacy === undefined ? 0 : legacy) : detailed;
|
|
54
|
+
if (
|
|
55
|
+
!count(cached) ||
|
|
56
|
+
cached > raw.prompt_tokens ||
|
|
57
|
+
(detailed !== undefined && legacy !== undefined && detailed !== legacy)
|
|
58
|
+
)
|
|
59
|
+
return null;
|
|
60
|
+
usage = {
|
|
61
|
+
input_tokens: raw.prompt_tokens - cached,
|
|
62
|
+
output_tokens: raw.completion_tokens,
|
|
63
|
+
cache_read_input_tokens: cached,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (!usage || typeof usage !== "object" || Array.isArray(usage)) return null;
|
|
67
|
+
const normalized = {
|
|
68
|
+
input_tokens: usage.input_tokens,
|
|
69
|
+
output_tokens: usage.output_tokens,
|
|
70
|
+
cache_read_input_tokens:
|
|
71
|
+
usage.cache_read_input_tokens === undefined
|
|
72
|
+
? 0
|
|
73
|
+
: usage.cache_read_input_tokens,
|
|
74
|
+
cache_creation_input_tokens:
|
|
75
|
+
usage.cache_creation_input_tokens === undefined
|
|
76
|
+
? 0
|
|
77
|
+
: usage.cache_creation_input_tokens,
|
|
78
|
+
};
|
|
79
|
+
return Object.values(normalized).every(count) ? normalized : null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function priceLlmProbeUsage(target, usage) {
|
|
83
|
+
if (
|
|
84
|
+
!usage ||
|
|
85
|
+
![
|
|
86
|
+
usage.input_tokens,
|
|
87
|
+
usage.output_tokens,
|
|
88
|
+
usage.cache_read_input_tokens,
|
|
89
|
+
usage.cache_creation_input_tokens,
|
|
90
|
+
].every(count)
|
|
91
|
+
)
|
|
92
|
+
return null;
|
|
93
|
+
const estimate = estimateCost({
|
|
94
|
+
provider: target.provider,
|
|
95
|
+
model: target.model,
|
|
96
|
+
inputTokens: usage.input_tokens,
|
|
97
|
+
outputTokens: usage.output_tokens,
|
|
98
|
+
cacheReadTokens: usage.cache_read_input_tokens,
|
|
99
|
+
cacheCreationTokens: usage.cache_creation_input_tokens,
|
|
100
|
+
});
|
|
101
|
+
return estimate.matched && Number.isFinite(estimate.totalCost)
|
|
102
|
+
? estimate.totalCost
|
|
103
|
+
: null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function llmProbeReceipt(
|
|
107
|
+
target,
|
|
108
|
+
{ ok = false, reply = null, usage = null } = {},
|
|
109
|
+
) {
|
|
110
|
+
const normalizedUsage =
|
|
111
|
+
usage === null
|
|
112
|
+
? null
|
|
113
|
+
: {
|
|
114
|
+
input_tokens: usage.input_tokens,
|
|
115
|
+
output_tokens: usage.output_tokens,
|
|
116
|
+
cache_read_input_tokens: usage.cache_read_input_tokens,
|
|
117
|
+
cache_creation_input_tokens: usage.cache_creation_input_tokens,
|
|
118
|
+
};
|
|
119
|
+
return {
|
|
120
|
+
schema: LLM_PROBE_SCHEMA,
|
|
121
|
+
ok,
|
|
122
|
+
provider: target.provider,
|
|
123
|
+
model: target.model,
|
|
124
|
+
reply:
|
|
125
|
+
target.apiKey && typeof reply === "string"
|
|
126
|
+
? reply.replaceAll(target.apiKey, "[REDACTED]")
|
|
127
|
+
: reply,
|
|
128
|
+
usage: normalizedUsage,
|
|
129
|
+
totalCostUsd: priceLlmProbeUsage(target, normalizedUsage),
|
|
130
|
+
currency: "USD",
|
|
131
|
+
costBasis: "token-estimate",
|
|
132
|
+
billingVerified: false,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
7
135
|
|
|
8
136
|
export async function probeLlmConnection(
|
|
9
137
|
target,
|
|
10
|
-
{ fetchImpl = fetch, timeoutMs = 20_000 } = {},
|
|
138
|
+
{ fetchImpl = fetch, timeoutMs = 20_000, includeUsage = false } = {},
|
|
11
139
|
) {
|
|
12
140
|
const base = target.baseUrl.replace(/\/+$/, "");
|
|
13
141
|
const headers = { "Content-Type": "application/json" };
|
|
@@ -50,6 +178,7 @@ export async function probeLlmConnection(
|
|
|
50
178
|
}
|
|
51
179
|
const controller = new AbortController();
|
|
52
180
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
181
|
+
let usage = null;
|
|
53
182
|
try {
|
|
54
183
|
const response = await fetchImpl(url, {
|
|
55
184
|
method: "POST",
|
|
@@ -60,9 +189,12 @@ export async function probeLlmConnection(
|
|
|
60
189
|
});
|
|
61
190
|
if (!response.ok)
|
|
62
191
|
throw new Error(
|
|
63
|
-
await formatProviderResponseError(target.provider, response
|
|
192
|
+
await formatProviderResponseError(target.provider, response, {
|
|
193
|
+
secrets: [target.apiKey],
|
|
194
|
+
}),
|
|
64
195
|
);
|
|
65
196
|
const data = await response.json();
|
|
197
|
+
usage = normalizeLlmProbeUsage(target.provider, data);
|
|
66
198
|
const text =
|
|
67
199
|
target.provider === "ollama"
|
|
68
200
|
? data.response
|
|
@@ -91,11 +223,20 @@ export async function probeLlmConnection(
|
|
|
91
223
|
"The endpoint returned no model text; check the protocol and model",
|
|
92
224
|
);
|
|
93
225
|
}
|
|
94
|
-
|
|
226
|
+
const reply = (
|
|
227
|
+
target.apiKey ? text.replaceAll(target.apiKey, "[REDACTED]") : text
|
|
228
|
+
)
|
|
229
|
+
.trim()
|
|
230
|
+
.slice(0, 100);
|
|
231
|
+
return includeUsage
|
|
232
|
+
? llmProbeReceipt(target, { ok: true, reply, usage })
|
|
233
|
+
: reply;
|
|
95
234
|
} catch (error) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
235
|
+
const failure = controller.signal.aborted
|
|
236
|
+
? new Error(`Connection test timed out after ${timeoutMs / 1000}s`)
|
|
237
|
+
: error;
|
|
238
|
+
if (includeUsage) failure.probe = llmProbeReceipt(target, { usage });
|
|
239
|
+
throw failure;
|
|
99
240
|
} finally {
|
|
100
241
|
clearTimeout(timer);
|
|
101
242
|
}
|
|
@@ -3,9 +3,14 @@
|
|
|
3
3
|
* Keep structured provider diagnostics while redacting credential-shaped text.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
function safePart(value) {
|
|
6
|
+
function safePart(value, secrets = []) {
|
|
7
7
|
if (value == null) return "";
|
|
8
|
-
|
|
8
|
+
let text = String(value);
|
|
9
|
+
for (const secret of secrets) {
|
|
10
|
+
if (typeof secret === "string" && secret)
|
|
11
|
+
text = text.replaceAll(secret, "***");
|
|
12
|
+
}
|
|
13
|
+
return text
|
|
9
14
|
.replace(/\s+/g, " ")
|
|
10
15
|
.replace(/\b(Bearer\s+)[A-Za-z0-9._~+/-]+=*\b/gi, "$1***")
|
|
11
16
|
.replace(/\bsk-[A-Za-z0-9_-]{8,}\b/gi, "sk-***")
|
|
@@ -13,21 +18,24 @@ function safePart(value) {
|
|
|
13
18
|
.slice(0, 400);
|
|
14
19
|
}
|
|
15
20
|
|
|
16
|
-
function errorDetail(payload) {
|
|
21
|
+
function errorDetail(payload, secrets) {
|
|
17
22
|
if (payload == null) return { code: "", message: "" };
|
|
18
23
|
const raw =
|
|
19
24
|
typeof payload === "object" && payload.error != null
|
|
20
25
|
? payload.error
|
|
21
26
|
: payload;
|
|
22
27
|
if (typeof raw === "string") {
|
|
23
|
-
return { code: "", message: safePart(raw) };
|
|
28
|
+
return { code: "", message: safePart(raw, secrets) };
|
|
24
29
|
}
|
|
25
30
|
if (!raw || typeof raw !== "object") {
|
|
26
|
-
return { code: "", message: safePart(raw) };
|
|
31
|
+
return { code: "", message: safePart(raw, secrets) };
|
|
27
32
|
}
|
|
28
33
|
return {
|
|
29
|
-
code: safePart(raw.code || raw.type),
|
|
30
|
-
message: safePart(
|
|
34
|
+
code: safePart(raw.code || raw.type, secrets),
|
|
35
|
+
message: safePart(
|
|
36
|
+
raw.message || raw.error_description || raw.detail,
|
|
37
|
+
secrets,
|
|
38
|
+
),
|
|
31
39
|
};
|
|
32
40
|
}
|
|
33
41
|
|
|
@@ -36,9 +44,14 @@ function errorDetail(payload) {
|
|
|
36
44
|
* accounts and model-access denials. Preserve the safe code/message so clients
|
|
37
45
|
* can show the real corrective action.
|
|
38
46
|
*/
|
|
39
|
-
export function formatProviderHttpError(
|
|
47
|
+
export function formatProviderHttpError(
|
|
48
|
+
provider,
|
|
49
|
+
status,
|
|
50
|
+
payload = null,
|
|
51
|
+
{ secrets = [] } = {},
|
|
52
|
+
) {
|
|
40
53
|
const base = `${provider} API error: HTTP ${status}`;
|
|
41
|
-
const detail = errorDetail(payload);
|
|
54
|
+
const detail = errorDetail(payload, secrets);
|
|
42
55
|
const detailText = [detail.code, detail.message].filter(Boolean).join(": ");
|
|
43
56
|
const detailSentence = detailText.replace(/[.!?]+$/, "");
|
|
44
57
|
const classified = `${detail.code} ${detail.message}`.toLowerCase();
|
|
@@ -76,7 +89,11 @@ export function formatProviderHttpError(provider, status, payload = null) {
|
|
|
76
89
|
return detailSentence ? `${base} — ${detailSentence}` : base;
|
|
77
90
|
}
|
|
78
91
|
|
|
79
|
-
export async function formatProviderResponseError(
|
|
92
|
+
export async function formatProviderResponseError(
|
|
93
|
+
provider,
|
|
94
|
+
response,
|
|
95
|
+
{ secrets = [] } = {},
|
|
96
|
+
) {
|
|
80
97
|
let payload = null;
|
|
81
98
|
try {
|
|
82
99
|
const text = await response.text();
|
|
@@ -90,5 +107,7 @@ export async function formatProviderResponseError(provider, response) {
|
|
|
90
107
|
} catch {
|
|
91
108
|
// A broken/empty body still retains the HTTP status diagnosis.
|
|
92
109
|
}
|
|
93
|
-
return formatProviderHttpError(provider, response.status, payload
|
|
110
|
+
return formatProviderHttpError(provider, response.status, payload, {
|
|
111
|
+
secrets,
|
|
112
|
+
});
|
|
94
113
|
}
|
|
@@ -470,6 +470,7 @@ export class TaskProgressTracker {
|
|
|
470
470
|
guidance:
|
|
471
471
|
message +
|
|
472
472
|
" For an implementation task, make the smallest justified, authorized change and validate it. " +
|
|
473
|
+
"If the user requested new or updated tests, actual test changes and focused validation remain required; reading tests or passing an existing baseline does not fulfill that request. Name the concrete missing fact before another read. " +
|
|
473
474
|
"For a bug fix, state the observed failure, your leading root-cause hypothesis and the smallest test that can disprove it. Run that focused reproduction or diagnostic next; use its actual output to choose the next step. Do not keep reading adjacent files without naming the specific missing fact. A timeout alone does not establish that increasing the timeout is the fix. " +
|
|
474
475
|
DIAGNOSTIC_WORKFLOW_GUIDANCE +
|
|
475
476
|
" " +
|
|
@@ -15405,6 +15405,27 @@ export async function* agentLoop(messages, options) {
|
|
|
15405
15405
|
}
|
|
15406
15406
|
}
|
|
15407
15407
|
const contextMemoryTrustedSystemIndexes = [];
|
|
15408
|
+
if (Number.isFinite(budget.limit)) {
|
|
15409
|
+
// consume() already charged this dispatch. The current request may still
|
|
15410
|
+
// act even when no further provider request remains. Rebuild this hint
|
|
15411
|
+
// after compaction and rejection-only turns; do not persist it in history.
|
|
15412
|
+
const furtherRequests = budget.remaining();
|
|
15413
|
+
// Keep the stable conversation prefix ahead of this changing counter.
|
|
15414
|
+
// The canonical planner protects the last conversational user bundle
|
|
15415
|
+
// even when trusted ephemeral system guidance follows it.
|
|
15416
|
+
callMessages = [
|
|
15417
|
+
...callMessages,
|
|
15418
|
+
{
|
|
15419
|
+
role: "system",
|
|
15420
|
+
content:
|
|
15421
|
+
`Execution budget: this request plus ${furtherRequests} further model requests. ` +
|
|
15422
|
+
"For requested changes, reserve requests for implementation, focused validation, and repair or an accurate unfinished-work report. " +
|
|
15423
|
+
"Reading or an existing passing baseline does not deliver requested changes. " +
|
|
15424
|
+
"For research or monitoring, use the remaining requests for evidence and the requested answer; do not create files just to show activity.",
|
|
15425
|
+
},
|
|
15426
|
+
];
|
|
15427
|
+
contextMemoryTrustedSystemIndexes.push(callMessages.length - 1);
|
|
15428
|
+
}
|
|
15408
15429
|
if (prActionTask && !prInvestigationExhausted) {
|
|
15409
15430
|
callMessages = [
|
|
15410
15431
|
...callMessages,
|
|
@@ -16304,6 +16325,7 @@ export async function* agentLoop(messages, options) {
|
|
|
16304
16325
|
tool: toolName,
|
|
16305
16326
|
result: earlyAuthorityDenial,
|
|
16306
16327
|
error: earlyAuthorityDenial.error,
|
|
16328
|
+
execution_started: false,
|
|
16307
16329
|
tool_use_id: call.id,
|
|
16308
16330
|
turn_id: `${runId}:t${budget.consumed}`,
|
|
16309
16331
|
permission_decision_id: decision?.id || null,
|