@agentv/core 2.5.3 → 2.5.4
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/index.cjs +1117 -89
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1111 -88
- package/dist/index.js.map +1 -1
- package/package.json +4 -7
package/dist/index.cjs
CHANGED
|
@@ -3377,16 +3377,16 @@ async function runClaudeCodeWithTempFiles(options, stdoutFile, stderrFile, exitF
|
|
|
3377
3377
|
let lastStdoutSize = 0;
|
|
3378
3378
|
const readFileIfExists = async (filePath) => {
|
|
3379
3379
|
try {
|
|
3380
|
-
const { readFile:
|
|
3381
|
-
return await
|
|
3380
|
+
const { readFile: readFile11 } = await import("fs/promises");
|
|
3381
|
+
return await readFile11(filePath, "utf8");
|
|
3382
3382
|
} catch {
|
|
3383
3383
|
return "";
|
|
3384
3384
|
}
|
|
3385
3385
|
};
|
|
3386
3386
|
const fileExists4 = async (filePath) => {
|
|
3387
3387
|
try {
|
|
3388
|
-
const { access:
|
|
3389
|
-
await
|
|
3388
|
+
const { access: access6 } = await import("fs/promises");
|
|
3389
|
+
await access6(filePath);
|
|
3390
3390
|
return true;
|
|
3391
3391
|
} catch {
|
|
3392
3392
|
return false;
|
|
@@ -6239,8 +6239,8 @@ function resolveCliConfig(target, env, evalFilePath) {
|
|
|
6239
6239
|
const parseResult = CliTargetInputSchema.safeParse(target, { errorMap: cliErrorMap });
|
|
6240
6240
|
if (!parseResult.success) {
|
|
6241
6241
|
const firstError = parseResult.error.errors[0];
|
|
6242
|
-
const
|
|
6243
|
-
const prefix =
|
|
6242
|
+
const path28 = firstError?.path.join(".") || "";
|
|
6243
|
+
const prefix = path28 ? `${target.name} ${path28}: ` : `${target.name}: `;
|
|
6244
6244
|
throw new Error(`${prefix}${firstError?.message}`);
|
|
6245
6245
|
}
|
|
6246
6246
|
const normalized = normalizeCliTargetInput(parseResult.data, env, evalFilePath);
|
|
@@ -6427,9 +6427,1037 @@ function resolveOptionalNumberArray(source, description) {
|
|
|
6427
6427
|
return resolved.length > 0 ? resolved : void 0;
|
|
6428
6428
|
}
|
|
6429
6429
|
|
|
6430
|
-
// src/evaluation/providers/vscode.ts
|
|
6430
|
+
// src/evaluation/providers/vscode-provider.ts
|
|
6431
|
+
var import_node_path25 = __toESM(require("path"), 1);
|
|
6432
|
+
|
|
6433
|
+
// src/evaluation/providers/vscode/dispatch/agentDispatch.ts
|
|
6434
|
+
var import_promises17 = require("fs/promises");
|
|
6435
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
6436
|
+
|
|
6437
|
+
// src/evaluation/providers/vscode/utils/fs.ts
|
|
6438
|
+
var import_node_fs6 = require("fs");
|
|
6439
|
+
var import_promises13 = require("fs/promises");
|
|
6431
6440
|
var import_node_path15 = __toESM(require("path"), 1);
|
|
6432
|
-
|
|
6441
|
+
async function pathExists(target) {
|
|
6442
|
+
try {
|
|
6443
|
+
await (0, import_promises13.access)(target, import_node_fs6.constants.F_OK);
|
|
6444
|
+
return true;
|
|
6445
|
+
} catch {
|
|
6446
|
+
return false;
|
|
6447
|
+
}
|
|
6448
|
+
}
|
|
6449
|
+
async function ensureDir(target) {
|
|
6450
|
+
await (0, import_promises13.mkdir)(target, { recursive: true });
|
|
6451
|
+
}
|
|
6452
|
+
async function readDirEntries(target) {
|
|
6453
|
+
const entries = await (0, import_promises13.readdir)(target, { withFileTypes: true });
|
|
6454
|
+
return entries.map((entry) => ({
|
|
6455
|
+
name: entry.name,
|
|
6456
|
+
absolutePath: import_node_path15.default.join(target, entry.name),
|
|
6457
|
+
isDirectory: entry.isDirectory()
|
|
6458
|
+
}));
|
|
6459
|
+
}
|
|
6460
|
+
async function removeIfExists(target) {
|
|
6461
|
+
try {
|
|
6462
|
+
await (0, import_promises13.rm)(target, { force: true, recursive: false });
|
|
6463
|
+
} catch (error) {
|
|
6464
|
+
if (error.code !== "ENOENT") {
|
|
6465
|
+
throw error;
|
|
6466
|
+
}
|
|
6467
|
+
}
|
|
6468
|
+
}
|
|
6469
|
+
|
|
6470
|
+
// src/evaluation/providers/vscode/utils/path.ts
|
|
6471
|
+
var import_node_path16 = __toESM(require("path"), 1);
|
|
6472
|
+
function pathToFileUri2(filePath) {
|
|
6473
|
+
const absolutePath = import_node_path16.default.isAbsolute(filePath) ? filePath : import_node_path16.default.resolve(filePath);
|
|
6474
|
+
const normalizedPath = absolutePath.replace(/\\/g, "/");
|
|
6475
|
+
if (/^[a-zA-Z]:\//.test(normalizedPath)) {
|
|
6476
|
+
return `file:///${normalizedPath}`;
|
|
6477
|
+
}
|
|
6478
|
+
return `file://${normalizedPath}`;
|
|
6479
|
+
}
|
|
6480
|
+
|
|
6481
|
+
// src/evaluation/providers/vscode/dispatch/promptBuilder.ts
|
|
6482
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
6483
|
+
|
|
6484
|
+
// src/evaluation/providers/vscode/utils/template.ts
|
|
6485
|
+
function renderTemplate2(content, variables) {
|
|
6486
|
+
if (!content) {
|
|
6487
|
+
return content;
|
|
6488
|
+
}
|
|
6489
|
+
const variableLookup = /* @__PURE__ */ new Map();
|
|
6490
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
6491
|
+
variableLookup.set(key.toLowerCase(), value);
|
|
6492
|
+
}
|
|
6493
|
+
const referencedVariables = /* @__PURE__ */ new Set();
|
|
6494
|
+
const result = content.replace(/\{\{([a-zA-Z_]+)\}\}/gi, (match, variableName) => {
|
|
6495
|
+
const lowerCaseKey = variableName.toLowerCase();
|
|
6496
|
+
referencedVariables.add(lowerCaseKey);
|
|
6497
|
+
if (!variableLookup.has(lowerCaseKey)) {
|
|
6498
|
+
throw new Error(
|
|
6499
|
+
`Template variable '${variableName}' is not provided in the variables object`
|
|
6500
|
+
);
|
|
6501
|
+
}
|
|
6502
|
+
return variableLookup.get(lowerCaseKey);
|
|
6503
|
+
});
|
|
6504
|
+
return result;
|
|
6505
|
+
}
|
|
6506
|
+
|
|
6507
|
+
// src/evaluation/providers/vscode/dispatch/templates.ts
|
|
6508
|
+
var DEFAULT_REQUEST_TEMPLATE = `[[ ## task ## ]]
|
|
6509
|
+
|
|
6510
|
+
{{userQuery}}
|
|
6511
|
+
|
|
6512
|
+
[[ ## system_instructions ## ]]
|
|
6513
|
+
|
|
6514
|
+
**IMPORTANT**: Follow these exact steps:
|
|
6515
|
+
1. Create and write your complete response to: {{responseFileTmp}}
|
|
6516
|
+
2. When completely finished, run these PowerShell commands to signal completion:
|
|
6517
|
+
\`\`\`
|
|
6518
|
+
Move-Item -LiteralPath '{{responseFileTmp}}' -Destination '{{responseFileFinal}}'
|
|
6519
|
+
if (Test-Path subagent.lock) { del subagent.lock }
|
|
6520
|
+
\`\`\`
|
|
6521
|
+
|
|
6522
|
+
Do not proceed to step 2 until your response is completely written to the temporary file.
|
|
6523
|
+
`;
|
|
6524
|
+
var DEFAULT_BATCH_REQUEST_TEMPLATE = `[[ ## task ## ]]
|
|
6525
|
+
|
|
6526
|
+
{{userQuery}}
|
|
6527
|
+
|
|
6528
|
+
[[ ## system_instructions ## ]]
|
|
6529
|
+
|
|
6530
|
+
**IMPORTANT**: Follow these exact steps:
|
|
6531
|
+
1. Create and write your complete response to: {{responseFileTmp}}
|
|
6532
|
+
2. When completely finished and the response is stable, rename it to: {{responseFileFinal}}
|
|
6533
|
+
3. Do not unlock the workspace from this request; batch orchestration will handle unlocking after all responses are ready.
|
|
6534
|
+
`;
|
|
6535
|
+
var DEFAULT_BATCH_ORCHESTRATOR_TEMPLATE = `MANDATORY: Run #runSubagent tool in your Available Actions for each request file to process them in isolated contexts.
|
|
6536
|
+
DO NOT read the request files yourself - only pass the file paths to each subagent:
|
|
6537
|
+
|
|
6538
|
+
{{requestFiles}}
|
|
6539
|
+
|
|
6540
|
+
After ALL queries complete, verify all responses exist and unlock:
|
|
6541
|
+
|
|
6542
|
+
\`\`\`powershell
|
|
6543
|
+
$responses = @({{responseList}})
|
|
6544
|
+
$missing = $responses | Where-Object { -not (Test-Path "messages/$_") }
|
|
6545
|
+
if ($missing.Count -eq 0) { del subagent.lock }
|
|
6546
|
+
\`\`\`
|
|
6547
|
+
`;
|
|
6548
|
+
|
|
6549
|
+
// src/evaluation/providers/vscode/dispatch/promptBuilder.ts
|
|
6550
|
+
function loadDefaultRequestTemplate() {
|
|
6551
|
+
return DEFAULT_REQUEST_TEMPLATE;
|
|
6552
|
+
}
|
|
6553
|
+
function loadDefaultBatchRequestTemplate() {
|
|
6554
|
+
return DEFAULT_BATCH_REQUEST_TEMPLATE;
|
|
6555
|
+
}
|
|
6556
|
+
function loadDefaultBatchOrchestratorTemplate() {
|
|
6557
|
+
return DEFAULT_BATCH_ORCHESTRATOR_TEMPLATE;
|
|
6558
|
+
}
|
|
6559
|
+
function createRequestPrompt(userQuery, responseFileTmp, responseFileFinal, templateContent) {
|
|
6560
|
+
return renderTemplate2(templateContent, {
|
|
6561
|
+
userQuery,
|
|
6562
|
+
responseFileTmp,
|
|
6563
|
+
responseFileFinal
|
|
6564
|
+
});
|
|
6565
|
+
}
|
|
6566
|
+
function createBatchRequestPrompt(userQuery, responseFileTmp, responseFileFinal, templateContent) {
|
|
6567
|
+
return renderTemplate2(templateContent, {
|
|
6568
|
+
userQuery,
|
|
6569
|
+
responseFileTmp,
|
|
6570
|
+
responseFileFinal
|
|
6571
|
+
});
|
|
6572
|
+
}
|
|
6573
|
+
function createBatchOrchestratorPrompt(requestFiles, responseFiles, templateContent) {
|
|
6574
|
+
const requestLines = requestFiles.map((file, index) => `${index + 1}. messages/${import_node_path17.default.basename(file)}`).join("\n");
|
|
6575
|
+
const responseList = responseFiles.map((file) => `"${import_node_path17.default.basename(file)}"`).join(", ");
|
|
6576
|
+
return renderTemplate2(templateContent, {
|
|
6577
|
+
requestFiles: requestLines,
|
|
6578
|
+
responseList
|
|
6579
|
+
});
|
|
6580
|
+
}
|
|
6581
|
+
|
|
6582
|
+
// src/evaluation/providers/vscode/dispatch/responseWaiter.ts
|
|
6583
|
+
var import_promises14 = require("fs/promises");
|
|
6584
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
6585
|
+
|
|
6586
|
+
// src/evaluation/providers/vscode/utils/time.ts
|
|
6587
|
+
function sleep2(ms) {
|
|
6588
|
+
return new Promise((resolve) => {
|
|
6589
|
+
setTimeout(resolve, ms);
|
|
6590
|
+
});
|
|
6591
|
+
}
|
|
6592
|
+
|
|
6593
|
+
// src/evaluation/providers/vscode/dispatch/responseWaiter.ts
|
|
6594
|
+
async function waitForResponseOutput(responseFileFinal, pollInterval = 1e3, silent = false) {
|
|
6595
|
+
if (!silent) {
|
|
6596
|
+
console.error(`waiting for agent to finish: ${responseFileFinal}`);
|
|
6597
|
+
}
|
|
6598
|
+
try {
|
|
6599
|
+
while (!await pathExists(responseFileFinal)) {
|
|
6600
|
+
await sleep2(pollInterval);
|
|
6601
|
+
}
|
|
6602
|
+
} catch (error) {
|
|
6603
|
+
if (error.code === "ENOENT") {
|
|
6604
|
+
return false;
|
|
6605
|
+
}
|
|
6606
|
+
throw error;
|
|
6607
|
+
}
|
|
6608
|
+
let attempts = 0;
|
|
6609
|
+
const maxAttempts = 10;
|
|
6610
|
+
while (attempts < maxAttempts) {
|
|
6611
|
+
try {
|
|
6612
|
+
const content = await (0, import_promises14.readFile)(responseFileFinal, { encoding: "utf8" });
|
|
6613
|
+
if (!silent) {
|
|
6614
|
+
process.stdout.write(`${content}
|
|
6615
|
+
`);
|
|
6616
|
+
}
|
|
6617
|
+
return true;
|
|
6618
|
+
} catch (error) {
|
|
6619
|
+
attempts += 1;
|
|
6620
|
+
if (error.code !== "EBUSY" || attempts >= maxAttempts) {
|
|
6621
|
+
if (!silent) {
|
|
6622
|
+
console.error(`error: failed to read agent response: ${error.message}`);
|
|
6623
|
+
}
|
|
6624
|
+
return false;
|
|
6625
|
+
}
|
|
6626
|
+
await sleep2(pollInterval);
|
|
6627
|
+
}
|
|
6628
|
+
}
|
|
6629
|
+
return false;
|
|
6630
|
+
}
|
|
6631
|
+
async function waitForBatchResponses(responseFilesFinal, pollInterval = 1e3, silent = false) {
|
|
6632
|
+
if (!silent) {
|
|
6633
|
+
const fileList = responseFilesFinal.map((file) => import_node_path18.default.basename(file)).join(", ");
|
|
6634
|
+
console.error(`waiting for ${responseFilesFinal.length} batch response(s): ${fileList}`);
|
|
6635
|
+
}
|
|
6636
|
+
try {
|
|
6637
|
+
const pending = new Set(responseFilesFinal);
|
|
6638
|
+
while (pending.size > 0) {
|
|
6639
|
+
for (const file of [...pending]) {
|
|
6640
|
+
if (await pathExists(file)) {
|
|
6641
|
+
pending.delete(file);
|
|
6642
|
+
}
|
|
6643
|
+
}
|
|
6644
|
+
if (pending.size > 0) {
|
|
6645
|
+
await sleep2(pollInterval);
|
|
6646
|
+
}
|
|
6647
|
+
}
|
|
6648
|
+
} catch (error) {
|
|
6649
|
+
if (error.code === "ENOENT") {
|
|
6650
|
+
return false;
|
|
6651
|
+
}
|
|
6652
|
+
throw error;
|
|
6653
|
+
}
|
|
6654
|
+
for (const file of responseFilesFinal) {
|
|
6655
|
+
let attempts = 0;
|
|
6656
|
+
const maxAttempts = 10;
|
|
6657
|
+
while (attempts < maxAttempts) {
|
|
6658
|
+
try {
|
|
6659
|
+
const content = await (0, import_promises14.readFile)(file, { encoding: "utf8" });
|
|
6660
|
+
if (!silent) {
|
|
6661
|
+
process.stdout.write(`${content}
|
|
6662
|
+
`);
|
|
6663
|
+
}
|
|
6664
|
+
break;
|
|
6665
|
+
} catch (error) {
|
|
6666
|
+
attempts += 1;
|
|
6667
|
+
if (error.code !== "EBUSY" || attempts >= maxAttempts) {
|
|
6668
|
+
if (!silent) {
|
|
6669
|
+
console.error(`error: failed to read agent response: ${error.message}`);
|
|
6670
|
+
}
|
|
6671
|
+
return false;
|
|
6672
|
+
}
|
|
6673
|
+
await sleep2(pollInterval);
|
|
6674
|
+
}
|
|
6675
|
+
}
|
|
6676
|
+
}
|
|
6677
|
+
return true;
|
|
6678
|
+
}
|
|
6679
|
+
|
|
6680
|
+
// src/evaluation/providers/vscode/dispatch/vscodeProcess.ts
|
|
6681
|
+
var import_node_child_process5 = require("child_process");
|
|
6682
|
+
var import_promises15 = require("fs/promises");
|
|
6683
|
+
var import_node_path20 = __toESM(require("path"), 1);
|
|
6684
|
+
var import_node_util3 = require("util");
|
|
6685
|
+
|
|
6686
|
+
// src/evaluation/providers/vscode/dispatch/constants.ts
|
|
6687
|
+
var import_node_os5 = __toESM(require("os"), 1);
|
|
6688
|
+
var import_node_path19 = __toESM(require("path"), 1);
|
|
6689
|
+
var DEFAULT_LOCK_NAME = "subagent.lock";
|
|
6690
|
+
var DEFAULT_ALIVE_FILENAME = ".alive";
|
|
6691
|
+
function getDefaultSubagentRoot(vscodeCmd = "code") {
|
|
6692
|
+
const folder = vscodeCmd === "code-insiders" ? "vscode-insiders-agents" : "vscode-agents";
|
|
6693
|
+
return import_node_path19.default.join(import_node_os5.default.homedir(), ".agentv", "subagents", folder);
|
|
6694
|
+
}
|
|
6695
|
+
var DEFAULT_SUBAGENT_ROOT = getDefaultSubagentRoot();
|
|
6696
|
+
|
|
6697
|
+
// src/evaluation/providers/vscode/dispatch/vscodeProcess.ts
|
|
6698
|
+
var execAsync3 = (0, import_node_util3.promisify)(import_node_child_process5.exec);
|
|
6699
|
+
var DEFAULT_WAKEUP_CONTENT = `---
|
|
6700
|
+
description: 'Wake-up Signal'
|
|
6701
|
+
model: Grok Code Fast 1 (copilot)
|
|
6702
|
+
---`;
|
|
6703
|
+
async function checkWorkspaceOpened(workspaceName, vscodeCmd) {
|
|
6704
|
+
try {
|
|
6705
|
+
const { stdout } = await execAsync3(`${vscodeCmd} --status`, {
|
|
6706
|
+
timeout: 1e4,
|
|
6707
|
+
windowsHide: true
|
|
6708
|
+
});
|
|
6709
|
+
return stdout.includes(workspaceName);
|
|
6710
|
+
} catch {
|
|
6711
|
+
return false;
|
|
6712
|
+
}
|
|
6713
|
+
}
|
|
6714
|
+
async function ensureWorkspaceFocused(workspacePath, workspaceName, subagentDir, vscodeCmd, pollInterval = 1, timeout = 60) {
|
|
6715
|
+
const alreadyOpen = await checkWorkspaceOpened(workspaceName, vscodeCmd);
|
|
6716
|
+
if (alreadyOpen) {
|
|
6717
|
+
(0, import_node_child_process5.spawn)(vscodeCmd, [workspacePath], { windowsHide: true, shell: true, detached: false });
|
|
6718
|
+
return true;
|
|
6719
|
+
}
|
|
6720
|
+
const aliveFile = import_node_path20.default.join(subagentDir, DEFAULT_ALIVE_FILENAME);
|
|
6721
|
+
await removeIfExists(aliveFile);
|
|
6722
|
+
const githubAgentsDir = import_node_path20.default.join(subagentDir, ".github", "agents");
|
|
6723
|
+
await (0, import_promises15.mkdir)(githubAgentsDir, { recursive: true });
|
|
6724
|
+
const wakeupDst = import_node_path20.default.join(githubAgentsDir, "wakeup.md");
|
|
6725
|
+
await (0, import_promises15.writeFile)(wakeupDst, DEFAULT_WAKEUP_CONTENT, "utf8");
|
|
6726
|
+
(0, import_node_child_process5.spawn)(vscodeCmd, [workspacePath], { windowsHide: true, shell: true, detached: false });
|
|
6727
|
+
await sleep2(100);
|
|
6728
|
+
const wakeupChatId = "wakeup";
|
|
6729
|
+
const chatArgs = [
|
|
6730
|
+
"-r",
|
|
6731
|
+
"chat",
|
|
6732
|
+
"-m",
|
|
6733
|
+
wakeupChatId,
|
|
6734
|
+
`create a file named .alive in the ${import_node_path20.default.basename(subagentDir)} folder`
|
|
6735
|
+
];
|
|
6736
|
+
(0, import_node_child_process5.spawn)(vscodeCmd, chatArgs, { windowsHide: true, shell: true, detached: false });
|
|
6737
|
+
const start = Date.now();
|
|
6738
|
+
while (!await pathExists(aliveFile)) {
|
|
6739
|
+
if (Date.now() - start > timeout * 1e3) {
|
|
6740
|
+
console.error(`warning: Workspace readiness timeout after ${timeout}s`);
|
|
6741
|
+
return false;
|
|
6742
|
+
}
|
|
6743
|
+
await sleep2(pollInterval * 1e3);
|
|
6744
|
+
}
|
|
6745
|
+
return true;
|
|
6746
|
+
}
|
|
6747
|
+
async function launchVsCodeWithChat(subagentDir, chatId, attachmentPaths, requestInstructions, timestamp, vscodeCmd) {
|
|
6748
|
+
try {
|
|
6749
|
+
const workspacePath = import_node_path20.default.join(subagentDir, `${import_node_path20.default.basename(subagentDir)}.code-workspace`);
|
|
6750
|
+
const messagesDir = import_node_path20.default.join(subagentDir, "messages");
|
|
6751
|
+
await (0, import_promises15.mkdir)(messagesDir, { recursive: true });
|
|
6752
|
+
const reqFile = import_node_path20.default.join(messagesDir, `${timestamp}_req.md`);
|
|
6753
|
+
await (0, import_promises15.writeFile)(reqFile, requestInstructions, { encoding: "utf8" });
|
|
6754
|
+
const reqUri = pathToFileUri2(reqFile);
|
|
6755
|
+
const chatArgs = ["-r", "chat", "-m", chatId];
|
|
6756
|
+
for (const attachment of attachmentPaths) {
|
|
6757
|
+
chatArgs.push("-a", attachment);
|
|
6758
|
+
}
|
|
6759
|
+
chatArgs.push("-a", reqFile);
|
|
6760
|
+
chatArgs.push(`Follow instructions in [${import_node_path20.default.basename(reqFile)}](${reqUri})`);
|
|
6761
|
+
const workspaceReady = await ensureWorkspaceFocused(
|
|
6762
|
+
workspacePath,
|
|
6763
|
+
import_node_path20.default.basename(subagentDir),
|
|
6764
|
+
subagentDir,
|
|
6765
|
+
vscodeCmd
|
|
6766
|
+
);
|
|
6767
|
+
if (!workspaceReady) {
|
|
6768
|
+
console.error("warning: Workspace may not be fully ready");
|
|
6769
|
+
}
|
|
6770
|
+
await sleep2(500);
|
|
6771
|
+
(0, import_node_child_process5.spawn)(vscodeCmd, chatArgs, { windowsHide: true, shell: true, detached: false });
|
|
6772
|
+
return true;
|
|
6773
|
+
} catch (error) {
|
|
6774
|
+
console.error(`warning: Failed to launch VS Code: ${error.message}`);
|
|
6775
|
+
return false;
|
|
6776
|
+
}
|
|
6777
|
+
}
|
|
6778
|
+
async function launchVsCodeWithBatchChat(subagentDir, chatId, attachmentPaths, chatInstruction, vscodeCmd) {
|
|
6779
|
+
try {
|
|
6780
|
+
const workspacePath = import_node_path20.default.join(subagentDir, `${import_node_path20.default.basename(subagentDir)}.code-workspace`);
|
|
6781
|
+
const messagesDir = import_node_path20.default.join(subagentDir, "messages");
|
|
6782
|
+
await (0, import_promises15.mkdir)(messagesDir, { recursive: true });
|
|
6783
|
+
const chatArgs = ["-r", "chat", "-m", chatId];
|
|
6784
|
+
for (const attachment of attachmentPaths) {
|
|
6785
|
+
chatArgs.push("-a", attachment);
|
|
6786
|
+
}
|
|
6787
|
+
chatArgs.push(chatInstruction);
|
|
6788
|
+
const workspaceReady = await ensureWorkspaceFocused(
|
|
6789
|
+
workspacePath,
|
|
6790
|
+
import_node_path20.default.basename(subagentDir),
|
|
6791
|
+
subagentDir,
|
|
6792
|
+
vscodeCmd
|
|
6793
|
+
);
|
|
6794
|
+
if (!workspaceReady) {
|
|
6795
|
+
console.error("warning: Workspace may not be fully ready");
|
|
6796
|
+
}
|
|
6797
|
+
await sleep2(500);
|
|
6798
|
+
(0, import_node_child_process5.spawn)(vscodeCmd, chatArgs, { windowsHide: true, shell: true, detached: false });
|
|
6799
|
+
return true;
|
|
6800
|
+
} catch (error) {
|
|
6801
|
+
console.error(`warning: Failed to launch VS Code: ${error.message}`);
|
|
6802
|
+
return false;
|
|
6803
|
+
}
|
|
6804
|
+
}
|
|
6805
|
+
|
|
6806
|
+
// src/evaluation/providers/vscode/dispatch/workspaceManager.ts
|
|
6807
|
+
var import_promises16 = require("fs/promises");
|
|
6808
|
+
var import_node_path22 = __toESM(require("path"), 1);
|
|
6809
|
+
|
|
6810
|
+
// src/evaluation/providers/vscode/utils/workspace.ts
|
|
6811
|
+
var import_node_path21 = __toESM(require("path"), 1);
|
|
6812
|
+
var import_json5 = __toESM(require("json5"), 1);
|
|
6813
|
+
function transformWorkspacePaths(workspaceContent, templateDir) {
|
|
6814
|
+
let workspace;
|
|
6815
|
+
try {
|
|
6816
|
+
workspace = import_json5.default.parse(workspaceContent);
|
|
6817
|
+
} catch (error) {
|
|
6818
|
+
throw new Error(`Invalid workspace JSON: ${error.message}`);
|
|
6819
|
+
}
|
|
6820
|
+
if (!workspace.folders) {
|
|
6821
|
+
throw new Error("Workspace file must contain a 'folders' array");
|
|
6822
|
+
}
|
|
6823
|
+
if (!Array.isArray(workspace.folders)) {
|
|
6824
|
+
throw new Error("Workspace 'folders' must be an array");
|
|
6825
|
+
}
|
|
6826
|
+
const transformedFolders = workspace.folders.map((folder) => {
|
|
6827
|
+
const folderPath = folder.path;
|
|
6828
|
+
if (import_node_path21.default.isAbsolute(folderPath)) {
|
|
6829
|
+
return folder;
|
|
6830
|
+
}
|
|
6831
|
+
const absolutePath = import_node_path21.default.resolve(templateDir, folderPath);
|
|
6832
|
+
return {
|
|
6833
|
+
...folder,
|
|
6834
|
+
path: absolutePath
|
|
6835
|
+
};
|
|
6836
|
+
});
|
|
6837
|
+
const updatedFolders = [{ path: "." }, ...transformedFolders];
|
|
6838
|
+
let transformedSettings = workspace.settings;
|
|
6839
|
+
if (workspace.settings) {
|
|
6840
|
+
transformedSettings = {
|
|
6841
|
+
...workspace.settings
|
|
6842
|
+
};
|
|
6843
|
+
const chatSettingsKeys = [
|
|
6844
|
+
"chat.promptFilesLocations",
|
|
6845
|
+
"chat.instructionsFilesLocations",
|
|
6846
|
+
"chat.modeFilesLocations"
|
|
6847
|
+
];
|
|
6848
|
+
for (const settingKey of chatSettingsKeys) {
|
|
6849
|
+
const locationMap = workspace.settings[settingKey];
|
|
6850
|
+
if (locationMap && typeof locationMap === "object") {
|
|
6851
|
+
const transformedMap = {};
|
|
6852
|
+
for (const [locationPath, value] of Object.entries(locationMap)) {
|
|
6853
|
+
const isAbsolute = import_node_path21.default.isAbsolute(locationPath);
|
|
6854
|
+
if (isAbsolute) {
|
|
6855
|
+
transformedMap[locationPath] = value;
|
|
6856
|
+
} else {
|
|
6857
|
+
const firstGlobIndex = locationPath.search(/[*]/);
|
|
6858
|
+
if (firstGlobIndex === -1) {
|
|
6859
|
+
const resolvedPath = import_node_path21.default.resolve(templateDir, locationPath).replace(/\\/g, "/");
|
|
6860
|
+
transformedMap[resolvedPath] = value;
|
|
6861
|
+
} else {
|
|
6862
|
+
const basePathEnd = locationPath.lastIndexOf("/", firstGlobIndex);
|
|
6863
|
+
const basePath = basePathEnd !== -1 ? locationPath.substring(0, basePathEnd) : ".";
|
|
6864
|
+
const patternPath = locationPath.substring(basePathEnd !== -1 ? basePathEnd : 0);
|
|
6865
|
+
const resolvedPath = (import_node_path21.default.resolve(templateDir, basePath) + patternPath).replace(
|
|
6866
|
+
/\\/g,
|
|
6867
|
+
"/"
|
|
6868
|
+
);
|
|
6869
|
+
transformedMap[resolvedPath] = value;
|
|
6870
|
+
}
|
|
6871
|
+
}
|
|
6872
|
+
}
|
|
6873
|
+
transformedSettings[settingKey] = transformedMap;
|
|
6874
|
+
}
|
|
6875
|
+
}
|
|
6876
|
+
}
|
|
6877
|
+
const transformedWorkspace = {
|
|
6878
|
+
...workspace,
|
|
6879
|
+
folders: updatedFolders,
|
|
6880
|
+
settings: transformedSettings
|
|
6881
|
+
};
|
|
6882
|
+
return JSON.stringify(transformedWorkspace, null, 2);
|
|
6883
|
+
}
|
|
6884
|
+
|
|
6885
|
+
// src/evaluation/providers/vscode/dispatch/workspaceManager.ts
|
|
6886
|
+
var DEFAULT_WORKSPACE_TEMPLATE = {
|
|
6887
|
+
folders: [
|
|
6888
|
+
{
|
|
6889
|
+
path: "."
|
|
6890
|
+
}
|
|
6891
|
+
]
|
|
6892
|
+
};
|
|
6893
|
+
function getSubagentRoot(vscodeCmd = "code") {
|
|
6894
|
+
return getDefaultSubagentRoot(vscodeCmd);
|
|
6895
|
+
}
|
|
6896
|
+
async function findUnlockedSubagent(subagentRoot) {
|
|
6897
|
+
if (!await pathExists(subagentRoot)) {
|
|
6898
|
+
return null;
|
|
6899
|
+
}
|
|
6900
|
+
const entries = await readDirEntries(subagentRoot);
|
|
6901
|
+
const subagents = entries.filter((entry) => entry.isDirectory && entry.name.startsWith("subagent-")).map((entry) => ({
|
|
6902
|
+
absolutePath: entry.absolutePath,
|
|
6903
|
+
number: Number.parseInt(entry.name.split("-")[1] ?? "", 10)
|
|
6904
|
+
})).filter((entry) => Number.isInteger(entry.number)).sort((a, b) => a.number - b.number);
|
|
6905
|
+
for (const subagent of subagents) {
|
|
6906
|
+
const lockFile = import_node_path22.default.join(subagent.absolutePath, DEFAULT_LOCK_NAME);
|
|
6907
|
+
if (!await pathExists(lockFile)) {
|
|
6908
|
+
return subagent.absolutePath;
|
|
6909
|
+
}
|
|
6910
|
+
}
|
|
6911
|
+
return null;
|
|
6912
|
+
}
|
|
6913
|
+
async function copyAgentConfig(subagentDir, workspaceTemplate) {
|
|
6914
|
+
let workspaceContent;
|
|
6915
|
+
if (workspaceTemplate) {
|
|
6916
|
+
const workspaceSrc = import_node_path22.default.resolve(workspaceTemplate);
|
|
6917
|
+
if (!await pathExists(workspaceSrc)) {
|
|
6918
|
+
throw new Error(`workspace template not found: ${workspaceSrc}`);
|
|
6919
|
+
}
|
|
6920
|
+
const stats = await (0, import_promises16.stat)(workspaceSrc);
|
|
6921
|
+
if (!stats.isFile()) {
|
|
6922
|
+
throw new Error(`workspace template must be a file, not a directory: ${workspaceSrc}`);
|
|
6923
|
+
}
|
|
6924
|
+
const templateText = await (0, import_promises16.readFile)(workspaceSrc, "utf8");
|
|
6925
|
+
workspaceContent = JSON.parse(templateText);
|
|
6926
|
+
} else {
|
|
6927
|
+
workspaceContent = DEFAULT_WORKSPACE_TEMPLATE;
|
|
6928
|
+
}
|
|
6929
|
+
const workspaceName = `${import_node_path22.default.basename(subagentDir)}.code-workspace`;
|
|
6930
|
+
const workspaceDst = import_node_path22.default.join(subagentDir, workspaceName);
|
|
6931
|
+
const templateDir = workspaceTemplate ? import_node_path22.default.dirname(import_node_path22.default.resolve(workspaceTemplate)) : subagentDir;
|
|
6932
|
+
const workspaceJson = JSON.stringify(workspaceContent, null, 2);
|
|
6933
|
+
const transformedContent = transformWorkspacePaths(workspaceJson, templateDir);
|
|
6934
|
+
await (0, import_promises16.writeFile)(workspaceDst, transformedContent, "utf8");
|
|
6935
|
+
const messagesDir = import_node_path22.default.join(subagentDir, "messages");
|
|
6936
|
+
await (0, import_promises16.mkdir)(messagesDir, { recursive: true });
|
|
6937
|
+
return { workspace: workspaceDst, messagesDir };
|
|
6938
|
+
}
|
|
6939
|
+
async function createSubagentLock(subagentDir) {
|
|
6940
|
+
const messagesDir = import_node_path22.default.join(subagentDir, "messages");
|
|
6941
|
+
if (await pathExists(messagesDir)) {
|
|
6942
|
+
const files = await (0, import_promises16.readdir)(messagesDir);
|
|
6943
|
+
await Promise.all(
|
|
6944
|
+
files.map(async (file) => {
|
|
6945
|
+
const target = import_node_path22.default.join(messagesDir, file);
|
|
6946
|
+
await removeIfExists(target);
|
|
6947
|
+
})
|
|
6948
|
+
);
|
|
6949
|
+
}
|
|
6950
|
+
const githubAgentsDir = import_node_path22.default.join(subagentDir, ".github", "agents");
|
|
6951
|
+
if (await pathExists(githubAgentsDir)) {
|
|
6952
|
+
const agentFiles = await (0, import_promises16.readdir)(githubAgentsDir);
|
|
6953
|
+
const preservedFiles = /* @__PURE__ */ new Set(["wakeup.md", "subagent.md"]);
|
|
6954
|
+
await Promise.all(
|
|
6955
|
+
agentFiles.filter((file) => file.endsWith(".md") && !preservedFiles.has(file)).map((file) => removeIfExists(import_node_path22.default.join(githubAgentsDir, file)))
|
|
6956
|
+
);
|
|
6957
|
+
}
|
|
6958
|
+
const lockFile = import_node_path22.default.join(subagentDir, DEFAULT_LOCK_NAME);
|
|
6959
|
+
await (0, import_promises16.writeFile)(lockFile, "", { encoding: "utf8" });
|
|
6960
|
+
return lockFile;
|
|
6961
|
+
}
|
|
6962
|
+
async function removeSubagentLock(subagentDir) {
|
|
6963
|
+
const lockFile = import_node_path22.default.join(subagentDir, DEFAULT_LOCK_NAME);
|
|
6964
|
+
await removeIfExists(lockFile);
|
|
6965
|
+
}
|
|
6966
|
+
async function prepareSubagentDirectory(subagentDir, promptFile, chatId, workspaceTemplate, dryRun) {
|
|
6967
|
+
if (dryRun) {
|
|
6968
|
+
return 0;
|
|
6969
|
+
}
|
|
6970
|
+
try {
|
|
6971
|
+
await copyAgentConfig(subagentDir, workspaceTemplate);
|
|
6972
|
+
} catch (error) {
|
|
6973
|
+
console.error(`error: ${error.message}`);
|
|
6974
|
+
return 1;
|
|
6975
|
+
}
|
|
6976
|
+
try {
|
|
6977
|
+
await createSubagentLock(subagentDir);
|
|
6978
|
+
} catch (error) {
|
|
6979
|
+
console.error(`error: Failed to create subagent lock: ${error.message}`);
|
|
6980
|
+
return 1;
|
|
6981
|
+
}
|
|
6982
|
+
if (promptFile) {
|
|
6983
|
+
const githubAgentsDir = import_node_path22.default.join(subagentDir, ".github", "agents");
|
|
6984
|
+
await (0, import_promises16.mkdir)(githubAgentsDir, { recursive: true });
|
|
6985
|
+
const agentFile = import_node_path22.default.join(githubAgentsDir, `${chatId}.md`);
|
|
6986
|
+
try {
|
|
6987
|
+
await (0, import_promises16.copyFile)(promptFile, agentFile);
|
|
6988
|
+
} catch (error) {
|
|
6989
|
+
console.error(`error: Failed to copy prompt file to agent mode: ${error.message}`);
|
|
6990
|
+
return 1;
|
|
6991
|
+
}
|
|
6992
|
+
}
|
|
6993
|
+
return 0;
|
|
6994
|
+
}
|
|
6995
|
+
|
|
6996
|
+
// src/evaluation/providers/vscode/dispatch/agentDispatch.ts
|
|
6997
|
+
function generateTimestamp() {
|
|
6998
|
+
return (/* @__PURE__ */ new Date()).toISOString().replace(/[-:TZ.]/g, "").slice(0, 14);
|
|
6999
|
+
}
|
|
7000
|
+
async function resolvePromptFile(promptFile) {
|
|
7001
|
+
if (!promptFile) {
|
|
7002
|
+
return void 0;
|
|
7003
|
+
}
|
|
7004
|
+
const resolvedPrompt = import_node_path23.default.resolve(promptFile);
|
|
7005
|
+
if (!await pathExists(resolvedPrompt)) {
|
|
7006
|
+
throw new Error(`Prompt file not found: ${resolvedPrompt}`);
|
|
7007
|
+
}
|
|
7008
|
+
const promptStats = await (0, import_promises17.stat)(resolvedPrompt);
|
|
7009
|
+
if (!promptStats.isFile()) {
|
|
7010
|
+
throw new Error(`Prompt file must be a file, not a directory: ${resolvedPrompt}`);
|
|
7011
|
+
}
|
|
7012
|
+
return resolvedPrompt;
|
|
7013
|
+
}
|
|
7014
|
+
async function resolveAttachments(extraAttachments) {
|
|
7015
|
+
if (!extraAttachments) {
|
|
7016
|
+
return [];
|
|
7017
|
+
}
|
|
7018
|
+
const resolved = [];
|
|
7019
|
+
for (const attachment of extraAttachments) {
|
|
7020
|
+
const resolvedPath = import_node_path23.default.resolve(attachment);
|
|
7021
|
+
if (!await pathExists(resolvedPath)) {
|
|
7022
|
+
throw new Error(`Attachment not found: ${resolvedPath}`);
|
|
7023
|
+
}
|
|
7024
|
+
resolved.push(resolvedPath);
|
|
7025
|
+
}
|
|
7026
|
+
return resolved;
|
|
7027
|
+
}
|
|
7028
|
+
async function dispatchAgentSession(options) {
|
|
7029
|
+
const {
|
|
7030
|
+
userQuery,
|
|
7031
|
+
promptFile,
|
|
7032
|
+
requestTemplate,
|
|
7033
|
+
extraAttachments,
|
|
7034
|
+
workspaceTemplate,
|
|
7035
|
+
dryRun = false,
|
|
7036
|
+
wait = true,
|
|
7037
|
+
vscodeCmd = "code",
|
|
7038
|
+
subagentRoot,
|
|
7039
|
+
silent = false
|
|
7040
|
+
} = options;
|
|
7041
|
+
try {
|
|
7042
|
+
let resolvedPrompt;
|
|
7043
|
+
try {
|
|
7044
|
+
resolvedPrompt = await resolvePromptFile(promptFile);
|
|
7045
|
+
} catch (error) {
|
|
7046
|
+
return {
|
|
7047
|
+
exitCode: 1,
|
|
7048
|
+
error: error.message
|
|
7049
|
+
};
|
|
7050
|
+
}
|
|
7051
|
+
const templateContent = requestTemplate ?? loadDefaultRequestTemplate();
|
|
7052
|
+
const subagentRootPath = subagentRoot ?? getSubagentRoot(vscodeCmd);
|
|
7053
|
+
const subagentDir = await findUnlockedSubagent(subagentRootPath);
|
|
7054
|
+
if (!subagentDir) {
|
|
7055
|
+
return {
|
|
7056
|
+
exitCode: 1,
|
|
7057
|
+
error: "No unlocked subagents available. Provision additional subagents with: subagent code provision --subagents <desired_total>"
|
|
7058
|
+
};
|
|
7059
|
+
}
|
|
7060
|
+
const subagentName = import_node_path23.default.basename(subagentDir);
|
|
7061
|
+
const chatId = Math.random().toString(16).slice(2, 10);
|
|
7062
|
+
const preparationResult = await prepareSubagentDirectory(
|
|
7063
|
+
subagentDir,
|
|
7064
|
+
resolvedPrompt,
|
|
7065
|
+
chatId,
|
|
7066
|
+
workspaceTemplate,
|
|
7067
|
+
dryRun
|
|
7068
|
+
);
|
|
7069
|
+
if (preparationResult !== 0) {
|
|
7070
|
+
return {
|
|
7071
|
+
exitCode: preparationResult,
|
|
7072
|
+
subagentName,
|
|
7073
|
+
error: "Failed to prepare subagent workspace"
|
|
7074
|
+
};
|
|
7075
|
+
}
|
|
7076
|
+
let attachments;
|
|
7077
|
+
try {
|
|
7078
|
+
attachments = await resolveAttachments(extraAttachments);
|
|
7079
|
+
} catch (attachmentError) {
|
|
7080
|
+
return {
|
|
7081
|
+
exitCode: 1,
|
|
7082
|
+
subagentName,
|
|
7083
|
+
error: attachmentError.message
|
|
7084
|
+
};
|
|
7085
|
+
}
|
|
7086
|
+
const timestamp = generateTimestamp();
|
|
7087
|
+
const messagesDir = import_node_path23.default.join(subagentDir, "messages");
|
|
7088
|
+
const responseFileTmp = import_node_path23.default.join(messagesDir, `${timestamp}_res.tmp.md`);
|
|
7089
|
+
const responseFileFinal = import_node_path23.default.join(messagesDir, `${timestamp}_res.md`);
|
|
7090
|
+
const requestInstructions = createRequestPrompt(
|
|
7091
|
+
userQuery,
|
|
7092
|
+
responseFileTmp,
|
|
7093
|
+
responseFileFinal,
|
|
7094
|
+
templateContent
|
|
7095
|
+
);
|
|
7096
|
+
if (dryRun) {
|
|
7097
|
+
return {
|
|
7098
|
+
exitCode: 0,
|
|
7099
|
+
subagentName,
|
|
7100
|
+
responseFile: responseFileFinal,
|
|
7101
|
+
tempFile: responseFileTmp
|
|
7102
|
+
};
|
|
7103
|
+
}
|
|
7104
|
+
const launchSuccess = await launchVsCodeWithChat(
|
|
7105
|
+
subagentDir,
|
|
7106
|
+
chatId,
|
|
7107
|
+
attachments,
|
|
7108
|
+
requestInstructions,
|
|
7109
|
+
timestamp,
|
|
7110
|
+
vscodeCmd
|
|
7111
|
+
);
|
|
7112
|
+
if (!launchSuccess) {
|
|
7113
|
+
return {
|
|
7114
|
+
exitCode: 1,
|
|
7115
|
+
subagentName,
|
|
7116
|
+
responseFile: responseFileFinal,
|
|
7117
|
+
tempFile: responseFileTmp,
|
|
7118
|
+
error: "Failed to launch VS Code for subagent session"
|
|
7119
|
+
};
|
|
7120
|
+
}
|
|
7121
|
+
if (!wait) {
|
|
7122
|
+
return {
|
|
7123
|
+
exitCode: 0,
|
|
7124
|
+
subagentName,
|
|
7125
|
+
responseFile: responseFileFinal,
|
|
7126
|
+
tempFile: responseFileTmp
|
|
7127
|
+
};
|
|
7128
|
+
}
|
|
7129
|
+
const received = await waitForResponseOutput(responseFileFinal, 1e3, silent);
|
|
7130
|
+
if (!received) {
|
|
7131
|
+
return {
|
|
7132
|
+
exitCode: 1,
|
|
7133
|
+
subagentName,
|
|
7134
|
+
responseFile: responseFileFinal,
|
|
7135
|
+
tempFile: responseFileTmp,
|
|
7136
|
+
error: "Timed out waiting for agent response"
|
|
7137
|
+
};
|
|
7138
|
+
}
|
|
7139
|
+
await removeSubagentLock(subagentDir);
|
|
7140
|
+
return {
|
|
7141
|
+
exitCode: 0,
|
|
7142
|
+
subagentName,
|
|
7143
|
+
responseFile: responseFileFinal,
|
|
7144
|
+
tempFile: responseFileTmp
|
|
7145
|
+
};
|
|
7146
|
+
} catch (error) {
|
|
7147
|
+
return {
|
|
7148
|
+
exitCode: 1,
|
|
7149
|
+
error: error.message
|
|
7150
|
+
};
|
|
7151
|
+
}
|
|
7152
|
+
}
|
|
7153
|
+
async function dispatchBatchAgent(options) {
|
|
7154
|
+
const {
|
|
7155
|
+
userQueries,
|
|
7156
|
+
promptFile,
|
|
7157
|
+
requestTemplate,
|
|
7158
|
+
extraAttachments,
|
|
7159
|
+
workspaceTemplate,
|
|
7160
|
+
dryRun = false,
|
|
7161
|
+
wait = false,
|
|
7162
|
+
vscodeCmd = "code",
|
|
7163
|
+
subagentRoot,
|
|
7164
|
+
silent = false
|
|
7165
|
+
} = options;
|
|
7166
|
+
if (!userQueries || userQueries.length === 0) {
|
|
7167
|
+
return {
|
|
7168
|
+
exitCode: 1,
|
|
7169
|
+
requestFiles: [],
|
|
7170
|
+
queryCount: 0,
|
|
7171
|
+
error: "At least one query is required for batch dispatch"
|
|
7172
|
+
};
|
|
7173
|
+
}
|
|
7174
|
+
const queryCount = userQueries.length;
|
|
7175
|
+
let requestFiles = [];
|
|
7176
|
+
let responseFilesFinal = [];
|
|
7177
|
+
let subagentName;
|
|
7178
|
+
try {
|
|
7179
|
+
let resolvedPrompt;
|
|
7180
|
+
try {
|
|
7181
|
+
resolvedPrompt = await resolvePromptFile(promptFile);
|
|
7182
|
+
} catch (error) {
|
|
7183
|
+
return {
|
|
7184
|
+
exitCode: 1,
|
|
7185
|
+
requestFiles,
|
|
7186
|
+
queryCount,
|
|
7187
|
+
error: error.message
|
|
7188
|
+
};
|
|
7189
|
+
}
|
|
7190
|
+
const batchRequestTemplateContent = requestTemplate ?? loadDefaultBatchRequestTemplate();
|
|
7191
|
+
const orchestratorTemplateContent = loadDefaultBatchOrchestratorTemplate();
|
|
7192
|
+
const subagentRootPath = subagentRoot ?? getSubagentRoot(vscodeCmd);
|
|
7193
|
+
const subagentDir = await findUnlockedSubagent(subagentRootPath);
|
|
7194
|
+
if (!subagentDir) {
|
|
7195
|
+
return {
|
|
7196
|
+
exitCode: 1,
|
|
7197
|
+
requestFiles,
|
|
7198
|
+
queryCount,
|
|
7199
|
+
error: "No unlocked subagents available. Provision additional subagents with: subagent code provision --subagents <desired_total>"
|
|
7200
|
+
};
|
|
7201
|
+
}
|
|
7202
|
+
subagentName = import_node_path23.default.basename(subagentDir);
|
|
7203
|
+
const chatId = Math.random().toString(16).slice(2, 10);
|
|
7204
|
+
const preparationResult = await prepareSubagentDirectory(
|
|
7205
|
+
subagentDir,
|
|
7206
|
+
resolvedPrompt,
|
|
7207
|
+
chatId,
|
|
7208
|
+
workspaceTemplate,
|
|
7209
|
+
dryRun
|
|
7210
|
+
);
|
|
7211
|
+
if (preparationResult !== 0) {
|
|
7212
|
+
return {
|
|
7213
|
+
exitCode: preparationResult,
|
|
7214
|
+
subagentName,
|
|
7215
|
+
requestFiles,
|
|
7216
|
+
queryCount,
|
|
7217
|
+
error: "Failed to prepare subagent workspace"
|
|
7218
|
+
};
|
|
7219
|
+
}
|
|
7220
|
+
let attachments;
|
|
7221
|
+
try {
|
|
7222
|
+
attachments = await resolveAttachments(extraAttachments);
|
|
7223
|
+
} catch (attachmentError) {
|
|
7224
|
+
return {
|
|
7225
|
+
exitCode: 1,
|
|
7226
|
+
subagentName,
|
|
7227
|
+
requestFiles,
|
|
7228
|
+
queryCount,
|
|
7229
|
+
error: attachmentError.message
|
|
7230
|
+
};
|
|
7231
|
+
}
|
|
7232
|
+
const timestamp = generateTimestamp();
|
|
7233
|
+
const messagesDir = import_node_path23.default.join(subagentDir, "messages");
|
|
7234
|
+
requestFiles = userQueries.map(
|
|
7235
|
+
(_, index) => import_node_path23.default.join(messagesDir, `${timestamp}_${index}_req.md`)
|
|
7236
|
+
);
|
|
7237
|
+
const responseTmpFiles = userQueries.map(
|
|
7238
|
+
(_, index) => import_node_path23.default.join(messagesDir, `${timestamp}_${index}_res.tmp.md`)
|
|
7239
|
+
);
|
|
7240
|
+
responseFilesFinal = userQueries.map(
|
|
7241
|
+
(_, index) => import_node_path23.default.join(messagesDir, `${timestamp}_${index}_res.md`)
|
|
7242
|
+
);
|
|
7243
|
+
const orchestratorFile = import_node_path23.default.join(messagesDir, `${timestamp}_orchestrator.md`);
|
|
7244
|
+
if (!dryRun) {
|
|
7245
|
+
await Promise.all(
|
|
7246
|
+
userQueries.map((query, index) => {
|
|
7247
|
+
const reqFile = requestFiles[index];
|
|
7248
|
+
const tmpFile = responseTmpFiles[index];
|
|
7249
|
+
const finalFile = responseFilesFinal[index];
|
|
7250
|
+
return (0, import_promises17.writeFile)(
|
|
7251
|
+
reqFile,
|
|
7252
|
+
createBatchRequestPrompt(query, tmpFile, finalFile, batchRequestTemplateContent),
|
|
7253
|
+
{ encoding: "utf8" }
|
|
7254
|
+
);
|
|
7255
|
+
})
|
|
7256
|
+
);
|
|
7257
|
+
const orchestratorContent = createBatchOrchestratorPrompt(
|
|
7258
|
+
requestFiles,
|
|
7259
|
+
responseFilesFinal,
|
|
7260
|
+
orchestratorTemplateContent
|
|
7261
|
+
);
|
|
7262
|
+
await (0, import_promises17.writeFile)(orchestratorFile, orchestratorContent, { encoding: "utf8" });
|
|
7263
|
+
}
|
|
7264
|
+
const chatAttachments = [orchestratorFile, ...attachments];
|
|
7265
|
+
const orchestratorUri = pathToFileUri2(orchestratorFile);
|
|
7266
|
+
const chatInstruction = `Follow instructions in [${timestamp}_orchestrator.md](${orchestratorUri}). Use #runSubagent tool.`;
|
|
7267
|
+
if (dryRun) {
|
|
7268
|
+
return {
|
|
7269
|
+
exitCode: 0,
|
|
7270
|
+
subagentName,
|
|
7271
|
+
requestFiles,
|
|
7272
|
+
responseFiles: wait ? responseFilesFinal : void 0,
|
|
7273
|
+
queryCount
|
|
7274
|
+
};
|
|
7275
|
+
}
|
|
7276
|
+
const launchSuccess = await launchVsCodeWithBatchChat(
|
|
7277
|
+
subagentDir,
|
|
7278
|
+
chatId,
|
|
7279
|
+
chatAttachments,
|
|
7280
|
+
chatInstruction,
|
|
7281
|
+
vscodeCmd
|
|
7282
|
+
);
|
|
7283
|
+
if (!launchSuccess) {
|
|
7284
|
+
return {
|
|
7285
|
+
exitCode: 1,
|
|
7286
|
+
subagentName,
|
|
7287
|
+
requestFiles,
|
|
7288
|
+
queryCount,
|
|
7289
|
+
error: "Failed to launch VS Code for batch dispatch"
|
|
7290
|
+
};
|
|
7291
|
+
}
|
|
7292
|
+
if (!wait) {
|
|
7293
|
+
return {
|
|
7294
|
+
exitCode: 0,
|
|
7295
|
+
subagentName,
|
|
7296
|
+
requestFiles,
|
|
7297
|
+
queryCount
|
|
7298
|
+
};
|
|
7299
|
+
}
|
|
7300
|
+
const responsesCompleted = await waitForBatchResponses(responseFilesFinal, 1e3, silent);
|
|
7301
|
+
if (!responsesCompleted) {
|
|
7302
|
+
return {
|
|
7303
|
+
exitCode: 1,
|
|
7304
|
+
subagentName,
|
|
7305
|
+
requestFiles,
|
|
7306
|
+
responseFiles: responseFilesFinal,
|
|
7307
|
+
queryCount,
|
|
7308
|
+
error: "Timed out waiting for batch responses"
|
|
7309
|
+
};
|
|
7310
|
+
}
|
|
7311
|
+
await removeSubagentLock(subagentDir);
|
|
7312
|
+
return {
|
|
7313
|
+
exitCode: 0,
|
|
7314
|
+
subagentName,
|
|
7315
|
+
requestFiles,
|
|
7316
|
+
responseFiles: responseFilesFinal,
|
|
7317
|
+
queryCount
|
|
7318
|
+
};
|
|
7319
|
+
} catch (error) {
|
|
7320
|
+
return {
|
|
7321
|
+
exitCode: 1,
|
|
7322
|
+
subagentName,
|
|
7323
|
+
requestFiles,
|
|
7324
|
+
responseFiles: responseFilesFinal.length > 0 ? responseFilesFinal : void 0,
|
|
7325
|
+
queryCount,
|
|
7326
|
+
error: error.message
|
|
7327
|
+
};
|
|
7328
|
+
}
|
|
7329
|
+
}
|
|
7330
|
+
|
|
7331
|
+
// src/evaluation/providers/vscode/dispatch/provision.ts
|
|
7332
|
+
var import_promises18 = require("fs/promises");
|
|
7333
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
7334
|
+
var DEFAULT_WORKSPACE_TEMPLATE2 = {
|
|
7335
|
+
folders: [
|
|
7336
|
+
{
|
|
7337
|
+
path: "."
|
|
7338
|
+
}
|
|
7339
|
+
],
|
|
7340
|
+
settings: {
|
|
7341
|
+
"chat.modeFilesLocations": {
|
|
7342
|
+
".github/agents/**/*.md": true
|
|
7343
|
+
}
|
|
7344
|
+
}
|
|
7345
|
+
};
|
|
7346
|
+
var DEFAULT_WAKEUP_CONTENT2 = `---
|
|
7347
|
+
description: 'Wake-up Signal'
|
|
7348
|
+
tools: ['edit', 'runNotebooks', 'search', 'new', 'runCommands', 'runTasks', 'usages', 'vscodeAPI', 'problems', 'changes', 'testFailure', 'openSimpleBrowser', 'fetch', 'githubRepo']
|
|
7349
|
+
model: GPT-4.1 (copilot)
|
|
7350
|
+
---`;
|
|
7351
|
+
async function provisionSubagents(options) {
|
|
7352
|
+
const {
|
|
7353
|
+
targetRoot,
|
|
7354
|
+
subagents,
|
|
7355
|
+
lockName = DEFAULT_LOCK_NAME,
|
|
7356
|
+
force = false,
|
|
7357
|
+
dryRun = false,
|
|
7358
|
+
workspaceTemplate = DEFAULT_WORKSPACE_TEMPLATE2,
|
|
7359
|
+
wakeupContent = DEFAULT_WAKEUP_CONTENT2
|
|
7360
|
+
} = options;
|
|
7361
|
+
if (!Number.isInteger(subagents) || subagents < 1) {
|
|
7362
|
+
throw new Error("subagents must be a positive integer");
|
|
7363
|
+
}
|
|
7364
|
+
const targetPath = import_node_path24.default.resolve(targetRoot);
|
|
7365
|
+
if (!dryRun) {
|
|
7366
|
+
await ensureDir(targetPath);
|
|
7367
|
+
}
|
|
7368
|
+
let highestNumber = 0;
|
|
7369
|
+
const lockedSubagents = /* @__PURE__ */ new Set();
|
|
7370
|
+
const existingSubagents = [];
|
|
7371
|
+
if (await pathExists(targetPath)) {
|
|
7372
|
+
const entries = await readDirEntries(targetPath);
|
|
7373
|
+
for (const entry of entries) {
|
|
7374
|
+
if (!entry.isDirectory || !entry.name.startsWith("subagent-")) {
|
|
7375
|
+
continue;
|
|
7376
|
+
}
|
|
7377
|
+
const suffix = entry.name.split("-")[1];
|
|
7378
|
+
if (!suffix) continue;
|
|
7379
|
+
const parsed = Number.parseInt(suffix, 10);
|
|
7380
|
+
if (!Number.isInteger(parsed)) {
|
|
7381
|
+
continue;
|
|
7382
|
+
}
|
|
7383
|
+
highestNumber = Math.max(highestNumber, parsed);
|
|
7384
|
+
const lockFile = import_node_path24.default.join(entry.absolutePath, lockName);
|
|
7385
|
+
const locked = await pathExists(lockFile);
|
|
7386
|
+
if (locked) {
|
|
7387
|
+
lockedSubagents.add(entry.absolutePath);
|
|
7388
|
+
}
|
|
7389
|
+
existingSubagents.push({ number: parsed, absolutePath: entry.absolutePath });
|
|
7390
|
+
}
|
|
7391
|
+
existingSubagents.sort((a, b) => a.number - b.number);
|
|
7392
|
+
}
|
|
7393
|
+
const created = [];
|
|
7394
|
+
const skippedExisting = [];
|
|
7395
|
+
let subagentsProvisioned = 0;
|
|
7396
|
+
for (const subagent of existingSubagents) {
|
|
7397
|
+
if (subagentsProvisioned >= subagents) {
|
|
7398
|
+
break;
|
|
7399
|
+
}
|
|
7400
|
+
const subagentDir = subagent.absolutePath;
|
|
7401
|
+
const githubAgentsDir = import_node_path24.default.join(subagentDir, ".github", "agents");
|
|
7402
|
+
const lockFile = import_node_path24.default.join(subagentDir, lockName);
|
|
7403
|
+
const workspaceDst = import_node_path24.default.join(subagentDir, `${import_node_path24.default.basename(subagentDir)}.code-workspace`);
|
|
7404
|
+
const wakeupDst = import_node_path24.default.join(githubAgentsDir, "wakeup.md");
|
|
7405
|
+
const isLocked = await pathExists(lockFile);
|
|
7406
|
+
if (isLocked && !force) {
|
|
7407
|
+
continue;
|
|
7408
|
+
}
|
|
7409
|
+
if (isLocked && force) {
|
|
7410
|
+
if (!dryRun) {
|
|
7411
|
+
await removeIfExists(lockFile);
|
|
7412
|
+
await ensureDir(githubAgentsDir);
|
|
7413
|
+
await (0, import_promises18.writeFile)(workspaceDst, JSON.stringify(workspaceTemplate, null, 2), "utf8");
|
|
7414
|
+
await (0, import_promises18.writeFile)(wakeupDst, wakeupContent, "utf8");
|
|
7415
|
+
}
|
|
7416
|
+
created.push(subagentDir);
|
|
7417
|
+
lockedSubagents.delete(subagentDir);
|
|
7418
|
+
subagentsProvisioned += 1;
|
|
7419
|
+
continue;
|
|
7420
|
+
}
|
|
7421
|
+
if (!isLocked && force) {
|
|
7422
|
+
if (!dryRun) {
|
|
7423
|
+
await ensureDir(githubAgentsDir);
|
|
7424
|
+
await (0, import_promises18.writeFile)(workspaceDst, JSON.stringify(workspaceTemplate, null, 2), "utf8");
|
|
7425
|
+
await (0, import_promises18.writeFile)(wakeupDst, wakeupContent, "utf8");
|
|
7426
|
+
}
|
|
7427
|
+
created.push(subagentDir);
|
|
7428
|
+
subagentsProvisioned += 1;
|
|
7429
|
+
continue;
|
|
7430
|
+
}
|
|
7431
|
+
if (!dryRun && !await pathExists(workspaceDst)) {
|
|
7432
|
+
await ensureDir(githubAgentsDir);
|
|
7433
|
+
await (0, import_promises18.writeFile)(workspaceDst, JSON.stringify(workspaceTemplate, null, 2), "utf8");
|
|
7434
|
+
await (0, import_promises18.writeFile)(wakeupDst, wakeupContent, "utf8");
|
|
7435
|
+
}
|
|
7436
|
+
skippedExisting.push(subagentDir);
|
|
7437
|
+
subagentsProvisioned += 1;
|
|
7438
|
+
}
|
|
7439
|
+
let nextIndex = highestNumber;
|
|
7440
|
+
while (subagentsProvisioned < subagents) {
|
|
7441
|
+
nextIndex += 1;
|
|
7442
|
+
const subagentDir = import_node_path24.default.join(targetPath, `subagent-${nextIndex}`);
|
|
7443
|
+
const githubAgentsDir = import_node_path24.default.join(subagentDir, ".github", "agents");
|
|
7444
|
+
const workspaceDst = import_node_path24.default.join(subagentDir, `${import_node_path24.default.basename(subagentDir)}.code-workspace`);
|
|
7445
|
+
const wakeupDst = import_node_path24.default.join(githubAgentsDir, "wakeup.md");
|
|
7446
|
+
if (!dryRun) {
|
|
7447
|
+
await ensureDir(subagentDir);
|
|
7448
|
+
await ensureDir(githubAgentsDir);
|
|
7449
|
+
await (0, import_promises18.writeFile)(workspaceDst, JSON.stringify(workspaceTemplate, null, 2), "utf8");
|
|
7450
|
+
await (0, import_promises18.writeFile)(wakeupDst, wakeupContent, "utf8");
|
|
7451
|
+
}
|
|
7452
|
+
created.push(subagentDir);
|
|
7453
|
+
subagentsProvisioned += 1;
|
|
7454
|
+
}
|
|
7455
|
+
return {
|
|
7456
|
+
created,
|
|
7457
|
+
skippedExisting,
|
|
7458
|
+
skippedLocked: Array.from(lockedSubagents).sort()
|
|
7459
|
+
};
|
|
7460
|
+
}
|
|
6433
7461
|
|
|
6434
7462
|
// src/evaluation/providers/vscode-templates.ts
|
|
6435
7463
|
var AGENTV_REQUEST_TEMPLATE = `[[ ## task ## ]]
|
|
@@ -6466,7 +7494,7 @@ var AGENTV_BATCH_REQUEST_TEMPLATE = `[[ ## task ## ]]
|
|
|
6466
7494
|
3. Do not unlock the workspace from this request; batch orchestration will handle unlocking after all responses are ready.
|
|
6467
7495
|
`;
|
|
6468
7496
|
|
|
6469
|
-
// src/evaluation/providers/vscode.ts
|
|
7497
|
+
// src/evaluation/providers/vscode-provider.ts
|
|
6470
7498
|
var VSCodeProvider = class {
|
|
6471
7499
|
id;
|
|
6472
7500
|
kind;
|
|
@@ -6485,7 +7513,7 @@ var VSCodeProvider = class {
|
|
|
6485
7513
|
}
|
|
6486
7514
|
const inputFiles = normalizeAttachments(request.inputFiles);
|
|
6487
7515
|
const promptContent = buildPromptDocument2(request, inputFiles, request.guideline_patterns);
|
|
6488
|
-
const session = await
|
|
7516
|
+
const session = await dispatchAgentSession({
|
|
6489
7517
|
userQuery: promptContent,
|
|
6490
7518
|
extraAttachments: inputFiles,
|
|
6491
7519
|
requestTemplate: AGENTV_REQUEST_TEMPLATE,
|
|
@@ -6532,7 +7560,7 @@ var VSCodeProvider = class {
|
|
|
6532
7560
|
const userQueries = normalizedRequests.map(
|
|
6533
7561
|
({ request, inputFiles }) => buildPromptDocument2(request, inputFiles, request.guideline_patterns)
|
|
6534
7562
|
);
|
|
6535
|
-
const session = await
|
|
7563
|
+
const session = await dispatchBatchAgent({
|
|
6536
7564
|
userQueries,
|
|
6537
7565
|
extraAttachments: combinedInputFiles,
|
|
6538
7566
|
requestTemplate: AGENTV_BATCH_REQUEST_TEMPLATE,
|
|
@@ -6598,8 +7626,8 @@ function buildMandatoryPrereadBlock2(guidelineFiles, attachmentFiles) {
|
|
|
6598
7626
|
return "";
|
|
6599
7627
|
}
|
|
6600
7628
|
const buildList = (files) => files.map((absolutePath) => {
|
|
6601
|
-
const fileName =
|
|
6602
|
-
const fileUri =
|
|
7629
|
+
const fileName = import_node_path25.default.basename(absolutePath);
|
|
7630
|
+
const fileUri = pathToFileUri3(absolutePath);
|
|
6603
7631
|
return `* [${fileName}](${fileUri})`;
|
|
6604
7632
|
});
|
|
6605
7633
|
const sections = [];
|
|
@@ -6623,8 +7651,8 @@ function collectGuidelineFiles2(attachments, guidelinePatterns) {
|
|
|
6623
7651
|
}
|
|
6624
7652
|
const unique = /* @__PURE__ */ new Map();
|
|
6625
7653
|
for (const attachment of attachments) {
|
|
6626
|
-
const absolutePath =
|
|
6627
|
-
const normalized = absolutePath.split(
|
|
7654
|
+
const absolutePath = import_node_path25.default.resolve(attachment);
|
|
7655
|
+
const normalized = absolutePath.split(import_node_path25.default.sep).join("/");
|
|
6628
7656
|
if (isGuidelineFile(normalized, guidelinePatterns)) {
|
|
6629
7657
|
if (!unique.has(absolutePath)) {
|
|
6630
7658
|
unique.set(absolutePath, absolutePath);
|
|
@@ -6639,15 +7667,15 @@ function collectAttachmentFiles(attachments) {
|
|
|
6639
7667
|
}
|
|
6640
7668
|
const unique = /* @__PURE__ */ new Map();
|
|
6641
7669
|
for (const attachment of attachments) {
|
|
6642
|
-
const absolutePath =
|
|
7670
|
+
const absolutePath = import_node_path25.default.resolve(attachment);
|
|
6643
7671
|
if (!unique.has(absolutePath)) {
|
|
6644
7672
|
unique.set(absolutePath, absolutePath);
|
|
6645
7673
|
}
|
|
6646
7674
|
}
|
|
6647
7675
|
return Array.from(unique.values());
|
|
6648
7676
|
}
|
|
6649
|
-
function
|
|
6650
|
-
const absolutePath =
|
|
7677
|
+
function pathToFileUri3(filePath) {
|
|
7678
|
+
const absolutePath = import_node_path25.default.isAbsolute(filePath) ? filePath : import_node_path25.default.resolve(filePath);
|
|
6651
7679
|
const normalizedPath = absolutePath.replace(/\\/g, "/");
|
|
6652
7680
|
if (/^[a-zA-Z]:\//.test(normalizedPath)) {
|
|
6653
7681
|
return `file:///${normalizedPath}`;
|
|
@@ -6660,7 +7688,7 @@ function normalizeAttachments(attachments) {
|
|
|
6660
7688
|
}
|
|
6661
7689
|
const deduped = /* @__PURE__ */ new Set();
|
|
6662
7690
|
for (const attachment of attachments) {
|
|
6663
|
-
deduped.add(
|
|
7691
|
+
deduped.add(import_node_path25.default.resolve(attachment));
|
|
6664
7692
|
}
|
|
6665
7693
|
return Array.from(deduped);
|
|
6666
7694
|
}
|
|
@@ -6669,7 +7697,7 @@ function mergeAttachments(all) {
|
|
|
6669
7697
|
for (const list of all) {
|
|
6670
7698
|
if (!list) continue;
|
|
6671
7699
|
for (const inputFile of list) {
|
|
6672
|
-
deduped.add(
|
|
7700
|
+
deduped.add(import_node_path25.default.resolve(inputFile));
|
|
6673
7701
|
}
|
|
6674
7702
|
}
|
|
6675
7703
|
return deduped.size > 0 ? Array.from(deduped) : void 0;
|
|
@@ -6677,12 +7705,12 @@ function mergeAttachments(all) {
|
|
|
6677
7705
|
async function ensureVSCodeSubagents(options) {
|
|
6678
7706
|
const { kind, count, verbose = false } = options;
|
|
6679
7707
|
const vscodeCmd = kind === "vscode-insiders" ? "code-insiders" : "code";
|
|
6680
|
-
const subagentRoot =
|
|
7708
|
+
const subagentRoot = getSubagentRoot(vscodeCmd);
|
|
6681
7709
|
try {
|
|
6682
7710
|
if (verbose) {
|
|
6683
7711
|
console.log(`Provisioning ${count} subagent(s) via: subagent ${vscodeCmd} provision`);
|
|
6684
7712
|
}
|
|
6685
|
-
const result = await
|
|
7713
|
+
const result = await provisionSubagents({
|
|
6686
7714
|
targetRoot: subagentRoot,
|
|
6687
7715
|
subagents: count,
|
|
6688
7716
|
dryRun: false
|
|
@@ -6716,9 +7744,9 @@ total unlocked subagents available: ${result.created.length + result.skippedExis
|
|
|
6716
7744
|
}
|
|
6717
7745
|
|
|
6718
7746
|
// src/evaluation/providers/targets-file.ts
|
|
6719
|
-
var
|
|
6720
|
-
var
|
|
6721
|
-
var
|
|
7747
|
+
var import_node_fs7 = require("fs");
|
|
7748
|
+
var import_promises19 = require("fs/promises");
|
|
7749
|
+
var import_node_path26 = __toESM(require("path"), 1);
|
|
6722
7750
|
var import_yaml4 = require("yaml");
|
|
6723
7751
|
function isRecord(value) {
|
|
6724
7752
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -6748,18 +7776,18 @@ function assertTargetDefinition(value, index, filePath) {
|
|
|
6748
7776
|
}
|
|
6749
7777
|
async function fileExists3(filePath) {
|
|
6750
7778
|
try {
|
|
6751
|
-
await (0,
|
|
7779
|
+
await (0, import_promises19.access)(filePath, import_node_fs7.constants.F_OK);
|
|
6752
7780
|
return true;
|
|
6753
7781
|
} catch {
|
|
6754
7782
|
return false;
|
|
6755
7783
|
}
|
|
6756
7784
|
}
|
|
6757
7785
|
async function readTargetDefinitions(filePath) {
|
|
6758
|
-
const absolutePath =
|
|
7786
|
+
const absolutePath = import_node_path26.default.resolve(filePath);
|
|
6759
7787
|
if (!await fileExists3(absolutePath)) {
|
|
6760
7788
|
throw new Error(`targets.yaml not found at ${absolutePath}`);
|
|
6761
7789
|
}
|
|
6762
|
-
const raw = await (0,
|
|
7790
|
+
const raw = await (0, import_promises19.readFile)(absolutePath, "utf8");
|
|
6763
7791
|
const parsed = (0, import_yaml4.parse)(raw);
|
|
6764
7792
|
if (!isRecord(parsed)) {
|
|
6765
7793
|
throw new Error(`targets.yaml at ${absolutePath} must be a YAML object with a 'targets' field`);
|
|
@@ -6923,10 +7951,10 @@ async function execFileWithStdinBun(argv, stdinPayload, options) {
|
|
|
6923
7951
|
}
|
|
6924
7952
|
}
|
|
6925
7953
|
async function execFileWithStdinNode(argv, stdinPayload, options) {
|
|
6926
|
-
const { spawn:
|
|
7954
|
+
const { spawn: spawn5 } = await import("child_process");
|
|
6927
7955
|
return new Promise((resolve, reject) => {
|
|
6928
7956
|
const [cmd, ...args] = argv;
|
|
6929
|
-
const child =
|
|
7957
|
+
const child = spawn5(cmd, args, {
|
|
6930
7958
|
cwd: options.cwd,
|
|
6931
7959
|
stdio: ["pipe", "pipe", "pipe"],
|
|
6932
7960
|
// Merge additional env vars with process.env
|
|
@@ -6966,21 +7994,21 @@ async function execFileWithStdinNode(argv, stdinPayload, options) {
|
|
|
6966
7994
|
});
|
|
6967
7995
|
}
|
|
6968
7996
|
async function execShellWithStdin(command, stdinPayload, options = {}) {
|
|
6969
|
-
const { mkdir:
|
|
7997
|
+
const { mkdir: mkdir8, readFile: readFile11, rm: rm5, writeFile: writeFile8 } = await import("fs/promises");
|
|
6970
7998
|
const { tmpdir: tmpdir4 } = await import("os");
|
|
6971
|
-
const
|
|
7999
|
+
const path28 = await import("path");
|
|
6972
8000
|
const { randomUUID: randomUUID4 } = await import("crypto");
|
|
6973
|
-
const dir =
|
|
6974
|
-
await
|
|
6975
|
-
const stdinPath =
|
|
6976
|
-
const stdoutPath =
|
|
6977
|
-
const stderrPath =
|
|
6978
|
-
await
|
|
8001
|
+
const dir = path28.join(tmpdir4(), `agentv-exec-${randomUUID4()}`);
|
|
8002
|
+
await mkdir8(dir, { recursive: true });
|
|
8003
|
+
const stdinPath = path28.join(dir, "stdin.txt");
|
|
8004
|
+
const stdoutPath = path28.join(dir, "stdout.txt");
|
|
8005
|
+
const stderrPath = path28.join(dir, "stderr.txt");
|
|
8006
|
+
await writeFile8(stdinPath, stdinPayload, "utf8");
|
|
6979
8007
|
const wrappedCommand = process.platform === "win32" ? `(${command}) < ${shellEscapePath(stdinPath)} > ${shellEscapePath(stdoutPath)} 2> ${shellEscapePath(stderrPath)}` : `(${command}) < ${shellEscapePath(stdinPath)} > ${shellEscapePath(stdoutPath)} 2> ${shellEscapePath(stderrPath)}`;
|
|
6980
|
-
const { spawn:
|
|
8008
|
+
const { spawn: spawn5 } = await import("child_process");
|
|
6981
8009
|
try {
|
|
6982
8010
|
const exitCode = await new Promise((resolve, reject) => {
|
|
6983
|
-
const child =
|
|
8011
|
+
const child = spawn5(wrappedCommand, {
|
|
6984
8012
|
shell: true,
|
|
6985
8013
|
cwd: options.cwd,
|
|
6986
8014
|
stdio: ["ignore", "ignore", "ignore"],
|
|
@@ -7004,11 +8032,11 @@ async function execShellWithStdin(command, stdinPayload, options = {}) {
|
|
|
7004
8032
|
resolve(code ?? 0);
|
|
7005
8033
|
});
|
|
7006
8034
|
});
|
|
7007
|
-
const stdout = (await
|
|
7008
|
-
const stderr = (await
|
|
8035
|
+
const stdout = (await readFile11(stdoutPath, "utf8")).replace(/\r\n/g, "\n");
|
|
8036
|
+
const stderr = (await readFile11(stderrPath, "utf8")).replace(/\r\n/g, "\n");
|
|
7009
8037
|
return { stdout, stderr, exitCode };
|
|
7010
8038
|
} finally {
|
|
7011
|
-
await
|
|
8039
|
+
await rm5(dir, { recursive: true, force: true });
|
|
7012
8040
|
}
|
|
7013
8041
|
}
|
|
7014
8042
|
|
|
@@ -7277,7 +8305,7 @@ var CodeEvaluator = class {
|
|
|
7277
8305
|
outputMessages: context.outputMessages ?? null,
|
|
7278
8306
|
guidelineFiles: context.evalCase.guideline_paths,
|
|
7279
8307
|
inputFiles: context.evalCase.file_paths.filter(
|
|
7280
|
-
(
|
|
8308
|
+
(path28) => !context.evalCase.guideline_paths.includes(path28)
|
|
7281
8309
|
),
|
|
7282
8310
|
inputMessages: context.evalCase.input_messages,
|
|
7283
8311
|
traceSummary: context.traceSummary ?? null,
|
|
@@ -8224,115 +9252,115 @@ var FieldAccuracyEvaluator = class {
|
|
|
8224
9252
|
* Evaluate a single field against the expected value.
|
|
8225
9253
|
*/
|
|
8226
9254
|
evaluateField(fieldConfig, candidateData, expectedData) {
|
|
8227
|
-
const { path:
|
|
8228
|
-
const candidateValue = resolvePath(candidateData,
|
|
8229
|
-
const expectedValue = resolvePath(expectedData,
|
|
9255
|
+
const { path: path28, match, required = true, weight = 1 } = fieldConfig;
|
|
9256
|
+
const candidateValue = resolvePath(candidateData, path28);
|
|
9257
|
+
const expectedValue = resolvePath(expectedData, path28);
|
|
8230
9258
|
if (expectedValue === void 0) {
|
|
8231
9259
|
return {
|
|
8232
|
-
path:
|
|
9260
|
+
path: path28,
|
|
8233
9261
|
score: 1,
|
|
8234
9262
|
// No expected value means no comparison needed
|
|
8235
9263
|
weight,
|
|
8236
9264
|
hit: true,
|
|
8237
|
-
message: `${
|
|
9265
|
+
message: `${path28}: no expected value`
|
|
8238
9266
|
};
|
|
8239
9267
|
}
|
|
8240
9268
|
if (candidateValue === void 0) {
|
|
8241
9269
|
if (required) {
|
|
8242
9270
|
return {
|
|
8243
|
-
path:
|
|
9271
|
+
path: path28,
|
|
8244
9272
|
score: 0,
|
|
8245
9273
|
weight,
|
|
8246
9274
|
hit: false,
|
|
8247
|
-
message: `${
|
|
9275
|
+
message: `${path28} (required, missing)`
|
|
8248
9276
|
};
|
|
8249
9277
|
}
|
|
8250
9278
|
return {
|
|
8251
|
-
path:
|
|
9279
|
+
path: path28,
|
|
8252
9280
|
score: 1,
|
|
8253
9281
|
// Don't penalize missing optional fields
|
|
8254
9282
|
weight: 0,
|
|
8255
9283
|
// Zero weight means it won't affect the score
|
|
8256
9284
|
hit: true,
|
|
8257
|
-
message: `${
|
|
9285
|
+
message: `${path28}: optional field missing`
|
|
8258
9286
|
};
|
|
8259
9287
|
}
|
|
8260
9288
|
switch (match) {
|
|
8261
9289
|
case "exact":
|
|
8262
|
-
return this.compareExact(
|
|
9290
|
+
return this.compareExact(path28, candidateValue, expectedValue, weight);
|
|
8263
9291
|
case "numeric_tolerance":
|
|
8264
9292
|
return this.compareNumericTolerance(
|
|
8265
|
-
|
|
9293
|
+
path28,
|
|
8266
9294
|
candidateValue,
|
|
8267
9295
|
expectedValue,
|
|
8268
9296
|
fieldConfig,
|
|
8269
9297
|
weight
|
|
8270
9298
|
);
|
|
8271
9299
|
case "date":
|
|
8272
|
-
return this.compareDate(
|
|
9300
|
+
return this.compareDate(path28, candidateValue, expectedValue, fieldConfig, weight);
|
|
8273
9301
|
default:
|
|
8274
9302
|
return {
|
|
8275
|
-
path:
|
|
9303
|
+
path: path28,
|
|
8276
9304
|
score: 0,
|
|
8277
9305
|
weight,
|
|
8278
9306
|
hit: false,
|
|
8279
|
-
message: `${
|
|
9307
|
+
message: `${path28}: unknown match type "${match}"`
|
|
8280
9308
|
};
|
|
8281
9309
|
}
|
|
8282
9310
|
}
|
|
8283
9311
|
/**
|
|
8284
9312
|
* Exact equality comparison.
|
|
8285
9313
|
*/
|
|
8286
|
-
compareExact(
|
|
9314
|
+
compareExact(path28, candidateValue, expectedValue, weight) {
|
|
8287
9315
|
if (deepEqual(candidateValue, expectedValue)) {
|
|
8288
9316
|
return {
|
|
8289
|
-
path:
|
|
9317
|
+
path: path28,
|
|
8290
9318
|
score: 1,
|
|
8291
9319
|
weight,
|
|
8292
9320
|
hit: true,
|
|
8293
|
-
message:
|
|
9321
|
+
message: path28
|
|
8294
9322
|
};
|
|
8295
9323
|
}
|
|
8296
9324
|
if (typeof candidateValue !== typeof expectedValue) {
|
|
8297
9325
|
return {
|
|
8298
|
-
path:
|
|
9326
|
+
path: path28,
|
|
8299
9327
|
score: 0,
|
|
8300
9328
|
weight,
|
|
8301
9329
|
hit: false,
|
|
8302
|
-
message: `${
|
|
9330
|
+
message: `${path28} (type mismatch: got ${typeof candidateValue}, expected ${typeof expectedValue})`
|
|
8303
9331
|
};
|
|
8304
9332
|
}
|
|
8305
9333
|
return {
|
|
8306
|
-
path:
|
|
9334
|
+
path: path28,
|
|
8307
9335
|
score: 0,
|
|
8308
9336
|
weight,
|
|
8309
9337
|
hit: false,
|
|
8310
|
-
message: `${
|
|
9338
|
+
message: `${path28} (value mismatch)`
|
|
8311
9339
|
};
|
|
8312
9340
|
}
|
|
8313
9341
|
/**
|
|
8314
9342
|
* Numeric comparison with absolute or relative tolerance.
|
|
8315
9343
|
*/
|
|
8316
|
-
compareNumericTolerance(
|
|
9344
|
+
compareNumericTolerance(path28, candidateValue, expectedValue, fieldConfig, weight) {
|
|
8317
9345
|
const { tolerance = 0, relative = false } = fieldConfig;
|
|
8318
9346
|
const candidateNum = toNumber(candidateValue);
|
|
8319
9347
|
const expectedNum = toNumber(expectedValue);
|
|
8320
9348
|
if (candidateNum === null || expectedNum === null) {
|
|
8321
9349
|
return {
|
|
8322
|
-
path:
|
|
9350
|
+
path: path28,
|
|
8323
9351
|
score: 0,
|
|
8324
9352
|
weight,
|
|
8325
9353
|
hit: false,
|
|
8326
|
-
message: `${
|
|
9354
|
+
message: `${path28} (non-numeric value)`
|
|
8327
9355
|
};
|
|
8328
9356
|
}
|
|
8329
9357
|
if (!Number.isFinite(candidateNum) || !Number.isFinite(expectedNum)) {
|
|
8330
9358
|
return {
|
|
8331
|
-
path:
|
|
9359
|
+
path: path28,
|
|
8332
9360
|
score: 0,
|
|
8333
9361
|
weight,
|
|
8334
9362
|
hit: false,
|
|
8335
|
-
message: `${
|
|
9363
|
+
message: `${path28} (invalid numeric value)`
|
|
8336
9364
|
};
|
|
8337
9365
|
}
|
|
8338
9366
|
const diff = Math.abs(candidateNum - expectedNum);
|
|
@@ -8345,61 +9373,61 @@ var FieldAccuracyEvaluator = class {
|
|
|
8345
9373
|
}
|
|
8346
9374
|
if (withinTolerance) {
|
|
8347
9375
|
return {
|
|
8348
|
-
path:
|
|
9376
|
+
path: path28,
|
|
8349
9377
|
score: 1,
|
|
8350
9378
|
weight,
|
|
8351
9379
|
hit: true,
|
|
8352
|
-
message: `${
|
|
9380
|
+
message: `${path28} (within tolerance: diff=${diff.toFixed(2)})`
|
|
8353
9381
|
};
|
|
8354
9382
|
}
|
|
8355
9383
|
return {
|
|
8356
|
-
path:
|
|
9384
|
+
path: path28,
|
|
8357
9385
|
score: 0,
|
|
8358
9386
|
weight,
|
|
8359
9387
|
hit: false,
|
|
8360
|
-
message: `${
|
|
9388
|
+
message: `${path28} (outside tolerance: diff=${diff.toFixed(2)}, tolerance=${tolerance})`
|
|
8361
9389
|
};
|
|
8362
9390
|
}
|
|
8363
9391
|
/**
|
|
8364
9392
|
* Date comparison with format normalization.
|
|
8365
9393
|
*/
|
|
8366
|
-
compareDate(
|
|
9394
|
+
compareDate(path28, candidateValue, expectedValue, fieldConfig, weight) {
|
|
8367
9395
|
const formats = fieldConfig.formats ?? DEFAULT_DATE_FORMATS;
|
|
8368
9396
|
const candidateDate = parseDate(String(candidateValue), formats);
|
|
8369
9397
|
const expectedDate = parseDate(String(expectedValue), formats);
|
|
8370
9398
|
if (candidateDate === null) {
|
|
8371
9399
|
return {
|
|
8372
|
-
path:
|
|
9400
|
+
path: path28,
|
|
8373
9401
|
score: 0,
|
|
8374
9402
|
weight,
|
|
8375
9403
|
hit: false,
|
|
8376
|
-
message: `${
|
|
9404
|
+
message: `${path28} (unparseable candidate date)`
|
|
8377
9405
|
};
|
|
8378
9406
|
}
|
|
8379
9407
|
if (expectedDate === null) {
|
|
8380
9408
|
return {
|
|
8381
|
-
path:
|
|
9409
|
+
path: path28,
|
|
8382
9410
|
score: 0,
|
|
8383
9411
|
weight,
|
|
8384
9412
|
hit: false,
|
|
8385
|
-
message: `${
|
|
9413
|
+
message: `${path28} (unparseable expected date)`
|
|
8386
9414
|
};
|
|
8387
9415
|
}
|
|
8388
9416
|
if (candidateDate.getFullYear() === expectedDate.getFullYear() && candidateDate.getMonth() === expectedDate.getMonth() && candidateDate.getDate() === expectedDate.getDate()) {
|
|
8389
9417
|
return {
|
|
8390
|
-
path:
|
|
9418
|
+
path: path28,
|
|
8391
9419
|
score: 1,
|
|
8392
9420
|
weight,
|
|
8393
9421
|
hit: true,
|
|
8394
|
-
message:
|
|
9422
|
+
message: path28
|
|
8395
9423
|
};
|
|
8396
9424
|
}
|
|
8397
9425
|
return {
|
|
8398
|
-
path:
|
|
9426
|
+
path: path28,
|
|
8399
9427
|
score: 0,
|
|
8400
9428
|
weight,
|
|
8401
9429
|
hit: false,
|
|
8402
|
-
message: `${
|
|
9430
|
+
message: `${path28} (date mismatch: got ${formatDateISO(candidateDate)}, expected ${formatDateISO(expectedDate)})`
|
|
8403
9431
|
};
|
|
8404
9432
|
}
|
|
8405
9433
|
/**
|
|
@@ -8439,11 +9467,11 @@ var FieldAccuracyEvaluator = class {
|
|
|
8439
9467
|
};
|
|
8440
9468
|
}
|
|
8441
9469
|
};
|
|
8442
|
-
function resolvePath(obj,
|
|
8443
|
-
if (!
|
|
9470
|
+
function resolvePath(obj, path28) {
|
|
9471
|
+
if (!path28 || !obj) {
|
|
8444
9472
|
return void 0;
|
|
8445
9473
|
}
|
|
8446
|
-
const parts =
|
|
9474
|
+
const parts = path28.split(/\.|\[|\]/).filter((p) => p.length > 0);
|
|
8447
9475
|
let current = obj;
|
|
8448
9476
|
for (const part of parts) {
|
|
8449
9477
|
if (current === null || current === void 0) {
|
|
@@ -8963,7 +9991,7 @@ var ToolTrajectoryEvaluator = class {
|
|
|
8963
9991
|
|
|
8964
9992
|
// src/evaluation/orchestrator.ts
|
|
8965
9993
|
var import_node_crypto5 = require("crypto");
|
|
8966
|
-
var
|
|
9994
|
+
var import_node_path27 = __toESM(require("path"), 1);
|
|
8967
9995
|
var import_micromatch4 = __toESM(require("micromatch"), 1);
|
|
8968
9996
|
|
|
8969
9997
|
// ../../node_modules/.bun/yocto-queue@1.2.2/node_modules/yocto-queue/index.js
|
|
@@ -9766,7 +10794,7 @@ async function runEvaluatorList(options) {
|
|
|
9766
10794
|
});
|
|
9767
10795
|
}
|
|
9768
10796
|
if (evaluator.type === "composite") {
|
|
9769
|
-
const evalFileDir = evalCase.guideline_paths[0] ?
|
|
10797
|
+
const evalFileDir = evalCase.guideline_paths[0] ? import_node_path27.default.dirname(evalCase.guideline_paths[0]) : process.cwd();
|
|
9770
10798
|
const createEvaluator = (memberConfig) => {
|
|
9771
10799
|
switch (memberConfig.type) {
|
|
9772
10800
|
case "llm_judge":
|
|
@@ -10122,7 +11150,7 @@ async function executePromptTemplate(script, context, config, timeoutMs) {
|
|
|
10122
11150
|
};
|
|
10123
11151
|
const inputJson = JSON.stringify(toSnakeCaseDeep(payload), null, 2);
|
|
10124
11152
|
const scriptPath = script[script.length - 1];
|
|
10125
|
-
const cwd =
|
|
11153
|
+
const cwd = import_node_path27.default.dirname(scriptPath);
|
|
10126
11154
|
try {
|
|
10127
11155
|
const stdout = await executeScript(script, inputJson, timeoutMs, cwd);
|
|
10128
11156
|
const prompt = stdout.trim();
|