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