bazilion 0.14.2 → 0.15.0
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/dist/cli.js +1126 -334
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +8180 -3651
- package/dist/daemon.js.map +1 -1
- package/dist/migrations/0001_init.sql +171 -3
- package/dist/web/client/assets/ChatPane-55j13bBj.js +74 -0
- package/dist/web/client/assets/{ConfirmDialog-_bmG-wVG.js → ConfirmDialog-CGZzom9E.js} +1 -1
- package/dist/web/client/assets/{FieldRow-Do1cBkRc.js → FieldRow-DYNU9gWb.js} +1 -1
- package/dist/web/client/assets/{ProductionTeamPolicyEditor-XP-QJul4.js → ProductionTeamPolicyEditor-DT5Sl8jd.js} +1 -1
- package/dist/web/client/assets/{ProfileCommunicationEditor-CwdFPdpk.js → ProfileCommunicationEditor-TyCU5vXX.js} +1 -1
- package/dist/web/client/assets/ResultCard-Cps_lXVN.js +1 -0
- package/dist/web/client/assets/ResultSourceConversation-CGhKTSTD.js +1 -0
- package/dist/web/client/assets/TeamTabs-BZHyRnbd.js +1 -0
- package/dist/web/client/assets/{TemplatesTabs-D4WHvs6b.js → TemplatesTabs-BHzkPMRC.js} +1 -1
- package/dist/web/client/assets/{UnsavedChangesGuard-B1aLqiK5.js → UnsavedChangesGuard-CFQcKsrf.js} +1 -1
- package/dist/web/client/assets/_id-9nCIhbVd.js +1 -0
- package/dist/web/client/assets/{_id-3w4PFfma.js → _id-BSu3AqKA.js} +1 -1
- package/dist/web/client/assets/_id-CGd21j3k.js +1 -0
- package/dist/web/client/assets/{_id-BH3v_vI_.js → _id-D_eKokkd.js} +1 -1
- package/dist/web/client/assets/{_id-Cx7o4Zmf.js → _id-SRMFlIgP.js} +1 -1
- package/dist/web/client/assets/{activity-A_HrG1Tv.js → activity-Cn2-9PpZ.js} +1 -1
- package/dist/web/client/assets/{agents-BeeFCt2c.js → agents-CCmiZek6.js} +1 -1
- package/dist/web/client/assets/{agents-C8OVKq3N.js → agents-NY3VrZgB.js} +1 -1
- package/dist/web/client/assets/{approvals-BIdZ9BSn.js → approvals-CPDAPgrM.js} +1 -1
- package/dist/web/client/assets/{attention-B9bUrxiU.js → attention-Qra_9_OI.js} +1 -1
- package/dist/web/client/assets/chevron-right-DXE4CWf2.js +1 -0
- package/dist/web/client/assets/{config-By86S7k-.js → config-D8EO0LPB.js} +1 -1
- package/dist/web/client/assets/{inbox-DlXQCJLe.js → inbox-C5W-sm1q.js} +1 -1
- package/dist/web/client/assets/{index-CLdmsmiN.js → index-BUhhk_u9.js} +2 -2
- package/dist/web/client/assets/{learning-BqZIw2nA.js → learning-Dr-7_7J4.js} +1 -1
- package/dist/web/client/assets/login-Bu5UxbJh.js +1 -0
- package/dist/web/client/assets/{mcp-DKSY2yVa.js → mcp-BueuwQiv.js} +1 -1
- package/dist/web/client/assets/{members-9GuOiq6J.js → members-ZikuYNcy.js} +1 -1
- package/dist/web/client/assets/{memory-DiGMI6FC.js → memory-1JUJlPrn.js} +1 -1
- package/dist/web/client/assets/{policy-TBGQffw5.js → policy-DbkhsFNA.js} +1 -1
- package/dist/web/client/assets/results-mMr8Ar2u.js +1 -0
- package/dist/web/client/assets/routes-DJYB-MS9.js +1 -0
- package/dist/web/client/assets/{services-1Z398CES.js → services-kfQA9cpJ.js} +1 -1
- package/dist/web/client/assets/{skills-BP2gciFt.js → skills-C6pcgxaC.js} +1 -1
- package/dist/web/client/assets/styles-CcNf8jT_.css +2 -0
- package/dist/web/client/assets/{teams-tNoMDJ_M.js → teams-C6_Noz5X.js} +1 -1
- package/dist/web/client/assets/{teams-DBIivGT7.js → teams-LB0KBXY9.js} +1 -1
- package/dist/web/client/assets/telegram-A2jaI1QM.js +1 -0
- package/dist/web/client/assets/{tokens-eDWCGQQ2.js → tokens-BGlUpJcL.js} +1 -1
- package/dist/web/client/assets/{triggers-DZME3IcK.js → triggers-C54_feGg.js} +1 -1
- package/dist/web/client/assets/{welcome-B49sh_uf.js → welcome-DyUIswRi.js} +1 -1
- package/dist/web/client/assets/wire-constants-CBD-lTaa.js +1 -0
- package/dist/web/client/assets/{x-CHc7_-TH.js → x-BY2MPLr9.js} +1 -1
- package/dist/web/server/assets/{ChatPane-CgSe7tsy.js → ChatPane-DJ30FdFG.js} +1122 -107
- package/dist/web/server/assets/ResultCard-B3zD9N0t.js +143 -0
- package/dist/web/server/assets/ResultSourceConversation-zYogeOWp.js +64 -0
- package/dist/web/server/assets/{TeamTabs-Co3n2exj.js → TeamTabs-TCKjCvMA.js} +4 -0
- package/dist/web/server/assets/{_id-sNu5aXZt.js → _id-1LwoHhJg.js} +2 -1
- package/dist/web/server/assets/{_id-BeKhPKw3.js → _id-1hTvnKLN2.js} +7 -3
- package/dist/web/server/assets/{_id-BAA9KJBU.js → _id-B2EEyStS.js} +1 -1
- package/dist/web/server/assets/_id-BDEpe6k0.js +6 -0
- package/dist/web/server/assets/{_id-BqWTB8Wl.js → _id-B_-CDHOi2.js} +1 -1
- package/dist/web/server/assets/{_id-DxCnEFpm.js → _id-BvSWsPI5.js} +3 -4
- package/dist/web/server/assets/{_id-ndxFHx0t.js → _id-CDBtO_jL.js} +2 -2
- package/dist/web/server/assets/{_id-DvlDkk04.js → _id-DDNVQx3y.js} +1 -1
- package/dist/web/server/assets/{_id-BYKpT2Tu.js → _id-DFHB9JFQ.js} +1 -1
- package/dist/web/server/assets/{_id-HMy7jM3P.js → _id-DxFLSIio.js} +1 -1
- package/dist/web/server/assets/{_id-DYU6uIBx.js → _id-T_8btpbB.js} +1 -1
- package/dist/web/server/assets/_id-wyjrf0JG.js +17 -0
- package/dist/web/server/assets/{_tanstack-start-manifest_v-Duhf0z7H.js → _tanstack-start-manifest_v-DP4ZUBw3.js} +102 -75
- package/dist/web/server/assets/{activity-BWv1goK6.js → activity-5fWKPDxj.js} +2 -2
- package/dist/web/server/assets/{activity-LjpblbDL.js → activity-C88qrNqv.js} +1 -1
- package/dist/web/server/assets/{activity-9VP6QDTH.js → activity-D73w4mkZ.js} +1 -1
- package/dist/web/server/assets/{agents-DjyQk94u.js → agents-DB5hCSAI.js} +1 -1
- package/dist/web/server/assets/{agents-BJAv919x.js → agents-DRSo7lRX.js} +1 -1
- package/dist/web/server/assets/{approvals-BYi84gwl.js → approvals-4y9bZF4r.js} +1 -1
- package/dist/web/server/assets/{approvals-7JOoBchn.js → approvals-DTdrltyk.js} +1 -1
- package/dist/web/server/assets/{approvals-Bz123liE.js → approvals-DXoN-T57.js} +15 -1
- package/dist/web/server/assets/{attention-UhqPK_Ro.js → attention-BFx8ZkmH.js} +1 -1
- package/dist/web/server/assets/{auth-7BHTH-KS.js → auth-_eaCwhyq.js} +1 -1
- package/dist/web/server/assets/{config-BMiajTZP.js → config-B7JIfv_7.js} +1 -1
- package/dist/web/server/assets/{daemon-client-CI5NHwNC.js → daemon-client-B06W1Qa2.js} +54 -0
- package/dist/web/server/assets/{inbox-Dv55rGYq.js → inbox-YRpDQcvp.js} +1 -1
- package/dist/web/server/assets/{learning-C2upa1CE.js → learning-UBZb6h6M.js} +1 -1
- package/dist/web/server/assets/{login-BNj3U6ok.js → login-B_-9L8TU.js} +7 -2
- package/dist/web/server/assets/{login-Be8eP4Jp.js → login-rDox7PRD.js} +5 -2
- package/dist/web/server/assets/{mcp-BvnvlVFd.js → mcp-Dv6RXMaS.js} +1 -1
- package/dist/web/server/assets/{members-BP3UTqu1.js → members-BFTKSlOe.js} +1 -1
- package/dist/web/server/assets/{members-DiYtr-zm.js → members-CD3GiTfF.js} +1 -1
- package/dist/web/server/assets/{members-DHYTVgwb.js → members-cc5SeEaW.js} +2 -2
- package/dist/web/server/assets/{memory-CkXUgf5s.js → memory-C5i_GxlY.js} +2 -2
- package/dist/web/server/assets/{memory-DTFEmfF3.js → memory-CVqnyUaM.js} +1 -1
- package/dist/web/server/assets/{memory-BqV-Afy1.js → memory-D0PQgZAn.js} +1 -1
- package/dist/web/server/assets/{policy-18fdTFO4.js → policy-C-p8HIhA.js} +1 -1
- package/dist/web/server/assets/{policy-Bvvav8fh.js → policy-Dgjb0_gK.js} +2 -2
- package/dist/web/server/assets/{policy-BddK4xom.js → policy-bLKwvnja.js} +1 -1
- package/dist/web/server/assets/results-Cfev4KNt.js +12 -0
- package/dist/web/server/assets/results-Cj-Dlw3C.js +173 -0
- package/dist/web/server/assets/results-CwEQ5EUL.js +12 -0
- package/dist/web/server/assets/{router-CY_pCgP1.js → router-d3sTMpMX.js} +60 -43
- package/dist/web/server/assets/{routes-DAU2g7Uz.js → routes-B765DVhj.js} +1 -1
- package/dist/web/server/assets/{routes-BgHisAxH.js → routes-MIZz6uMr.js} +2 -2
- package/dist/web/server/assets/{routes-COtkyZG1.js → routes-cW4MWU18.js} +3 -3
- package/dist/web/server/assets/{services-DozuJtzX.js → services-BCbdn3R9.js} +1 -1
- package/dist/web/server/assets/{skills-DfGSJTCB.js → skills-Bpoa8MIp.js} +1 -1
- package/dist/web/server/assets/{teams-be05ci17.js → teams-CXzwqzcE.js} +1 -1
- package/dist/web/server/assets/{teams-DPnAX4wD.js → teams-hWGjbpUA.js} +1 -1
- package/dist/web/server/assets/{telegram-Dj4Wwhd6.js → telegram-CoNeOgqZ.js} +465 -1
- package/dist/web/server/assets/{telegram-1AWL6lFw.js → telegram-DhpvtGUc.js} +1 -1
- package/dist/web/server/assets/{telegram-DbOFpTFm.js → telegram-Zd1rIZxg.js} +1 -1
- package/dist/web/server/assets/{tokens-DjM8GsgS.js → tokens-Bjp19Vkn.js} +1 -1
- package/dist/web/server/assets/{triggers-Nezfw-Bd.js → triggers-DJlcvXzn.js} +1 -1
- package/dist/web/server/server.js +31 -27
- package/dist/worker.js +294 -104
- package/dist/worker.js.map +1 -1
- package/package.json +3 -3
- package/dist/web/client/assets/TeamTabs-DIRiKcqx.js +0 -1
- package/dist/web/client/assets/_id-DIiVVxBl.js +0 -1
- package/dist/web/client/assets/chevron-right-VWrk_dTX.js +0 -1
- package/dist/web/client/assets/login-CCMPXiny.js +0 -1
- package/dist/web/client/assets/routes-g3yUOhCb.js +0 -1
- package/dist/web/client/assets/styles-B5vcgXln.css +0 -2
- package/dist/web/client/assets/telegram-CJG_DFdI.js +0 -1
- package/dist/web/client/assets/wire-constants-zZ7Wjb9C.js +0 -74
package/dist/worker.js
CHANGED
|
@@ -1136,7 +1136,7 @@ function translatePiEvent(e) {
|
|
|
1136
1136
|
type: "tool_call",
|
|
1137
1137
|
id: block.id,
|
|
1138
1138
|
name: block.name,
|
|
1139
|
-
arguments: JSON.stringify(block.arguments ?? {})
|
|
1139
|
+
arguments: block.name === "ask_user" ? "{}" : JSON.stringify(block.arguments ?? {})
|
|
1140
1140
|
});
|
|
1141
1141
|
}
|
|
1142
1142
|
}
|
|
@@ -1148,6 +1148,15 @@ function translatePiEvent(e) {
|
|
|
1148
1148
|
return out;
|
|
1149
1149
|
}
|
|
1150
1150
|
case "tool_execution_end": {
|
|
1151
|
+
if (e.toolName === "ask_user")
|
|
1152
|
+
return [
|
|
1153
|
+
{
|
|
1154
|
+
type: "tool_result",
|
|
1155
|
+
id: e.toolCallId,
|
|
1156
|
+
name: e.toolName,
|
|
1157
|
+
result: "Question outcome is available through the question card or authorized conversation history."
|
|
1158
|
+
}
|
|
1159
|
+
];
|
|
1151
1160
|
const text = extractToolResultText(e.result);
|
|
1152
1161
|
if (e.isError) {
|
|
1153
1162
|
return [{ type: "tool_error", id: e.toolCallId, name: e.toolName, error: text }];
|
|
@@ -1159,6 +1168,7 @@ function translatePiEvent(e) {
|
|
|
1159
1168
|
id: e.toolCallId,
|
|
1160
1169
|
name: e.toolName,
|
|
1161
1170
|
result: text,
|
|
1171
|
+
resultReference: extractResultReference(e.result),
|
|
1162
1172
|
...images.length > 0 ? { images } : {}
|
|
1163
1173
|
}
|
|
1164
1174
|
];
|
|
@@ -1178,7 +1188,11 @@ function extractAssistantToolCalls(m) {
|
|
|
1178
1188
|
const out = [];
|
|
1179
1189
|
for (const block of m.content ?? []) {
|
|
1180
1190
|
if (block.type === "toolCall") {
|
|
1181
|
-
out.push({
|
|
1191
|
+
out.push({
|
|
1192
|
+
id: block.id,
|
|
1193
|
+
name: block.name,
|
|
1194
|
+
arguments: block.name === "ask_user" ? "{}" : JSON.stringify(block.arguments ?? {})
|
|
1195
|
+
});
|
|
1182
1196
|
}
|
|
1183
1197
|
}
|
|
1184
1198
|
return out;
|
|
@@ -1215,7 +1229,7 @@ function stringifyContent(content) {
|
|
|
1215
1229
|
}
|
|
1216
1230
|
return out;
|
|
1217
1231
|
}
|
|
1218
|
-
function piMessagesToProviderView(messages) {
|
|
1232
|
+
function piMessagesToProviderView(messages, questionResultVisible) {
|
|
1219
1233
|
const out = [];
|
|
1220
1234
|
for (const m of messages) {
|
|
1221
1235
|
switch (m.role) {
|
|
@@ -1240,12 +1254,22 @@ function piMessagesToProviderView(messages) {
|
|
|
1240
1254
|
}
|
|
1241
1255
|
case "toolResult": {
|
|
1242
1256
|
const tr = m;
|
|
1257
|
+
if (tr.toolName === "ask_user" && !questionResultVisible?.(m)) {
|
|
1258
|
+
out.push({
|
|
1259
|
+
role: "tool",
|
|
1260
|
+
toolCallId: tr.toolCallId,
|
|
1261
|
+
toolName: "ask_user",
|
|
1262
|
+
content: "Question content has not been released for this view."
|
|
1263
|
+
});
|
|
1264
|
+
break;
|
|
1265
|
+
}
|
|
1243
1266
|
const images = extractToolResultImages({ content: tr.content });
|
|
1244
1267
|
out.push({
|
|
1245
1268
|
role: "tool",
|
|
1246
1269
|
content: stringifyContent(tr.content),
|
|
1247
1270
|
toolCallId: tr.toolCallId,
|
|
1248
1271
|
toolName: tr.toolName,
|
|
1272
|
+
result: extractResultReference(m),
|
|
1249
1273
|
...images.length > 0 ? { images } : {}
|
|
1250
1274
|
});
|
|
1251
1275
|
break;
|
|
@@ -1256,14 +1280,58 @@ function piMessagesToProviderView(messages) {
|
|
|
1256
1280
|
}
|
|
1257
1281
|
return out;
|
|
1258
1282
|
}
|
|
1283
|
+
function extractResultReference(value) {
|
|
1284
|
+
if (!value || typeof value !== "object") return void 0;
|
|
1285
|
+
const details = value.details;
|
|
1286
|
+
const id = details?.result?.resultId;
|
|
1287
|
+
return typeof id === "string" && /^[a-f0-9-]{36}$/.test(id) ? { resultId: id } : void 0;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
// ../daemon/src/lib/result-source.ts
|
|
1291
|
+
import { closeSync as closeSync2, constants as constants2, fstatSync as fstatSync2, openSync as openSync2, readSync, realpathSync as realpathSync2 } from "fs";
|
|
1292
|
+
import { basename as basename2, join as join13 } from "path";
|
|
1293
|
+
function readCanonicalSessionFile(directory, filename, sessionId, minimumEntryOffset = 0) {
|
|
1294
|
+
if (basename2(filename) !== filename) throw new Error("Invalid session filename");
|
|
1295
|
+
if (realpathSync2(directory) !== directory) throw new Error("Result session escaped its owner");
|
|
1296
|
+
const fd = openSync2(
|
|
1297
|
+
join13(directory, filename),
|
|
1298
|
+
constants2.O_RDONLY | constants2.O_NOFOLLOW | constants2.O_NONBLOCK
|
|
1299
|
+
);
|
|
1300
|
+
try {
|
|
1301
|
+
const stat2 = fstatSync2(fd);
|
|
1302
|
+
if (!stat2.isFile() || stat2.size > 64 * 1024 * 1024)
|
|
1303
|
+
throw new Error("Result source session is unavailable or too large");
|
|
1304
|
+
const buffer = Buffer.alloc(stat2.size + 1);
|
|
1305
|
+
let count = 0;
|
|
1306
|
+
while (count < buffer.length) {
|
|
1307
|
+
const n = readSync(fd, buffer, count, buffer.length - count, null);
|
|
1308
|
+
if (n === 0) break;
|
|
1309
|
+
count += n;
|
|
1310
|
+
}
|
|
1311
|
+
if (count !== stat2.size) throw new Error("Result source session changed while reading");
|
|
1312
|
+
const entries = [];
|
|
1313
|
+
let position = 0;
|
|
1314
|
+
for (const line of buffer.subarray(0, count).toString("utf8").split("\n")) {
|
|
1315
|
+
if (line.trim()) entries.push({ entry: JSON.parse(line), offset: position });
|
|
1316
|
+
position += Buffer.byteLength(line) + 1;
|
|
1317
|
+
}
|
|
1318
|
+
const header = entries[0]?.entry;
|
|
1319
|
+
if (header?.type !== "session" || header.id !== sessionId)
|
|
1320
|
+
throw new Error("Result source session does not match the active Agent session");
|
|
1321
|
+
return entries.filter((row, index) => index === 0 || row.offset >= minimumEntryOffset).map((row) => row.entry);
|
|
1322
|
+
} finally {
|
|
1323
|
+
closeSync2(fd);
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1259
1326
|
|
|
1260
1327
|
// ../daemon/src/runtime/pi/session.ts
|
|
1261
|
-
import { existsSync as existsSync14, mkdirSync as mkdirSync7,
|
|
1262
|
-
import { basename as
|
|
1328
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync7, statSync as statSync5, writeFileSync as writeFileSync9 } from "fs";
|
|
1329
|
+
import { basename as basename4, join as join20 } from "path";
|
|
1263
1330
|
import {
|
|
1264
1331
|
createAssistantMessageEventStream
|
|
1265
1332
|
} from "@earendil-works/pi-ai";
|
|
1266
1333
|
import {
|
|
1334
|
+
buildSessionContext,
|
|
1267
1335
|
createAgentSession,
|
|
1268
1336
|
DefaultResourceLoader,
|
|
1269
1337
|
SessionManager,
|
|
@@ -1523,18 +1591,18 @@ import {
|
|
|
1523
1591
|
|
|
1524
1592
|
// ../daemon/src/runtime/session/prompt.ts
|
|
1525
1593
|
import { existsSync as existsSync10, readdirSync as readdirSync6 } from "fs";
|
|
1526
|
-
import { join as
|
|
1594
|
+
import { join as join14 } from "path";
|
|
1527
1595
|
|
|
1528
1596
|
// ../daemon/src/runtime/safe-files.ts
|
|
1529
1597
|
import {
|
|
1530
|
-
closeSync as
|
|
1531
|
-
constants as
|
|
1532
|
-
fstatSync as
|
|
1598
|
+
closeSync as closeSync3,
|
|
1599
|
+
constants as constants3,
|
|
1600
|
+
fstatSync as fstatSync3,
|
|
1533
1601
|
lstatSync as lstatSync2,
|
|
1534
1602
|
mkdirSync as mkdirSync5,
|
|
1535
|
-
openSync as
|
|
1603
|
+
openSync as openSync3,
|
|
1536
1604
|
readFileSync as readFileSync9,
|
|
1537
|
-
realpathSync as
|
|
1605
|
+
realpathSync as realpathSync3
|
|
1538
1606
|
} from "fs";
|
|
1539
1607
|
import { dirname as dirname3, isAbsolute as isAbsolute2, relative as relative2, resolve as resolve4 } from "path";
|
|
1540
1608
|
function resolveRealDirectory(path) {
|
|
@@ -1543,7 +1611,7 @@ function resolveRealDirectory(path) {
|
|
|
1543
1611
|
if (entry.isSymbolicLink() || !entry.isDirectory()) {
|
|
1544
1612
|
throw new Error("expected a real directory");
|
|
1545
1613
|
}
|
|
1546
|
-
return
|
|
1614
|
+
return realpathSync3(requested);
|
|
1547
1615
|
}
|
|
1548
1616
|
function readRegularFileNoFollow(path) {
|
|
1549
1617
|
const entry = lstatSync2(path);
|
|
@@ -1551,15 +1619,15 @@ function readRegularFileNoFollow(path) {
|
|
|
1551
1619
|
if (!entry.isFile()) throw new Error("target is not a regular file");
|
|
1552
1620
|
let fd;
|
|
1553
1621
|
try {
|
|
1554
|
-
fd =
|
|
1555
|
-
if (!
|
|
1622
|
+
fd = openSync3(path, constants3.O_RDONLY | noFollowFlag());
|
|
1623
|
+
if (!fstatSync3(fd).isFile()) throw new Error("target is not a regular file");
|
|
1556
1624
|
return readFileSync9(fd, "utf8");
|
|
1557
1625
|
} finally {
|
|
1558
|
-
if (fd !== void 0)
|
|
1626
|
+
if (fd !== void 0) closeSync3(fd);
|
|
1559
1627
|
}
|
|
1560
1628
|
}
|
|
1561
1629
|
function noFollowFlag() {
|
|
1562
|
-
return typeof
|
|
1630
|
+
return typeof constants3.O_NOFOLLOW === "number" ? constants3.O_NOFOLLOW : 0;
|
|
1563
1631
|
}
|
|
1564
1632
|
|
|
1565
1633
|
// ../daemon/src/runtime/session/prompt.ts
|
|
@@ -1570,9 +1638,9 @@ function loadPromptSkills(skillsDir, attachedNames) {
|
|
|
1570
1638
|
const discovered = readdirSync6(skillsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && attached.has(entry.name)).sort((a, b) => a.name.localeCompare(b.name));
|
|
1571
1639
|
const loaded = [];
|
|
1572
1640
|
for (const entry of discovered) {
|
|
1573
|
-
const hostDir =
|
|
1641
|
+
const hostDir = join14(skillsDir, entry.name);
|
|
1574
1642
|
try {
|
|
1575
|
-
const parsed = parseSkillContent(readRegularFileNoFollow(
|
|
1643
|
+
const parsed = parseSkillContent(readRegularFileNoFollow(join14(hostDir, "SKILL.md")));
|
|
1576
1644
|
const safeLabel = entry.name.replace(/[^A-Za-z0-9._-]/g, "_") || "skill";
|
|
1577
1645
|
loaded.push({
|
|
1578
1646
|
name: entry.name,
|
|
@@ -1591,7 +1659,7 @@ function loadProtectedHomeDocuments(agentDir) {
|
|
|
1591
1659
|
const root = resolveRealDirectory(agentDir);
|
|
1592
1660
|
const read = (file) => {
|
|
1593
1661
|
try {
|
|
1594
|
-
return readRegularFileNoFollow(
|
|
1662
|
+
return readRegularFileNoFollow(join14(root, file));
|
|
1595
1663
|
} catch (error) {
|
|
1596
1664
|
if (error.code === "ENOENT") return null;
|
|
1597
1665
|
throw new Error(`private Agent home is unsafe at ${file}`);
|
|
@@ -1733,8 +1801,8 @@ function boundReviewedLessons(lessons, maxCharacters = 8e3) {
|
|
|
1733
1801
|
}
|
|
1734
1802
|
|
|
1735
1803
|
// ../daemon/src/runtime/shell/tooling.ts
|
|
1736
|
-
import { existsSync as existsSync11, lstatSync as lstatSync3, realpathSync as
|
|
1737
|
-
import { dirname as dirname4, isAbsolute as isAbsolute4, join as
|
|
1804
|
+
import { existsSync as existsSync11, lstatSync as lstatSync3, realpathSync as realpathSync4 } from "fs";
|
|
1805
|
+
import { dirname as dirname4, isAbsolute as isAbsolute4, join as join16, relative as relative4, sep as sep4 } from "path";
|
|
1738
1806
|
import {
|
|
1739
1807
|
createBashToolDefinition,
|
|
1740
1808
|
createLocalBashOperations,
|
|
@@ -2122,10 +2190,10 @@ function createApprovalGatedBashTool(base, host) {
|
|
|
2122
2190
|
// ../daemon/src/runtime/shell/docker.ts
|
|
2123
2191
|
import { spawn } from "child_process";
|
|
2124
2192
|
import { randomUUID as randomUUID18 } from "crypto";
|
|
2125
|
-
import { closeSync as
|
|
2193
|
+
import { closeSync as closeSync4, constants as constants4, mkdtempSync as mkdtempSync2, openSync as openSync4, rmSync as rmSync10, writeFileSync as writeFileSync7 } from "fs";
|
|
2126
2194
|
import { access, lstat, realpath, stat } from "fs/promises";
|
|
2127
2195
|
import { tmpdir as tmpdir2 } from "os";
|
|
2128
|
-
import { delimiter, isAbsolute as isAbsolute3, join as
|
|
2196
|
+
import { delimiter, isAbsolute as isAbsolute3, join as join15, relative as relative3, sep as sep3 } from "path";
|
|
2129
2197
|
var CONTAINER_WORKDIR = "/workspace";
|
|
2130
2198
|
var MAX_TIMEOUT_MS = 2147483647;
|
|
2131
2199
|
var MAX_STDERR_CHARS = 16 * 1024;
|
|
@@ -2314,7 +2382,7 @@ async function resolveRequiredRoot(root) {
|
|
|
2314
2382
|
}
|
|
2315
2383
|
async function inspectDockerExecutableIdentity(dockerPath) {
|
|
2316
2384
|
try {
|
|
2317
|
-
await access(dockerPath,
|
|
2385
|
+
await access(dockerPath, constants4.X_OK);
|
|
2318
2386
|
const info = await stat(dockerPath, { bigint: true });
|
|
2319
2387
|
if (!info.isFile()) throw new Error("not a regular file");
|
|
2320
2388
|
return {
|
|
@@ -2349,7 +2417,7 @@ async function assertLocalDockerSocket(endpoint) {
|
|
|
2349
2417
|
try {
|
|
2350
2418
|
const info = await stat(socketPath);
|
|
2351
2419
|
if (!info.isSocket()) throw new Error("not a Unix socket");
|
|
2352
|
-
await access(socketPath,
|
|
2420
|
+
await access(socketPath, constants4.R_OK | constants4.W_OK);
|
|
2353
2421
|
} catch {
|
|
2354
2422
|
throw new Error("Docker sandbox local Unix socket is unavailable");
|
|
2355
2423
|
}
|
|
@@ -2454,7 +2522,7 @@ function executeDockerRun(spec, options) {
|
|
|
2454
2522
|
windowsHide: true,
|
|
2455
2523
|
env: spec.processEnv
|
|
2456
2524
|
});
|
|
2457
|
-
if (envFileFd !== void 0)
|
|
2525
|
+
if (envFileFd !== void 0) closeSync4(envFileFd);
|
|
2458
2526
|
let settled = false;
|
|
2459
2527
|
let termination;
|
|
2460
2528
|
let timeoutHandle;
|
|
@@ -2510,16 +2578,16 @@ function executeDockerRun(spec, options) {
|
|
|
2510
2578
|
});
|
|
2511
2579
|
}
|
|
2512
2580
|
function openAnonymousEnvFile(content) {
|
|
2513
|
-
const dir = mkdtempSync2(
|
|
2514
|
-
const path =
|
|
2581
|
+
const dir = mkdtempSync2(join15(tmpdir2(), "bazilion-docker-env-"));
|
|
2582
|
+
const path = join15(dir, "environment");
|
|
2515
2583
|
let fd;
|
|
2516
2584
|
try {
|
|
2517
2585
|
writeFileSync7(path, content, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
2518
|
-
fd =
|
|
2586
|
+
fd = openSync4(path, constants4.O_RDONLY | constants4.O_NOFOLLOW);
|
|
2519
2587
|
rmSync10(dir, { recursive: true, force: true });
|
|
2520
2588
|
return fd;
|
|
2521
2589
|
} catch (error) {
|
|
2522
|
-
if (fd !== void 0)
|
|
2590
|
+
if (fd !== void 0) closeSync4(fd);
|
|
2523
2591
|
rmSync10(dir, { recursive: true, force: true });
|
|
2524
2592
|
throw error;
|
|
2525
2593
|
}
|
|
@@ -2537,7 +2605,7 @@ function resolveTimeoutMs(timeout) {
|
|
|
2537
2605
|
}
|
|
2538
2606
|
async function resolveMountSource(cwd) {
|
|
2539
2607
|
try {
|
|
2540
|
-
await access(cwd,
|
|
2608
|
+
await access(cwd, constants4.F_OK);
|
|
2541
2609
|
const info = await stat(cwd);
|
|
2542
2610
|
if (!info.isDirectory()) {
|
|
2543
2611
|
throw new Error(`Docker sandbox mount is not a directory: ${cwd}`);
|
|
@@ -2894,7 +2962,7 @@ function createSessionShellTools(cwd, env, options = {}) {
|
|
|
2894
2962
|
image: config.sandboxImage,
|
|
2895
2963
|
env: buildSandboxContainerEnv(env, config.envAllowlist),
|
|
2896
2964
|
readOnlyMounts: [
|
|
2897
|
-
...existsSync11(
|
|
2965
|
+
...existsSync11(join16(cwd, "memory")) ? [safeReadOnlyMount(join16(cwd, "memory"), SANDBOX_MEMORY_DIR, cwd)] : [],
|
|
2898
2966
|
...options.inputsDir ? [safeReadOnlyMount(options.inputsDir, SANDBOX_INPUTS_DIR, dirname4(options.inputsDir))] : [],
|
|
2899
2967
|
...(options.skillMounts ?? []).map(
|
|
2900
2968
|
(mount) => safeReadOnlyMount(mount.source, mount.target, dirname4(mount.source))
|
|
@@ -2915,8 +2983,8 @@ function safeReadOnlyMount(source, target, expectedRoot) {
|
|
|
2915
2983
|
if (info.isSymbolicLink() || !info.isDirectory()) {
|
|
2916
2984
|
throw new Error(`Docker sandbox read-only mount must be a real directory: ${source}`);
|
|
2917
2985
|
}
|
|
2918
|
-
const sourceRoot =
|
|
2919
|
-
const canonicalSource =
|
|
2986
|
+
const sourceRoot = realpathSync4(expectedRoot);
|
|
2987
|
+
const canonicalSource = realpathSync4(source);
|
|
2920
2988
|
const rel = relative4(sourceRoot, canonicalSource);
|
|
2921
2989
|
const contained = rel === "" || rel !== ".." && !rel.startsWith(`..${sep4}`) && !isAbsolute4(rel);
|
|
2922
2990
|
if (!contained) {
|
|
@@ -2927,18 +2995,18 @@ function safeReadOnlyMount(source, target, expectedRoot) {
|
|
|
2927
2995
|
|
|
2928
2996
|
// ../daemon/src/runtime/worker/runtime.ts
|
|
2929
2997
|
import {
|
|
2930
|
-
constants as
|
|
2998
|
+
constants as constants5,
|
|
2931
2999
|
existsSync as existsSync12,
|
|
2932
3000
|
lstatSync as lstatSync4,
|
|
2933
3001
|
mkdirSync as mkdirSync6,
|
|
2934
3002
|
mkdtempSync as mkdtempSync3,
|
|
2935
|
-
realpathSync as
|
|
3003
|
+
realpathSync as realpathSync5,
|
|
2936
3004
|
rmSync as rmSync11,
|
|
2937
3005
|
statSync as statSync3
|
|
2938
3006
|
} from "fs";
|
|
2939
3007
|
import { access as access2 } from "fs/promises";
|
|
2940
3008
|
import { tmpdir as tmpdir3 } from "os";
|
|
2941
|
-
import { isAbsolute as isAbsolute5, join as
|
|
3009
|
+
import { isAbsolute as isAbsolute5, join as join17, relative as relative5, sep as sep5 } from "path";
|
|
2942
3010
|
var REDACTED_VALUE = "[REDACTED]";
|
|
2943
3011
|
var REASONING_LEVELS = /* @__PURE__ */ new Set([
|
|
2944
3012
|
"off",
|
|
@@ -2949,6 +3017,8 @@ var REASONING_LEVELS = /* @__PURE__ */ new Set([
|
|
|
2949
3017
|
"xhigh"
|
|
2950
3018
|
]);
|
|
2951
3019
|
var CONFIGURED_KEYS = /* @__PURE__ */ new Set([
|
|
3020
|
+
"questionEnabled",
|
|
3021
|
+
"conversation",
|
|
2952
3022
|
"kind",
|
|
2953
3023
|
"agent",
|
|
2954
3024
|
"message",
|
|
@@ -2962,6 +3032,7 @@ var CONFIGURED_KEYS = /* @__PURE__ */ new Set([
|
|
|
2962
3032
|
"bashApprovalMode"
|
|
2963
3033
|
]);
|
|
2964
3034
|
var CONFIGURED_REQUIRED_KEYS = /* @__PURE__ */ new Set([
|
|
3035
|
+
"conversation",
|
|
2965
3036
|
"kind",
|
|
2966
3037
|
"agent",
|
|
2967
3038
|
"message",
|
|
@@ -2971,6 +3042,8 @@ var CONFIGURED_REQUIRED_KEYS = /* @__PURE__ */ new Set([
|
|
|
2971
3042
|
"bashApprovalMode"
|
|
2972
3043
|
]);
|
|
2973
3044
|
var PROTECTED_KEYS = /* @__PURE__ */ new Set([
|
|
3045
|
+
"questionEnabled",
|
|
3046
|
+
"conversation",
|
|
2974
3047
|
"kind",
|
|
2975
3048
|
"agent",
|
|
2976
3049
|
"message",
|
|
@@ -2984,7 +3057,9 @@ var PROTECTED_KEYS = /* @__PURE__ */ new Set([
|
|
|
2984
3057
|
"apiKeyRefreshEnabled",
|
|
2985
3058
|
"scratch"
|
|
2986
3059
|
]);
|
|
2987
|
-
var PROTECTED_REQUIRED_KEYS = new Set(
|
|
3060
|
+
var PROTECTED_REQUIRED_KEYS = new Set(
|
|
3061
|
+
[...PROTECTED_KEYS].filter((key) => key !== "images" && key !== "questionEnabled")
|
|
3062
|
+
);
|
|
2988
3063
|
var REVIEW_KEYS = /* @__PURE__ */ new Set([
|
|
2989
3064
|
"kind",
|
|
2990
3065
|
"agentId",
|
|
@@ -3044,6 +3119,8 @@ function validateMinimalWorkerProcessEnv(env, scratch, platform = process.platfo
|
|
|
3044
3119
|
function parseWorkerInput(value) {
|
|
3045
3120
|
const input = objectRecord(value, "worker input");
|
|
3046
3121
|
const kind = input.kind;
|
|
3122
|
+
if (input.questionEnabled !== void 0 && typeof input.questionEnabled !== "boolean")
|
|
3123
|
+
throw new Error("Invalid worker question capability");
|
|
3047
3124
|
if (kind === "configured_operator_http") {
|
|
3048
3125
|
assertExactKeys(input, CONFIGURED_KEYS, "configured worker input", CONFIGURED_REQUIRED_KEYS);
|
|
3049
3126
|
if (!isResolvedAgent(input.agent)) throw new Error("worker: configured input requires an agent");
|
|
@@ -3052,6 +3129,7 @@ function parseWorkerInput(value) {
|
|
|
3052
3129
|
throw new Error("worker: configured input requires enabledProviders");
|
|
3053
3130
|
}
|
|
3054
3131
|
requireString(input.turnId, "turnId");
|
|
3132
|
+
assertConversationTarget(input.conversation);
|
|
3055
3133
|
if (input.bashApprovalMode !== "interactive" && input.bashApprovalMode !== "auto_deny") {
|
|
3056
3134
|
throw new Error("worker: configured input requires a valid bashApprovalMode");
|
|
3057
3135
|
}
|
|
@@ -3073,6 +3151,7 @@ function parseWorkerInput(value) {
|
|
|
3073
3151
|
if (!isResolvedAgent(input.agent)) throw new Error("worker: protected input requires an agent");
|
|
3074
3152
|
requireString(input.message, "message");
|
|
3075
3153
|
requireString(input.turnId, "turnId");
|
|
3154
|
+
assertConversationTarget(input.conversation);
|
|
3076
3155
|
if (input.bashApprovalMode !== "auto_deny") {
|
|
3077
3156
|
throw new Error("worker: protected input requires auto-deny shell approval");
|
|
3078
3157
|
}
|
|
@@ -3469,7 +3548,7 @@ function requireCanonicalRealDirectory(value, name) {
|
|
|
3469
3548
|
if (entry.isSymbolicLink() || !entry.isDirectory()) {
|
|
3470
3549
|
throw new Error("unsafe entry");
|
|
3471
3550
|
}
|
|
3472
|
-
const canonical =
|
|
3551
|
+
const canonical = realpathSync5(value);
|
|
3473
3552
|
if (canonical !== value) throw new Error("non-canonical entry");
|
|
3474
3553
|
return canonical;
|
|
3475
3554
|
} catch {
|
|
@@ -3480,7 +3559,7 @@ function resolveCanonicalDirectory(value, name) {
|
|
|
3480
3559
|
try {
|
|
3481
3560
|
const entry = statSync3(value);
|
|
3482
3561
|
if (!entry.isDirectory()) throw new Error("not a directory");
|
|
3483
|
-
return
|
|
3562
|
+
return realpathSync5(value);
|
|
3484
3563
|
} catch {
|
|
3485
3564
|
throw new Error(`worker: ${name} is unavailable or unsafe`);
|
|
3486
3565
|
}
|
|
@@ -3516,13 +3595,13 @@ function requireCanonicalWindowsDirectory(value, name) {
|
|
|
3516
3595
|
if (!value || !isAbsolute5(value) || !existsSync12(value) || !statSync3(value).isDirectory()) {
|
|
3517
3596
|
throw new Error(`minimal worker bootstrap requires a valid ${name} directory`);
|
|
3518
3597
|
}
|
|
3519
|
-
return
|
|
3598
|
+
return realpathSync5(value);
|
|
3520
3599
|
}
|
|
3521
3600
|
function requireCanonicalWindowsFile(value, name) {
|
|
3522
3601
|
if (!value || !isAbsolute5(value) || !existsSync12(value) || !statSync3(value).isFile()) {
|
|
3523
3602
|
throw new Error(`minimal worker bootstrap requires a valid ${name} executable`);
|
|
3524
3603
|
}
|
|
3525
|
-
return
|
|
3604
|
+
return realpathSync5(value);
|
|
3526
3605
|
}
|
|
3527
3606
|
function objectRecord(value, label) {
|
|
3528
3607
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -3565,13 +3644,61 @@ function lexicallyWithin(root, candidate) {
|
|
|
3565
3644
|
const rel = relative5(root, candidate);
|
|
3566
3645
|
return rel === "" || rel !== ".." && !rel.startsWith(`..${sep5}`) && !isAbsolute5(rel);
|
|
3567
3646
|
}
|
|
3647
|
+
function assertConversationTarget(value) {
|
|
3648
|
+
const target = objectRecord(value, "conversation target");
|
|
3649
|
+
assertExactKeys(target, /* @__PURE__ */ new Set(["id", "filename"]), "conversation target");
|
|
3650
|
+
if (typeof target.id !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(target.id) || target.filename !== `${target.id}.jsonl`)
|
|
3651
|
+
throw new Error("Invalid worker conversation target");
|
|
3652
|
+
}
|
|
3653
|
+
|
|
3654
|
+
// ../daemon/src/runtime/tools/ask-user.ts
|
|
3655
|
+
function askUserTool(ask) {
|
|
3656
|
+
return {
|
|
3657
|
+
def: {
|
|
3658
|
+
name: "ask_user",
|
|
3659
|
+
description: "Ask the operator one clarification question and wait for an explicit choice, free-text answer, Skip, or a typed no-answer outcome. An answer is information only: it never grants shell or communication permission. Do not ask for credentials. Do not invent a response when no answer is returned.",
|
|
3660
|
+
parameters: {
|
|
3661
|
+
type: "object",
|
|
3662
|
+
additionalProperties: false,
|
|
3663
|
+
required: ["prompt", "choices"],
|
|
3664
|
+
properties: {
|
|
3665
|
+
prompt: { type: "string", minLength: 1, maxLength: 4096 },
|
|
3666
|
+
choices: {
|
|
3667
|
+
type: "array",
|
|
3668
|
+
minItems: 2,
|
|
3669
|
+
maxItems: 4,
|
|
3670
|
+
items: {
|
|
3671
|
+
type: "object",
|
|
3672
|
+
additionalProperties: false,
|
|
3673
|
+
required: ["label"],
|
|
3674
|
+
properties: {
|
|
3675
|
+
label: { type: "string", minLength: 1, maxLength: 120 },
|
|
3676
|
+
description: { type: "string", minLength: 1, maxLength: 500 }
|
|
3677
|
+
}
|
|
3678
|
+
}
|
|
3679
|
+
},
|
|
3680
|
+
recommendedIndex: { type: "integer", minimum: 0, maximum: 3 }
|
|
3681
|
+
}
|
|
3682
|
+
}
|
|
3683
|
+
},
|
|
3684
|
+
async invoke(args, context) {
|
|
3685
|
+
if (!context?.toolCallId) throw new Error("Question requires its actual tool call identity");
|
|
3686
|
+
const { receipt, ...result } = await ask(
|
|
3687
|
+
context.toolCallId,
|
|
3688
|
+
args
|
|
3689
|
+
);
|
|
3690
|
+
const text = JSON.stringify(result);
|
|
3691
|
+
return receipt ? { content: [{ type: "text", text }], questionReceipt: receipt } : text;
|
|
3692
|
+
}
|
|
3693
|
+
};
|
|
3694
|
+
}
|
|
3568
3695
|
|
|
3569
3696
|
// ../daemon/src/runtime/pi/tools.ts
|
|
3570
3697
|
import { Type as Type2 } from "typebox";
|
|
3571
3698
|
|
|
3572
3699
|
// ../daemon/src/runtime/tools/bootstrap.ts
|
|
3573
3700
|
import { existsSync as existsSync13, rmSync as rmSync12 } from "fs";
|
|
3574
|
-
import { join as
|
|
3701
|
+
import { join as join18 } from "path";
|
|
3575
3702
|
function bootstrapTool(agentDir) {
|
|
3576
3703
|
return {
|
|
3577
3704
|
def: {
|
|
@@ -3580,7 +3707,7 @@ function bootstrapTool(agentDir) {
|
|
|
3580
3707
|
parameters: { type: "object", properties: {} }
|
|
3581
3708
|
},
|
|
3582
3709
|
async invoke() {
|
|
3583
|
-
const path =
|
|
3710
|
+
const path = join18(agentDir, "BOOTSTRAP.md");
|
|
3584
3711
|
if (existsSync13(path)) {
|
|
3585
3712
|
rmSync12(path);
|
|
3586
3713
|
return "BOOTSTRAP.md removed. Bootstrap is complete.";
|
|
@@ -3721,15 +3848,15 @@ function browserTools(host, agentId) {
|
|
|
3721
3848
|
|
|
3722
3849
|
// ../daemon/src/runtime/tools/deliver-file.ts
|
|
3723
3850
|
import {
|
|
3724
|
-
closeSync as
|
|
3725
|
-
constants as
|
|
3726
|
-
fstatSync as
|
|
3727
|
-
openSync as
|
|
3728
|
-
|
|
3729
|
-
realpathSync as
|
|
3851
|
+
closeSync as closeSync5,
|
|
3852
|
+
constants as constants6,
|
|
3853
|
+
fstatSync as fstatSync4,
|
|
3854
|
+
openSync as openSync5,
|
|
3855
|
+
readSync as readSync2,
|
|
3856
|
+
realpathSync as realpathSync6,
|
|
3730
3857
|
statSync as statSync4
|
|
3731
3858
|
} from "fs";
|
|
3732
|
-
import { basename as
|
|
3859
|
+
import { basename as basename3, extname, isAbsolute as isAbsolute6, relative as relative6, resolve as resolve5, sep as sep6 } from "path";
|
|
3733
3860
|
var MAX_DELIVER_BYTES = 25 * 1024 * 1024;
|
|
3734
3861
|
var MIME = {
|
|
3735
3862
|
".pdf": "application/pdf",
|
|
@@ -3749,17 +3876,17 @@ function isWithin2(root, candidate) {
|
|
|
3749
3876
|
const rel = relative6(root, candidate);
|
|
3750
3877
|
return rel === "" || rel !== ".." && !rel.startsWith(`..${sep6}`) && !isAbsolute6(rel);
|
|
3751
3878
|
}
|
|
3752
|
-
function deliverFileTool(cwd, sink) {
|
|
3879
|
+
function deliverFileTool(cwd, sink, sessionId = "") {
|
|
3753
3880
|
const workspacePath = resolve5(cwd);
|
|
3754
3881
|
let workspaceRealPath = null;
|
|
3755
3882
|
try {
|
|
3756
|
-
workspaceRealPath =
|
|
3883
|
+
workspaceRealPath = realpathSync6(workspacePath);
|
|
3757
3884
|
} catch {
|
|
3758
3885
|
}
|
|
3759
3886
|
return {
|
|
3760
3887
|
def: {
|
|
3761
3888
|
name: "deliver_file",
|
|
3762
|
-
description: "Send a file from your workspace to the user so they can download it (web), receive it as a document (Telegram), or save it (CLI). Use this to deliver reports, exports, or any artifact you produced. Max 25
|
|
3889
|
+
description: "Send a file from your workspace to the user so they can download it (web), receive it as a document (Telegram), or save it (CLI). Use this to deliver reports, exports, or any artifact you produced. Max 25 MiB. Saved delivery remains subject to Team Policy.",
|
|
3763
3890
|
parameters: {
|
|
3764
3891
|
type: "object",
|
|
3765
3892
|
properties: {
|
|
@@ -3772,7 +3899,7 @@ function deliverFileTool(cwd, sink) {
|
|
|
3772
3899
|
additionalProperties: false
|
|
3773
3900
|
}
|
|
3774
3901
|
},
|
|
3775
|
-
async invoke(args) {
|
|
3902
|
+
async invoke(args, context) {
|
|
3776
3903
|
const p = String(args.path ?? "");
|
|
3777
3904
|
if (!p) throw new Error("deliver_file: path is required");
|
|
3778
3905
|
if (isAbsolute6(p)) {
|
|
@@ -3788,7 +3915,7 @@ function deliverFileTool(cwd, sink) {
|
|
|
3788
3915
|
let real;
|
|
3789
3916
|
let expected;
|
|
3790
3917
|
try {
|
|
3791
|
-
real =
|
|
3918
|
+
real = realpathSync6(abs);
|
|
3792
3919
|
expected = statSync4(real);
|
|
3793
3920
|
} catch {
|
|
3794
3921
|
throw new Error(`deliver_file: no such file: ${p}`);
|
|
@@ -3798,13 +3925,13 @@ function deliverFileTool(cwd, sink) {
|
|
|
3798
3925
|
}
|
|
3799
3926
|
let fd;
|
|
3800
3927
|
try {
|
|
3801
|
-
fd =
|
|
3928
|
+
fd = openSync5(real, constants6.O_RDONLY | constants6.O_NOFOLLOW | constants6.O_NONBLOCK);
|
|
3802
3929
|
} catch {
|
|
3803
3930
|
throw new Error(`deliver_file: no such file: ${p}`);
|
|
3804
3931
|
}
|
|
3805
3932
|
let data;
|
|
3806
3933
|
try {
|
|
3807
|
-
const stat2 =
|
|
3934
|
+
const stat2 = fstatSync4(fd);
|
|
3808
3935
|
if (!stat2.isFile()) {
|
|
3809
3936
|
throw new Error(`deliver_file: not a regular file: ${p}`);
|
|
3810
3937
|
}
|
|
@@ -3813,7 +3940,7 @@ function deliverFileTool(cwd, sink) {
|
|
|
3813
3940
|
}
|
|
3814
3941
|
let confirmedReal;
|
|
3815
3942
|
try {
|
|
3816
|
-
confirmedReal =
|
|
3943
|
+
confirmedReal = realpathSync6(abs);
|
|
3817
3944
|
} catch {
|
|
3818
3945
|
throw new Error(`deliver_file: path changed during validation: ${p}`);
|
|
3819
3946
|
}
|
|
@@ -3822,32 +3949,53 @@ function deliverFileTool(cwd, sink) {
|
|
|
3822
3949
|
}
|
|
3823
3950
|
if (stat2.size > MAX_DELIVER_BYTES) {
|
|
3824
3951
|
throw new Error(
|
|
3825
|
-
`deliver_file: "${
|
|
3952
|
+
`deliver_file: "${basename3(abs)}" is too large (${(stat2.size / 1024 / 1024).toFixed(1)} MB > 25 MB)`
|
|
3826
3953
|
);
|
|
3827
3954
|
}
|
|
3828
|
-
|
|
3955
|
+
const buffer = Buffer.alloc(MAX_DELIVER_BYTES + 1);
|
|
3956
|
+
let length = 0;
|
|
3957
|
+
while (length < buffer.length) {
|
|
3958
|
+
const count = readSync2(fd, buffer, length, buffer.length - length, null);
|
|
3959
|
+
if (count === 0) break;
|
|
3960
|
+
length += count;
|
|
3961
|
+
}
|
|
3962
|
+
if (length > MAX_DELIVER_BYTES) throw new Error("deliver_file: file exceeds 25 MiB");
|
|
3963
|
+
data = buffer.subarray(0, length).toString("base64");
|
|
3829
3964
|
} finally {
|
|
3830
|
-
|
|
3965
|
+
closeSync5(fd);
|
|
3831
3966
|
}
|
|
3832
|
-
const name =
|
|
3967
|
+
const name = basename3(abs);
|
|
3833
3968
|
const mimeType = MIME[extname(abs).toLowerCase()] ?? "application/octet-stream";
|
|
3834
|
-
|
|
3835
|
-
|
|
3969
|
+
if (!context?.toolCallId || !sessionId)
|
|
3970
|
+
throw new Error("deliver_file: missing source operation");
|
|
3971
|
+
const result = await sink(
|
|
3972
|
+
{ name, mimeType, data },
|
|
3973
|
+
{ sessionId, toolCallId: context.toolCallId }
|
|
3974
|
+
);
|
|
3975
|
+
return {
|
|
3976
|
+
content: [
|
|
3977
|
+
{
|
|
3978
|
+
type: "text",
|
|
3979
|
+
text: `Saved "${name}" (${mimeType}) as result ${result.resultId}. Delivery is subject to Team Policy.`
|
|
3980
|
+
}
|
|
3981
|
+
],
|
|
3982
|
+
result
|
|
3983
|
+
};
|
|
3836
3984
|
}
|
|
3837
3985
|
};
|
|
3838
3986
|
}
|
|
3839
3987
|
|
|
3840
3988
|
// ../daemon/src/runtime/tools/home.ts
|
|
3841
3989
|
import {
|
|
3842
|
-
closeSync as
|
|
3843
|
-
constants as
|
|
3844
|
-
fstatSync as
|
|
3990
|
+
closeSync as closeSync6,
|
|
3991
|
+
constants as constants7,
|
|
3992
|
+
fstatSync as fstatSync5,
|
|
3845
3993
|
lstatSync as lstatSync5,
|
|
3846
|
-
openSync as
|
|
3994
|
+
openSync as openSync6,
|
|
3847
3995
|
readdirSync as readdirSync7,
|
|
3848
3996
|
writeFileSync as writeFileSync8
|
|
3849
3997
|
} from "fs";
|
|
3850
|
-
import { join as
|
|
3998
|
+
import { join as join19 } from "path";
|
|
3851
3999
|
var HOME_FILES_READABLE = [
|
|
3852
4000
|
"IDENTITY.md",
|
|
3853
4001
|
"SOUL.md",
|
|
@@ -3912,18 +4060,18 @@ function homeTools(agentDir) {
|
|
|
3912
4060
|
let fd;
|
|
3913
4061
|
try {
|
|
3914
4062
|
rejectExistingSymlinkOrNonFile(path);
|
|
3915
|
-
fd =
|
|
4063
|
+
fd = openSync6(
|
|
3916
4064
|
path,
|
|
3917
|
-
|
|
4065
|
+
constants7.O_WRONLY | constants7.O_CREAT | constants7.O_TRUNC | noFollowFlag(),
|
|
3918
4066
|
384
|
|
3919
4067
|
);
|
|
3920
|
-
if (!
|
|
4068
|
+
if (!fstatSync5(fd).isFile()) throw new Error("target is not a regular file");
|
|
3921
4069
|
writeFileSync8(fd, content, "utf8");
|
|
3922
4070
|
} catch (err) {
|
|
3923
4071
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3924
4072
|
throw new Error(`home_write: could not write ${file}: ${msg}`);
|
|
3925
4073
|
} finally {
|
|
3926
|
-
if (fd !== void 0)
|
|
4074
|
+
if (fd !== void 0) closeSync6(fd);
|
|
3927
4075
|
}
|
|
3928
4076
|
return `wrote ${file} (${Buffer.byteLength(content, "utf8")} bytes)`;
|
|
3929
4077
|
}
|
|
@@ -3968,7 +4116,7 @@ function resolvePrivateHomeRoot(agentDir) {
|
|
|
3968
4116
|
}
|
|
3969
4117
|
}
|
|
3970
4118
|
function privateHomeFile(homeRoot, file) {
|
|
3971
|
-
return
|
|
4119
|
+
return join19(homeRoot, file);
|
|
3972
4120
|
}
|
|
3973
4121
|
function rejectSymlinkOrNonFile(path) {
|
|
3974
4122
|
const entry = lstatSync5(path);
|
|
@@ -4912,18 +5060,18 @@ function ourToolToPiTool(h) {
|
|
|
4912
5060
|
label: h.def.name,
|
|
4913
5061
|
description: h.def.description,
|
|
4914
5062
|
parameters: Type2.Unsafe(h.def.parameters),
|
|
4915
|
-
async execute(
|
|
4916
|
-
const out = await h.invoke(params);
|
|
5063
|
+
async execute(toolCallId, params) {
|
|
5064
|
+
const out = await h.invoke(params, { toolCallId });
|
|
4917
5065
|
return {
|
|
4918
5066
|
content: toPiContent(out),
|
|
4919
|
-
details: {}
|
|
5067
|
+
details: typeof out === "object" && !Array.isArray(out) ? "result" in out ? { result: out.result } : { questionReceipt: out.questionReceipt } : {}
|
|
4920
5068
|
};
|
|
4921
5069
|
}
|
|
4922
5070
|
};
|
|
4923
5071
|
}
|
|
4924
5072
|
function toPiContent(out) {
|
|
4925
5073
|
if (typeof out === "string") return [{ type: "text", text: out }];
|
|
4926
|
-
return out.map(
|
|
5074
|
+
return (Array.isArray(out) ? out : out.content).map(
|
|
4927
5075
|
(p) => p.type === "text" ? { type: "text", text: p.text } : { type: "image", data: p.data, mimeType: p.mimeType }
|
|
4928
5076
|
);
|
|
4929
5077
|
}
|
|
@@ -4947,8 +5095,9 @@ function createBazilionCustomTools(opts) {
|
|
|
4947
5095
|
handlers.push(...mcpProxyTools(opts.mcpHost, opts.mcpTools));
|
|
4948
5096
|
}
|
|
4949
5097
|
if (opts.fileSink) {
|
|
4950
|
-
handlers.push(deliverFileTool(opts.agent.team.path, opts.fileSink));
|
|
5098
|
+
handlers.push(deliverFileTool(opts.agent.team.path, opts.fileSink, opts.sessionId));
|
|
4951
5099
|
}
|
|
5100
|
+
if (opts.askUser) handlers.push(askUserTool(opts.askUser));
|
|
4952
5101
|
return handlers.map(ourToolToPiTool);
|
|
4953
5102
|
}
|
|
4954
5103
|
function createProtectedBazilionCustomTools(opts) {
|
|
@@ -4959,8 +5108,9 @@ function createProtectedBazilionCustomTools(opts) {
|
|
|
4959
5108
|
protectedWebFetchTool(),
|
|
4960
5109
|
...messagingTools(opts.messagingHost, opts.agent.agent.id),
|
|
4961
5110
|
...userMdTools(opts.userMdHost, opts.agent.team.id),
|
|
4962
|
-
deliverFileTool(opts.agent.team.path, opts.fileSink)
|
|
5111
|
+
deliverFileTool(opts.agent.team.path, opts.fileSink, opts.sessionId)
|
|
4963
5112
|
];
|
|
5113
|
+
if (opts.askUser) handlers.push(askUserTool(opts.askUser));
|
|
4964
5114
|
return handlers.map(ourToolToPiTool);
|
|
4965
5115
|
}
|
|
4966
5116
|
|
|
@@ -4984,6 +5134,7 @@ async function createBazilionSession(opts) {
|
|
|
4984
5134
|
mcpHost,
|
|
4985
5135
|
mcpTools,
|
|
4986
5136
|
fileSink,
|
|
5137
|
+
askUser,
|
|
4987
5138
|
bashApprovalHost,
|
|
4988
5139
|
refreshApiKey,
|
|
4989
5140
|
restricted
|
|
@@ -5005,7 +5156,7 @@ async function createBazilionSession(opts) {
|
|
|
5005
5156
|
const cwd = agent.team.path;
|
|
5006
5157
|
if (!existsSync14(cwd)) mkdirSync7(cwd, { recursive: true });
|
|
5007
5158
|
const promptSkills = restricted ? [] : loadPromptSkills(paths.skillsDir, agent.skills);
|
|
5008
|
-
const uploadsDir =
|
|
5159
|
+
const uploadsDir = join20(agent.agent.dir, "uploads");
|
|
5009
5160
|
const shellTools = restricted ? null : createSessionShellTools(cwd, env, {
|
|
5010
5161
|
...existsSync14(uploadsDir) ? { inputsDir: uploadsDir } : {},
|
|
5011
5162
|
skillMounts: promptSkills.map((skill) => ({
|
|
@@ -5014,9 +5165,9 @@ async function createBazilionSession(opts) {
|
|
|
5014
5165
|
})),
|
|
5015
5166
|
approvalHost: bashApprovalHost
|
|
5016
5167
|
});
|
|
5017
|
-
const sessionDir = restricted?.sessionDir ??
|
|
5168
|
+
const sessionDir = restricted?.sessionDir ?? join20(paths.agentDir(agent.agent.id), "sessions");
|
|
5018
5169
|
mkdirSync7(sessionDir, { recursive: true });
|
|
5019
|
-
const existing = restricted ? null :
|
|
5170
|
+
const existing = restricted ? null : explicitConversationFile(sessionDir, opts.conversation);
|
|
5020
5171
|
const sessionManager = existing ? SessionManager.open(existing, sessionDir, cwd) : SessionManager.create(cwd, sessionDir);
|
|
5021
5172
|
const settingsManager = SettingsManager.inMemory({
|
|
5022
5173
|
compaction: { enabled: false },
|
|
@@ -5033,7 +5184,7 @@ async function createBazilionSession(opts) {
|
|
|
5033
5184
|
});
|
|
5034
5185
|
const resourceLoader = new DefaultResourceLoader({
|
|
5035
5186
|
cwd,
|
|
5036
|
-
agentDir:
|
|
5187
|
+
agentDir: join20(paths.home, "pi"),
|
|
5037
5188
|
settingsManager,
|
|
5038
5189
|
noExtensions: true,
|
|
5039
5190
|
noSkills: true,
|
|
@@ -5052,13 +5203,15 @@ async function createBazilionSession(opts) {
|
|
|
5052
5203
|
mcpHost,
|
|
5053
5204
|
mcpTools,
|
|
5054
5205
|
fileSink,
|
|
5206
|
+
askUser,
|
|
5207
|
+
sessionId: sessionManager.getSessionId(),
|
|
5055
5208
|
env
|
|
5056
5209
|
});
|
|
5057
5210
|
const customTools = shellTools?.customBash ? [...bazilionTools, shellTools.customBash] : bazilionTools;
|
|
5058
5211
|
const allowedTools = [...shellTools?.hostToolNames ?? [], ...customTools.map((t) => t.name)];
|
|
5059
5212
|
const { session } = await createAgentSession({
|
|
5060
5213
|
cwd,
|
|
5061
|
-
agentDir:
|
|
5214
|
+
agentDir: join20(paths.home, "pi"),
|
|
5062
5215
|
model,
|
|
5063
5216
|
thinkingLevel: toPiThinkingLevel(restricted?.reasoningLevel ?? agent.reasoningLevel),
|
|
5064
5217
|
tools: allowedTools,
|
|
@@ -5115,7 +5268,7 @@ async function createProtectedBazilionSession(opts) {
|
|
|
5115
5268
|
opts.bashApprovalHost
|
|
5116
5269
|
);
|
|
5117
5270
|
mkdirSync7(opts.paths.sessionDir, { recursive: true });
|
|
5118
|
-
const existing =
|
|
5271
|
+
const existing = explicitConversationFile(opts.paths.sessionDir, opts.conversation);
|
|
5119
5272
|
const sessionManager = existing ? SessionManager.open(existing, opts.paths.sessionDir, opts.paths.teamDir) : SessionManager.create(opts.paths.teamDir, opts.paths.sessionDir);
|
|
5120
5273
|
const settingsManager = createInMemorySettingsManager();
|
|
5121
5274
|
const bazilionPrompt = redactJsonValue(
|
|
@@ -5144,7 +5297,9 @@ async function createProtectedBazilionSession(opts) {
|
|
|
5144
5297
|
memory: opts.memory,
|
|
5145
5298
|
messagingHost: opts.messagingHost,
|
|
5146
5299
|
userMdHost: opts.userMdHost,
|
|
5147
|
-
fileSink: opts.fileSink
|
|
5300
|
+
fileSink: opts.fileSink,
|
|
5301
|
+
askUser: opts.askUser,
|
|
5302
|
+
sessionId: sessionManager.getSessionId()
|
|
5148
5303
|
});
|
|
5149
5304
|
if (!shellTools.customBash) throw new Error("protected Docker bash tool is unavailable");
|
|
5150
5305
|
const customTools = [...bazilionTools, shellTools.customBash];
|
|
@@ -5222,7 +5377,7 @@ async function createRestrictedReviewSession(opts) {
|
|
|
5222
5377
|
function materializeProtectedCredentialFile(runtime, scratch) {
|
|
5223
5378
|
const fields = [...runtime.credentialEnv ?? []];
|
|
5224
5379
|
if (runtime.credentialFile) {
|
|
5225
|
-
const path =
|
|
5380
|
+
const path = join20(scratch.tempDir, "provider-credential.json");
|
|
5226
5381
|
writeFileSync9(path, runtime.credentialFile.content, {
|
|
5227
5382
|
encoding: "utf8",
|
|
5228
5383
|
mode: 384,
|
|
@@ -5357,19 +5512,12 @@ function toPiThinkingLevel(level) {
|
|
|
5357
5512
|
return "medium";
|
|
5358
5513
|
}
|
|
5359
5514
|
}
|
|
5360
|
-
function
|
|
5361
|
-
if (!
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
try {
|
|
5367
|
-
const s = statSync5(path);
|
|
5368
|
-
if (!newest || s.mtimeMs > newest.mtimeMs) newest = { path, mtimeMs: s.mtimeMs };
|
|
5369
|
-
} catch {
|
|
5370
|
-
}
|
|
5371
|
-
}
|
|
5372
|
-
return newest?.path ?? null;
|
|
5515
|
+
function explicitConversationFile(directory, target) {
|
|
5516
|
+
if (!target || !/^[0-9a-f-]{36}$/i.test(target.id) || target.filename !== `${target.id}.jsonl`)
|
|
5517
|
+
throw new Error("Explicit conversation target is required");
|
|
5518
|
+
const file = join20(directory, target.filename);
|
|
5519
|
+
readCanonicalSessionFile(directory, target.filename, target.id);
|
|
5520
|
+
return file;
|
|
5373
5521
|
}
|
|
5374
5522
|
|
|
5375
5523
|
// ../daemon/src/runtime/worker/api-key-refresh.ts
|
|
@@ -5602,6 +5750,7 @@ async function createSessionForInput(input, ipcCall) {
|
|
|
5602
5750
|
}) : void 0;
|
|
5603
5751
|
const handle2 = await createBazilionSession({
|
|
5604
5752
|
agent: input.agent,
|
|
5753
|
+
conversation: input.conversation,
|
|
5605
5754
|
paths,
|
|
5606
5755
|
env: process.env,
|
|
5607
5756
|
memory: memory2,
|
|
@@ -5614,7 +5763,15 @@ async function createSessionForInput(input, ipcCall) {
|
|
|
5614
5763
|
mcpHost,
|
|
5615
5764
|
mcpTools: input.mcpTools,
|
|
5616
5765
|
bashApprovalHost: bashApprovalHost2,
|
|
5617
|
-
|
|
5766
|
+
askUser: input.questionEnabled ? (toolCallId, question) => ipcCall("askUser", { toolCallId, question }) : void 0,
|
|
5767
|
+
fileSink: async (file, source) => {
|
|
5768
|
+
const result = await ipcCall(
|
|
5769
|
+
"publishResult",
|
|
5770
|
+
{ ...file, ...source }
|
|
5771
|
+
);
|
|
5772
|
+
emit({ kind: "event", event: { type: "file", ...file, result } });
|
|
5773
|
+
return result;
|
|
5774
|
+
}
|
|
5618
5775
|
});
|
|
5619
5776
|
return { handle: handle2 };
|
|
5620
5777
|
}
|
|
@@ -5646,6 +5803,7 @@ async function createSessionForInput(input, ipcCall) {
|
|
|
5646
5803
|
});
|
|
5647
5804
|
const handle = await createProtectedBazilionSession({
|
|
5648
5805
|
agent: input.agent,
|
|
5806
|
+
conversation: input.conversation,
|
|
5649
5807
|
runtime: input.runtime,
|
|
5650
5808
|
paths: input.paths,
|
|
5651
5809
|
scratch: input.scratch,
|
|
@@ -5654,8 +5812,16 @@ async function createSessionForInput(input, ipcCall) {
|
|
|
5654
5812
|
messagingHost,
|
|
5655
5813
|
userMdHost,
|
|
5656
5814
|
bashApprovalHost,
|
|
5815
|
+
askUser: input.questionEnabled ? (toolCallId, question) => ipcCall("askUser", { toolCallId, question }) : void 0,
|
|
5657
5816
|
refreshApiKey,
|
|
5658
|
-
fileSink: (file) =>
|
|
5817
|
+
fileSink: async (file, source) => {
|
|
5818
|
+
const result = await ipcCall("publishResult", {
|
|
5819
|
+
...file,
|
|
5820
|
+
...source
|
|
5821
|
+
});
|
|
5822
|
+
emit({ kind: "event", event: { type: "file", ...file, result } });
|
|
5823
|
+
return result;
|
|
5824
|
+
}
|
|
5659
5825
|
});
|
|
5660
5826
|
return { handle };
|
|
5661
5827
|
}
|
|
@@ -5684,7 +5850,30 @@ async function main() {
|
|
|
5684
5850
|
const ipcCall = createWorkerIpcCall();
|
|
5685
5851
|
const { handle, reviewState } = await createSessionForInput(input, ipcCall);
|
|
5686
5852
|
session = handle.session;
|
|
5853
|
+
const consumptionAcks = /* @__PURE__ */ new Set();
|
|
5687
5854
|
const unsubscribe = session.subscribe((piEvent) => {
|
|
5855
|
+
if (input.kind !== "restricted_review" && input.questionEnabled && piEvent.type === "message_end" && piEvent.message.role === "toolResult" && piEvent.message.toolName === "ask_user" && !piEvent.message.isError) {
|
|
5856
|
+
const message = piEvent.message;
|
|
5857
|
+
const content = message.content[0];
|
|
5858
|
+
if (content?.type === "text") {
|
|
5859
|
+
try {
|
|
5860
|
+
const result = JSON.parse(content.text);
|
|
5861
|
+
if (typeof result.questionId === "string") {
|
|
5862
|
+
const ack = new Promise((resolve6) => setImmediate(resolve6)).then(
|
|
5863
|
+
() => ipcCall("questionConsumed", {
|
|
5864
|
+
questionId: result.questionId,
|
|
5865
|
+
toolCallId: message.toolCallId
|
|
5866
|
+
})
|
|
5867
|
+
).catch(() => {
|
|
5868
|
+
}).finally(() => {
|
|
5869
|
+
consumptionAcks.delete(ack);
|
|
5870
|
+
});
|
|
5871
|
+
consumptionAcks.add(ack);
|
|
5872
|
+
}
|
|
5873
|
+
} catch {
|
|
5874
|
+
}
|
|
5875
|
+
}
|
|
5876
|
+
}
|
|
5688
5877
|
if (reviewState && piEvent.type === "tool_execution_end" && piEvent.toolName === "propose_lesson" && piEvent.isError) {
|
|
5689
5878
|
reviewState.recordValidationFailure();
|
|
5690
5879
|
if (reviewState.validationFailures() >= 2) void session?.abort();
|
|
@@ -5704,6 +5893,7 @@ async function main() {
|
|
|
5704
5893
|
promptImages.length > 0 ? { images: promptImages } : void 0
|
|
5705
5894
|
);
|
|
5706
5895
|
await session.agent.waitForIdle();
|
|
5896
|
+
await Promise.all(consumptionAcks);
|
|
5707
5897
|
if (reviewState) {
|
|
5708
5898
|
if (reviewState.validationFailures() >= 2) {
|
|
5709
5899
|
throw new Error("review output remained invalid after one schema-repair attempt");
|