@bunny-agent/daemon 0.9.28 → 0.9.29-beta.10
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/bundle.mjs +735 -256
- package/dist/index.js +735 -256
- package/dist/nextjs.js +734 -256
- package/dist/routes/coding.d.ts.map +1 -1
- package/dist/routes/fs.d.ts +2 -0
- package/dist/routes/fs.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/bundle.mjs
CHANGED
|
@@ -116839,7 +116839,7 @@ var require_core3 = __commonJS({
|
|
|
116839
116839
|
return match2 && match2.index === 0;
|
|
116840
116840
|
}
|
|
116841
116841
|
var BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
|
|
116842
|
-
function
|
|
116842
|
+
function join39(regexps, separator = "|") {
|
|
116843
116843
|
let numCaptures = 0;
|
|
116844
116844
|
return regexps.map((regex2) => {
|
|
116845
116845
|
numCaptures += 1;
|
|
@@ -117143,7 +117143,7 @@ var require_core3 = __commonJS({
|
|
|
117143
117143
|
this.exec = () => null;
|
|
117144
117144
|
}
|
|
117145
117145
|
const terminators = this.regexes.map((el) => el[1]);
|
|
117146
|
-
this.matcherRe = langRe(
|
|
117146
|
+
this.matcherRe = langRe(join39(terminators), true);
|
|
117147
117147
|
this.lastIndex = 0;
|
|
117148
117148
|
}
|
|
117149
117149
|
/** @param {string} s */
|
|
@@ -168061,14 +168061,14 @@ var require_graceful_fs = __commonJS({
|
|
|
168061
168061
|
return close;
|
|
168062
168062
|
})(fs16.close);
|
|
168063
168063
|
fs16.closeSync = (function(fs$closeSync) {
|
|
168064
|
-
function
|
|
168064
|
+
function closeSync3(fd) {
|
|
168065
168065
|
fs$closeSync.apply(fs16, arguments);
|
|
168066
168066
|
resetQueue();
|
|
168067
168067
|
}
|
|
168068
|
-
Object.defineProperty(
|
|
168068
|
+
Object.defineProperty(closeSync3, previousSymbol, {
|
|
168069
168069
|
value: fs$closeSync
|
|
168070
168070
|
});
|
|
168071
|
-
return
|
|
168071
|
+
return closeSync3;
|
|
168072
168072
|
})(fs16.closeSync);
|
|
168073
168073
|
if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
|
|
168074
168074
|
process.on("exit", function() {
|
|
@@ -206500,10 +206500,15 @@ async function fsStat(state, q2) {
|
|
|
206500
206500
|
const root2 = resolveVolumeRoot(state, q2.volume);
|
|
206501
206501
|
const target = resolveUnderRoot(root2, q2.path);
|
|
206502
206502
|
const stat6 = await fs2.stat(target);
|
|
206503
|
+
const created_at = msToIsoOrNull(stat6.birthtimeMs) ?? msToIsoOrNull(stat6.ctimeMs);
|
|
206503
206504
|
return ok({
|
|
206504
206505
|
path: target,
|
|
206505
206506
|
is_dir: stat6.isDirectory(),
|
|
206506
|
-
size: stat6.isFile() ? stat6.size : 0
|
|
206507
|
+
size: stat6.isFile() ? stat6.size : 0,
|
|
206508
|
+
created_at,
|
|
206509
|
+
modified_at: msToIsoOrNull(
|
|
206510
|
+
stat6.mtimeMs
|
|
206511
|
+
)
|
|
206507
206512
|
});
|
|
206508
206513
|
}
|
|
206509
206514
|
async function fsExists(state, q2) {
|
|
@@ -208383,7 +208388,7 @@ function createOpenCodeRunner(options2 = {}) {
|
|
|
208383
208388
|
|
|
208384
208389
|
// ../../packages/runner-pi/dist/pi-runner.js
|
|
208385
208390
|
import { appendFileSync as appendFileSync5, existsSync as existsSync28, unlinkSync as unlinkSync6 } from "node:fs";
|
|
208386
|
-
import { join as
|
|
208391
|
+
import { join as join36 } from "node:path";
|
|
208387
208392
|
|
|
208388
208393
|
// ../../node_modules/.pnpm/@mariozechner+pi-ai@0.64.0_ws@8.19.0_zod@4.3.6/node_modules/@mariozechner/pi-ai/dist/index.js
|
|
208389
208394
|
var dist_exports = {};
|
|
@@ -263369,25 +263374,146 @@ var generateImageSchema = {
|
|
|
263369
263374
|
},
|
|
263370
263375
|
quality: {
|
|
263371
263376
|
type: "string",
|
|
263372
|
-
enum: ["
|
|
263373
|
-
description: "Image quality
|
|
263377
|
+
enum: ["low", "medium", "high", "auto"],
|
|
263378
|
+
description: "Image quality. Defaults to auto."
|
|
263374
263379
|
}
|
|
263375
263380
|
},
|
|
263376
263381
|
required: ["prompt"],
|
|
263377
263382
|
additionalProperties: false
|
|
263378
263383
|
};
|
|
263379
|
-
async function resolveB64(item) {
|
|
263384
|
+
async function resolveB64(item, apiKey) {
|
|
263380
263385
|
if (item.b64_json)
|
|
263381
263386
|
return item.b64_json;
|
|
263382
|
-
if (item.
|
|
263383
|
-
|
|
263387
|
+
if (item.b64Json)
|
|
263388
|
+
return item.b64Json;
|
|
263389
|
+
if (item.image_base64)
|
|
263390
|
+
return item.image_base64;
|
|
263391
|
+
if (item.imageBase64)
|
|
263392
|
+
return item.imageBase64;
|
|
263393
|
+
if (item.base64)
|
|
263394
|
+
return item.base64;
|
|
263395
|
+
if (typeof item.image === "string")
|
|
263396
|
+
return item.image;
|
|
263397
|
+
if (item.image?.b64_json)
|
|
263398
|
+
return item.image.b64_json;
|
|
263399
|
+
if (item.image?.base64)
|
|
263400
|
+
return item.image.base64;
|
|
263401
|
+
const url = item.url ?? item.image_url ?? item.imageUrl ?? item.image?.url;
|
|
263402
|
+
if (url) {
|
|
263403
|
+
const headers = {};
|
|
263404
|
+
if (apiKey) {
|
|
263405
|
+
headers.Authorization = `Bearer ${apiKey}`;
|
|
263406
|
+
}
|
|
263407
|
+
const res = await fetch(url, { headers });
|
|
263384
263408
|
if (res.ok)
|
|
263385
263409
|
return Buffer.from(await res.arrayBuffer()).toString("base64");
|
|
263386
263410
|
}
|
|
263387
263411
|
return void 0;
|
|
263388
263412
|
}
|
|
263389
|
-
|
|
263390
|
-
const
|
|
263413
|
+
function pickImageItem(response) {
|
|
263414
|
+
const tryFromObject = (value2) => {
|
|
263415
|
+
if (!value2 || typeof value2 !== "object")
|
|
263416
|
+
return void 0;
|
|
263417
|
+
const obj = value2;
|
|
263418
|
+
return {
|
|
263419
|
+
b64_json: obj.b64_json ?? obj.b64Json,
|
|
263420
|
+
b64Json: obj.b64Json,
|
|
263421
|
+
url: obj.url ?? obj.imageUrl,
|
|
263422
|
+
image_base64: obj.image_base64 ?? obj.imageBase64,
|
|
263423
|
+
imageBase64: obj.imageBase64,
|
|
263424
|
+
image_url: obj.image_url ?? obj.imageUrl,
|
|
263425
|
+
imageUrl: obj.imageUrl,
|
|
263426
|
+
base64: obj.base64,
|
|
263427
|
+
image: obj.image
|
|
263428
|
+
};
|
|
263429
|
+
};
|
|
263430
|
+
const asItem = (value2) => {
|
|
263431
|
+
if (value2 == null)
|
|
263432
|
+
return void 0;
|
|
263433
|
+
if (typeof value2 === "string") {
|
|
263434
|
+
return { base64: value2 };
|
|
263435
|
+
}
|
|
263436
|
+
if (typeof value2 === "object") {
|
|
263437
|
+
const normalized = tryFromObject(value2);
|
|
263438
|
+
if (normalized)
|
|
263439
|
+
return normalized;
|
|
263440
|
+
}
|
|
263441
|
+
return void 0;
|
|
263442
|
+
};
|
|
263443
|
+
const fromDataArray = Array.isArray(response.data) ? asItem(response.data[0]) : void 0;
|
|
263444
|
+
if (fromDataArray)
|
|
263445
|
+
return fromDataArray;
|
|
263446
|
+
const fromDataValue = asItem(response.data);
|
|
263447
|
+
if (fromDataValue)
|
|
263448
|
+
return fromDataValue;
|
|
263449
|
+
const responseRecord = response;
|
|
263450
|
+
const imagesValue = responseRecord.images;
|
|
263451
|
+
const outputValue = responseRecord.output;
|
|
263452
|
+
const fromImagesArray = Array.isArray(imagesValue) ? asItem(imagesValue[0]) : void 0;
|
|
263453
|
+
if (fromImagesArray)
|
|
263454
|
+
return fromImagesArray;
|
|
263455
|
+
const fromImagesValue = asItem(imagesValue);
|
|
263456
|
+
if (fromImagesValue)
|
|
263457
|
+
return fromImagesValue;
|
|
263458
|
+
const fromOutputArray = Array.isArray(outputValue) ? asItem(outputValue[0]) : void 0;
|
|
263459
|
+
if (fromOutputArray)
|
|
263460
|
+
return fromOutputArray;
|
|
263461
|
+
const fromOutputValue = asItem(outputValue);
|
|
263462
|
+
if (fromOutputValue)
|
|
263463
|
+
return fromOutputValue;
|
|
263464
|
+
const fromTopLevel = asItem(response);
|
|
263465
|
+
if (fromTopLevel)
|
|
263466
|
+
return fromTopLevel;
|
|
263467
|
+
const queue = [response];
|
|
263468
|
+
while (queue.length > 0) {
|
|
263469
|
+
const current = queue.shift();
|
|
263470
|
+
if (current == null)
|
|
263471
|
+
continue;
|
|
263472
|
+
if (typeof current === "string") {
|
|
263473
|
+
if (/^[A-Za-z0-9+/=]{32,}$/.test(current))
|
|
263474
|
+
return { base64: current };
|
|
263475
|
+
continue;
|
|
263476
|
+
}
|
|
263477
|
+
if (typeof current !== "object")
|
|
263478
|
+
continue;
|
|
263479
|
+
const normalized = tryFromObject(current);
|
|
263480
|
+
if (normalized) {
|
|
263481
|
+
const hasUsefulField = Boolean(normalized.b64_json ?? normalized.b64Json ?? normalized.image_base64 ?? normalized.imageBase64 ?? normalized.base64 ?? normalized.url ?? normalized.image_url ?? normalized.imageUrl ?? (typeof normalized.image === "string" ? normalized.image : normalized.image?.b64_json ?? normalized.image?.base64 ?? normalized.image?.url));
|
|
263482
|
+
if (hasUsefulField)
|
|
263483
|
+
return normalized;
|
|
263484
|
+
}
|
|
263485
|
+
if (Array.isArray(current)) {
|
|
263486
|
+
queue.push(...current);
|
|
263487
|
+
continue;
|
|
263488
|
+
}
|
|
263489
|
+
for (const value2 of Object.values(current)) {
|
|
263490
|
+
queue.push(value2);
|
|
263491
|
+
}
|
|
263492
|
+
}
|
|
263493
|
+
return {};
|
|
263494
|
+
}
|
|
263495
|
+
function detectImageMime(filePath) {
|
|
263496
|
+
const ext2 = extname2(filePath).toLowerCase();
|
|
263497
|
+
if (ext2 === ".jpg" || ext2 === ".jpeg")
|
|
263498
|
+
return "image/jpeg";
|
|
263499
|
+
if (ext2 === ".webp")
|
|
263500
|
+
return "image/webp";
|
|
263501
|
+
if (ext2 === ".gif")
|
|
263502
|
+
return "image/gif";
|
|
263503
|
+
return "image/png";
|
|
263504
|
+
}
|
|
263505
|
+
function buildPolicySafeEditPrompt(prompt) {
|
|
263506
|
+
const riskyPattern = /\b(watermark|watermarks|logo|logos|copyright|brand mark|remove branding)\b/i;
|
|
263507
|
+
if (!riskyPattern.test(prompt)) {
|
|
263508
|
+
return { prompt, rewritten: false };
|
|
263509
|
+
}
|
|
263510
|
+
return {
|
|
263511
|
+
prompt: "Clean up distracting overlay text or marks naturally while preserving the original scene, style, and layout. Keep the result seamless and high quality.",
|
|
263512
|
+
rewritten: true
|
|
263513
|
+
};
|
|
263514
|
+
}
|
|
263515
|
+
async function saveImageItem(item, filePath, apiKey) {
|
|
263516
|
+
const b64 = await resolveB64(item, apiKey);
|
|
263391
263517
|
if (!b64)
|
|
263392
263518
|
return void 0;
|
|
263393
263519
|
mkdirSync10(dirname19(filePath), { recursive: true });
|
|
@@ -263407,11 +263533,11 @@ function buildImageGenerateTool(cwd, imageModelId, baseUrl, apiKey) {
|
|
|
263407
263533
|
],
|
|
263408
263534
|
// biome-ignore lint/suspicious/noExplicitAny: plain JSON Schema compatible with TypeBox TSchema
|
|
263409
263535
|
parameters: generateImageSchema,
|
|
263410
|
-
async execute(_toolCallId, params,
|
|
263536
|
+
async execute(_toolCallId, params, signal, _onUpdate) {
|
|
263411
263537
|
const p = params;
|
|
263412
263538
|
const prompt = p.prompt;
|
|
263413
263539
|
const size = p.size ?? "1024x1024";
|
|
263414
|
-
const quality = p.quality ?? "
|
|
263540
|
+
const quality = p.quality ?? "auto";
|
|
263415
263541
|
const rawFilename = p.filename;
|
|
263416
263542
|
const filename = rawFilename ? extname2(rawFilename) ? rawFilename : `${rawFilename}.png` : `image_${Date.now()}.png`;
|
|
263417
263543
|
const filePath = join34(cwd, filename.replace(/[^a-zA-Z0-9_\-./]/g, "_"));
|
|
@@ -263428,24 +263554,28 @@ function buildImageGenerateTool(cwd, imageModelId, baseUrl, apiKey) {
|
|
|
263428
263554
|
prompt,
|
|
263429
263555
|
n: 1,
|
|
263430
263556
|
size,
|
|
263431
|
-
quality
|
|
263432
|
-
|
|
263557
|
+
quality,
|
|
263558
|
+
response_format: "b64_json",
|
|
263559
|
+
output_format: "png"
|
|
263560
|
+
}),
|
|
263561
|
+
signal
|
|
263433
263562
|
});
|
|
263434
263563
|
if (!res.ok) {
|
|
263435
263564
|
throw new Error(`Image generation failed (${res.status}): ${await res.text()}`);
|
|
263436
263565
|
}
|
|
263437
263566
|
const json = await res.json();
|
|
263438
|
-
const item = json
|
|
263439
|
-
const savedPath = await saveImageItem(item, filePath);
|
|
263567
|
+
const item = pickImageItem(json);
|
|
263568
|
+
const savedPath = await saveImageItem(item, filePath, apiKey);
|
|
263440
263569
|
return {
|
|
263441
263570
|
content: [
|
|
263442
263571
|
{
|
|
263443
263572
|
type: "text",
|
|
263444
|
-
text: savedPath ??
|
|
263573
|
+
text: savedPath ?? `Image generated but could not be saved: no image payload returned; image_model: ${imageModelId}`
|
|
263445
263574
|
}
|
|
263446
263575
|
],
|
|
263447
263576
|
details: {
|
|
263448
263577
|
filePath: savedPath,
|
|
263578
|
+
...json.usage != null ? { usage: { raw: { [imageModelId]: json.usage } } } : {},
|
|
263449
263579
|
response: json
|
|
263450
263580
|
}
|
|
263451
263581
|
};
|
|
@@ -263461,13 +263591,504 @@ function buildImageGenerateTool(cwd, imageModelId, baseUrl, apiKey) {
|
|
|
263461
263591
|
}
|
|
263462
263592
|
};
|
|
263463
263593
|
}
|
|
263594
|
+
var editImageSchema = {
|
|
263595
|
+
type: "object",
|
|
263596
|
+
properties: {
|
|
263597
|
+
image: {
|
|
263598
|
+
type: "string",
|
|
263599
|
+
description: "Path to the source image file to edit (relative to working directory or absolute)."
|
|
263600
|
+
},
|
|
263601
|
+
prompt: {
|
|
263602
|
+
type: "string",
|
|
263603
|
+
description: "Text description of the desired final image. Describe the full result, not just the change."
|
|
263604
|
+
},
|
|
263605
|
+
mask: {
|
|
263606
|
+
type: "string",
|
|
263607
|
+
description: "Optional path to a mask image (PNG with transparent areas indicating where to edit). If omitted, the model decides what to change based on the prompt."
|
|
263608
|
+
},
|
|
263609
|
+
filename: {
|
|
263610
|
+
type: "string",
|
|
263611
|
+
description: "Output filename with extension, e.g. 'edited_cat.png'. Defaults to a timestamp-based name."
|
|
263612
|
+
},
|
|
263613
|
+
size: {
|
|
263614
|
+
type: "string",
|
|
263615
|
+
enum: ["1024x1024", "1024x1536", "1536x1024", "auto"],
|
|
263616
|
+
description: "Output image dimensions. Optional; omit or set auto to let model decide."
|
|
263617
|
+
},
|
|
263618
|
+
quality: {
|
|
263619
|
+
type: "string",
|
|
263620
|
+
enum: ["low", "medium", "high", "auto"],
|
|
263621
|
+
description: "Image quality. Optional; omit or set auto to let model decide."
|
|
263622
|
+
}
|
|
263623
|
+
},
|
|
263624
|
+
required: ["image", "prompt"],
|
|
263625
|
+
additionalProperties: false
|
|
263626
|
+
};
|
|
263627
|
+
function buildMultipartBody(fields, files) {
|
|
263628
|
+
const boundary = `----SandagentBoundary${Date.now()}${Math.random().toString(36).slice(2)}`;
|
|
263629
|
+
const parts = [];
|
|
263630
|
+
for (const { name, value: value2 } of fields) {
|
|
263631
|
+
parts.push(Buffer.from(`--${boundary}\r
|
|
263632
|
+
Content-Disposition: form-data; name="${name}"\r
|
|
263633
|
+
\r
|
|
263634
|
+
${value2}\r
|
|
263635
|
+
`));
|
|
263636
|
+
}
|
|
263637
|
+
for (const { name, filename, buffer, mime } of files) {
|
|
263638
|
+
parts.push(Buffer.from(`--${boundary}\r
|
|
263639
|
+
Content-Disposition: form-data; name="${name}"; filename="${filename}"\r
|
|
263640
|
+
Content-Type: ${mime}\r
|
|
263641
|
+
\r
|
|
263642
|
+
`));
|
|
263643
|
+
parts.push(buffer);
|
|
263644
|
+
parts.push(Buffer.from("\r\n"));
|
|
263645
|
+
}
|
|
263646
|
+
parts.push(Buffer.from(`--${boundary}--\r
|
|
263647
|
+
`));
|
|
263648
|
+
return {
|
|
263649
|
+
body: Buffer.concat(parts),
|
|
263650
|
+
contentType: `multipart/form-data; boundary=${boundary}`
|
|
263651
|
+
};
|
|
263652
|
+
}
|
|
263653
|
+
function buildImageEditTool(cwd, imageModelId, baseUrl, apiKey) {
|
|
263654
|
+
return {
|
|
263655
|
+
name: "edit_image",
|
|
263656
|
+
label: "edit image",
|
|
263657
|
+
description: "Edit an existing image based on a text prompt. Optionally use a mask to control which areas to modify. Saves the result to disk and returns the file path.",
|
|
263658
|
+
promptSnippet: "edit_image(image, prompt, mask?, filename?, size?, quality?) - edit an existing image",
|
|
263659
|
+
promptGuidelines: [
|
|
263660
|
+
"Use edit_image when the user wants to modify, retouch, or transform an existing image.",
|
|
263661
|
+
"The prompt should describe the full desired final image, not just the change.",
|
|
263662
|
+
"Provide the source image path. Use a mask image (PNG with transparent areas) to control where edits happen.",
|
|
263663
|
+
"Without a mask, the model decides what to change based on the prompt."
|
|
263664
|
+
],
|
|
263665
|
+
// biome-ignore lint/suspicious/noExplicitAny: plain JSON Schema compatible with TypeBox TSchema
|
|
263666
|
+
parameters: editImageSchema,
|
|
263667
|
+
async execute(_toolCallId, params, signal, _onUpdate) {
|
|
263668
|
+
const { readFileSync: readFileSync24, existsSync: existsSync31 } = await import("node:fs");
|
|
263669
|
+
const { resolve: resolve14, basename: basename12 } = await import("node:path");
|
|
263670
|
+
const p = params;
|
|
263671
|
+
const imagePath = p.image;
|
|
263672
|
+
const prompt = p.prompt;
|
|
263673
|
+
const maskPath = p.mask;
|
|
263674
|
+
const size = p.size;
|
|
263675
|
+
const quality = p.quality;
|
|
263676
|
+
const rawFilename = p.filename;
|
|
263677
|
+
const safePrompt = buildPolicySafeEditPrompt(prompt);
|
|
263678
|
+
const resolvedImage = resolve14(cwd, imagePath);
|
|
263679
|
+
if (!existsSync31(resolvedImage)) {
|
|
263680
|
+
return {
|
|
263681
|
+
content: [
|
|
263682
|
+
{
|
|
263683
|
+
type: "text",
|
|
263684
|
+
text: `Image edit error: source image not found at ${resolvedImage}`
|
|
263685
|
+
}
|
|
263686
|
+
],
|
|
263687
|
+
details: void 0
|
|
263688
|
+
};
|
|
263689
|
+
}
|
|
263690
|
+
const filename = rawFilename ? extname2(rawFilename) ? rawFilename : `${rawFilename}.png` : `edited_${Date.now()}.png`;
|
|
263691
|
+
const filePath = join34(cwd, filename.replace(/[^a-zA-Z0-9_\-./]/g, "_"));
|
|
263692
|
+
try {
|
|
263693
|
+
const imageBuffer = readFileSync24(resolvedImage);
|
|
263694
|
+
const fields = [
|
|
263695
|
+
{ name: "model", value: imageModelId },
|
|
263696
|
+
{ name: "prompt", value: safePrompt.prompt },
|
|
263697
|
+
{ name: "n", value: "1" },
|
|
263698
|
+
{ name: "response_format", value: "b64_json" },
|
|
263699
|
+
{ name: "output_format", value: "png" }
|
|
263700
|
+
];
|
|
263701
|
+
if (size && size !== "auto") {
|
|
263702
|
+
fields.push({ name: "size", value: size });
|
|
263703
|
+
}
|
|
263704
|
+
if (quality && quality !== "auto") {
|
|
263705
|
+
fields.push({ name: "quality", value: quality });
|
|
263706
|
+
}
|
|
263707
|
+
const files = [
|
|
263708
|
+
{
|
|
263709
|
+
name: "image",
|
|
263710
|
+
filename: basename12(resolvedImage),
|
|
263711
|
+
buffer: imageBuffer,
|
|
263712
|
+
mime: detectImageMime(resolvedImage)
|
|
263713
|
+
}
|
|
263714
|
+
];
|
|
263715
|
+
if (maskPath) {
|
|
263716
|
+
const resolvedMask = resolve14(cwd, maskPath);
|
|
263717
|
+
if (existsSync31(resolvedMask)) {
|
|
263718
|
+
files.push({
|
|
263719
|
+
name: "mask",
|
|
263720
|
+
filename: basename12(resolvedMask),
|
|
263721
|
+
buffer: readFileSync24(resolvedMask),
|
|
263722
|
+
mime: detectImageMime(resolvedMask)
|
|
263723
|
+
});
|
|
263724
|
+
}
|
|
263725
|
+
}
|
|
263726
|
+
const { body: multipartBody, contentType } = buildMultipartBody(fields, files);
|
|
263727
|
+
const url = `${baseUrl.replace(/\/$/, "")}/v1/images/edits`;
|
|
263728
|
+
const sendRequest = async (body, type) => {
|
|
263729
|
+
const res = await fetch(url, {
|
|
263730
|
+
method: "POST",
|
|
263731
|
+
headers: {
|
|
263732
|
+
"Content-Type": type,
|
|
263733
|
+
Authorization: `Bearer ${apiKey}`
|
|
263734
|
+
},
|
|
263735
|
+
body,
|
|
263736
|
+
signal
|
|
263737
|
+
});
|
|
263738
|
+
if (!res.ok) {
|
|
263739
|
+
throw new Error(`Image edit failed (${res.status}): ${await res.text()}`);
|
|
263740
|
+
}
|
|
263741
|
+
return await res.json();
|
|
263742
|
+
};
|
|
263743
|
+
let json = await sendRequest(multipartBody, contentType);
|
|
263744
|
+
const item = pickImageItem(json);
|
|
263745
|
+
let savedPath = await saveImageItem(item, filePath, apiKey);
|
|
263746
|
+
const firstResponseHasEmptyDataArray = Array.isArray(json.data) && json.data.length === 0;
|
|
263747
|
+
if (!savedPath && safePrompt.rewritten && firstResponseHasEmptyDataArray) {
|
|
263748
|
+
const retryFields = fields.map((f3) => f3.name === "prompt" ? {
|
|
263749
|
+
name: "prompt",
|
|
263750
|
+
value: "Remove only distracting overlay text artifacts naturally and keep all original content unchanged."
|
|
263751
|
+
} : f3);
|
|
263752
|
+
const retryMultipart = buildMultipartBody(retryFields, files);
|
|
263753
|
+
json = await sendRequest(retryMultipart.body, retryMultipart.contentType);
|
|
263754
|
+
const retryItem = pickImageItem(json);
|
|
263755
|
+
savedPath = await saveImageItem(retryItem, filePath, apiKey);
|
|
263756
|
+
}
|
|
263757
|
+
return {
|
|
263758
|
+
content: [
|
|
263759
|
+
{
|
|
263760
|
+
type: "text",
|
|
263761
|
+
text: savedPath ?? `Image edited but could not be saved: no image payload returned; image_model: ${imageModelId}`
|
|
263762
|
+
}
|
|
263763
|
+
],
|
|
263764
|
+
details: {
|
|
263765
|
+
filePath: savedPath,
|
|
263766
|
+
...json.usage != null ? { usage: { raw: { [imageModelId]: json.usage } } } : {},
|
|
263767
|
+
response: json
|
|
263768
|
+
}
|
|
263769
|
+
};
|
|
263770
|
+
} catch (e2) {
|
|
263771
|
+
const msg = e2 instanceof Error ? e2.message : String(e2);
|
|
263772
|
+
return {
|
|
263773
|
+
content: [
|
|
263774
|
+
{ type: "text", text: `Image edit error: ${msg}` }
|
|
263775
|
+
],
|
|
263776
|
+
details: void 0
|
|
263777
|
+
};
|
|
263778
|
+
}
|
|
263779
|
+
}
|
|
263780
|
+
};
|
|
263781
|
+
}
|
|
263782
|
+
|
|
263783
|
+
// ../../packages/runner-pi/dist/session-utils.js
|
|
263784
|
+
import { closeSync as closeSync2, fstatSync, openSync as openSync2, readdirSync as readdirSync12, readSync as readSync2, statSync as statSync13 } from "node:fs";
|
|
263785
|
+
import { join as join35 } from "node:path";
|
|
263786
|
+
var MAX_SESSION_FILE_BYTES = Number(process.env.SANDAGENT_MAX_SESSION_BYTES) || 10 * 1024 * 1024;
|
|
263787
|
+
function resolveSessionPathById(cwd, sessionId) {
|
|
263788
|
+
const tempMgr = SessionManager.create(cwd);
|
|
263789
|
+
const sessionsDir = tempMgr.getSessionDir();
|
|
263790
|
+
try {
|
|
263791
|
+
const suffix = `_${sessionId}.jsonl`;
|
|
263792
|
+
const match2 = readdirSync12(sessionsDir).find((f3) => f3.endsWith(suffix));
|
|
263793
|
+
return match2 ? join35(sessionsDir, match2) : void 0;
|
|
263794
|
+
} catch {
|
|
263795
|
+
return void 0;
|
|
263796
|
+
}
|
|
263797
|
+
}
|
|
263798
|
+
function isSessionFileTooLarge(sessionPath2) {
|
|
263799
|
+
try {
|
|
263800
|
+
return statSync13(sessionPath2).size > MAX_SESSION_FILE_BYTES;
|
|
263801
|
+
} catch {
|
|
263802
|
+
return false;
|
|
263803
|
+
}
|
|
263804
|
+
}
|
|
263805
|
+
function readTailEntries(sessionPath2, tailBytes = 1024 * 1024) {
|
|
263806
|
+
let fd;
|
|
263807
|
+
try {
|
|
263808
|
+
fd = openSync2(sessionPath2, "r");
|
|
263809
|
+
} catch {
|
|
263810
|
+
return [];
|
|
263811
|
+
}
|
|
263812
|
+
try {
|
|
263813
|
+
const fileSize = fstatSync(fd).size;
|
|
263814
|
+
const readStart = Math.max(0, fileSize - tailBytes);
|
|
263815
|
+
const readLen = fileSize - readStart;
|
|
263816
|
+
const buf = Buffer.alloc(readLen);
|
|
263817
|
+
readSync2(fd, buf, 0, readLen, readStart);
|
|
263818
|
+
const tail = buf.toString("utf8");
|
|
263819
|
+
const entries = [];
|
|
263820
|
+
for (const line of tail.split("\n")) {
|
|
263821
|
+
const trimmed = line.trim();
|
|
263822
|
+
if (!trimmed)
|
|
263823
|
+
continue;
|
|
263824
|
+
try {
|
|
263825
|
+
entries.push(JSON.parse(trimmed));
|
|
263826
|
+
} catch {
|
|
263827
|
+
}
|
|
263828
|
+
}
|
|
263829
|
+
return entries;
|
|
263830
|
+
} finally {
|
|
263831
|
+
closeSync2(fd);
|
|
263832
|
+
}
|
|
263833
|
+
}
|
|
263834
|
+
function extractSessionContext(sessionPath2) {
|
|
263835
|
+
const entries = readTailEntries(sessionPath2);
|
|
263836
|
+
if (entries.length === 0)
|
|
263837
|
+
return void 0;
|
|
263838
|
+
for (let i2 = entries.length - 1; i2 >= 0; i2--) {
|
|
263839
|
+
const e2 = entries[i2];
|
|
263840
|
+
if (e2.type === "compaction" && typeof e2.summary === "string") {
|
|
263841
|
+
return e2.summary;
|
|
263842
|
+
}
|
|
263843
|
+
}
|
|
263844
|
+
const recentMessages = [];
|
|
263845
|
+
const MAX_MESSAGES = 6;
|
|
263846
|
+
for (let i2 = entries.length - 1; i2 >= 0 && recentMessages.length < MAX_MESSAGES; i2--) {
|
|
263847
|
+
const e2 = entries[i2];
|
|
263848
|
+
if (e2.type !== "message")
|
|
263849
|
+
continue;
|
|
263850
|
+
const msg = e2.message;
|
|
263851
|
+
if (!msg)
|
|
263852
|
+
continue;
|
|
263853
|
+
if (msg.role !== "user" && msg.role !== "assistant")
|
|
263854
|
+
continue;
|
|
263855
|
+
let text = "";
|
|
263856
|
+
if (typeof msg.content === "string") {
|
|
263857
|
+
text = msg.content;
|
|
263858
|
+
} else if (Array.isArray(msg.content)) {
|
|
263859
|
+
text = msg.content.filter((c) => c.type === "text" && c.text).map((c) => c.text).join("\n");
|
|
263860
|
+
}
|
|
263861
|
+
if (text) {
|
|
263862
|
+
recentMessages.unshift(`[${msg.role}]: ${text}`);
|
|
263863
|
+
}
|
|
263864
|
+
}
|
|
263865
|
+
if (recentMessages.length === 0)
|
|
263866
|
+
return void 0;
|
|
263867
|
+
return "## Previous Session Context (auto-extracted)\n\nThe following is the tail of the previous conversation:\n\n" + recentMessages.join("\n\n");
|
|
263868
|
+
}
|
|
263869
|
+
|
|
263870
|
+
// ../../packages/runner-pi/dist/usage-metadata.js
|
|
263871
|
+
function usageToMessageMetadata(usage) {
|
|
263872
|
+
return {
|
|
263873
|
+
input_tokens: usage.input,
|
|
263874
|
+
output_tokens: usage.output,
|
|
263875
|
+
cache_read_input_tokens: usage.cacheRead,
|
|
263876
|
+
cache_creation_input_tokens: usage.cacheWrite
|
|
263877
|
+
};
|
|
263878
|
+
}
|
|
263879
|
+
function accumulateToolUsage(tally, raw) {
|
|
263880
|
+
for (const [key, row] of Object.entries(raw)) {
|
|
263881
|
+
const existing = tally[key];
|
|
263882
|
+
if (existing) {
|
|
263883
|
+
for (const [field, val] of Object.entries(row)) {
|
|
263884
|
+
if (typeof val === "number")
|
|
263885
|
+
existing[field] = (existing[field] ?? 0) + val;
|
|
263886
|
+
}
|
|
263887
|
+
} else {
|
|
263888
|
+
const nums = {};
|
|
263889
|
+
for (const [field, val] of Object.entries(row)) {
|
|
263890
|
+
if (typeof val === "number")
|
|
263891
|
+
nums[field] = val;
|
|
263892
|
+
}
|
|
263893
|
+
tally[key] = nums;
|
|
263894
|
+
}
|
|
263895
|
+
}
|
|
263896
|
+
}
|
|
263897
|
+
function getUsageFromAgentEndMessages(messages) {
|
|
263898
|
+
for (let i2 = messages.length - 1; i2 >= 0; i2--) {
|
|
263899
|
+
const m2 = messages[i2];
|
|
263900
|
+
if (m2.role === "assistant" && m2.usage != null)
|
|
263901
|
+
return m2.usage;
|
|
263902
|
+
}
|
|
263903
|
+
return void 0;
|
|
263904
|
+
}
|
|
263905
|
+
|
|
263906
|
+
// ../../packages/runner-pi/dist/stream-converter.js
|
|
263907
|
+
function emitStreamError(errorText) {
|
|
263908
|
+
const errorLine = "data: " + JSON.stringify({ type: "error", errorText }) + "\n\n";
|
|
263909
|
+
const finishLine = "data: " + JSON.stringify({ type: "finish", finishReason: "error" }) + "\n\n";
|
|
263910
|
+
return [errorLine, finishLine, "data: [DONE]\n\n"];
|
|
263911
|
+
}
|
|
263912
|
+
function extractToolResultText(result) {
|
|
263913
|
+
if (result !== null && typeof result === "object") {
|
|
263914
|
+
const r2 = result;
|
|
263915
|
+
if (Array.isArray(r2.content) && r2.content.length > 0) {
|
|
263916
|
+
const text = r2.content.filter((c) => c.type === "text" && typeof c.text === "string").map((c) => c.text).join("\n");
|
|
263917
|
+
if (text.length > 0)
|
|
263918
|
+
return text;
|
|
263919
|
+
}
|
|
263920
|
+
}
|
|
263921
|
+
if (typeof result === "string")
|
|
263922
|
+
return result;
|
|
263923
|
+
try {
|
|
263924
|
+
return JSON.stringify(result);
|
|
263925
|
+
} catch {
|
|
263926
|
+
return String(result);
|
|
263927
|
+
}
|
|
263928
|
+
}
|
|
263929
|
+
function sseData(obj) {
|
|
263930
|
+
return "data: " + JSON.stringify(obj) + "\n\n";
|
|
263931
|
+
}
|
|
263932
|
+
var PiAISDKStreamConverter = class {
|
|
263933
|
+
constructor(options2) {
|
|
263934
|
+
this.options = options2;
|
|
263935
|
+
this.messageId = "msg_" + Date.now() + "_" + Math.random().toString(36).slice(2);
|
|
263936
|
+
this.toolUsageTally = {};
|
|
263937
|
+
this.activeTextPartId = null;
|
|
263938
|
+
this.hasStarted = false;
|
|
263939
|
+
this.hasFinished = false;
|
|
263940
|
+
}
|
|
263941
|
+
get finished() {
|
|
263942
|
+
return this.hasFinished;
|
|
263943
|
+
}
|
|
263944
|
+
forceError(errorText) {
|
|
263945
|
+
if (this.hasFinished)
|
|
263946
|
+
return [];
|
|
263947
|
+
return [...this.ensureStart(), ...this.finishError(errorText)];
|
|
263948
|
+
}
|
|
263949
|
+
handleEvent(event, aborted) {
|
|
263950
|
+
if (this.hasFinished)
|
|
263951
|
+
return [];
|
|
263952
|
+
const chunks = [...this.ensureStart()];
|
|
263953
|
+
if (event.type === "message_start") {
|
|
263954
|
+
const msg = event.message;
|
|
263955
|
+
if (msg?.role === "assistant")
|
|
263956
|
+
chunks.push(...this.endTextStreamIfOpen());
|
|
263957
|
+
return chunks;
|
|
263958
|
+
}
|
|
263959
|
+
if (event.type === "message_end")
|
|
263960
|
+
return chunks;
|
|
263961
|
+
if (event.type === "message_update") {
|
|
263962
|
+
const sub = event.assistantMessageEvent;
|
|
263963
|
+
if (sub.type === "text_start")
|
|
263964
|
+
chunks.push(...this.endTextStreamIfOpen(), ...this.openTextStream());
|
|
263965
|
+
else if (sub.type === "text_delta")
|
|
263966
|
+
chunks.push(...this.emitTextDelta(sub.delta));
|
|
263967
|
+
else if (sub.type === "toolcall_start")
|
|
263968
|
+
chunks.push(...this.endTextStreamIfOpen());
|
|
263969
|
+
return chunks;
|
|
263970
|
+
}
|
|
263971
|
+
if (event.type === "tool_execution_start") {
|
|
263972
|
+
chunks.push(...this.endTextStreamIfOpen());
|
|
263973
|
+
chunks.push(sseData({
|
|
263974
|
+
type: "tool-input-start",
|
|
263975
|
+
toolCallId: event.toolCallId,
|
|
263976
|
+
toolName: event.toolName,
|
|
263977
|
+
dynamic: true,
|
|
263978
|
+
providerExecuted: true
|
|
263979
|
+
}), sseData({
|
|
263980
|
+
type: "tool-input-available",
|
|
263981
|
+
toolCallId: event.toolCallId,
|
|
263982
|
+
toolName: event.toolName,
|
|
263983
|
+
input: event.args,
|
|
263984
|
+
dynamic: true,
|
|
263985
|
+
providerExecuted: true
|
|
263986
|
+
}));
|
|
263987
|
+
return chunks;
|
|
263988
|
+
}
|
|
263989
|
+
if (event.type === "tool_execution_end") {
|
|
263990
|
+
const output = this.options.redactText(this.options.normalizeToolOutput(event.result));
|
|
263991
|
+
const raw = event.result?.details?.usage?.raw;
|
|
263992
|
+
if (raw != null)
|
|
263993
|
+
accumulateToolUsage(this.toolUsageTally, raw);
|
|
263994
|
+
chunks.push(sseData({
|
|
263995
|
+
type: "tool-output-available",
|
|
263996
|
+
toolCallId: event.toolCallId,
|
|
263997
|
+
output,
|
|
263998
|
+
isError: event.isError,
|
|
263999
|
+
dynamic: true,
|
|
264000
|
+
providerExecuted: true
|
|
264001
|
+
}));
|
|
264002
|
+
return chunks;
|
|
264003
|
+
}
|
|
264004
|
+
if (event.type === "agent_end") {
|
|
264005
|
+
if (aborted) {
|
|
264006
|
+
chunks.push(...this.finishError("Run aborted by signal."));
|
|
264007
|
+
} else {
|
|
264008
|
+
const errorMsg = this.options.getErrorFromAgentEndMessages(event.messages);
|
|
264009
|
+
if (errorMsg)
|
|
264010
|
+
chunks.push(...this.finishError(errorMsg));
|
|
264011
|
+
else
|
|
264012
|
+
chunks.push(...this.finishSuccess(this.options.getUsageFromAgentEndMessages(event.messages)));
|
|
264013
|
+
}
|
|
264014
|
+
return chunks;
|
|
264015
|
+
}
|
|
264016
|
+
return chunks;
|
|
264017
|
+
}
|
|
264018
|
+
ensureStart() {
|
|
264019
|
+
if (this.hasStarted)
|
|
264020
|
+
return [];
|
|
264021
|
+
this.hasStarted = true;
|
|
264022
|
+
return [
|
|
264023
|
+
sseData({ type: "start", messageId: this.messageId }),
|
|
264024
|
+
sseData({
|
|
264025
|
+
type: "message-metadata",
|
|
264026
|
+
messageMetadata: { sessionId: this.options.sessionId }
|
|
264027
|
+
})
|
|
264028
|
+
];
|
|
264029
|
+
}
|
|
264030
|
+
newTextPartId() {
|
|
264031
|
+
return "text_" + Date.now() + "_" + Math.random().toString(36).slice(2) + "_" + Math.random().toString(36).slice(2);
|
|
264032
|
+
}
|
|
264033
|
+
openTextStream() {
|
|
264034
|
+
this.activeTextPartId = this.newTextPartId();
|
|
264035
|
+
return [sseData({ type: "text-start", id: this.activeTextPartId })];
|
|
264036
|
+
}
|
|
264037
|
+
emitTextDelta(rawDelta) {
|
|
264038
|
+
const delta = rawDelta ? this.options.redactText(rawDelta) : void 0;
|
|
264039
|
+
if (!delta)
|
|
264040
|
+
return [];
|
|
264041
|
+
const startChunk = this.activeTextPartId == null ? this.openTextStream() : [];
|
|
264042
|
+
return [
|
|
264043
|
+
...startChunk,
|
|
264044
|
+
sseData({ type: "text-delta", id: this.activeTextPartId, delta })
|
|
264045
|
+
];
|
|
264046
|
+
}
|
|
264047
|
+
endTextStreamIfOpen() {
|
|
264048
|
+
if (this.activeTextPartId == null)
|
|
264049
|
+
return [];
|
|
264050
|
+
const id = this.activeTextPartId;
|
|
264051
|
+
this.activeTextPartId = null;
|
|
264052
|
+
return [sseData({ type: "text-end", id })];
|
|
264053
|
+
}
|
|
264054
|
+
finishSuccess(usage) {
|
|
264055
|
+
const chunks = [...this.endTextStreamIfOpen()];
|
|
264056
|
+
const raw = {};
|
|
264057
|
+
let chatUsage;
|
|
264058
|
+
if (usage) {
|
|
264059
|
+
const { id } = this.options.model;
|
|
264060
|
+
chatUsage = {
|
|
264061
|
+
type: "chat",
|
|
264062
|
+
...usageToMessageMetadata(usage)
|
|
264063
|
+
};
|
|
264064
|
+
raw[id] = chatUsage;
|
|
264065
|
+
}
|
|
264066
|
+
for (const [key, tally] of Object.entries(this.toolUsageTally)) {
|
|
264067
|
+
raw[key] = { ...tally };
|
|
264068
|
+
}
|
|
264069
|
+
const finishPayload = {
|
|
264070
|
+
type: "finish",
|
|
264071
|
+
finishReason: "stop"
|
|
264072
|
+
};
|
|
264073
|
+
if (usage) {
|
|
264074
|
+
finishPayload.messageMetadata = { usage: { ...chatUsage, raw } };
|
|
264075
|
+
}
|
|
264076
|
+
chunks.push(sseData(finishPayload), "data: [DONE]\n\n");
|
|
264077
|
+
this.hasFinished = true;
|
|
264078
|
+
return chunks;
|
|
264079
|
+
}
|
|
264080
|
+
finishError(errorText) {
|
|
264081
|
+
this.hasFinished = true;
|
|
264082
|
+
return emitStreamError(errorText);
|
|
264083
|
+
}
|
|
264084
|
+
};
|
|
263464
264085
|
|
|
263465
264086
|
// ../../packages/runner-pi/dist/web-tools.js
|
|
263466
264087
|
var braveProvider = {
|
|
263467
264088
|
id: "brave",
|
|
263468
264089
|
label: "Brave Search",
|
|
263469
264090
|
envKeys: ["BRAVE_API_KEY"],
|
|
263470
|
-
async search({ apiKey, query, count, country, freshness }) {
|
|
264091
|
+
async search({ apiKey, query, count, country, freshness, signal }) {
|
|
263471
264092
|
const params = new URLSearchParams({
|
|
263472
264093
|
q: query,
|
|
263473
264094
|
count: String(Math.min(count, 20))
|
|
@@ -263481,7 +264102,8 @@ var braveProvider = {
|
|
|
263481
264102
|
Accept: "application/json",
|
|
263482
264103
|
"Accept-Encoding": "gzip",
|
|
263483
264104
|
"X-Subscription-Token": apiKey
|
|
263484
|
-
}
|
|
264105
|
+
},
|
|
264106
|
+
signal
|
|
263485
264107
|
});
|
|
263486
264108
|
if (!res.ok) {
|
|
263487
264109
|
const body = await res.text().catch(() => "");
|
|
@@ -263502,14 +264124,14 @@ ${body}`);
|
|
|
263502
264124
|
});
|
|
263503
264125
|
}
|
|
263504
264126
|
}
|
|
263505
|
-
return results;
|
|
264127
|
+
return { results };
|
|
263506
264128
|
}
|
|
263507
264129
|
};
|
|
263508
264130
|
var tavilyProvider = {
|
|
263509
264131
|
id: "tavily",
|
|
263510
264132
|
label: "Tavily",
|
|
263511
264133
|
envKeys: ["TAVILY_API_KEY"],
|
|
263512
|
-
async search({ apiKey, query, count }) {
|
|
264134
|
+
async search({ apiKey, query, count, signal }) {
|
|
263513
264135
|
const res = await fetch("https://api.tavily.com/search", {
|
|
263514
264136
|
method: "POST",
|
|
263515
264137
|
headers: { "Content-Type": "application/json" },
|
|
@@ -263518,7 +264140,8 @@ var tavilyProvider = {
|
|
|
263518
264140
|
query,
|
|
263519
264141
|
max_results: Math.min(count, 10),
|
|
263520
264142
|
include_answer: false
|
|
263521
|
-
})
|
|
264143
|
+
}),
|
|
264144
|
+
signal
|
|
263522
264145
|
});
|
|
263523
264146
|
if (!res.ok) {
|
|
263524
264147
|
const body = await res.text().catch(() => "");
|
|
@@ -263536,7 +264159,7 @@ ${body}`);
|
|
|
263536
264159
|
});
|
|
263537
264160
|
}
|
|
263538
264161
|
}
|
|
263539
|
-
return results;
|
|
264162
|
+
return { results };
|
|
263540
264163
|
}
|
|
263541
264164
|
};
|
|
263542
264165
|
var AUTO_DETECT_ORDER = [braveProvider, tavilyProvider];
|
|
@@ -263571,9 +264194,12 @@ var BROWSER_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/53
|
|
|
263571
264194
|
function htmlToText(html2) {
|
|
263572
264195
|
return html2.replace(/<(script|style|noscript)[^>]*>[\s\S]*?<\/\1>/gi, "").replace(/<br\s*\/?>/gi, "\n").replace(/<\/(p|div|h[1-6]|li|tr)>/gi, "\n").replace(/<(p|div|h[1-6]|li|tr)[^>]*>/gi, "\n").replace(/<[^>]+>/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/ /g, " ").replace(/[ \t]+/g, " ").replace(/\n{3,}/g, "\n\n").trim();
|
|
263573
264196
|
}
|
|
263574
|
-
async function fetchPageContent(url) {
|
|
264197
|
+
async function fetchPageContent(url, externalSignal) {
|
|
263575
264198
|
const controller = new AbortController();
|
|
263576
264199
|
const timeout = setTimeout(() => controller.abort(), 15e3);
|
|
264200
|
+
externalSignal?.addEventListener("abort", () => controller.abort(), {
|
|
264201
|
+
once: true
|
|
264202
|
+
});
|
|
263577
264203
|
try {
|
|
263578
264204
|
const res = await fetch(url, {
|
|
263579
264205
|
headers: {
|
|
@@ -263670,7 +264296,7 @@ function buildWebSearchTool(env2) {
|
|
|
263670
264296
|
],
|
|
263671
264297
|
// biome-ignore lint/suspicious/noExplicitAny: plain JSON Schema compatible with TypeBox TSchema
|
|
263672
264298
|
parameters: webSearchSchema,
|
|
263673
|
-
async execute(_toolCallId, params,
|
|
264299
|
+
async execute(_toolCallId, params, signal, _onUpdate) {
|
|
263674
264300
|
const p = params;
|
|
263675
264301
|
const query = p.query;
|
|
263676
264302
|
const count = p.count ?? 5;
|
|
@@ -263680,18 +264306,29 @@ function buildWebSearchTool(env2) {
|
|
|
263680
264306
|
let lastError;
|
|
263681
264307
|
for (const { provider, apiKey } of providers) {
|
|
263682
264308
|
try {
|
|
263683
|
-
const results = await provider.search({
|
|
264309
|
+
const { results } = await provider.search({
|
|
263684
264310
|
apiKey,
|
|
263685
264311
|
query,
|
|
263686
264312
|
count,
|
|
263687
264313
|
country,
|
|
263688
|
-
freshness
|
|
264314
|
+
freshness,
|
|
264315
|
+
signal
|
|
263689
264316
|
});
|
|
264317
|
+
let fetchedPages = 0;
|
|
263690
264318
|
if (shouldFetchContent) {
|
|
263691
264319
|
for (const r2 of results) {
|
|
263692
|
-
r2.content = await fetchPageContent(r2.link);
|
|
264320
|
+
r2.content = await fetchPageContent(r2.link, signal);
|
|
264321
|
+
fetchedPages += 1;
|
|
263693
264322
|
}
|
|
263694
264323
|
}
|
|
264324
|
+
const usage = {
|
|
264325
|
+
raw: {
|
|
264326
|
+
[provider.id]: {
|
|
264327
|
+
requests: 1,
|
|
264328
|
+
fetchedPages
|
|
264329
|
+
}
|
|
264330
|
+
}
|
|
264331
|
+
};
|
|
263695
264332
|
return {
|
|
263696
264333
|
content: [
|
|
263697
264334
|
{
|
|
@@ -263699,7 +264336,9 @@ function buildWebSearchTool(env2) {
|
|
|
263699
264336
|
text: formatSearchResults(results, provider.label)
|
|
263700
264337
|
}
|
|
263701
264338
|
],
|
|
263702
|
-
details:
|
|
264339
|
+
details: {
|
|
264340
|
+
usage
|
|
264341
|
+
}
|
|
263703
264342
|
};
|
|
263704
264343
|
} catch (e2) {
|
|
263705
264344
|
lastError = e2;
|
|
@@ -263735,11 +264374,11 @@ function buildWebFetchTool() {
|
|
|
263735
264374
|
],
|
|
263736
264375
|
// biome-ignore lint/suspicious/noExplicitAny: plain JSON Schema compatible with TypeBox TSchema
|
|
263737
264376
|
parameters: webFetchSchema,
|
|
263738
|
-
async execute(_toolCallId, params,
|
|
264377
|
+
async execute(_toolCallId, params, signal, _onUpdate) {
|
|
263739
264378
|
const p = params;
|
|
263740
264379
|
const url = p.url;
|
|
263741
264380
|
try {
|
|
263742
|
-
const content = await fetchPageContent(url);
|
|
264381
|
+
const content = await fetchPageContent(url, signal);
|
|
263743
264382
|
return {
|
|
263744
264383
|
content: [{ type: "text", text: content }],
|
|
263745
264384
|
details: void 0
|
|
@@ -263882,52 +264521,6 @@ function applyModelOverrides(model, provider, optionsEnv) {
|
|
|
263882
264521
|
model.baseUrl = anthropicBaseUrl;
|
|
263883
264522
|
}
|
|
263884
264523
|
}
|
|
263885
|
-
function emitStreamError(errorText) {
|
|
263886
|
-
return [
|
|
263887
|
-
`data: ${JSON.stringify({ type: "error", errorText })}
|
|
263888
|
-
|
|
263889
|
-
`,
|
|
263890
|
-
`data: ${JSON.stringify({ type: "finish", finishReason: "error" })}
|
|
263891
|
-
|
|
263892
|
-
`,
|
|
263893
|
-
"data: [DONE]\n\n"
|
|
263894
|
-
];
|
|
263895
|
-
}
|
|
263896
|
-
function extractToolResultText(result) {
|
|
263897
|
-
if (result !== null && typeof result === "object") {
|
|
263898
|
-
const r2 = result;
|
|
263899
|
-
if (Array.isArray(r2.content) && r2.content.length > 0) {
|
|
263900
|
-
const text = r2.content.filter((c) => c.type === "text" && typeof c.text === "string").map((c) => c.text).join("\n");
|
|
263901
|
-
if (text.length > 0) {
|
|
263902
|
-
return text;
|
|
263903
|
-
}
|
|
263904
|
-
}
|
|
263905
|
-
}
|
|
263906
|
-
if (typeof result === "string")
|
|
263907
|
-
return result;
|
|
263908
|
-
try {
|
|
263909
|
-
return JSON.stringify(result);
|
|
263910
|
-
} catch {
|
|
263911
|
-
return String(result);
|
|
263912
|
-
}
|
|
263913
|
-
}
|
|
263914
|
-
function usageToMessageMetadata(usage) {
|
|
263915
|
-
return {
|
|
263916
|
-
input_tokens: usage.input,
|
|
263917
|
-
output_tokens: usage.output,
|
|
263918
|
-
cache_read_input_tokens: usage.cacheRead,
|
|
263919
|
-
cache_creation_input_tokens: usage.cacheWrite
|
|
263920
|
-
};
|
|
263921
|
-
}
|
|
263922
|
-
function getUsageFromAgentEndMessages(messages) {
|
|
263923
|
-
for (let i2 = messages.length - 1; i2 >= 0; i2--) {
|
|
263924
|
-
const m2 = messages[i2];
|
|
263925
|
-
if (m2.role === "assistant" && m2.usage != null) {
|
|
263926
|
-
return m2.usage;
|
|
263927
|
-
}
|
|
263928
|
-
}
|
|
263929
|
-
return void 0;
|
|
263930
|
-
}
|
|
263931
264524
|
function getErrorFromAgentEndMessages(messages) {
|
|
263932
264525
|
for (let i2 = messages.length - 1; i2 >= 0; i2--) {
|
|
263933
264526
|
const m2 = messages[i2];
|
|
@@ -263943,7 +264536,7 @@ function traceRawMessage(debugCwd, data, reset = false, optionsEnv) {
|
|
|
263943
264536
|
if (!enabled)
|
|
263944
264537
|
return;
|
|
263945
264538
|
try {
|
|
263946
|
-
const file =
|
|
264539
|
+
const file = join36(debugCwd, "pi-message-stream-debug.json");
|
|
263947
264540
|
if (reset && existsSync28(file))
|
|
263948
264541
|
unlinkSync6(file);
|
|
263949
264542
|
const type = data !== null && typeof data === "object" ? data.type : void 0;
|
|
@@ -264012,9 +264605,22 @@ function createPiRunner(options2 = {}) {
|
|
|
264012
264605
|
if (resume.includes("/")) {
|
|
264013
264606
|
return SessionManager.open(resume);
|
|
264014
264607
|
}
|
|
264015
|
-
const
|
|
264016
|
-
|
|
264017
|
-
|
|
264608
|
+
const sessionPath2 = resolveSessionPathById(cwd, resume);
|
|
264609
|
+
console.error(`${LOG_PREFIX2} resume: id=${resume} path=${sessionPath2 ?? "(not found)"}`);
|
|
264610
|
+
if (sessionPath2) {
|
|
264611
|
+
if (isSessionFileTooLarge(sessionPath2)) {
|
|
264612
|
+
const context = extractSessionContext(sessionPath2);
|
|
264613
|
+
console.error(`${LOG_PREFIX2} session file too large, starting fresh${context ? " (with context)" : ""}`);
|
|
264614
|
+
const newMgr = SessionManager.create(cwd);
|
|
264615
|
+
if (context) {
|
|
264616
|
+
const firstId = newMgr.getEntries()[0]?.id ?? "";
|
|
264617
|
+
newMgr.appendCompaction(context, firstId, 0);
|
|
264618
|
+
}
|
|
264619
|
+
return newMgr;
|
|
264620
|
+
}
|
|
264621
|
+
return SessionManager.open(sessionPath2);
|
|
264622
|
+
}
|
|
264623
|
+
return SessionManager.create(cwd);
|
|
264018
264624
|
}
|
|
264019
264625
|
return SessionManager.create(cwd);
|
|
264020
264626
|
})();
|
|
@@ -264032,7 +264638,7 @@ function createPiRunner(options2 = {}) {
|
|
|
264032
264638
|
const customTools = options2.env && Object.keys(options2.env).length > 0 ? buildSecretAwareTools(cwd, options2.env) : [];
|
|
264033
264639
|
if (imageModelName) {
|
|
264034
264640
|
const apiKey = await modelRegistry2.authStorage.getApiKey(provider) ?? "";
|
|
264035
|
-
customTools.push(buildImageGenerateTool(cwd, imageModelName, model.baseUrl, apiKey));
|
|
264641
|
+
customTools.push(buildImageGenerateTool(cwd, imageModelName, model.baseUrl, apiKey), buildImageEditTool(cwd, imageModelName, model.baseUrl, apiKey));
|
|
264036
264642
|
}
|
|
264037
264643
|
const { session } = await createAgentSession({
|
|
264038
264644
|
cwd,
|
|
@@ -264072,165 +264678,34 @@ function createPiRunner(options2 = {}) {
|
|
|
264072
264678
|
}
|
|
264073
264679
|
try {
|
|
264074
264680
|
traceRawMessage(cwd, null, true, options2.env);
|
|
264075
|
-
|
|
264076
|
-
|
|
264077
|
-
|
|
264078
|
-
|
|
264079
|
-
|
|
264080
|
-
|
|
264081
|
-
|
|
264082
|
-
|
|
264083
|
-
if (imageParts.length > 0) {
|
|
264084
|
-
images = imageParts.map((p) => ({
|
|
264085
|
-
type: "image",
|
|
264086
|
-
data: p.data,
|
|
264087
|
-
mimeType: p.mimeType
|
|
264088
|
-
}));
|
|
264089
|
-
}
|
|
264681
|
+
const promptText = userInput;
|
|
264682
|
+
const promptPromise = session.prompt(promptText);
|
|
264683
|
+
const streamConverter = new PiAISDKStreamConverter({
|
|
264684
|
+
sessionId: session.sessionId,
|
|
264685
|
+
model,
|
|
264686
|
+
redactText: (value2) => {
|
|
264687
|
+
if (options2.env && Object.keys(options2.env).length > 0) {
|
|
264688
|
+
return redactSecrets(value2, options2.env);
|
|
264090
264689
|
}
|
|
264091
|
-
|
|
264092
|
-
|
|
264093
|
-
|
|
264094
|
-
|
|
264095
|
-
|
|
264096
|
-
|
|
264097
|
-
let hasFinished = false;
|
|
264098
|
-
const imageToolUsage = { input_tokens: 0, output_tokens: 0 };
|
|
264099
|
-
const newTextPartId = () => `text_${Date.now()}_${Math.random().toString(36).slice(2)}_${Math.random().toString(36).slice(2)}`;
|
|
264100
|
-
let activeTextPartId = null;
|
|
264101
|
-
let textStreamOpen = false;
|
|
264102
|
-
const endTextStreamIfOpen = function* () {
|
|
264103
|
-
if (textStreamOpen && activeTextPartId != null) {
|
|
264104
|
-
yield `data: ${JSON.stringify({ type: "text-end", id: activeTextPartId })}
|
|
264105
|
-
|
|
264106
|
-
`;
|
|
264107
|
-
textStreamOpen = false;
|
|
264108
|
-
activeTextPartId = null;
|
|
264109
|
-
}
|
|
264110
|
-
};
|
|
264111
|
-
const beginTextStream = function* () {
|
|
264112
|
-
activeTextPartId = newTextPartId();
|
|
264113
|
-
yield `data: ${JSON.stringify({ type: "text-start", id: activeTextPartId })}
|
|
264114
|
-
|
|
264115
|
-
`;
|
|
264116
|
-
textStreamOpen = true;
|
|
264117
|
-
};
|
|
264118
|
-
const ensureStartEvent = async function* () {
|
|
264119
|
-
if (!hasStarted) {
|
|
264120
|
-
yield `data: ${JSON.stringify({ type: "start", messageId })}
|
|
264121
|
-
|
|
264122
|
-
`;
|
|
264123
|
-
yield `data: ${JSON.stringify({
|
|
264124
|
-
type: "message-metadata",
|
|
264125
|
-
messageMetadata: { sessionId: session.sessionId }
|
|
264126
|
-
})}
|
|
264127
|
-
|
|
264128
|
-
`;
|
|
264129
|
-
hasStarted = true;
|
|
264130
|
-
}
|
|
264131
|
-
};
|
|
264132
|
-
const finishSuccess = async function* (usage) {
|
|
264133
|
-
yield* endTextStreamIfOpen();
|
|
264134
|
-
const finishPayload = { type: "finish", finishReason: "stop" };
|
|
264135
|
-
const hasImageUsage = imageToolUsage.input_tokens > 0 || imageToolUsage.output_tokens > 0;
|
|
264136
|
-
if (usage != null || hasImageUsage) {
|
|
264137
|
-
const base = usage != null ? usageToMessageMetadata(usage) : {};
|
|
264138
|
-
finishPayload.messageMetadata = {
|
|
264139
|
-
usage: {
|
|
264140
|
-
...base,
|
|
264141
|
-
input_tokens: (base.input_tokens ?? 0) + imageToolUsage.input_tokens,
|
|
264142
|
-
output_tokens: (base.output_tokens ?? 0) + imageToolUsage.output_tokens
|
|
264143
|
-
}
|
|
264144
|
-
};
|
|
264145
|
-
}
|
|
264146
|
-
yield `data: ${JSON.stringify(finishPayload)}
|
|
264147
|
-
|
|
264148
|
-
`;
|
|
264149
|
-
yield "data: [DONE]\n\n";
|
|
264150
|
-
hasFinished = true;
|
|
264151
|
-
};
|
|
264152
|
-
const finishError = async function* (errorText) {
|
|
264153
|
-
for (const chunk of emitStreamError(errorText)) {
|
|
264154
|
-
yield chunk;
|
|
264155
|
-
}
|
|
264156
|
-
hasFinished = true;
|
|
264157
|
-
};
|
|
264690
|
+
return value2;
|
|
264691
|
+
},
|
|
264692
|
+
normalizeToolOutput: extractToolResultText,
|
|
264693
|
+
getUsageFromAgentEndMessages,
|
|
264694
|
+
getErrorFromAgentEndMessages
|
|
264695
|
+
});
|
|
264158
264696
|
while (!isComplete || eventQueue.length > 0) {
|
|
264159
264697
|
while (eventQueue.length > 0) {
|
|
264160
264698
|
const event = eventQueue.shift();
|
|
264161
264699
|
traceRawMessage(cwd, event, false, options2.env);
|
|
264162
|
-
|
|
264163
|
-
|
|
264164
|
-
|
|
264165
|
-
if (msg?.role === "assistant") {
|
|
264166
|
-
yield* endTextStreamIfOpen();
|
|
264167
|
-
}
|
|
264168
|
-
} else if (event.type === "message_update") {
|
|
264169
|
-
const sub = event.assistantMessageEvent;
|
|
264170
|
-
if (sub.type === "text_start") {
|
|
264171
|
-
yield* endTextStreamIfOpen();
|
|
264172
|
-
yield* beginTextStream();
|
|
264173
|
-
} else if (sub.type === "text_delta") {
|
|
264174
|
-
let delta = sub.delta;
|
|
264175
|
-
if (delta) {
|
|
264176
|
-
if (options2.env && Object.keys(options2.env).length > 0) {
|
|
264177
|
-
delta = redactSecrets(delta, options2.env);
|
|
264178
|
-
}
|
|
264179
|
-
if (!textStreamOpen) {
|
|
264180
|
-
yield* beginTextStream();
|
|
264181
|
-
}
|
|
264182
|
-
yield `data: ${JSON.stringify({
|
|
264183
|
-
type: "text-delta",
|
|
264184
|
-
id: activeTextPartId,
|
|
264185
|
-
delta
|
|
264186
|
-
})}
|
|
264187
|
-
|
|
264188
|
-
`;
|
|
264189
|
-
}
|
|
264190
|
-
} else if (sub.type === "toolcall_start") {
|
|
264191
|
-
yield* endTextStreamIfOpen();
|
|
264192
|
-
}
|
|
264193
|
-
} else if (event.type === "tool_execution_start") {
|
|
264194
|
-
yield* endTextStreamIfOpen();
|
|
264195
|
-
yield `data: ${JSON.stringify({ type: "tool-input-start", toolCallId: event.toolCallId, toolName: event.toolName, dynamic: true, providerExecuted: true })}
|
|
264196
|
-
|
|
264197
|
-
`;
|
|
264198
|
-
yield `data: ${JSON.stringify({ type: "tool-input-available", toolCallId: event.toolCallId, toolName: event.toolName, input: event.args, dynamic: true, providerExecuted: true })}
|
|
264199
|
-
|
|
264200
|
-
`;
|
|
264201
|
-
} else if (event.type === "tool_execution_end") {
|
|
264202
|
-
let output = extractToolResultText(event.result);
|
|
264203
|
-
if (options2.env && Object.keys(options2.env).length > 0) {
|
|
264204
|
-
output = redactSecrets(output, options2.env);
|
|
264205
|
-
}
|
|
264206
|
-
if (event.toolName === "generate_image" && event.result !== null && typeof event.result === "object") {
|
|
264207
|
-
const details = event.result.details;
|
|
264208
|
-
const u = details?.response?.usage;
|
|
264209
|
-
if (u) {
|
|
264210
|
-
imageToolUsage.input_tokens += u.input_tokens ?? 0;
|
|
264211
|
-
imageToolUsage.output_tokens += u.output_tokens ?? 0;
|
|
264212
|
-
}
|
|
264213
|
-
}
|
|
264214
|
-
yield `data: ${JSON.stringify({ type: "tool-output-available", toolCallId: event.toolCallId, output, isError: event.isError, dynamic: true, providerExecuted: true })}
|
|
264215
|
-
|
|
264216
|
-
`;
|
|
264217
|
-
} else if (event.type === "agent_end") {
|
|
264218
|
-
if (aborted) {
|
|
264219
|
-
yield* finishError("Run aborted by signal.");
|
|
264220
|
-
} else {
|
|
264221
|
-
const errorMsg = getErrorFromAgentEndMessages(event.messages);
|
|
264222
|
-
if (errorMsg) {
|
|
264223
|
-
yield* finishError(errorMsg);
|
|
264224
|
-
} else {
|
|
264225
|
-
const usage = getUsageFromAgentEndMessages(event.messages);
|
|
264226
|
-
yield* finishSuccess(usage);
|
|
264227
|
-
}
|
|
264228
|
-
}
|
|
264700
|
+
const chunks = streamConverter.handleEvent(event, aborted);
|
|
264701
|
+
for (const chunk of chunks) {
|
|
264702
|
+
yield chunk;
|
|
264229
264703
|
}
|
|
264230
264704
|
}
|
|
264231
|
-
if (aborted && !
|
|
264232
|
-
|
|
264233
|
-
|
|
264705
|
+
if (aborted && !streamConverter.finished) {
|
|
264706
|
+
for (const chunk of streamConverter.forceError("Run aborted by signal.")) {
|
|
264707
|
+
yield chunk;
|
|
264708
|
+
}
|
|
264234
264709
|
break;
|
|
264235
264710
|
}
|
|
264236
264711
|
if (!isComplete && eventQueue.length === 0) {
|
|
@@ -264239,22 +264714,24 @@ function createPiRunner(options2 = {}) {
|
|
|
264239
264714
|
});
|
|
264240
264715
|
}
|
|
264241
264716
|
}
|
|
264242
|
-
if (
|
|
264717
|
+
if (streamConverter.finished) {
|
|
264243
264718
|
return;
|
|
264244
264719
|
}
|
|
264245
264720
|
try {
|
|
264246
264721
|
await promptPromise;
|
|
264247
264722
|
} catch (error) {
|
|
264248
|
-
if (!
|
|
264249
|
-
yield* ensureStartEvent();
|
|
264723
|
+
if (!streamConverter.finished) {
|
|
264250
264724
|
const message = error instanceof Error ? error.message : "Pi agent run failed.";
|
|
264251
|
-
|
|
264725
|
+
for (const chunk of streamConverter.forceError(message)) {
|
|
264726
|
+
yield chunk;
|
|
264727
|
+
}
|
|
264252
264728
|
}
|
|
264253
264729
|
return;
|
|
264254
264730
|
}
|
|
264255
|
-
if (!
|
|
264256
|
-
|
|
264257
|
-
|
|
264731
|
+
if (!streamConverter.finished && session.agent.state.error) {
|
|
264732
|
+
for (const chunk of streamConverter.forceError(session.agent.state.error)) {
|
|
264733
|
+
yield chunk;
|
|
264734
|
+
}
|
|
264258
264735
|
}
|
|
264259
264736
|
} finally {
|
|
264260
264737
|
if (abortSignal) {
|
|
@@ -264274,11 +264751,11 @@ function createPiRunner(options2 = {}) {
|
|
|
264274
264751
|
|
|
264275
264752
|
// ../../packages/runner-harness/dist/session.js
|
|
264276
264753
|
import { existsSync as existsSync29, mkdirSync as mkdirSync11, readFileSync as readFileSync23, writeFileSync as writeFileSync14 } from "node:fs";
|
|
264277
|
-
import { join as
|
|
264754
|
+
import { join as join37 } from "node:path";
|
|
264278
264755
|
var DIR = ".bunny-agent";
|
|
264279
264756
|
var FILE = "session-id";
|
|
264280
264757
|
function sessionPath(cwd) {
|
|
264281
|
-
return
|
|
264758
|
+
return join37(cwd, DIR, FILE);
|
|
264282
264759
|
}
|
|
264283
264760
|
function readSessionId(cwd) {
|
|
264284
264761
|
try {
|
|
@@ -264292,28 +264769,28 @@ function readSessionId(cwd) {
|
|
|
264292
264769
|
}
|
|
264293
264770
|
function writeSessionId(cwd, id) {
|
|
264294
264771
|
try {
|
|
264295
|
-
mkdirSync11(
|
|
264772
|
+
mkdirSync11(join37(cwd, DIR), { recursive: true });
|
|
264296
264773
|
writeFileSync14(sessionPath(cwd), id, "utf8");
|
|
264297
264774
|
} catch {
|
|
264298
264775
|
}
|
|
264299
264776
|
}
|
|
264300
264777
|
|
|
264301
264778
|
// ../../packages/runner-harness/dist/skills.js
|
|
264302
|
-
import { existsSync as existsSync30, readdirSync as
|
|
264779
|
+
import { existsSync as existsSync30, readdirSync as readdirSync13, statSync as statSync14 } from "node:fs";
|
|
264303
264780
|
import { homedir as homedir14 } from "node:os";
|
|
264304
|
-
import { join as
|
|
264781
|
+
import { join as join38 } from "node:path";
|
|
264305
264782
|
function discoverSkillPaths(cwd) {
|
|
264306
264783
|
const paths = [];
|
|
264307
264784
|
for (const base of [
|
|
264308
|
-
|
|
264309
|
-
|
|
264785
|
+
join38(cwd, "skills"),
|
|
264786
|
+
join38(homedir14(), ".bunny-agent", "skills")
|
|
264310
264787
|
]) {
|
|
264311
264788
|
if (!existsSync30(base))
|
|
264312
264789
|
continue;
|
|
264313
264790
|
try {
|
|
264314
|
-
for (const entry of
|
|
264315
|
-
const full =
|
|
264316
|
-
if (
|
|
264791
|
+
for (const entry of readdirSync13(base)) {
|
|
264792
|
+
const full = join38(base, entry);
|
|
264793
|
+
if (statSync14(full).isDirectory() && existsSync30(join38(full, "SKILL.md"))) {
|
|
264317
264794
|
paths.push(full);
|
|
264318
264795
|
}
|
|
264319
264796
|
}
|
|
@@ -264436,7 +264913,9 @@ async function bunnyAgentRun(req, res, env2) {
|
|
|
264436
264913
|
cwd: req.cwd ?? process.env.BUNNY_AGENT_ROOT ?? "/workspace",
|
|
264437
264914
|
yolo: req.yolo,
|
|
264438
264915
|
env: env2,
|
|
264439
|
-
abortController
|
|
264916
|
+
abortController,
|
|
264917
|
+
// API: caller owns resume/session; do not read/write cwd/.bunny-agent or auto-load CLAUDE.md.
|
|
264918
|
+
autoInject: false
|
|
264440
264919
|
});
|
|
264441
264920
|
for await (const chunk of stream2) {
|
|
264442
264921
|
res.write(chunk);
|