privateer-agent 0.15.4 → 0.15.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/bin/boot-bundle.d.mts +2 -0
- package/bin/boot-bundle.mjs +44 -0
- package/bin/fresh-supervisor.d.mts +5 -1
- package/bin/fresh-supervisor.mjs +47 -10
- package/bin/privateer-launch.mjs +27 -3
- package/bin/privateer-subagent.mjs +5 -2
- package/bin/privateer-verify.mjs +12 -0
- package/bin/session-recovery.d.mts +53 -0
- package/bin/session-recovery.mjs +240 -0
- package/bin/session-seal-preload.mjs +17 -0
- package/bin/session-seal.d.mts +25 -0
- package/bin/session-seal.mjs +242 -0
- package/dist-boot/boot.mjs +3 -0
- package/dist-boot/c-27JKSMWL.mjs +1460 -0
- package/dist-boot/c-2BMRFV24.mjs +269 -0
- package/dist-boot/c-2CTF6JA3.mjs +166 -0
- package/dist-boot/c-2G3BBHRJ.mjs +84 -0
- package/dist-boot/c-2IDLKXX6.mjs +250 -0
- package/dist-boot/c-2NJD5VYM.mjs +8 -0
- package/dist-boot/c-2S5EEQPW.mjs +1602 -0
- package/dist-boot/c-2WRDCUVI.mjs +25 -0
- package/dist-boot/c-2YN3M256.mjs +14 -0
- package/dist-boot/c-37GM3GMU.mjs +187 -0
- package/dist-boot/c-3STKRSVO.mjs +2480 -0
- package/dist-boot/c-3TPV6TQQ.mjs +2320 -0
- package/dist-boot/c-3UVHLQDJ.mjs +225 -0
- package/dist-boot/c-42PUUZYC.mjs +697 -0
- package/dist-boot/c-4D5UMWVW.mjs +683 -0
- package/dist-boot/c-4ETZRMTA.mjs +46 -0
- package/dist-boot/c-4QT25BD5.mjs +1482 -0
- package/dist-boot/c-4WVR32AP.mjs +2579 -0
- package/dist-boot/c-5EMM567G.mjs +152 -0
- package/dist-boot/c-5FA4CV63.mjs +145 -0
- package/dist-boot/c-5GV3X3RB.mjs +14 -0
- package/dist-boot/c-5JCEPRIY.mjs +52 -0
- package/dist-boot/c-5NDKIIWT.mjs +16 -0
- package/dist-boot/c-5QL3AR26.mjs +4665 -0
- package/dist-boot/c-5XY6MFKN.mjs +5142 -0
- package/dist-boot/c-65UZIZC7.mjs +2897 -0
- package/dist-boot/c-6FUXKHOK.mjs +1969 -0
- package/dist-boot/c-6JHWQE4V.mjs +18242 -0
- package/dist-boot/c-6LOBR4I6.mjs +5280 -0
- package/dist-boot/c-6QHOZXKQ.mjs +14394 -0
- package/dist-boot/c-6ZO2SADQ.mjs +178 -0
- package/dist-boot/c-6ZORVVZP.mjs +1449 -0
- package/dist-boot/c-76QH4UCP.mjs +2441 -0
- package/dist-boot/c-77GO5L5Y.mjs +20982 -0
- package/dist-boot/c-7M23XFTN.mjs +5052 -0
- package/dist-boot/c-7TC367E2.mjs +32 -0
- package/dist-boot/c-7UOG7POX.mjs +1524 -0
- package/dist-boot/c-7VHP3FLN.mjs +376 -0
- package/dist-boot/c-A73JHZP2.mjs +13207 -0
- package/dist-boot/c-ABXULAFL.mjs +71 -0
- package/dist-boot/c-ANDD2AQO.mjs +74 -0
- package/dist-boot/c-AOY77AZL.mjs +1430 -0
- package/dist-boot/c-AXEPZ22I.mjs +108 -0
- package/dist-boot/c-B2Y7VNHU.mjs +427 -0
- package/dist-boot/c-B7VJUH73.mjs +77 -0
- package/dist-boot/c-BFW6CDVL.mjs +24 -0
- package/dist-boot/c-BHNIF2AR.mjs +188 -0
- package/dist-boot/c-BKF2O6BL.mjs +23 -0
- package/dist-boot/c-BOZXFTZN.mjs +8 -0
- package/dist-boot/c-BRNYJWZL.mjs +28 -0
- package/dist-boot/c-C3N4Z2HO.mjs +93 -0
- package/dist-boot/c-C4IV7ZFG.mjs +717 -0
- package/dist-boot/c-C5NK6UYV.mjs +793 -0
- package/dist-boot/c-C67644MB.mjs +1659 -0
- package/dist-boot/c-C6S2YB53.mjs +620 -0
- package/dist-boot/c-CDBEJSBF.mjs +37 -0
- package/dist-boot/c-CG47HBKU.mjs +435 -0
- package/dist-boot/c-CKCTWCT5.mjs +51 -0
- package/dist-boot/c-CN77DCGF.mjs +60 -0
- package/dist-boot/c-CRBXNKFO.mjs +1795 -0
- package/dist-boot/c-CRIHASQ6.mjs +973 -0
- package/dist-boot/c-CU4NGAUO.mjs +3786 -0
- package/dist-boot/c-CWRFLGQU.mjs +1883 -0
- package/dist-boot/c-CYQB2USO.mjs +32 -0
- package/dist-boot/c-DEE67DJO.mjs +379 -0
- package/dist-boot/c-DIFDBYOP.mjs +1258 -0
- package/dist-boot/c-DOSGVXDZ.mjs +34879 -0
- package/dist-boot/c-DR7XQI32.mjs +381 -0
- package/dist-boot/c-DTGPSB46.mjs +14666 -0
- package/dist-boot/c-DTHDNA4P.mjs +320 -0
- package/dist-boot/c-E4Z3Y5B5.mjs +3864 -0
- package/dist-boot/c-E66Z2TI7.mjs +203 -0
- package/dist-boot/c-EBU6RLRV.mjs +1527 -0
- package/dist-boot/c-EBZZNGSF.mjs +432 -0
- package/dist-boot/c-EC3LJ2KF.mjs +1032 -0
- package/dist-boot/c-EQBKXWNX.mjs +15829 -0
- package/dist-boot/c-EUEPIW4S.mjs +574 -0
- package/dist-boot/c-EX4YVWAT.mjs +378 -0
- package/dist-boot/c-EYZGSAJU.mjs +98 -0
- package/dist-boot/c-F75VRKY4.mjs +172 -0
- package/dist-boot/c-FH4NXKHV.mjs +177 -0
- package/dist-boot/c-FHNUCTEM.mjs +140 -0
- package/dist-boot/c-FJ5T42DS.mjs +5349 -0
- package/dist-boot/c-FPCNRL7G.mjs +1728 -0
- package/dist-boot/c-G4DLN7Q4.mjs +8 -0
- package/dist-boot/c-G56GYQFZ.mjs +2507 -0
- package/dist-boot/c-GLIOERDQ.mjs +1200 -0
- package/dist-boot/c-GMJ5HUBM.mjs +14 -0
- package/dist-boot/c-H3HSGMAQ.mjs +461 -0
- package/dist-boot/c-HIKTO6P7.mjs +275 -0
- package/dist-boot/c-I2MCJ34O.mjs +464 -0
- package/dist-boot/c-I3C6LBW4.mjs +765 -0
- package/dist-boot/c-I54OKQHW.mjs +387 -0
- package/dist-boot/c-IFSP3R4D.mjs +80 -0
- package/dist-boot/c-IZK77VB7.mjs +171 -0
- package/dist-boot/c-J3Y25UGE.mjs +54 -0
- package/dist-boot/c-J5IESS7W.mjs +27750 -0
- package/dist-boot/c-JJWZBY7L.mjs +254 -0
- package/dist-boot/c-JKTFXTGF.mjs +463 -0
- package/dist-boot/c-JN57AXQ4.mjs +77 -0
- package/dist-boot/c-KFIO6LUW.mjs +1096 -0
- package/dist-boot/c-KIEMEFWW.mjs +478 -0
- package/dist-boot/c-KIVXWBYD.mjs +28 -0
- package/dist-boot/c-KP6CRIP4.mjs +580 -0
- package/dist-boot/c-L26VOJX4.mjs +11558 -0
- package/dist-boot/c-L5GHWG5G.mjs +5988 -0
- package/dist-boot/c-M7NSQAKK.mjs +353 -0
- package/dist-boot/c-MCEWOPBW.mjs +56 -0
- package/dist-boot/c-MGPIEG7I.mjs +20 -0
- package/dist-boot/c-NREXJV3M.mjs +393 -0
- package/dist-boot/c-O5PP6CTX.mjs +162 -0
- package/dist-boot/c-OBQDHSXM.mjs +1774 -0
- package/dist-boot/c-OLQHHDD4.mjs +21 -0
- package/dist-boot/c-OXW4JQQH.mjs +319 -0
- package/dist-boot/c-P3D7ZUWN.mjs +1288 -0
- package/dist-boot/c-P4PQZVV5.mjs +948 -0
- package/dist-boot/c-P63T3XL2.mjs +26373 -0
- package/dist-boot/c-P6N5DQGZ.mjs +194 -0
- package/dist-boot/c-P7MLKQFC.mjs +58 -0
- package/dist-boot/c-PB3PZJL5.mjs +1276 -0
- package/dist-boot/c-PTN4S6G2.mjs +1259 -0
- package/dist-boot/c-PYCE5J7U.mjs +1083 -0
- package/dist-boot/c-Q4HYCRLB.mjs +19410 -0
- package/dist-boot/c-QUXMETGG.mjs +68 -0
- package/dist-boot/c-RDMJZCOX.mjs +356 -0
- package/dist-boot/c-ROGJK76M.mjs +17 -0
- package/dist-boot/c-RQJJ26T4.mjs +708 -0
- package/dist-boot/c-RSKCUPJF.mjs +7559 -0
- package/dist-boot/c-RVJU4O6P.mjs +37 -0
- package/dist-boot/c-S2RVHR3M.mjs +165 -0
- package/dist-boot/c-SKMK3PEE.mjs +91120 -0
- package/dist-boot/c-TI7SM4EG.mjs +20 -0
- package/dist-boot/c-TILJ6GXD.mjs +1235 -0
- package/dist-boot/c-TT6BCUJD.mjs +114 -0
- package/dist-boot/c-U4ITOXAN.mjs +2107 -0
- package/dist-boot/c-UGERXVO2.mjs +7120 -0
- package/dist-boot/c-UPBH5AXY.mjs +1363 -0
- package/dist-boot/c-US2PUNZL.mjs +597 -0
- package/dist-boot/c-UU4WZPPE.mjs +20 -0
- package/dist-boot/c-UWVIYPQS.mjs +39 -0
- package/dist-boot/c-V4RHQBPQ.mjs +17683 -0
- package/dist-boot/c-V5MRVK47.mjs +351 -0
- package/dist-boot/c-V6CL266R.mjs +1755 -0
- package/dist-boot/c-VJTMFKYE.mjs +14975 -0
- package/dist-boot/c-VJTRUKIB.mjs +773 -0
- package/dist-boot/c-W4IFSHPW.mjs +43 -0
- package/dist-boot/c-WETGB2CF.mjs +113 -0
- package/dist-boot/c-WO3QSZUU.mjs +1337 -0
- package/dist-boot/c-WQLH73TY.mjs +242 -0
- package/dist-boot/c-XL735JW5.mjs +500 -0
- package/dist-boot/c-Y7HADL5B.mjs +1107 -0
- package/dist-boot/c-YGQHSVSK.mjs +41 -0
- package/dist-boot/c-YMP2AMEB.mjs +10350 -0
- package/dist-boot/c-YRDO2WEF.mjs +12012 -0
- package/dist-boot/c-YUSTRATJ.mjs +8 -0
- package/dist-boot/c-Z2262R22.mjs +2697 -0
- package/dist-boot/c-Z4ALQMJC.mjs +709 -0
- package/dist-boot/c-Z5ZUQVUY.mjs +62 -0
- package/dist-boot/c-ZDZUKXF7.mjs +874 -0
- package/dist-boot/c-ZJYLGIC3.mjs +32 -0
- package/dist-boot/c-ZNA5CDMI.mjs +77 -0
- package/dist-boot/c-ZSO6DI3M.mjs +204 -0
- package/dist-boot/c-ZWUVHKMK.mjs +100 -0
- package/dist-boot/c-ZY4MESEW.mjs +832 -0
- package/dist-boot/c-ZZ5REI4L.mjs +329 -0
- package/dist-boot/cli.mjs +51 -0
- package/dist-boot/ext-anthropic-attribution.mjs +207 -0
- package/dist-boot/ext-pi-background-tasks.mjs +7234 -0
- package/dist-boot/ext-pi-subagents.mjs +37 -0
- package/dist-boot/ext-privateer-account.mjs +4426 -0
- package/dist-boot/ext-privateer-brand.mjs +5274 -0
- package/dist-boot/ext-privateer-codemode.mjs +37 -0
- package/dist-boot/ext-privateer-computer.mjs +626 -0
- package/dist-boot/ext-privateer-connect.mjs +1862 -0
- package/dist-boot/ext-privateer-context.mjs +323 -0
- package/dist-boot/ext-privateer-desktop.mjs +92 -0
- package/dist-boot/ext-privateer-final-audit.mjs +48 -0
- package/dist-boot/ext-privateer-fresh.mjs +81 -0
- package/dist-boot/ext-privateer-gate.mjs +5959 -0
- package/dist-boot/ext-privateer-hints.mjs +236 -0
- package/dist-boot/ext-privateer-media.mjs +2626 -0
- package/dist-boot/ext-privateer-models.mjs +3397 -0
- package/dist-boot/ext-privateer-posture.mjs +3006 -0
- package/dist-boot/ext-privateer-privacy.mjs +4578 -0
- package/dist-boot/ext-privateer-recovery.mjs +287 -0
- package/dist-boot/ext-privateer-speak.mjs +4754 -0
- package/dist-boot/ext-privateer-terminals.mjs +725 -0
- package/dist-boot/ext-privateer-tools.mjs +528 -0
- package/dist-boot/ext-privateer-truncation.mjs +74 -0
- package/dist-boot/ext-privateer-update.mjs +210 -0
- package/dist-boot/ext-privateer-vision.mjs +148 -0
- package/dist-boot/ext-privateer-web.mjs +543 -0
- package/dist-boot/ext-rpiv-ask-user-question.mjs +710 -0
- package/dist-boot/manifest.json +9 -0
- package/extensions/privateer-brand.ts +3 -1
- package/extensions/privateer-context.ts +4 -2
- package/extensions/privateer-final-audit.ts +17 -0
- package/extensions/privateer-gate.ts +55 -9
- package/extensions/privateer-recovery.ts +175 -0
- package/extensions/privateer-web.ts +4 -4
- package/package.json +3 -1
- package/patches/@earendil-works+pi-coding-agent+1.3.0.patch +199 -2
- package/patches/pi-background-tasks+2.6.10.patch +91 -7
- package/src/cli/chat.ts +7 -1
- package/src/config/moatManifest.json +2 -0
- package/src/config/whatsNew.json +4 -4
- package/src/context.ts +33 -5
- package/src/engine/finalAudit.ts +38 -0
- package/src/engine/stallWatchdog.ts +8 -1
- package/src/providers/account.ts +34 -3
- package/src/remote/attentionPush.ts +40 -0
- package/src/remote/liveTaskSession.ts +7 -1
- package/src/remote/relayClient.ts +38 -4
- package/src/remote/remoteBridge.ts +17 -0
- package/src/remote/transcriptSnapshot.ts +104 -0
|
@@ -0,0 +1,1096 @@
|
|
|
1
|
+
import{createRequire as __pvCR}from"node:module";import{fileURLToPath as __pvF}from"node:url";import{dirname as __pvD}from"node:path";const require=__pvCR(import.meta.url);const __pvUrl=(r)=>new URL(r,import.meta.url).href;const __pvFile=(r)=>__pvF(new URL(r,import.meta.url));
|
|
2
|
+
import {
|
|
3
|
+
buildDelegateChildArgv,
|
|
4
|
+
delegateChildEnv,
|
|
5
|
+
ensureDelegateChildSessionDir,
|
|
6
|
+
preflightDelegateLaunch,
|
|
7
|
+
resolveDelegateChildExtensionPath
|
|
8
|
+
} from "./c-C5NK6UYV.mjs";
|
|
9
|
+
import {
|
|
10
|
+
DELEGATE_INLINE_ANSWER_BYTES,
|
|
11
|
+
DELEGATE_MANIFEST_SCHEMA_VERSION,
|
|
12
|
+
DELEGATE_RECEIPT_SCHEMA_VERSION,
|
|
13
|
+
DELEGATE_RESULT_PACKAGE_SCHEMA_VERSION,
|
|
14
|
+
DelegateError
|
|
15
|
+
} from "./c-IFSP3R4D.mjs";
|
|
16
|
+
import {
|
|
17
|
+
canonicalJson
|
|
18
|
+
} from "./c-KIVXWBYD.mjs";
|
|
19
|
+
import {
|
|
20
|
+
resolveAnthropicAttributionExtensionPath
|
|
21
|
+
} from "./c-BFW6CDVL.mjs";
|
|
22
|
+
import {
|
|
23
|
+
replaceFileDurable
|
|
24
|
+
} from "./c-DR7XQI32.mjs";
|
|
25
|
+
import {
|
|
26
|
+
sanitizePathSegment
|
|
27
|
+
} from "./c-I3C6LBW4.mjs";
|
|
28
|
+
import {
|
|
29
|
+
__name
|
|
30
|
+
} from "./c-CN77DCGF.mjs";
|
|
31
|
+
|
|
32
|
+
// node_modules/pi-background-tasks/src/core/delegate/runner.ts?ext=pi-background-tasks
|
|
33
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
34
|
+
import { readFile as readFile2, rmdir } from "node:fs/promises";
|
|
35
|
+
import { dirname, join as join2 } from "node:path";
|
|
36
|
+
|
|
37
|
+
// node_modules/pi-background-tasks/src/core/delegate/artifacts.ts?ext=pi-background-tasks
|
|
38
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
39
|
+
import { existsSync } from "node:fs";
|
|
40
|
+
import { chmod, mkdir, open, readFile, rename, rm } from "node:fs/promises";
|
|
41
|
+
import { basename, isAbsolute, join, relative, sep } from "node:path";
|
|
42
|
+
|
|
43
|
+
// node_modules/pi-background-tasks/src/core/delegate/result-package.ts?ext=pi-background-tasks
|
|
44
|
+
import { createHash } from "node:crypto";
|
|
45
|
+
var DELEGATE_RESULT_PACKAGE_FILENAME = "result.json";
|
|
46
|
+
function sha256Bytes(bytes) {
|
|
47
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
48
|
+
}
|
|
49
|
+
__name(sha256Bytes, "sha256Bytes");
|
|
50
|
+
function isRecord(value) {
|
|
51
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
52
|
+
}
|
|
53
|
+
__name(isRecord, "isRecord");
|
|
54
|
+
function fail(message, code, taskId) {
|
|
55
|
+
const details = { code, childCreated: true };
|
|
56
|
+
if (taskId !== void 0) details.taskId = taskId;
|
|
57
|
+
throw new DelegateError(message, details);
|
|
58
|
+
}
|
|
59
|
+
__name(fail, "fail");
|
|
60
|
+
function serializeDelegateResultPackage(pkg) {
|
|
61
|
+
return `${canonicalJson(pkg)}
|
|
62
|
+
`;
|
|
63
|
+
}
|
|
64
|
+
__name(serializeDelegateResultPackage, "serializeDelegateResultPackage");
|
|
65
|
+
function requireString(record, key, taskId) {
|
|
66
|
+
const value = record[key];
|
|
67
|
+
if (typeof value !== "string")
|
|
68
|
+
fail(`delegate result package field ${key} must be a string`, "child_result_invalid", taskId);
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
71
|
+
__name(requireString, "requireString");
|
|
72
|
+
function requireInteger(record, key, taskId) {
|
|
73
|
+
const value = record[key];
|
|
74
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
|
|
75
|
+
fail(
|
|
76
|
+
`delegate result package field ${key} must be a non-negative safe integer`,
|
|
77
|
+
"child_result_invalid",
|
|
78
|
+
taskId
|
|
79
|
+
);
|
|
80
|
+
return value;
|
|
81
|
+
}
|
|
82
|
+
__name(requireInteger, "requireInteger");
|
|
83
|
+
var SHA256_PATTERN = /^[0-9a-f]{64}$/;
|
|
84
|
+
function requireSha256(record, key, taskId) {
|
|
85
|
+
const value = requireString(record, key, taskId);
|
|
86
|
+
if (!SHA256_PATTERN.test(value))
|
|
87
|
+
fail(
|
|
88
|
+
`delegate result package field ${key} must be a lowercase SHA-256 digest`,
|
|
89
|
+
"child_result_invalid",
|
|
90
|
+
taskId
|
|
91
|
+
);
|
|
92
|
+
return value;
|
|
93
|
+
}
|
|
94
|
+
__name(requireSha256, "requireSha256");
|
|
95
|
+
function parseUsage(value, taskId) {
|
|
96
|
+
if (!isRecord(value))
|
|
97
|
+
fail("delegate result package usage must be an object", "child_result_invalid", taskId);
|
|
98
|
+
const status = value["status"];
|
|
99
|
+
if (status === "unavailable") {
|
|
100
|
+
const reason = value["reason"];
|
|
101
|
+
if (typeof reason !== "string")
|
|
102
|
+
fail(
|
|
103
|
+
"delegate result package unavailable usage must state a reason",
|
|
104
|
+
"child_result_invalid",
|
|
105
|
+
taskId
|
|
106
|
+
);
|
|
107
|
+
return { status: "unavailable", reason };
|
|
108
|
+
}
|
|
109
|
+
if (status !== "observed")
|
|
110
|
+
fail(
|
|
111
|
+
"delegate result package usage status must be observed or unavailable",
|
|
112
|
+
"child_result_invalid",
|
|
113
|
+
taskId
|
|
114
|
+
);
|
|
115
|
+
const usage = value["usage"];
|
|
116
|
+
if (!isRecord(usage))
|
|
117
|
+
fail(
|
|
118
|
+
"delegate result package observed usage must be an object",
|
|
119
|
+
"child_result_invalid",
|
|
120
|
+
taskId
|
|
121
|
+
);
|
|
122
|
+
const cost = usage["cost"];
|
|
123
|
+
if (!isRecord(cost))
|
|
124
|
+
fail(
|
|
125
|
+
"delegate result package observed usage must carry a complete cost breakdown",
|
|
126
|
+
"child_result_invalid",
|
|
127
|
+
taskId
|
|
128
|
+
);
|
|
129
|
+
const number = /* @__PURE__ */ __name((record, key) => {
|
|
130
|
+
const raw = record[key];
|
|
131
|
+
if (typeof raw !== "number" || !Number.isFinite(raw) || raw < 0)
|
|
132
|
+
fail(
|
|
133
|
+
`delegate result package usage.${key} must be a non-negative finite number`,
|
|
134
|
+
"child_result_invalid",
|
|
135
|
+
taskId
|
|
136
|
+
);
|
|
137
|
+
return raw;
|
|
138
|
+
}, "number");
|
|
139
|
+
return {
|
|
140
|
+
status: "observed",
|
|
141
|
+
usage: {
|
|
142
|
+
input: number(usage, "input"),
|
|
143
|
+
output: number(usage, "output"),
|
|
144
|
+
cacheRead: number(usage, "cacheRead"),
|
|
145
|
+
cacheWrite: number(usage, "cacheWrite"),
|
|
146
|
+
totalTokens: number(usage, "totalTokens"),
|
|
147
|
+
cost: {
|
|
148
|
+
input: number(cost, "input"),
|
|
149
|
+
output: number(cost, "output"),
|
|
150
|
+
cacheRead: number(cost, "cacheRead"),
|
|
151
|
+
cacheWrite: number(cost, "cacheWrite"),
|
|
152
|
+
total: number(cost, "total")
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
__name(parseUsage, "parseUsage");
|
|
158
|
+
function parseAttestations(value, taskId) {
|
|
159
|
+
if (!Array.isArray(value))
|
|
160
|
+
fail(
|
|
161
|
+
"delegate result package route_attestations must be an array",
|
|
162
|
+
"route_attestation_missing",
|
|
163
|
+
taskId
|
|
164
|
+
);
|
|
165
|
+
if (value.length === 0)
|
|
166
|
+
fail(
|
|
167
|
+
"delegate result package carries no route attestation, so the route the child actually used cannot be proven",
|
|
168
|
+
"route_attestation_missing",
|
|
169
|
+
taskId
|
|
170
|
+
);
|
|
171
|
+
return value.map((entry) => {
|
|
172
|
+
if (!isRecord(entry))
|
|
173
|
+
fail("delegate route attestation must be an object", "route_attestation_missing", taskId);
|
|
174
|
+
return {
|
|
175
|
+
provider: requireString(entry, "provider", taskId),
|
|
176
|
+
model: requireString(entry, "model", taskId),
|
|
177
|
+
stop_reason: requireString(entry, "stop_reason", taskId)
|
|
178
|
+
};
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
__name(parseAttestations, "parseAttestations");
|
|
182
|
+
function parseSpillContentFormat(value, taskId) {
|
|
183
|
+
if (value === void 0) return void 0;
|
|
184
|
+
if (value !== "single_text_utf8" && value !== "tool_result_content_json_v1" && value !== "opaque_bytes") {
|
|
185
|
+
fail("delegate spill receipt content_format is invalid", "child_result_invalid", taskId);
|
|
186
|
+
}
|
|
187
|
+
return value;
|
|
188
|
+
}
|
|
189
|
+
__name(parseSpillContentFormat, "parseSpillContentFormat");
|
|
190
|
+
function parseSpillReceipts(value, taskId) {
|
|
191
|
+
if (!Array.isArray(value))
|
|
192
|
+
fail(
|
|
193
|
+
"delegate result package spilled_artifacts must be an array",
|
|
194
|
+
"child_result_invalid",
|
|
195
|
+
taskId
|
|
196
|
+
);
|
|
197
|
+
return value.map((entry) => {
|
|
198
|
+
if (!isRecord(entry))
|
|
199
|
+
fail("delegate spill receipt must be an object", "child_result_invalid", taskId);
|
|
200
|
+
if (entry["schema_version"] !== DELEGATE_RECEIPT_SCHEMA_VERSION)
|
|
201
|
+
fail("delegate spill receipt schema_version mismatch", "child_result_invalid", taskId);
|
|
202
|
+
return {
|
|
203
|
+
schema_version: DELEGATE_RECEIPT_SCHEMA_VERSION,
|
|
204
|
+
artifact: requireString(entry, "artifact", taskId),
|
|
205
|
+
tool_name: requireString(entry, "tool_name", taskId),
|
|
206
|
+
tool_call_id: requireString(entry, "tool_call_id", taskId),
|
|
207
|
+
turn_sequence: requireInteger(entry, "turn_sequence", taskId),
|
|
208
|
+
source_call_index: requireInteger(entry, "source_call_index", taskId),
|
|
209
|
+
byte_length: requireInteger(entry, "byte_length", taskId),
|
|
210
|
+
sha256: requireSha256(entry, "sha256", taskId),
|
|
211
|
+
content_format: parseSpillContentFormat(entry["content_format"], taskId)
|
|
212
|
+
};
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
__name(parseSpillReceipts, "parseSpillReceipts");
|
|
216
|
+
function verifyDelegateResultPackage(raw, expected) {
|
|
217
|
+
let parsed;
|
|
218
|
+
try {
|
|
219
|
+
parsed = JSON.parse(raw);
|
|
220
|
+
} catch (error) {
|
|
221
|
+
fail(
|
|
222
|
+
`delegate result package is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
223
|
+
"child_result_invalid",
|
|
224
|
+
expected.taskId
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
if (!isRecord(parsed))
|
|
228
|
+
fail("delegate result package must be a JSON object", "child_result_invalid", expected.taskId);
|
|
229
|
+
if (parsed["schema_version"] !== DELEGATE_RESULT_PACKAGE_SCHEMA_VERSION)
|
|
230
|
+
fail(
|
|
231
|
+
`delegate result package schema_version must be ${DELEGATE_RESULT_PACKAGE_SCHEMA_VERSION}`,
|
|
232
|
+
"child_result_invalid",
|
|
233
|
+
expected.taskId
|
|
234
|
+
);
|
|
235
|
+
const taskId = requireString(parsed, "task_id", expected.taskId);
|
|
236
|
+
const launchNonce = requireString(parsed, "launch_nonce", expected.taskId);
|
|
237
|
+
if (taskId !== expected.taskId || launchNonce !== expected.launchNonce)
|
|
238
|
+
fail(
|
|
239
|
+
"delegate result package identity does not match the launched task; a stale or foreign package is never accepted",
|
|
240
|
+
"child_result_invalid",
|
|
241
|
+
expected.taskId
|
|
242
|
+
);
|
|
243
|
+
const seedSha256 = requireSha256(parsed, "seed_sha256", expected.taskId);
|
|
244
|
+
if (seedSha256 !== expected.seedSha256)
|
|
245
|
+
fail(
|
|
246
|
+
`delegate result package was produced from a different seed: expected ${expected.seedSha256}, package declares ${seedSha256}`,
|
|
247
|
+
"seed_hash_mismatch",
|
|
248
|
+
expected.taskId
|
|
249
|
+
);
|
|
250
|
+
const routeRecord = parsed["route"];
|
|
251
|
+
if (!isRecord(routeRecord))
|
|
252
|
+
fail(
|
|
253
|
+
"delegate result package route must be an object",
|
|
254
|
+
"child_result_invalid",
|
|
255
|
+
expected.taskId
|
|
256
|
+
);
|
|
257
|
+
const provider = requireString(routeRecord, "provider", expected.taskId);
|
|
258
|
+
const model = requireString(routeRecord, "model", expected.taskId);
|
|
259
|
+
if (provider !== expected.route.provider || model !== expected.route.model)
|
|
260
|
+
fail(
|
|
261
|
+
`delegate result package route ${provider}/${model} does not match the pinned route ${expected.route.provider}/${expected.route.model}`,
|
|
262
|
+
"route_mismatch",
|
|
263
|
+
expected.taskId
|
|
264
|
+
);
|
|
265
|
+
const attestations = parseAttestations(parsed["route_attestations"], expected.taskId);
|
|
266
|
+
for (const attestation of attestations) {
|
|
267
|
+
if (attestation.provider !== expected.route.provider || attestation.model !== expected.route.model)
|
|
268
|
+
fail(
|
|
269
|
+
`delegate child produced an assistant message on ${attestation.provider}/${attestation.model}, but the pinned route is ${expected.route.provider}/${expected.route.model}`,
|
|
270
|
+
"route_mismatch",
|
|
271
|
+
expected.taskId
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
const answerRecord = parsed["answer"];
|
|
275
|
+
if (!isRecord(answerRecord))
|
|
276
|
+
fail(
|
|
277
|
+
"delegate result package answer must be an object",
|
|
278
|
+
"child_result_invalid",
|
|
279
|
+
expected.taskId
|
|
280
|
+
);
|
|
281
|
+
if (answerRecord["encoding"] !== "utf-8")
|
|
282
|
+
fail(
|
|
283
|
+
"delegate result package answer encoding must be utf-8",
|
|
284
|
+
"child_result_encoding_invalid",
|
|
285
|
+
expected.taskId
|
|
286
|
+
);
|
|
287
|
+
const declaredLength = requireInteger(answerRecord, "byte_length", expected.taskId);
|
|
288
|
+
const declaredSha = requireSha256(answerRecord, "sha256", expected.taskId);
|
|
289
|
+
const blocksValue = answerRecord["blocks"];
|
|
290
|
+
if (!Array.isArray(blocksValue))
|
|
291
|
+
fail(
|
|
292
|
+
"delegate result package answer blocks must be an array",
|
|
293
|
+
"child_result_invalid",
|
|
294
|
+
expected.taskId
|
|
295
|
+
);
|
|
296
|
+
const blocks = [];
|
|
297
|
+
const buffers = [];
|
|
298
|
+
for (const [index, entry] of blocksValue.entries()) {
|
|
299
|
+
if (!isRecord(entry))
|
|
300
|
+
fail(
|
|
301
|
+
`delegate answer block ${String(index)} must be an object`,
|
|
302
|
+
"child_result_invalid",
|
|
303
|
+
expected.taskId
|
|
304
|
+
);
|
|
305
|
+
if (entry["kind"] !== "text")
|
|
306
|
+
fail(
|
|
307
|
+
`delegate answer block ${String(index)} kind must be text`,
|
|
308
|
+
"child_result_invalid",
|
|
309
|
+
expected.taskId
|
|
310
|
+
);
|
|
311
|
+
const byteLength = requireInteger(entry, "byte_length", expected.taskId);
|
|
312
|
+
const sha = requireSha256(entry, "sha256", expected.taskId);
|
|
313
|
+
const dataBase64 = requireString(entry, "data_base64", expected.taskId);
|
|
314
|
+
const bytes = Buffer.from(dataBase64, "base64");
|
|
315
|
+
if (bytes.toString("base64") !== dataBase64)
|
|
316
|
+
fail(
|
|
317
|
+
`delegate answer block ${String(index)} is not strict base64`,
|
|
318
|
+
"child_result_invalid",
|
|
319
|
+
expected.taskId
|
|
320
|
+
);
|
|
321
|
+
if (bytes.length !== byteLength)
|
|
322
|
+
fail(
|
|
323
|
+
`delegate answer block ${String(index)} declares ${String(byteLength)} bytes but carries ${String(bytes.length)}`,
|
|
324
|
+
"answer_hash_mismatch",
|
|
325
|
+
expected.taskId
|
|
326
|
+
);
|
|
327
|
+
const actual = sha256Bytes(bytes);
|
|
328
|
+
if (actual !== sha)
|
|
329
|
+
fail(
|
|
330
|
+
`delegate answer block ${String(index)} hash mismatch: declared ${sha}, computed ${actual}`,
|
|
331
|
+
"answer_hash_mismatch",
|
|
332
|
+
expected.taskId
|
|
333
|
+
);
|
|
334
|
+
blocks.push({ kind: "text", byte_length: byteLength, sha256: sha, data_base64: dataBase64 });
|
|
335
|
+
buffers.push(bytes);
|
|
336
|
+
}
|
|
337
|
+
const aggregate = Buffer.concat(buffers);
|
|
338
|
+
if (aggregate.length !== declaredLength)
|
|
339
|
+
fail(
|
|
340
|
+
`delegate answer declares ${String(declaredLength)} bytes but its blocks total ${String(aggregate.length)}`,
|
|
341
|
+
"answer_hash_mismatch",
|
|
342
|
+
expected.taskId
|
|
343
|
+
);
|
|
344
|
+
const aggregateSha = sha256Bytes(aggregate);
|
|
345
|
+
if (aggregateSha !== declaredSha)
|
|
346
|
+
fail(
|
|
347
|
+
`delegate answer aggregate hash mismatch: declared ${declaredSha}, computed ${aggregateSha}`,
|
|
348
|
+
"answer_hash_mismatch",
|
|
349
|
+
expected.taskId
|
|
350
|
+
);
|
|
351
|
+
const answer = aggregate.toString("utf8");
|
|
352
|
+
if (!Buffer.from(answer, "utf8").equals(aggregate))
|
|
353
|
+
fail(
|
|
354
|
+
"delegate answer bytes are not well-formed UTF-8; they are preserved on disk and never returned with substitution characters",
|
|
355
|
+
"child_result_encoding_invalid",
|
|
356
|
+
expected.taskId
|
|
357
|
+
);
|
|
358
|
+
return {
|
|
359
|
+
package: {
|
|
360
|
+
schema_version: DELEGATE_RESULT_PACKAGE_SCHEMA_VERSION,
|
|
361
|
+
task_id: taskId,
|
|
362
|
+
launch_nonce: launchNonce,
|
|
363
|
+
seed_sha256: seedSha256,
|
|
364
|
+
directive_sha256: requireSha256(parsed, "directive_sha256", expected.taskId),
|
|
365
|
+
route: { provider, model },
|
|
366
|
+
route_attestations: attestations,
|
|
367
|
+
stop_reason: requireString(parsed, "stop_reason", expected.taskId),
|
|
368
|
+
turns: requireInteger(parsed, "turns", expected.taskId),
|
|
369
|
+
tool_calls: requireInteger(parsed, "tool_calls", expected.taskId),
|
|
370
|
+
usage: parseUsage(parsed["usage"], expected.taskId),
|
|
371
|
+
answer: {
|
|
372
|
+
encoding: "utf-8",
|
|
373
|
+
byte_length: declaredLength,
|
|
374
|
+
sha256: declaredSha,
|
|
375
|
+
blocks
|
|
376
|
+
},
|
|
377
|
+
spilled_artifacts: parseSpillReceipts(parsed["spilled_artifacts"], expected.taskId)
|
|
378
|
+
},
|
|
379
|
+
answer,
|
|
380
|
+
answerBytes: aggregate
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
__name(verifyDelegateResultPackage, "verifyDelegateResultPackage");
|
|
384
|
+
|
|
385
|
+
// node_modules/pi-background-tasks/src/core/delegate/artifacts.ts?ext=pi-background-tasks
|
|
386
|
+
var DELEGATE_ARTIFACT_NAMES = {
|
|
387
|
+
seed: "seed.json",
|
|
388
|
+
ledger: "context-omission-ledger.json",
|
|
389
|
+
budgetPlan: "budget-plan.json",
|
|
390
|
+
manifest: "manifest.json",
|
|
391
|
+
outcome: "outcome.json",
|
|
392
|
+
result: DELEGATE_RESULT_PACKAGE_FILENAME,
|
|
393
|
+
childPrompt: "child-prompt.txt",
|
|
394
|
+
runtimeBudget: "runtime-budget.json",
|
|
395
|
+
error: "error.json"
|
|
396
|
+
};
|
|
397
|
+
var DELEGATE_SPILL_DIRNAME = "spill";
|
|
398
|
+
function sha256Bytes2(bytes) {
|
|
399
|
+
return createHash2("sha256").update(bytes).digest("hex");
|
|
400
|
+
}
|
|
401
|
+
__name(sha256Bytes2, "sha256Bytes");
|
|
402
|
+
function pathInside(parent, child) {
|
|
403
|
+
const rel = relative(parent, child);
|
|
404
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel) && !rel.split(sep).includes("..");
|
|
405
|
+
}
|
|
406
|
+
__name(pathInside, "pathInside");
|
|
407
|
+
function artifactError(message, cause) {
|
|
408
|
+
const suffix = cause === void 0 ? "" : `: ${cause instanceof Error ? cause.message : String(cause)}`;
|
|
409
|
+
return new DelegateError(`${message}${suffix}`, {
|
|
410
|
+
code: "artifact_error",
|
|
411
|
+
childCreated: true,
|
|
412
|
+
remediation: [
|
|
413
|
+
"The delegate artifact directory could not be written. Check free disk space and directory permissions."
|
|
414
|
+
]
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
__name(artifactError, "artifactError");
|
|
418
|
+
var DelegateArtifactStore = class _DelegateArtifactStore {
|
|
419
|
+
static {
|
|
420
|
+
__name(this, "DelegateArtifactStore");
|
|
421
|
+
}
|
|
422
|
+
rootAbs;
|
|
423
|
+
rootDisplay;
|
|
424
|
+
spillAbs;
|
|
425
|
+
now;
|
|
426
|
+
manifest;
|
|
427
|
+
writeChain = Promise.resolve();
|
|
428
|
+
totalSpilledBytes = 0;
|
|
429
|
+
constructor(rootAbs, rootDisplay, now, manifest) {
|
|
430
|
+
this.rootAbs = rootAbs;
|
|
431
|
+
this.rootDisplay = rootDisplay;
|
|
432
|
+
this.spillAbs = join(rootAbs, DELEGATE_SPILL_DIRNAME);
|
|
433
|
+
this.now = now;
|
|
434
|
+
this.manifest = manifest;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Create the artifact root with exclusive semantics.
|
|
438
|
+
*
|
|
439
|
+
* The directory name embeds the task id, which is cryptographically random, so
|
|
440
|
+
* two delegates launched in the same assistant message cannot collide. The
|
|
441
|
+
* directory is created with `recursive: false` so a pre-existing directory is
|
|
442
|
+
* a loud failure rather than a silent reuse.
|
|
443
|
+
*/
|
|
444
|
+
static async create(options) {
|
|
445
|
+
const sessionSegment = sanitizePathSegment(
|
|
446
|
+
options.sessionId ?? `session-${String(process.pid)}`
|
|
447
|
+
);
|
|
448
|
+
const runDirName = `${sessionSegment}-${String(process.pid)}`;
|
|
449
|
+
const parentAbs = join(options.cwd, ".pi", "delegate", runDirName);
|
|
450
|
+
const rootAbs = join(parentAbs, options.taskId);
|
|
451
|
+
const rootDisplay = join(".pi", "delegate", runDirName, options.taskId);
|
|
452
|
+
try {
|
|
453
|
+
await mkdir(parentAbs, { recursive: true, mode: 448 });
|
|
454
|
+
await mkdir(rootAbs, { recursive: false, mode: 448 });
|
|
455
|
+
await chmod(rootAbs, 448);
|
|
456
|
+
await mkdir(join(rootAbs, DELEGATE_SPILL_DIRNAME), { recursive: false, mode: 448 });
|
|
457
|
+
} catch (error) {
|
|
458
|
+
throw artifactError(`could not create delegate artifact directory ${rootDisplay}`, error);
|
|
459
|
+
}
|
|
460
|
+
const timestamp = (options.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
|
|
461
|
+
const manifest = {
|
|
462
|
+
schema_version: DELEGATE_MANIFEST_SCHEMA_VERSION,
|
|
463
|
+
task_id: options.taskId,
|
|
464
|
+
launch_nonce: options.launchNonce,
|
|
465
|
+
created_at: timestamp,
|
|
466
|
+
updated_at: timestamp,
|
|
467
|
+
cwd: options.cwd,
|
|
468
|
+
child_session_id: options.childSessionId,
|
|
469
|
+
child_session_dir: options.childSessionDir,
|
|
470
|
+
extension_mode: options.extensionMode,
|
|
471
|
+
route: options.route,
|
|
472
|
+
limits: options.limits,
|
|
473
|
+
seed_sha256: options.seedSha256,
|
|
474
|
+
state: "launched",
|
|
475
|
+
artifacts: {}
|
|
476
|
+
};
|
|
477
|
+
const store = new _DelegateArtifactStore(
|
|
478
|
+
rootAbs,
|
|
479
|
+
rootDisplay,
|
|
480
|
+
options.now ?? (() => /* @__PURE__ */ new Date()),
|
|
481
|
+
manifest
|
|
482
|
+
);
|
|
483
|
+
await store.persistManifest();
|
|
484
|
+
return store;
|
|
485
|
+
}
|
|
486
|
+
get artifactDir() {
|
|
487
|
+
return this.rootDisplay;
|
|
488
|
+
}
|
|
489
|
+
get artifactDirAbs() {
|
|
490
|
+
return this.rootAbs;
|
|
491
|
+
}
|
|
492
|
+
get spillDirAbs() {
|
|
493
|
+
return this.spillAbs;
|
|
494
|
+
}
|
|
495
|
+
get resultPathAbs() {
|
|
496
|
+
return join(this.rootAbs, DELEGATE_ARTIFACT_NAMES.result);
|
|
497
|
+
}
|
|
498
|
+
snapshot() {
|
|
499
|
+
return { ...this.manifest, artifacts: { ...this.manifest.artifacts } };
|
|
500
|
+
}
|
|
501
|
+
async writeSeed(serialized) {
|
|
502
|
+
return this.write(DELEGATE_ARTIFACT_NAMES.seed, serialized);
|
|
503
|
+
}
|
|
504
|
+
/** Persist the exact prompt bytes handed to the child over stdin. */
|
|
505
|
+
async writeChildPrompt(bytes) {
|
|
506
|
+
return this.write(DELEGATE_ARTIFACT_NAMES.childPrompt, bytes);
|
|
507
|
+
}
|
|
508
|
+
async writeLedger(ledger) {
|
|
509
|
+
return this.write(DELEGATE_ARTIFACT_NAMES.ledger, `${canonicalJson(ledger)}
|
|
510
|
+
`);
|
|
511
|
+
}
|
|
512
|
+
async writeBudgetPlan(plan) {
|
|
513
|
+
return this.write(DELEGATE_ARTIFACT_NAMES.budgetPlan, `${canonicalJson(plan)}
|
|
514
|
+
`);
|
|
515
|
+
}
|
|
516
|
+
/** Commit the run. The rename performed here is the single success point. */
|
|
517
|
+
async commitResult(pkg) {
|
|
518
|
+
const ref = await this.write(
|
|
519
|
+
DELEGATE_ARTIFACT_NAMES.result,
|
|
520
|
+
serializeDelegateResultPackage(pkg)
|
|
521
|
+
);
|
|
522
|
+
await this.setState("committed");
|
|
523
|
+
return ref;
|
|
524
|
+
}
|
|
525
|
+
async readCommittedResult() {
|
|
526
|
+
try {
|
|
527
|
+
return await readFile(this.resultPathAbs, "utf8");
|
|
528
|
+
} catch (error) {
|
|
529
|
+
const diagnosticNames = [
|
|
530
|
+
DELEGATE_ARTIFACT_NAMES.error,
|
|
531
|
+
DELEGATE_ARTIFACT_NAMES.outcome,
|
|
532
|
+
DELEGATE_ARTIFACT_NAMES.runtimeBudget,
|
|
533
|
+
DELEGATE_ARTIFACT_NAMES.manifest
|
|
534
|
+
].filter((name) => existsSync(join(this.rootAbs, name)));
|
|
535
|
+
throw new DelegateError(
|
|
536
|
+
`delegate result package could not be read at ${join(this.rootDisplay, DELEGATE_ARTIFACT_NAMES.result)}; no committed answer is available (${error instanceof Error ? error.message : String(error)})`,
|
|
537
|
+
{
|
|
538
|
+
code: "result_unavailable",
|
|
539
|
+
childCreated: true,
|
|
540
|
+
taskId: this.manifest.task_id,
|
|
541
|
+
artifactDir: this.rootDisplay,
|
|
542
|
+
preserved: diagnosticNames,
|
|
543
|
+
remediation: diagnosticNames.length === 0 ? [
|
|
544
|
+
"No diagnostic control artifact exists; inspect the background task merged output if one was created."
|
|
545
|
+
] : [`Inspect the existing delegate control artifacts: ${diagnosticNames.join(", ")}.`]
|
|
546
|
+
}
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
async writeError(state, message) {
|
|
551
|
+
await this.write(
|
|
552
|
+
DELEGATE_ARTIFACT_NAMES.error,
|
|
553
|
+
`${canonicalJson({ state, error: message })}
|
|
554
|
+
`
|
|
555
|
+
);
|
|
556
|
+
await this.setState(state, message);
|
|
557
|
+
}
|
|
558
|
+
async setState(state, error) {
|
|
559
|
+
await this.update((manifest) => {
|
|
560
|
+
manifest.state = state;
|
|
561
|
+
if (error !== void 0) manifest.error = error;
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Spill one oversized tool payload.
|
|
566
|
+
*
|
|
567
|
+
* The filename encodes `(turnSequence, sourceCallIndex, toolCallId)` assigned
|
|
568
|
+
* before the tool executed, so a receipt can never be associated with the
|
|
569
|
+
* wrong call when parallel results complete out of order.
|
|
570
|
+
*
|
|
571
|
+
* A spill that cannot be committed is a terminal failure. The original payload
|
|
572
|
+
* is never returned as a fallback and no receipt is emitted for a file that
|
|
573
|
+
* was not committed.
|
|
574
|
+
*/
|
|
575
|
+
async spillToolPayload(input) {
|
|
576
|
+
const nextTotal = this.totalSpilledBytes + input.payload.length;
|
|
577
|
+
if (nextTotal > input.maxTotalBytes) {
|
|
578
|
+
throw new DelegateError(
|
|
579
|
+
`delegate aggregate tool output would reach ${String(nextTotal)} bytes, exceeding the ${String(input.maxTotalBytes)}-byte cap for one run`,
|
|
580
|
+
{
|
|
581
|
+
code: "aggregate_tool_output_cap",
|
|
582
|
+
childCreated: true,
|
|
583
|
+
taskId: this.manifest.task_id,
|
|
584
|
+
artifactDir: this.rootDisplay,
|
|
585
|
+
preserved: [this.rootDisplay],
|
|
586
|
+
remediation: [
|
|
587
|
+
"The delegate read more tool output than one run is allowed to accumulate. Narrow the investigation prompt or raise the cap deliberately."
|
|
588
|
+
]
|
|
589
|
+
}
|
|
590
|
+
);
|
|
591
|
+
}
|
|
592
|
+
const safeCallId = sanitizePathSegment(input.toolCallId).slice(0, 64);
|
|
593
|
+
const name = `t${String(input.turnSequence).padStart(4, "0")}-c${String(
|
|
594
|
+
input.sourceCallIndex
|
|
595
|
+
).padStart(4, "0")}-${safeCallId}.bin`;
|
|
596
|
+
const absPath = join(this.spillAbs, name);
|
|
597
|
+
if (!pathInside(this.spillAbs, absPath)) {
|
|
598
|
+
throw artifactError(`delegate spill path escapes the artifact directory: ${name}`);
|
|
599
|
+
}
|
|
600
|
+
try {
|
|
601
|
+
await this.durableReplace(absPath, input.payload);
|
|
602
|
+
} catch (error) {
|
|
603
|
+
throw new DelegateError(
|
|
604
|
+
`delegate could not durably spill a ${String(input.payload.length)}-byte tool result; the payload is not forwarded and no receipt is emitted`,
|
|
605
|
+
{
|
|
606
|
+
code: "artifact_spill_failed",
|
|
607
|
+
childCreated: true,
|
|
608
|
+
taskId: this.manifest.task_id,
|
|
609
|
+
artifactDir: this.rootDisplay,
|
|
610
|
+
preserved: [this.rootDisplay],
|
|
611
|
+
remediation: [
|
|
612
|
+
`Underlying cause: ${error instanceof Error ? error.message : String(error)}`,
|
|
613
|
+
"Check free disk space and permissions on the delegate artifact directory."
|
|
614
|
+
]
|
|
615
|
+
}
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
this.totalSpilledBytes = nextTotal;
|
|
619
|
+
return {
|
|
620
|
+
schema_version: DELEGATE_RECEIPT_SCHEMA_VERSION,
|
|
621
|
+
artifact: join(DELEGATE_SPILL_DIRNAME, name),
|
|
622
|
+
tool_name: input.toolName,
|
|
623
|
+
tool_call_id: input.toolCallId,
|
|
624
|
+
turn_sequence: input.turnSequence,
|
|
625
|
+
source_call_index: input.sourceCallIndex,
|
|
626
|
+
byte_length: input.payload.length,
|
|
627
|
+
sha256: sha256Bytes2(input.payload),
|
|
628
|
+
content_format: "opaque_bytes"
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Read an exact byte range from a spilled artifact.
|
|
633
|
+
*
|
|
634
|
+
* Returns exactly the requested range or fails. It never returns a shorter
|
|
635
|
+
* range than requested, and it never clamps the request to what happens to be
|
|
636
|
+
* available: a request past end-of-file is a loud error naming the real size.
|
|
637
|
+
*/
|
|
638
|
+
async readSpillRange(relativePath, offset, length) {
|
|
639
|
+
if (!Number.isSafeInteger(offset) || offset < 0)
|
|
640
|
+
throw this.readFailure(relativePath, "offset must be a non-negative integer");
|
|
641
|
+
if (!Number.isSafeInteger(length) || length <= 0)
|
|
642
|
+
throw this.readFailure(relativePath, "length must be a positive integer");
|
|
643
|
+
const absPath = join(this.rootAbs, relativePath);
|
|
644
|
+
if (!pathInside(this.rootAbs, absPath))
|
|
645
|
+
throw this.readFailure(relativePath, "path escapes the delegate artifact directory");
|
|
646
|
+
let handle;
|
|
647
|
+
try {
|
|
648
|
+
handle = await open(absPath, "r");
|
|
649
|
+
} catch (error) {
|
|
650
|
+
throw this.readFailure(
|
|
651
|
+
relativePath,
|
|
652
|
+
`cannot open artifact: ${error instanceof Error ? error.message : String(error)}`
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
try {
|
|
656
|
+
const stats = await handle.stat();
|
|
657
|
+
const totalBytes = stats.size;
|
|
658
|
+
if (offset + length > totalBytes) {
|
|
659
|
+
throw this.readFailure(
|
|
660
|
+
relativePath,
|
|
661
|
+
`requested bytes ${String(offset)}..${String(offset + length)} exceed the artifact size of ${String(totalBytes)} bytes; the read is refused rather than silently shortened`
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
const buffer = Buffer.alloc(length);
|
|
665
|
+
const { bytesRead } = await handle.read(buffer, 0, length, offset);
|
|
666
|
+
if (bytesRead !== length) {
|
|
667
|
+
throw this.readFailure(
|
|
668
|
+
relativePath,
|
|
669
|
+
`read returned ${String(bytesRead)} of ${String(length)} requested bytes`
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
return { bytes: buffer, totalBytes };
|
|
673
|
+
} finally {
|
|
674
|
+
await handle.close();
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
readFailure(relativePath, reason) {
|
|
678
|
+
return new DelegateError(`delegate artifact read failed for ${relativePath}: ${reason}`, {
|
|
679
|
+
code: "artifact_read_failed",
|
|
680
|
+
childCreated: true,
|
|
681
|
+
taskId: this.manifest.task_id,
|
|
682
|
+
artifactDir: this.rootDisplay
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
async durableReplace(absPath, data) {
|
|
686
|
+
await replaceFileDurable(absPath, data);
|
|
687
|
+
}
|
|
688
|
+
async write(name, data) {
|
|
689
|
+
const absPath = join(this.rootAbs, name);
|
|
690
|
+
if (name.length === 0 || name.includes("/") || name.includes("\\"))
|
|
691
|
+
throw artifactError(`invalid delegate artifact name: ${name}`);
|
|
692
|
+
if (!pathInside(this.rootAbs, absPath))
|
|
693
|
+
throw artifactError(`delegate artifact path escapes the run directory: ${name}`);
|
|
694
|
+
const bytes = Buffer.isBuffer(data) ? data : Buffer.from(data, "utf8");
|
|
695
|
+
try {
|
|
696
|
+
await this.durableReplace(absPath, data);
|
|
697
|
+
} catch (error) {
|
|
698
|
+
throw artifactError(`could not durably write delegate artifact ${name}`, error);
|
|
699
|
+
}
|
|
700
|
+
const ref = {
|
|
701
|
+
path: basename(absPath),
|
|
702
|
+
byte_length: bytes.length,
|
|
703
|
+
sha256: sha256Bytes2(bytes)
|
|
704
|
+
};
|
|
705
|
+
await this.update((manifest) => {
|
|
706
|
+
manifest.artifacts = { ...manifest.artifacts, [name]: ref };
|
|
707
|
+
});
|
|
708
|
+
return ref;
|
|
709
|
+
}
|
|
710
|
+
async persistManifest() {
|
|
711
|
+
const absPath = join(this.rootAbs, DELEGATE_ARTIFACT_NAMES.manifest);
|
|
712
|
+
try {
|
|
713
|
+
await this.durableReplace(absPath, `${canonicalJson(this.snapshot())}
|
|
714
|
+
`);
|
|
715
|
+
} catch (error) {
|
|
716
|
+
throw artifactError("could not durably write the delegate manifest", error);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
async update(mutator) {
|
|
720
|
+
const apply = /* @__PURE__ */ __name(async () => {
|
|
721
|
+
mutator(this.manifest);
|
|
722
|
+
this.manifest.updated_at = this.now().toISOString();
|
|
723
|
+
await this.persistManifest();
|
|
724
|
+
}, "apply");
|
|
725
|
+
const next = this.writeChain.then(apply, apply);
|
|
726
|
+
this.writeChain = next.catch(() => void 0);
|
|
727
|
+
await next;
|
|
728
|
+
}
|
|
729
|
+
};
|
|
730
|
+
async function discardDelegateArtifactRoot(rootAbs) {
|
|
731
|
+
await rm(rootAbs, { recursive: true, force: true });
|
|
732
|
+
}
|
|
733
|
+
__name(discardDelegateArtifactRoot, "discardDelegateArtifactRoot");
|
|
734
|
+
|
|
735
|
+
// node_modules/pi-background-tasks/src/core/delegate/runner.ts?ext=pi-background-tasks
|
|
736
|
+
var PREPARATION_CLEANUP_ERROR_MAX_CHARS = 320;
|
|
737
|
+
function boundedPreparationError(error) {
|
|
738
|
+
const text = (error instanceof Error ? error.message : String(error)).replace(/\s+/gu, " ").trim();
|
|
739
|
+
if (text.length <= PREPARATION_CLEANUP_ERROR_MAX_CHARS) return text;
|
|
740
|
+
return `${text.slice(0, PREPARATION_CLEANUP_ERROR_MAX_CHARS)}\u2026`;
|
|
741
|
+
}
|
|
742
|
+
__name(boundedPreparationError, "boundedPreparationError");
|
|
743
|
+
function filesystemErrorCode(error) {
|
|
744
|
+
if (typeof error !== "object" || error === null) return void 0;
|
|
745
|
+
const code = Reflect.get(error, "code");
|
|
746
|
+
return typeof code === "string" ? code : void 0;
|
|
747
|
+
}
|
|
748
|
+
__name(filesystemErrorCode, "filesystemErrorCode");
|
|
749
|
+
async function removeEmptyDirectory(path) {
|
|
750
|
+
try {
|
|
751
|
+
await rmdir(path);
|
|
752
|
+
return true;
|
|
753
|
+
} catch (error) {
|
|
754
|
+
const code = filesystemErrorCode(error);
|
|
755
|
+
if (code === "ENOENT") return true;
|
|
756
|
+
if (code === "ENOTEMPTY" || code === "EEXIST") return false;
|
|
757
|
+
throw error;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
__name(removeEmptyDirectory, "removeEmptyDirectory");
|
|
761
|
+
async function discardUnownedDelegatePreparation(rootAbs) {
|
|
762
|
+
await discardDelegateArtifactRoot(rootAbs);
|
|
763
|
+
const runParent = dirname(rootAbs);
|
|
764
|
+
if (!await removeEmptyDirectory(runParent)) return;
|
|
765
|
+
await removeEmptyDirectory(dirname(runParent));
|
|
766
|
+
}
|
|
767
|
+
__name(discardUnownedDelegatePreparation, "discardUnownedDelegatePreparation");
|
|
768
|
+
function throwIfPreparationAborted(signal) {
|
|
769
|
+
if (signal?.aborted !== true) return;
|
|
770
|
+
const reason = signal.reason;
|
|
771
|
+
if (reason instanceof Error) throw reason;
|
|
772
|
+
throw new Error("delegate launch preparation was cancelled before task registration");
|
|
773
|
+
}
|
|
774
|
+
__name(throwIfPreparationAborted, "throwIfPreparationAborted");
|
|
775
|
+
function preparationCleanupFailure(original, cleanup) {
|
|
776
|
+
return new AggregateError(
|
|
777
|
+
[original, cleanup],
|
|
778
|
+
`delegate launch preparation failed and rollback also failed: ${boundedPreparationError(cleanup)}`
|
|
779
|
+
);
|
|
780
|
+
}
|
|
781
|
+
__name(preparationCleanupFailure, "preparationCleanupFailure");
|
|
782
|
+
async function prepareDelegateLaunch(input) {
|
|
783
|
+
throwIfPreparationAborted(input.signal);
|
|
784
|
+
const childExtensionPath = input.childExtensionPath ?? resolveDelegateChildExtensionPath();
|
|
785
|
+
let attributionExtensionPath;
|
|
786
|
+
if (input.route.provider === "anthropic") {
|
|
787
|
+
try {
|
|
788
|
+
attributionExtensionPath = input.attributionExtensionPath ?? resolveAnthropicAttributionExtensionPath();
|
|
789
|
+
} catch (error) {
|
|
790
|
+
throw new DelegateError(
|
|
791
|
+
`Anthropic delegate attribution extension could not be resolved: ${error instanceof Error ? error.message : String(error)}`,
|
|
792
|
+
{
|
|
793
|
+
code: "delegate_isolation_unsupported",
|
|
794
|
+
childCreated: false,
|
|
795
|
+
remediation: ["Reinstall the package; Anthropic delegates require attribution."]
|
|
796
|
+
}
|
|
797
|
+
);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
throwIfPreparationAborted(input.signal);
|
|
801
|
+
const preflight = preflightDelegateLaunch(input);
|
|
802
|
+
throwIfPreparationAborted(input.signal);
|
|
803
|
+
let store;
|
|
804
|
+
try {
|
|
805
|
+
store = await DelegateArtifactStore.create({
|
|
806
|
+
cwd: input.cwd,
|
|
807
|
+
taskId: preflight.taskId,
|
|
808
|
+
launchNonce: preflight.launchNonce,
|
|
809
|
+
sessionId: input.sessionId,
|
|
810
|
+
childSessionId: preflight.childSessionId,
|
|
811
|
+
childSessionDir: "",
|
|
812
|
+
extensionMode: input.extensionMode,
|
|
813
|
+
route: input.route,
|
|
814
|
+
limits: preflight.limits,
|
|
815
|
+
seedSha256: preflight.seed.sha256,
|
|
816
|
+
...input.now === void 0 ? {} : { now: input.now }
|
|
817
|
+
});
|
|
818
|
+
throwIfPreparationAborted(input.signal);
|
|
819
|
+
const seedRef = await store.writeSeed(preflight.seed.serialized);
|
|
820
|
+
throwIfPreparationAborted(input.signal);
|
|
821
|
+
if (seedRef.sha256 !== preflight.seed.sha256) {
|
|
822
|
+
throw new DelegateError("delegate seed hash changed between construction and persistence", {
|
|
823
|
+
code: "seed_persist_failed",
|
|
824
|
+
childCreated: false,
|
|
825
|
+
taskId: preflight.taskId,
|
|
826
|
+
artifactDir: store.artifactDir
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
await store.writeLedger(preflight.seed.ledger);
|
|
830
|
+
throwIfPreparationAborted(input.signal);
|
|
831
|
+
await store.writeBudgetPlan(preflight.plan);
|
|
832
|
+
throwIfPreparationAborted(input.signal);
|
|
833
|
+
const childSessionDirAbs = await ensureDelegateChildSessionDir(store.artifactDirAbs);
|
|
834
|
+
throwIfPreparationAborted(input.signal);
|
|
835
|
+
const seedPathAbs = join2(store.artifactDirAbs, "seed.json");
|
|
836
|
+
const argv = buildDelegateChildArgv({
|
|
837
|
+
route: input.route,
|
|
838
|
+
capability: input.capability,
|
|
839
|
+
extensionMode: input.extensionMode,
|
|
840
|
+
childSessionId: preflight.childSessionId,
|
|
841
|
+
childSessionDir: childSessionDirAbs,
|
|
842
|
+
childExtensionPath,
|
|
843
|
+
attributionExtensionPath,
|
|
844
|
+
systemPrompt: preflight.childSystemPrompt
|
|
845
|
+
});
|
|
846
|
+
const env = delegateChildEnv(
|
|
847
|
+
{
|
|
848
|
+
artifactDirAbs: store.artifactDirAbs,
|
|
849
|
+
seedPathAbs,
|
|
850
|
+
seedSha256: preflight.seed.sha256,
|
|
851
|
+
taskId: preflight.taskId,
|
|
852
|
+
launchNonce: preflight.launchNonce
|
|
853
|
+
},
|
|
854
|
+
input.env ?? process.env
|
|
855
|
+
);
|
|
856
|
+
const facts = {
|
|
857
|
+
taskId: preflight.taskId,
|
|
858
|
+
launchNonce: preflight.launchNonce,
|
|
859
|
+
artifactDir: store.artifactDir,
|
|
860
|
+
artifactDirAbs: store.artifactDirAbs,
|
|
861
|
+
seedSha256: preflight.seed.sha256,
|
|
862
|
+
childSessionId: preflight.childSessionId,
|
|
863
|
+
route: {
|
|
864
|
+
provider: input.route.provider,
|
|
865
|
+
model: input.route.model,
|
|
866
|
+
qualifiedId: input.route.qualified_id
|
|
867
|
+
},
|
|
868
|
+
budget: {
|
|
869
|
+
family: preflight.plan.route.family,
|
|
870
|
+
rate_source: preflight.plan.route.rate_source,
|
|
871
|
+
conservative_rate_source: preflight.plan.conservative_estimate.rateSource
|
|
872
|
+
},
|
|
873
|
+
extensionMode: input.extensionMode,
|
|
874
|
+
autoDeliver: input.autoDeliver
|
|
875
|
+
};
|
|
876
|
+
const stdinBytes = Buffer.from(preflight.childPrompt, "utf8");
|
|
877
|
+
await store.writeChildPrompt(stdinBytes);
|
|
878
|
+
throwIfPreparationAborted(input.signal);
|
|
879
|
+
const artifactDirAbs = store.artifactDirAbs;
|
|
880
|
+
let rollbackPromise;
|
|
881
|
+
const rollback = /* @__PURE__ */ __name(() => {
|
|
882
|
+
rollbackPromise ??= discardUnownedDelegatePreparation(artifactDirAbs);
|
|
883
|
+
return rollbackPromise;
|
|
884
|
+
}, "rollback");
|
|
885
|
+
return {
|
|
886
|
+
preflight,
|
|
887
|
+
store,
|
|
888
|
+
argv,
|
|
889
|
+
env,
|
|
890
|
+
facts,
|
|
891
|
+
childSessionDirAbs,
|
|
892
|
+
seedPathAbs,
|
|
893
|
+
stdinBytes,
|
|
894
|
+
rollback
|
|
895
|
+
};
|
|
896
|
+
} catch (error) {
|
|
897
|
+
if (store === void 0) throw error;
|
|
898
|
+
try {
|
|
899
|
+
await discardUnownedDelegatePreparation(store.artifactDirAbs);
|
|
900
|
+
} catch (cleanupError) {
|
|
901
|
+
throw preparationCleanupFailure(error, cleanupError);
|
|
902
|
+
}
|
|
903
|
+
throw error;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
__name(prepareDelegateLaunch, "prepareDelegateLaunch");
|
|
907
|
+
async function evaluateDelegateTerminal(input) {
|
|
908
|
+
const evaluation = await adjudicateDelegateTerminal(input);
|
|
909
|
+
try {
|
|
910
|
+
await replaceFileDurable(
|
|
911
|
+
join2(input.artifactDirAbs, "outcome.json"),
|
|
912
|
+
`${canonicalJson({
|
|
913
|
+
schema_version: "pi-background-tasks.delegate-outcome.v1",
|
|
914
|
+
task_id: input.taskId,
|
|
915
|
+
launch_nonce: input.launchNonce,
|
|
916
|
+
observed_task_status: input.taskStatus,
|
|
917
|
+
outcome: evaluation.outcome,
|
|
918
|
+
error_code: evaluation.error?.code ?? null
|
|
919
|
+
})}
|
|
920
|
+
`
|
|
921
|
+
);
|
|
922
|
+
} catch {
|
|
923
|
+
}
|
|
924
|
+
return evaluation;
|
|
925
|
+
}
|
|
926
|
+
__name(evaluateDelegateTerminal, "evaluateDelegateTerminal");
|
|
927
|
+
async function adjudicateDelegateTerminal(input) {
|
|
928
|
+
const resultPath = join2(input.artifactDirAbs, "result.json");
|
|
929
|
+
const terminalPath = join2(input.artifactDirAbs, "child-terminal.json");
|
|
930
|
+
if (!existsSync2(resultPath)) {
|
|
931
|
+
const recorded = existsSync2(terminalPath) ? await readChildTerminal(terminalPath) : void 0;
|
|
932
|
+
const cancelled = input.taskStatus === "killed";
|
|
933
|
+
const code = recorded?.code ?? (cancelled ? "child_cancelled" : "child_exited_without_commit");
|
|
934
|
+
const detail = recorded?.message ?? input.taskError ?? "the delegate child exited without committing a result package";
|
|
935
|
+
const preserved = [
|
|
936
|
+
"seed.json",
|
|
937
|
+
"budget-plan.json",
|
|
938
|
+
"child-terminal.json",
|
|
939
|
+
"runtime-budget.json"
|
|
940
|
+
].filter((name) => existsSync2(join2(input.artifactDirAbs, name)));
|
|
941
|
+
if (input.taskOutputPath !== void 0 && input.taskOutputAbsPath !== void 0 && existsSync2(input.taskOutputAbsPath)) {
|
|
942
|
+
preserved.push(input.taskOutputPath);
|
|
943
|
+
}
|
|
944
|
+
const diagnosticTargets = preserved.filter(
|
|
945
|
+
(name) => name === "child-terminal.json" || name === "runtime-budget.json" || name === input.taskOutputPath
|
|
946
|
+
);
|
|
947
|
+
const diagnostic = diagnosticTargets.length === 0 ? "No child terminal record or merged task output exists; inspect the preserved launch artifacts listed above." : `Inspect the preserved diagnostic evidence: ${diagnosticTargets.join(", ")}.`;
|
|
948
|
+
const error = new DelegateError(`bg_delegate produced no committed answer: ${detail}`, {
|
|
949
|
+
code: isDelegateErrorCode(code) ? code : "child_exited_without_commit",
|
|
950
|
+
childCreated: true,
|
|
951
|
+
taskId: input.taskId,
|
|
952
|
+
artifactDir: input.artifactDirAbs,
|
|
953
|
+
preserved,
|
|
954
|
+
remediation: [
|
|
955
|
+
diagnostic,
|
|
956
|
+
"No partial answer is returned; nothing was truncated to look like success."
|
|
957
|
+
]
|
|
958
|
+
});
|
|
959
|
+
const outcome = {
|
|
960
|
+
status: cancelled ? "cancelled" : "failed",
|
|
961
|
+
errorCode: error.code
|
|
962
|
+
};
|
|
963
|
+
return { outcome, error };
|
|
964
|
+
}
|
|
965
|
+
let raw;
|
|
966
|
+
try {
|
|
967
|
+
raw = await readFile2(resultPath, "utf8");
|
|
968
|
+
} catch (error) {
|
|
969
|
+
const failure = new DelegateError(
|
|
970
|
+
`bg_delegate could not read its committed result package: ${error instanceof Error ? error.message : String(error)}`,
|
|
971
|
+
{
|
|
972
|
+
code: "artifact_read_failed",
|
|
973
|
+
childCreated: true,
|
|
974
|
+
taskId: input.taskId,
|
|
975
|
+
artifactDir: input.artifactDirAbs
|
|
976
|
+
}
|
|
977
|
+
);
|
|
978
|
+
return { outcome: { status: "failed", errorCode: failure.code }, error: failure };
|
|
979
|
+
}
|
|
980
|
+
try {
|
|
981
|
+
const verified = verifyDelegateResultPackage(raw, {
|
|
982
|
+
taskId: input.taskId,
|
|
983
|
+
launchNonce: input.launchNonce,
|
|
984
|
+
seedSha256: input.seedSha256,
|
|
985
|
+
route: input.route
|
|
986
|
+
});
|
|
987
|
+
return {
|
|
988
|
+
outcome: {
|
|
989
|
+
status: "committed",
|
|
990
|
+
answerBytes: verified.package.answer.byte_length,
|
|
991
|
+
answerSha256: verified.package.answer.sha256,
|
|
992
|
+
turns: verified.package.turns,
|
|
993
|
+
toolCalls: verified.package.tool_calls
|
|
994
|
+
},
|
|
995
|
+
result: verified
|
|
996
|
+
};
|
|
997
|
+
} catch (error) {
|
|
998
|
+
if (error instanceof DelegateError) {
|
|
999
|
+
return { outcome: { status: "failed", errorCode: error.code }, error };
|
|
1000
|
+
}
|
|
1001
|
+
throw error;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
__name(adjudicateDelegateTerminal, "adjudicateDelegateTerminal");
|
|
1005
|
+
async function readChildTerminal(path) {
|
|
1006
|
+
try {
|
|
1007
|
+
const parsed = JSON.parse(await readFile2(path, "utf8"));
|
|
1008
|
+
if (typeof parsed !== "object" || parsed === null) return void 0;
|
|
1009
|
+
const code = Reflect.get(parsed, "code");
|
|
1010
|
+
const message = Reflect.get(parsed, "message");
|
|
1011
|
+
if (typeof code !== "string" || typeof message !== "string") return void 0;
|
|
1012
|
+
return { code, message };
|
|
1013
|
+
} catch {
|
|
1014
|
+
return void 0;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
__name(readChildTerminal, "readChildTerminal");
|
|
1018
|
+
var DELEGATE_ERROR_CODE_SET = /* @__PURE__ */ new Set([
|
|
1019
|
+
"delegate_hook_contract_unsupported",
|
|
1020
|
+
"delegate_isolation_unsupported",
|
|
1021
|
+
"route_unresolved",
|
|
1022
|
+
"route_capacity_unknown",
|
|
1023
|
+
"seed_projection_failed",
|
|
1024
|
+
"seed_budget_exceeded",
|
|
1025
|
+
"seed_persist_failed",
|
|
1026
|
+
"invalid_arguments",
|
|
1027
|
+
"child_spawn_failed",
|
|
1028
|
+
"child_startup_failed",
|
|
1029
|
+
"child_timeout",
|
|
1030
|
+
"child_cancelled",
|
|
1031
|
+
"child_turn_limit",
|
|
1032
|
+
"child_tool_call_limit",
|
|
1033
|
+
"child_exited_without_commit",
|
|
1034
|
+
"provider_context_budget_exhausted",
|
|
1035
|
+
"aggregate_tool_output_cap",
|
|
1036
|
+
"child_model_output_limit",
|
|
1037
|
+
"child_capture_limit",
|
|
1038
|
+
"child_result_invalid",
|
|
1039
|
+
"child_result_encoding_invalid",
|
|
1040
|
+
"route_attestation_missing",
|
|
1041
|
+
"route_mismatch",
|
|
1042
|
+
"seed_hash_mismatch",
|
|
1043
|
+
"answer_hash_mismatch",
|
|
1044
|
+
"artifact_spill_failed",
|
|
1045
|
+
"artifact_read_failed",
|
|
1046
|
+
"artifact_error",
|
|
1047
|
+
"result_not_ready",
|
|
1048
|
+
"result_unavailable",
|
|
1049
|
+
"result_too_large_for_inline",
|
|
1050
|
+
"task_unknown"
|
|
1051
|
+
]);
|
|
1052
|
+
function isDelegateErrorCode(value) {
|
|
1053
|
+
return DELEGATE_ERROR_CODE_SET.has(value);
|
|
1054
|
+
}
|
|
1055
|
+
__name(isDelegateErrorCode, "isDelegateErrorCode");
|
|
1056
|
+
function decideDelegateDelivery(answerBytes, requested, cap = DELEGATE_INLINE_ANSWER_BYTES) {
|
|
1057
|
+
if (requested === "artifact") {
|
|
1058
|
+
return { mode: "artifact", reason: "artifact delivery was requested explicitly" };
|
|
1059
|
+
}
|
|
1060
|
+
if (answerBytes <= cap) {
|
|
1061
|
+
return {
|
|
1062
|
+
mode: "inline",
|
|
1063
|
+
reason: `the answer is ${String(answerBytes)} bytes, within the ${String(cap)}-byte inline cap`
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
return {
|
|
1067
|
+
mode: "artifact",
|
|
1068
|
+
reason: `the answer is ${String(answerBytes)} bytes, over the ${String(cap)}-byte inline cap`
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
__name(decideDelegateDelivery, "decideDelegateDelivery");
|
|
1072
|
+
function inlineTooLarge(taskId, artifactDir, answerBytes, cap = DELEGATE_INLINE_ANSWER_BYTES) {
|
|
1073
|
+
return new DelegateError(
|
|
1074
|
+
`bg_result cannot return this answer inline: it is ${String(answerBytes)} bytes, over the ${String(cap)}-byte inline cap. The complete verified answer is preserved at ${join2(artifactDir, "result.json")}. It is not truncated to fit.`,
|
|
1075
|
+
{
|
|
1076
|
+
code: "result_too_large_for_inline",
|
|
1077
|
+
childCreated: true,
|
|
1078
|
+
taskId,
|
|
1079
|
+
artifactDir,
|
|
1080
|
+
preserved: [join2(artifactDir, "result.json")],
|
|
1081
|
+
remediation: [
|
|
1082
|
+
'Call bg_result with delivery:"artifact" to receive the verified metadata plus the artifact reference.',
|
|
1083
|
+
"Read the answer from the artifact path directly if the full text is required."
|
|
1084
|
+
]
|
|
1085
|
+
}
|
|
1086
|
+
);
|
|
1087
|
+
}
|
|
1088
|
+
__name(inlineTooLarge, "inlineTooLarge");
|
|
1089
|
+
|
|
1090
|
+
export {
|
|
1091
|
+
prepareDelegateLaunch,
|
|
1092
|
+
evaluateDelegateTerminal,
|
|
1093
|
+
adjudicateDelegateTerminal,
|
|
1094
|
+
decideDelegateDelivery,
|
|
1095
|
+
inlineTooLarge
|
|
1096
|
+
};
|