agentv 3.11.0 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -301,7 +301,7 @@ var require_dist = __commonJS({
301
301
  }
302
302
  });
303
303
 
304
- // ../../packages/core/dist/chunk-AVTN5AB7.js
304
+ // ../../packages/core/dist/chunk-4XWPXNQM.js
305
305
  import { constants } from "node:fs";
306
306
  import { access, readFile } from "node:fs/promises";
307
307
  import path from "node:path";
@@ -419,7 +419,7 @@ __export(external_exports2, {
419
419
  void: () => voidType
420
420
  });
421
421
 
422
- // ../../packages/core/dist/chunk-AVTN5AB7.js
422
+ // ../../packages/core/dist/chunk-4XWPXNQM.js
423
423
  import { readFile as readFile2 } from "node:fs/promises";
424
424
  import path3 from "node:path";
425
425
  import fg from "fast-glob";
@@ -938,14 +938,14 @@ function resolveTargetDefinition(definition, env = process.env, evalFilePath) {
938
938
  providerBatching,
939
939
  config: resolvePiCodingAgentConfig(parsed, env, evalFilePath)
940
940
  };
941
- case "pi-agent-sdk":
941
+ case "pi-cli":
942
942
  return {
943
- kind: "pi-agent-sdk",
943
+ kind: "pi-cli",
944
944
  name: parsed.name,
945
945
  graderTarget: parsed.grader_target ?? parsed.judge_target,
946
946
  workers: parsed.workers,
947
947
  providerBatching,
948
- config: resolvePiAgentSdkConfig(parsed, env)
948
+ config: resolvePiCliConfig(parsed, env, evalFilePath)
949
949
  };
950
950
  case "claude":
951
951
  case "claude-code":
@@ -1362,23 +1362,17 @@ function normalizeCopilotLogFormat(value) {
1362
1362
  throw new Error("copilot log format must be 'summary' or 'json'");
1363
1363
  }
1364
1364
  function resolvePiCodingAgentConfig(target, env, evalFilePath) {
1365
- const executableSource = target.executable ?? target.command ?? target.binary;
1366
1365
  const subproviderSource = target.subprovider;
1367
1366
  const modelSource = target.model ?? target.pi_model ?? target.piModel;
1368
1367
  const apiKeySource = target.api_key ?? target.apiKey;
1369
1368
  const toolsSource = target.tools ?? target.pi_tools ?? target.piTools;
1370
1369
  const thinkingSource = target.thinking ?? target.pi_thinking ?? target.piThinking;
1371
- const argsSource = target.args ?? target.arguments;
1372
1370
  const cwdSource = target.cwd;
1373
1371
  const workspaceTemplateSource = target.workspace_template ?? target.workspaceTemplate;
1374
1372
  const timeoutSource = target.timeout_seconds ?? target.timeoutSeconds;
1375
1373
  const logDirSource = target.log_dir ?? target.logDir ?? target.log_directory ?? target.logDirectory;
1376
1374
  const logFormatSource = target.log_format ?? target.logFormat;
1377
1375
  const systemPromptSource = target.system_prompt ?? target.systemPrompt;
1378
- const executable = resolveOptionalString(executableSource, env, `${target.name} pi executable`, {
1379
- allowLiteral: true,
1380
- optionalEnv: true
1381
- }) ?? "pi";
1382
1376
  const subprovider = resolveOptionalString(
1383
1377
  subproviderSource,
1384
1378
  env,
@@ -1404,7 +1398,6 @@ function resolvePiCodingAgentConfig(target, env, evalFilePath) {
1404
1398
  allowLiteral: true,
1405
1399
  optionalEnv: true
1406
1400
  });
1407
- const args = resolveOptionalStringArray(argsSource, env, `${target.name} pi args`);
1408
1401
  const cwd = resolveOptionalString(cwdSource, env, `${target.name} pi cwd`, {
1409
1402
  allowLiteral: true,
1410
1403
  optionalEnv: true
@@ -1434,13 +1427,11 @@ function resolvePiCodingAgentConfig(target, env, evalFilePath) {
1434
1427
  const logFormat = logFormatSource === "json" || logFormatSource === "summary" ? logFormatSource : void 0;
1435
1428
  const systemPrompt = typeof systemPromptSource === "string" && systemPromptSource.trim().length > 0 ? systemPromptSource.trim() : void 0;
1436
1429
  return {
1437
- executable,
1438
1430
  subprovider,
1439
1431
  model,
1440
1432
  apiKey,
1441
1433
  tools,
1442
1434
  thinking,
1443
- args,
1444
1435
  cwd,
1445
1436
  workspaceTemplate,
1446
1437
  timeoutMs,
@@ -1449,36 +1440,83 @@ function resolvePiCodingAgentConfig(target, env, evalFilePath) {
1449
1440
  systemPrompt
1450
1441
  };
1451
1442
  }
1452
- function resolvePiAgentSdkConfig(target, env) {
1443
+ function resolvePiCliConfig(target, env, evalFilePath) {
1444
+ const executableSource = target.executable ?? target.command ?? target.binary;
1453
1445
  const subproviderSource = target.subprovider;
1454
1446
  const modelSource = target.model ?? target.pi_model ?? target.piModel;
1455
1447
  const apiKeySource = target.api_key ?? target.apiKey;
1448
+ const toolsSource = target.tools ?? target.pi_tools ?? target.piTools;
1449
+ const thinkingSource = target.thinking ?? target.pi_thinking ?? target.piThinking;
1450
+ const cwdSource = target.cwd;
1451
+ const workspaceTemplateSource = target.workspace_template ?? target.workspaceTemplate;
1456
1452
  const timeoutSource = target.timeout_seconds ?? target.timeoutSeconds;
1453
+ const logDirSource = target.log_dir ?? target.logDir ?? target.log_directory ?? target.logDirectory;
1454
+ const logFormatSource = target.log_format ?? target.logFormat;
1457
1455
  const systemPromptSource = target.system_prompt ?? target.systemPrompt;
1456
+ const executable = resolveOptionalString(executableSource, env, `${target.name} pi-cli executable`, {
1457
+ allowLiteral: true,
1458
+ optionalEnv: true
1459
+ }) ?? "pi";
1458
1460
  const subprovider = resolveOptionalString(
1459
1461
  subproviderSource,
1460
1462
  env,
1461
- `${target.name} pi-agent-sdk subprovider`,
1462
- {
1463
- allowLiteral: true,
1464
- optionalEnv: true
1465
- }
1463
+ `${target.name} pi-cli subprovider`,
1464
+ { allowLiteral: true, optionalEnv: true }
1466
1465
  );
1467
- const model = resolveOptionalString(modelSource, env, `${target.name} pi-agent-sdk model`, {
1466
+ const model = resolveOptionalString(modelSource, env, `${target.name} pi-cli model`, {
1468
1467
  allowLiteral: true,
1469
1468
  optionalEnv: true
1470
1469
  });
1471
- const apiKey = resolveOptionalString(apiKeySource, env, `${target.name} pi-agent-sdk api key`, {
1470
+ const apiKey = resolveOptionalString(apiKeySource, env, `${target.name} pi-cli api key`, {
1472
1471
  allowLiteral: false,
1473
1472
  optionalEnv: true
1474
1473
  });
1475
- const timeoutMs = resolveTimeoutMs(timeoutSource, `${target.name} pi-agent-sdk timeout`);
1474
+ const tools = resolveOptionalString(toolsSource, env, `${target.name} pi-cli tools`, {
1475
+ allowLiteral: true,
1476
+ optionalEnv: true
1477
+ });
1478
+ const thinking = resolveOptionalString(thinkingSource, env, `${target.name} pi-cli thinking`, {
1479
+ allowLiteral: true,
1480
+ optionalEnv: true
1481
+ });
1482
+ const rawArgs = target.args ?? target.arguments;
1483
+ const args = resolveOptionalStringArray(rawArgs, env, `${target.name} pi-cli args`);
1484
+ const cwd = resolveOptionalString(cwdSource, env, `${target.name} pi-cli cwd`, {
1485
+ allowLiteral: true,
1486
+ optionalEnv: true
1487
+ });
1488
+ let workspaceTemplate = resolveOptionalString(
1489
+ workspaceTemplateSource,
1490
+ env,
1491
+ `${target.name} pi-cli workspace template`,
1492
+ { allowLiteral: true, optionalEnv: true }
1493
+ );
1494
+ if (workspaceTemplate && evalFilePath && !path2.isAbsolute(workspaceTemplate)) {
1495
+ workspaceTemplate = path2.resolve(path2.dirname(path2.resolve(evalFilePath)), workspaceTemplate);
1496
+ }
1497
+ if (cwd && workspaceTemplate) {
1498
+ throw new Error(`${target.name}: 'cwd' and 'workspace_template' are mutually exclusive.`);
1499
+ }
1500
+ const timeoutMs = resolveTimeoutMs(timeoutSource, `${target.name} pi-cli timeout`);
1501
+ const logDir = resolveOptionalString(logDirSource, env, `${target.name} pi-cli log directory`, {
1502
+ allowLiteral: true,
1503
+ optionalEnv: true
1504
+ });
1505
+ const logFormat = logFormatSource === "json" || logFormatSource === "summary" ? logFormatSource : void 0;
1476
1506
  const systemPrompt = typeof systemPromptSource === "string" && systemPromptSource.trim().length > 0 ? systemPromptSource.trim() : void 0;
1477
1507
  return {
1508
+ executable,
1478
1509
  subprovider,
1479
1510
  model,
1480
1511
  apiKey,
1512
+ tools,
1513
+ thinking,
1514
+ args,
1515
+ cwd,
1516
+ workspaceTemplate,
1481
1517
  timeoutMs,
1518
+ logDir,
1519
+ logFormat,
1482
1520
  systemPrompt
1483
1521
  };
1484
1522
  }
@@ -1608,8 +1646,8 @@ function resolveCliConfig(target, env, evalFilePath) {
1608
1646
  const parseResult = CliTargetInputSchema.safeParse(target, { errorMap: cliErrorMap });
1609
1647
  if (!parseResult.success) {
1610
1648
  const firstError = parseResult.error.errors[0];
1611
- const path44 = firstError?.path.join(".") || "";
1612
- const prefix = path44 ? `${target.name} ${path44}: ` : `${target.name}: `;
1649
+ const path45 = firstError?.path.join(".") || "";
1650
+ const prefix = path45 ? `${target.name} ${path45}: ` : `${target.name}: `;
1613
1651
  throw new Error(`${prefix}${firstError?.message}`);
1614
1652
  }
1615
1653
  const normalized = normalizeCliTargetInput(parseResult.data, env, evalFilePath);
@@ -1949,7 +1987,7 @@ var AGENT_PROVIDER_KINDS = [
1949
1987
  "copilot-sdk",
1950
1988
  "copilot-cli",
1951
1989
  "pi-coding-agent",
1952
- "pi-agent-sdk",
1990
+ "pi-cli",
1953
1991
  "claude",
1954
1992
  "claude-cli",
1955
1993
  "claude-sdk",
@@ -1966,7 +2004,7 @@ var KNOWN_PROVIDERS = [
1966
2004
  "copilot-sdk",
1967
2005
  "copilot-cli",
1968
2006
  "pi-coding-agent",
1969
- "pi-agent-sdk",
2007
+ "pi-cli",
1970
2008
  "claude",
1971
2009
  "claude-cli",
1972
2010
  "claude-sdk",
@@ -6651,7 +6689,7 @@ function createOpenRouter(options = {}) {
6651
6689
  );
6652
6690
  const createChatModel = (modelId, settings = {}) => new OpenRouterChatLanguageModel(modelId, settings, {
6653
6691
  provider: "openrouter.chat",
6654
- url: ({ path: path44 }) => `${baseURL}${path44}`,
6692
+ url: ({ path: path45 }) => `${baseURL}${path45}`,
6655
6693
  headers: getHeaders,
6656
6694
  compatibility,
6657
6695
  fetch: options.fetch,
@@ -6659,7 +6697,7 @@ function createOpenRouter(options = {}) {
6659
6697
  });
6660
6698
  const createCompletionModel = (modelId, settings = {}) => new OpenRouterCompletionLanguageModel(modelId, settings, {
6661
6699
  provider: "openrouter.completion",
6662
- url: ({ path: path44 }) => `${baseURL}${path44}`,
6700
+ url: ({ path: path45 }) => `${baseURL}${path45}`,
6663
6701
  headers: getHeaders,
6664
6702
  compatibility,
6665
6703
  fetch: options.fetch,
@@ -6667,14 +6705,14 @@ function createOpenRouter(options = {}) {
6667
6705
  });
6668
6706
  const createEmbeddingModel = (modelId, settings = {}) => new OpenRouterEmbeddingModel(modelId, settings, {
6669
6707
  provider: "openrouter.embedding",
6670
- url: ({ path: path44 }) => `${baseURL}${path44}`,
6708
+ url: ({ path: path45 }) => `${baseURL}${path45}`,
6671
6709
  headers: getHeaders,
6672
6710
  fetch: options.fetch,
6673
6711
  extraBody: options.extraBody
6674
6712
  });
6675
6713
  const createImageModel = (modelId, settings = {}) => new OpenRouterImageModel(modelId, settings, {
6676
6714
  provider: "openrouter.image",
6677
- url: ({ path: path44 }) => `${baseURL}${path44}`,
6715
+ url: ({ path: path45 }) => `${baseURL}${path45}`,
6678
6716
  headers: getHeaders,
6679
6717
  fetch: options.fetch,
6680
6718
  extraBody: options.extraBody
@@ -14183,37 +14221,43 @@ import { createWriteStream as createWriteStream5 } from "node:fs";
14183
14221
  import { mkdir as mkdir6, mkdtemp, rm, writeFile } from "node:fs/promises";
14184
14222
  import { tmpdir } from "node:os";
14185
14223
  import path17 from "node:path";
14224
+ import { execSync } from "node:child_process";
14225
+ import { randomUUID as randomUUID8 } from "node:crypto";
14226
+ import { createWriteStream as createWriteStream6 } from "node:fs";
14227
+ import { mkdir as mkdir7 } from "node:fs/promises";
14228
+ import path18 from "node:path";
14229
+ import { createInterface } from "node:readline";
14186
14230
  import { exec as exec2 } from "node:child_process";
14187
14231
  import { constants as constants3, access as access3, stat as stat4 } from "node:fs/promises";
14188
- import path29 from "node:path";
14232
+ import path30 from "node:path";
14189
14233
  import { promisify as promisify3 } from "node:util";
14190
14234
  import { stat as stat3, writeFile as writeFile4 } from "node:fs/promises";
14191
- import path27 from "node:path";
14235
+ import path28 from "node:path";
14192
14236
  import { constants as constants22 } from "node:fs";
14193
- import { access as access22, mkdir as mkdir7, readdir, rm as rm2, stat } from "node:fs/promises";
14194
- import path18 from "node:path";
14237
+ import { access as access22, mkdir as mkdir8, readdir, rm as rm2, stat } from "node:fs/promises";
14195
14238
  import path19 from "node:path";
14196
14239
  import path20 from "node:path";
14197
- import { readFile as readFile7 } from "node:fs/promises";
14198
14240
  import path21 from "node:path";
14241
+ import { readFile as readFile7 } from "node:fs/promises";
14242
+ import path222 from "node:path";
14199
14243
  import { exec, spawn as spawn4 } from "node:child_process";
14200
- import { mkdir as mkdir8, writeFile as writeFile2 } from "node:fs/promises";
14201
- import path24 from "node:path";
14244
+ import { mkdir as mkdir9, writeFile as writeFile2 } from "node:fs/promises";
14245
+ import path25 from "node:path";
14202
14246
  import { promisify as promisify2 } from "node:util";
14203
- import path23 from "node:path";
14247
+ import path24 from "node:path";
14204
14248
  import os2 from "node:os";
14205
- import path222 from "node:path";
14206
- import { copyFile, mkdir as mkdir9, readFile as readFile8, readdir as readdir2, stat as stat2, writeFile as writeFile3 } from "node:fs/promises";
14249
+ import path23 from "node:path";
14250
+ import { copyFile, mkdir as mkdir10, readFile as readFile8, readdir as readdir2, stat as stat2, writeFile as writeFile3 } from "node:fs/promises";
14251
+ import path27 from "node:path";
14207
14252
  import path26 from "node:path";
14208
- import path25 from "node:path";
14209
14253
  import JSON5 from "json5";
14210
14254
  import { writeFile as writeFile5 } from "node:fs/promises";
14211
- import path28 from "node:path";
14255
+ import path29 from "node:path";
14212
14256
  import { constants as constants4 } from "node:fs";
14213
14257
  import { access as access4, readFile as readFile9 } from "node:fs/promises";
14214
- import path30 from "node:path";
14215
- import { parse as parse4 } from "yaml";
14216
14258
  import path31 from "node:path";
14259
+ import { parse as parse4 } from "yaml";
14260
+ import path322 from "node:path";
14217
14261
  import fg2 from "fast-glob";
14218
14262
  import { mkdtemp as mkdtemp2, rm as rm3, writeFile as writeFile6 } from "node:fs/promises";
14219
14263
  import { tmpdir as tmpdir2 } from "node:os";
@@ -14221,38 +14265,38 @@ import { dirname, join } from "node:path";
14221
14265
  import { randomBytes } from "node:crypto";
14222
14266
  import { createServer } from "node:http";
14223
14267
  import fs2 from "node:fs/promises";
14224
- import path322 from "node:path";
14225
- import { createHash as createHash2, randomUUID as randomUUID8 } from "node:crypto";
14226
- import { copyFile as copyFile2, mkdir as mkdir13, readdir as readdir6, stat as stat7 } from "node:fs/promises";
14227
- import path41 from "node:path";
14228
- import micromatch3 from "micromatch";
14229
14268
  import path33 from "node:path";
14269
+ import { createHash as createHash2, randomUUID as randomUUID9 } from "node:crypto";
14270
+ import { copyFile as copyFile2, mkdir as mkdir14, readdir as readdir6, stat as stat7 } from "node:fs/promises";
14271
+ import path422 from "node:path";
14272
+ import micromatch3 from "micromatch";
14230
14273
  import path34 from "node:path";
14231
- import fg22 from "fast-glob";
14232
14274
  import path35 from "node:path";
14275
+ import fg22 from "fast-glob";
14276
+ import path36 from "node:path";
14233
14277
  import fg3 from "fast-glob";
14234
14278
  import { exec as execCallback } from "node:child_process";
14235
14279
  import { readdirSync as readdirSync2, statSync } from "node:fs";
14236
- import path36 from "node:path";
14237
- import { promisify as promisify4 } from "node:util";
14238
- import { cp, mkdir as mkdir11, readdir as readdir3, rm as rm4, stat as stat5 } from "node:fs/promises";
14239
14280
  import path37 from "node:path";
14281
+ import { promisify as promisify4 } from "node:util";
14282
+ import { cp, mkdir as mkdir12, readdir as readdir3, rm as rm4, stat as stat5 } from "node:fs/promises";
14283
+ import path38 from "node:path";
14240
14284
  import { execFile } from "node:child_process";
14241
14285
  import { createHash } from "node:crypto";
14242
14286
  import { existsSync as existsSync2 } from "node:fs";
14243
- import { cp as cp2, mkdir as mkdir12, readFile as readFile10, readdir as readdir4, rm as rm5, unlink, writeFile as writeFile7 } from "node:fs/promises";
14244
- import path38 from "node:path";
14287
+ import { cp as cp2, mkdir as mkdir13, readFile as readFile10, readdir as readdir4, rm as rm5, unlink, writeFile as writeFile7 } from "node:fs/promises";
14288
+ import path39 from "node:path";
14245
14289
  import { promisify as promisify5 } from "node:util";
14246
14290
  import { execFile as execFile2 } from "node:child_process";
14247
14291
  import { existsSync as existsSync3 } from "node:fs";
14248
- import path39 from "node:path";
14292
+ import path40 from "node:path";
14249
14293
  import { promisify as promisify6 } from "node:util";
14250
14294
  import { readdir as readdir5, stat as stat6 } from "node:fs/promises";
14251
- import path40 from "node:path";
14295
+ import path41 from "node:path";
14252
14296
  import { existsSync as existsSync4 } from "node:fs";
14253
- import path422 from "node:path";
14254
- import { mkdir as mkdir14, readFile as readFile11, writeFile as writeFile8 } from "node:fs/promises";
14255
14297
  import path43 from "node:path";
14298
+ import { mkdir as mkdir15, readFile as readFile11, writeFile as writeFile8 } from "node:fs/promises";
14299
+ import path44 from "node:path";
14256
14300
  function computeTraceSummary(messages) {
14257
14301
  const toolCallCounts = {};
14258
14302
  const toolDurations = {};
@@ -20871,260 +20915,6 @@ var MockProvider = class {
20871
20915
  return this.delayMs;
20872
20916
  }
20873
20917
  };
20874
- function extractPiTextContent(content) {
20875
- if (typeof content === "string") {
20876
- return content;
20877
- }
20878
- if (!Array.isArray(content)) {
20879
- return void 0;
20880
- }
20881
- const textParts = [];
20882
- for (const part of content) {
20883
- if (!part || typeof part !== "object") {
20884
- continue;
20885
- }
20886
- const p = part;
20887
- if (p.type === "text" && typeof p.text === "string") {
20888
- textParts.push(p.text);
20889
- }
20890
- }
20891
- return textParts.length > 0 ? textParts.join("\n") : void 0;
20892
- }
20893
- function toFiniteNumber(value) {
20894
- if (typeof value === "number" && Number.isFinite(value)) return value;
20895
- return void 0;
20896
- }
20897
- var piAgentModule = null;
20898
- var piAiModule = null;
20899
- async function loadPiModules() {
20900
- if (!piAgentModule || !piAiModule) {
20901
- try {
20902
- [piAgentModule, piAiModule] = await Promise.all([
20903
- import("@mariozechner/pi-agent-core"),
20904
- import("@mariozechner/pi-ai")
20905
- ]);
20906
- } catch (error) {
20907
- throw new Error(
20908
- `Failed to load pi-agent-sdk dependencies. Please install them:
20909
- npm install @mariozechner/pi-agent-core @mariozechner/pi-ai
20910
-
20911
- Original error: ${error instanceof Error ? error.message : String(error)}`
20912
- );
20913
- }
20914
- }
20915
- return {
20916
- Agent: piAgentModule.Agent,
20917
- getModel: piAiModule.getModel,
20918
- getEnvApiKey: piAiModule.getEnvApiKey
20919
- };
20920
- }
20921
- var PiAgentSdkProvider = class {
20922
- id;
20923
- kind = "pi-agent-sdk";
20924
- targetName;
20925
- supportsBatch = false;
20926
- config;
20927
- constructor(targetName, config) {
20928
- this.id = `pi-agent-sdk:${targetName}`;
20929
- this.targetName = targetName;
20930
- this.config = config;
20931
- }
20932
- async invoke(request) {
20933
- if (request.signal?.aborted) {
20934
- throw new Error("Pi agent SDK request was aborted before execution");
20935
- }
20936
- const { Agent, getModel, getEnvApiKey } = await loadPiModules();
20937
- const startTimeIso = (/* @__PURE__ */ new Date()).toISOString();
20938
- const startMs = Date.now();
20939
- const providerName = this.config.subprovider ?? "anthropic";
20940
- const modelId = this.config.model ?? "claude-sonnet-4-20250514";
20941
- const model = getModel(providerName, modelId);
20942
- const systemPrompt = this.config.systemPrompt ?? "Answer directly and concisely.";
20943
- const agent = new Agent({
20944
- initialState: {
20945
- systemPrompt,
20946
- model,
20947
- tools: [],
20948
- // No tools for simple Q&A
20949
- messages: []
20950
- },
20951
- getApiKey: async (provider) => {
20952
- return this.config.apiKey ?? getEnvApiKey(provider) ?? void 0;
20953
- }
20954
- });
20955
- let tokenUsage;
20956
- let costUsd;
20957
- const toolTrackers = /* @__PURE__ */ new Map();
20958
- const completedToolResults = /* @__PURE__ */ new Map();
20959
- const unsubscribe = agent.subscribe((event) => {
20960
- switch (event.type) {
20961
- case "message_end": {
20962
- const msg = event.message;
20963
- if (msg && typeof msg === "object" && "role" in msg && msg.role === "assistant" && "usage" in msg) {
20964
- const usage = msg.usage;
20965
- if (usage && typeof usage === "object") {
20966
- const u = usage;
20967
- const input = toFiniteNumber(u.input);
20968
- const output = toFiniteNumber(u.output);
20969
- const cached = toFiniteNumber(u.cacheRead);
20970
- let callDelta;
20971
- if (input !== void 0 || output !== void 0) {
20972
- callDelta = {
20973
- input: input ?? 0,
20974
- output: output ?? 0,
20975
- ...cached !== void 0 ? { cached } : {}
20976
- };
20977
- tokenUsage = {
20978
- input: (tokenUsage?.input ?? 0) + callDelta.input,
20979
- output: (tokenUsage?.output ?? 0) + callDelta.output,
20980
- ...cached !== void 0 ? { cached: (tokenUsage?.cached ?? 0) + cached } : tokenUsage?.cached !== void 0 ? { cached: tokenUsage.cached } : {}
20981
- };
20982
- }
20983
- const cost = u.cost;
20984
- if (cost && typeof cost === "object") {
20985
- const total = toFiniteNumber(cost.total);
20986
- if (total !== void 0) {
20987
- costUsd = (costUsd ?? 0) + total;
20988
- }
20989
- }
20990
- request.streamCallbacks?.onLlmCallEnd?.(modelId, callDelta);
20991
- }
20992
- }
20993
- break;
20994
- }
20995
- case "tool_execution_start": {
20996
- toolTrackers.set(event.toolCallId, {
20997
- toolCallId: event.toolCallId,
20998
- toolName: event.toolName,
20999
- args: event.args,
21000
- startMs: Date.now(),
21001
- startTime: (/* @__PURE__ */ new Date()).toISOString()
21002
- });
21003
- request.streamCallbacks?.onToolCallStart?.(event.toolName, event.toolCallId);
21004
- break;
21005
- }
21006
- case "tool_execution_end": {
21007
- const tracker = toolTrackers.get(event.toolCallId);
21008
- const durationMs = tracker ? Date.now() - tracker.startMs : 0;
21009
- completedToolResults.set(event.toolCallId, {
21010
- output: event.result,
21011
- durationMs
21012
- });
21013
- request.streamCallbacks?.onToolCallEnd?.(
21014
- event.toolName,
21015
- tracker?.args,
21016
- event.result,
21017
- durationMs,
21018
- event.toolCallId
21019
- );
21020
- toolTrackers.delete(event.toolCallId);
21021
- break;
21022
- }
21023
- }
21024
- });
21025
- try {
21026
- if (this.config.timeoutMs) {
21027
- const timeoutMs = this.config.timeoutMs;
21028
- const timeoutPromise = new Promise((_, reject) => {
21029
- setTimeout(
21030
- () => reject(new Error(`Pi agent SDK timed out after ${timeoutMs}ms`)),
21031
- timeoutMs
21032
- );
21033
- });
21034
- await Promise.race([agent.prompt(request.question), timeoutPromise]);
21035
- } else {
21036
- await agent.prompt(request.question);
21037
- }
21038
- await agent.waitForIdle();
21039
- const agentMessages = agent.state.messages;
21040
- const output = [];
21041
- for (const msg of agentMessages) {
21042
- output.push(convertAgentMessage(msg, toolTrackers, completedToolResults));
21043
- }
21044
- const endTimeIso = (/* @__PURE__ */ new Date()).toISOString();
21045
- const durationMs = Date.now() - startMs;
21046
- return {
21047
- raw: {
21048
- messages: agentMessages,
21049
- systemPrompt,
21050
- model: this.config.model,
21051
- subprovider: this.config.subprovider
21052
- },
21053
- output,
21054
- tokenUsage,
21055
- costUsd,
21056
- durationMs,
21057
- startTime: startTimeIso,
21058
- endTime: endTimeIso
21059
- };
21060
- } finally {
21061
- unsubscribe();
21062
- }
21063
- }
21064
- };
21065
- function convertAgentMessage(message, toolTrackers, completedToolResults) {
21066
- if (!message || typeof message !== "object") {
21067
- return { role: "unknown", content: String(message) };
21068
- }
21069
- const msg = message;
21070
- const role = typeof msg.role === "string" ? msg.role : "unknown";
21071
- const content = extractPiTextContent(msg.content);
21072
- const toolCalls = extractToolCalls3(msg.content, toolTrackers, completedToolResults);
21073
- const startTime = typeof msg.timestamp === "number" ? new Date(msg.timestamp).toISOString() : typeof msg.timestamp === "string" ? msg.timestamp : void 0;
21074
- let msgTokenUsage;
21075
- if (msg.usage && typeof msg.usage === "object") {
21076
- const u = msg.usage;
21077
- const input = toFiniteNumber(u.input);
21078
- const output = toFiniteNumber(u.output);
21079
- if (input !== void 0 || output !== void 0) {
21080
- msgTokenUsage = {
21081
- input: input ?? 0,
21082
- output: output ?? 0,
21083
- ...toFiniteNumber(u.cacheRead) !== void 0 ? { cached: toFiniteNumber(u.cacheRead) } : {}
21084
- };
21085
- }
21086
- }
21087
- const metadata = {};
21088
- if (msg.api) metadata.api = msg.api;
21089
- if (msg.provider) metadata.provider = msg.provider;
21090
- if (msg.model) metadata.model = msg.model;
21091
- if (msg.stopReason) metadata.stopReason = msg.stopReason;
21092
- return {
21093
- role,
21094
- content,
21095
- toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
21096
- startTime,
21097
- metadata: Object.keys(metadata).length > 0 ? metadata : void 0,
21098
- tokenUsage: msgTokenUsage
21099
- };
21100
- }
21101
- function extractToolCalls3(content, toolTrackers, completedToolResults) {
21102
- if (!Array.isArray(content)) {
21103
- return [];
21104
- }
21105
- const toolCalls = [];
21106
- for (const part of content) {
21107
- if (!part || typeof part !== "object") {
21108
- continue;
21109
- }
21110
- const p = part;
21111
- if (p.type === "toolCall" && typeof p.name === "string") {
21112
- const id = typeof p.id === "string" ? p.id : void 0;
21113
- const tracker = id ? toolTrackers.get(id) : void 0;
21114
- const completed = id ? completedToolResults.get(id) : void 0;
21115
- toolCalls.push({
21116
- tool: p.name,
21117
- input: p.arguments,
21118
- id,
21119
- output: completed?.output,
21120
- durationMs: completed?.durationMs,
21121
- startTime: tracker?.startTime,
21122
- endTime: tracker?.startTime && completed?.durationMs !== void 0 ? new Date(new Date(tracker.startTime).getTime() + completed.durationMs).toISOString() : void 0
21123
- });
21124
- }
21125
- }
21126
- return toolCalls;
21127
- }
21128
20918
  var GLOBAL_LOGS_KEY5 = Symbol.for("agentv.piLogs");
21129
20919
  var GLOBAL_SUBSCRIBERS_KEY5 = Symbol.for("agentv.piLogSubscribers");
21130
20920
  function getPiLogStore() {
@@ -21176,24 +20966,47 @@ function subscribeToPiLogEntries(listener) {
21176
20966
  store.delete(listener);
21177
20967
  };
21178
20968
  }
21179
- var WORKSPACE_PREFIX = "agentv-pi-";
21180
- var PROMPT_FILENAME = "prompt.md";
21181
- var PiCodingAgentProvider = class {
20969
+ function extractPiTextContent(content) {
20970
+ if (typeof content === "string") {
20971
+ return content;
20972
+ }
20973
+ if (!Array.isArray(content)) {
20974
+ return void 0;
20975
+ }
20976
+ const textParts = [];
20977
+ for (const part of content) {
20978
+ if (!part || typeof part !== "object") {
20979
+ continue;
20980
+ }
20981
+ const p = part;
20982
+ if (p.type === "text" && typeof p.text === "string") {
20983
+ textParts.push(p.text);
20984
+ }
20985
+ }
20986
+ return textParts.length > 0 ? textParts.join("\n") : void 0;
20987
+ }
20988
+ function toFiniteNumber(value) {
20989
+ if (typeof value === "number" && Number.isFinite(value)) return value;
20990
+ return void 0;
20991
+ }
20992
+ var WORKSPACE_PREFIX = "agentv-pi-";
20993
+ var PROMPT_FILENAME = "prompt.md";
20994
+ var PiCliProvider = class {
21182
20995
  id;
21183
- kind = "pi-coding-agent";
20996
+ kind = "pi-cli";
21184
20997
  targetName;
21185
20998
  supportsBatch = false;
21186
20999
  config;
21187
21000
  runPi;
21188
21001
  constructor(targetName, config, runner = defaultPiRunner) {
21189
- this.id = `pi-coding-agent:${targetName}`;
21002
+ this.id = `pi-cli:${targetName}`;
21190
21003
  this.targetName = targetName;
21191
21004
  this.config = config;
21192
21005
  this.runPi = runner;
21193
21006
  }
21194
21007
  async invoke(request) {
21195
21008
  if (request.signal?.aborted) {
21196
- throw new Error("Pi coding agent request was aborted before execution");
21009
+ throw new Error("Pi CLI request was aborted before execution");
21197
21010
  }
21198
21011
  const inputFiles = normalizeInputFiles(request.inputFiles);
21199
21012
  const startTime = (/* @__PURE__ */ new Date()).toISOString();
@@ -21203,17 +21016,17 @@ var PiCodingAgentProvider = class {
21203
21016
  try {
21204
21017
  const promptFile = path17.join(workspaceRoot, PROMPT_FILENAME);
21205
21018
  await writeFile(promptFile, request.question, "utf8");
21206
- const args = this.buildPiArgs(request.question, inputFiles, request.captureFileChanges);
21019
+ const args = this.buildPiArgs(request.question, inputFiles);
21207
21020
  const cwd = this.resolveCwd(workspaceRoot, request.cwd);
21208
21021
  const result = await this.executePi(args, cwd, request.signal, logger);
21209
21022
  if (result.timedOut) {
21210
21023
  throw new Error(
21211
- `Pi coding agent timed out${formatTimeoutSuffix3(this.config.timeoutMs ?? void 0)}`
21024
+ `Pi CLI timed out${formatTimeoutSuffix3(this.config.timeoutMs ?? void 0)}`
21212
21025
  );
21213
21026
  }
21214
21027
  if (result.exitCode !== 0) {
21215
21028
  const detail = pickDetail(result.stderr, result.stdout);
21216
- const prefix = `Pi coding agent exited with code ${result.exitCode}`;
21029
+ const prefix = `Pi CLI exited with code ${result.exitCode}`;
21217
21030
  throw new Error(detail ? `${prefix}: ${detail}` : prefix);
21218
21031
  }
21219
21032
  const parsed = parsePiJsonl(result.stdout);
@@ -21270,7 +21083,7 @@ var PiCodingAgentProvider = class {
21270
21083
  }
21271
21084
  return path17.resolve(this.config.cwd);
21272
21085
  }
21273
- buildPiArgs(prompt, inputFiles, _captureFileChanges) {
21086
+ buildPiArgs(prompt, inputFiles) {
21274
21087
  const args = [];
21275
21088
  if (this.config.subprovider) {
21276
21089
  args.push("--provider", this.config.subprovider);
@@ -21322,7 +21135,7 @@ ${prompt}` : prompt;
21322
21135
  const err = error;
21323
21136
  if (err.code === "ENOENT") {
21324
21137
  throw new Error(
21325
- `Pi coding agent executable '${this.config.executable}' was not found. Update the target settings.executable or add it to PATH.`
21138
+ `Pi CLI executable '${this.config.executable}' was not found. Update the target executable or add it to PATH.`
21326
21139
  );
21327
21140
  }
21328
21141
  throw error;
@@ -21332,26 +21145,18 @@ ${prompt}` : prompt;
21332
21145
  const env = { ...process.env };
21333
21146
  if (this.config.apiKey) {
21334
21147
  const provider = this.config.subprovider?.toLowerCase() ?? "google";
21335
- switch (provider) {
21336
- case "google":
21337
- case "gemini":
21338
- env.GEMINI_API_KEY = this.config.apiKey;
21339
- break;
21340
- case "anthropic":
21341
- env.ANTHROPIC_API_KEY = this.config.apiKey;
21342
- break;
21343
- case "openai":
21344
- env.OPENAI_API_KEY = this.config.apiKey;
21345
- break;
21346
- case "groq":
21347
- env.GROQ_API_KEY = this.config.apiKey;
21348
- break;
21349
- case "xai":
21350
- env.XAI_API_KEY = this.config.apiKey;
21351
- break;
21352
- case "openrouter":
21353
- env.OPENROUTER_API_KEY = this.config.apiKey;
21354
- break;
21148
+ const ENV_KEY_MAP = {
21149
+ google: "GEMINI_API_KEY",
21150
+ gemini: "GEMINI_API_KEY",
21151
+ anthropic: "ANTHROPIC_API_KEY",
21152
+ openai: "OPENAI_API_KEY",
21153
+ groq: "GROQ_API_KEY",
21154
+ xai: "XAI_API_KEY",
21155
+ openrouter: "OPENROUTER_API_KEY"
21156
+ };
21157
+ const envKey = ENV_KEY_MAP[provider];
21158
+ if (envKey) {
21159
+ env[envKey] = this.config.apiKey;
21355
21160
  }
21356
21161
  }
21357
21162
  return env;
@@ -21369,7 +21174,7 @@ ${prompt}` : prompt;
21369
21174
  if (this.config.logDir) {
21370
21175
  return path17.resolve(this.config.logDir);
21371
21176
  }
21372
- return path17.join(process.cwd(), ".agentv", "logs", "pi-coding-agent");
21177
+ return path17.join(process.cwd(), ".agentv", "logs", "pi-cli");
21373
21178
  }
21374
21179
  async createStreamLogger(request) {
21375
21180
  const logDir = this.resolveLogDirectory();
@@ -21421,7 +21226,7 @@ var PiStreamLogger = class _PiStreamLogger {
21421
21226
  static async create(options) {
21422
21227
  const logger = new _PiStreamLogger(options.filePath, options.format);
21423
21228
  const header = [
21424
- "# Pi Coding Agent stream log",
21229
+ "# Pi CLI stream log",
21425
21230
  `# target: ${options.targetName}`,
21426
21231
  options.evalCaseId ? `# eval: ${options.evalCaseId}` : void 0,
21427
21232
  options.attempt !== void 0 ? `# attempt: ${options.attempt + 1}` : void 0,
@@ -21570,10 +21375,10 @@ function summarizePiEvent(event) {
21570
21375
  return `${type}: ${role}`;
21571
21376
  }
21572
21377
  case "message_update": {
21573
- const event2 = record.assistantMessageEvent;
21574
- const eventType = event2?.type;
21378
+ const evt = record.assistantMessageEvent;
21379
+ const eventType = evt?.type;
21575
21380
  if (eventType === "text_delta") {
21576
- const delta = event2?.delta;
21381
+ const delta = evt?.delta;
21577
21382
  if (typeof delta === "string") {
21578
21383
  const preview = delta.length > 50 ? `${delta.slice(0, 50)}...` : delta;
21579
21384
  return `text_delta: ${preview}`;
@@ -21595,7 +21400,7 @@ function tryParseJsonValue(rawLine) {
21595
21400
  function parsePiJsonl(output) {
21596
21401
  const trimmed = output.trim();
21597
21402
  if (trimmed.length === 0) {
21598
- throw new Error("Pi coding agent produced no output");
21403
+ throw new Error("Pi CLI produced no output");
21599
21404
  }
21600
21405
  const lines = trimmed.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
21601
21406
  const parsed = [];
@@ -21606,38 +21411,27 @@ function parsePiJsonl(output) {
21606
21411
  }
21607
21412
  }
21608
21413
  if (parsed.length === 0) {
21609
- throw new Error("Pi coding agent produced no valid JSON output");
21414
+ throw new Error("Pi CLI produced no valid JSON output");
21610
21415
  }
21611
21416
  return parsed;
21612
21417
  }
21613
21418
  function extractMessages(events) {
21614
21419
  for (let i = events.length - 1; i >= 0; i--) {
21615
21420
  const event = events[i];
21616
- if (!event || typeof event !== "object") {
21617
- continue;
21618
- }
21421
+ if (!event || typeof event !== "object") continue;
21619
21422
  const record = event;
21620
- if (record.type !== "agent_end") {
21621
- continue;
21622
- }
21423
+ if (record.type !== "agent_end") continue;
21623
21424
  const messages = record.messages;
21624
- if (!Array.isArray(messages)) {
21625
- continue;
21626
- }
21425
+ if (!Array.isArray(messages)) continue;
21627
21426
  return messages.map(convertPiMessage).filter((m) => m !== void 0);
21628
21427
  }
21629
21428
  const output = [];
21630
21429
  for (const event of events) {
21631
- if (!event || typeof event !== "object") {
21632
- continue;
21633
- }
21430
+ if (!event || typeof event !== "object") continue;
21634
21431
  const record = event;
21635
21432
  if (record.type === "turn_end") {
21636
- const message = record.message;
21637
- const converted = convertPiMessage(message);
21638
- if (converted) {
21639
- output.push(converted);
21640
- }
21433
+ const converted = convertPiMessage(record.message);
21434
+ if (converted) output.push(converted);
21641
21435
  }
21642
21436
  }
21643
21437
  return output;
@@ -21654,10 +21448,7 @@ function extractTokenUsage(events) {
21654
21448
  const input = toFiniteNumber(u.input_tokens ?? u.inputTokens ?? u.input);
21655
21449
  const output = toFiniteNumber(u.output_tokens ?? u.outputTokens ?? u.output);
21656
21450
  if (input !== void 0 || output !== void 0) {
21657
- const result = {
21658
- input: input ?? 0,
21659
- output: output ?? 0
21660
- };
21451
+ const result = { input: input ?? 0, output: output ?? 0 };
21661
21452
  const cached = toFiniteNumber(u.cache_read_input_tokens ?? u.cached ?? u.cachedTokens);
21662
21453
  const reasoning = toFiniteNumber(u.reasoning_tokens ?? u.reasoningTokens ?? u.reasoning);
21663
21454
  return {
@@ -21705,16 +21496,12 @@ function aggregateUsageFromMessages(messages) {
21705
21496
  return result;
21706
21497
  }
21707
21498
  function convertPiMessage(message) {
21708
- if (!message || typeof message !== "object") {
21709
- return void 0;
21710
- }
21499
+ if (!message || typeof message !== "object") return void 0;
21711
21500
  const msg = message;
21712
21501
  const role = msg.role;
21713
- if (typeof role !== "string") {
21714
- return void 0;
21715
- }
21502
+ if (typeof role !== "string") return void 0;
21716
21503
  const content = extractPiTextContent(msg.content);
21717
- const toolCalls = extractToolCalls4(msg.content);
21504
+ const toolCalls = extractToolCalls3(msg.content);
21718
21505
  const startTime = typeof msg.timestamp === "number" ? new Date(msg.timestamp).toISOString() : typeof msg.timestamp === "string" ? msg.timestamp : void 0;
21719
21506
  const metadata = {};
21720
21507
  if (msg.api) metadata.api = msg.api;
@@ -21730,15 +21517,11 @@ function convertPiMessage(message) {
21730
21517
  metadata: Object.keys(metadata).length > 0 ? metadata : void 0
21731
21518
  };
21732
21519
  }
21733
- function extractToolCalls4(content) {
21734
- if (!Array.isArray(content)) {
21735
- return [];
21736
- }
21520
+ function extractToolCalls3(content) {
21521
+ if (!Array.isArray(content)) return [];
21737
21522
  const toolCalls = [];
21738
21523
  for (const part of content) {
21739
- if (!part || typeof part !== "object") {
21740
- continue;
21741
- }
21524
+ if (!part || typeof part !== "object") continue;
21742
21525
  const p = part;
21743
21526
  if (p.type === "tool_use" && typeof p.name === "string") {
21744
21527
  toolCalls.push({
@@ -21758,10 +21541,7 @@ function extractToolCalls4(content) {
21758
21541
  const existing = toolCalls.find((tc) => tc.id === p.tool_use_id);
21759
21542
  if (existing) {
21760
21543
  const idx = toolCalls.indexOf(existing);
21761
- toolCalls[idx] = {
21762
- ...existing,
21763
- output: p.content
21764
- };
21544
+ toolCalls[idx] = { ...existing, output: p.content };
21765
21545
  }
21766
21546
  }
21767
21547
  }
@@ -21772,18 +21552,13 @@ function escapeAtSymbols(prompt) {
21772
21552
  }
21773
21553
  function pickDetail(stderr, stdout) {
21774
21554
  const errorText = stderr.trim();
21775
- if (errorText.length > 0) {
21776
- return errorText;
21777
- }
21555
+ if (errorText.length > 0) return errorText;
21778
21556
  const stdoutText = stdout.trim();
21779
21557
  return stdoutText.length > 0 ? stdoutText : void 0;
21780
21558
  }
21781
21559
  function formatTimeoutSuffix3(timeoutMs) {
21782
- if (!timeoutMs || timeoutMs <= 0) {
21783
- return "";
21784
- }
21785
- const seconds = Math.ceil(timeoutMs / 1e3);
21786
- return ` after ${seconds}s`;
21560
+ if (!timeoutMs || timeoutMs <= 0) return "";
21561
+ return ` after ${Math.ceil(timeoutMs / 1e3)}s`;
21787
21562
  }
21788
21563
  async function defaultPiRunner(options) {
21789
21564
  return await new Promise((resolve2, reject) => {
@@ -21830,12 +21605,8 @@ async function defaultPiRunner(options) {
21830
21605
  });
21831
21606
  child.stdin.end();
21832
21607
  const cleanup = () => {
21833
- if (timeoutHandle) {
21834
- clearTimeout(timeoutHandle);
21835
- }
21836
- if (options.signal) {
21837
- options.signal.removeEventListener("abort", onAbort);
21838
- }
21608
+ if (timeoutHandle) clearTimeout(timeoutHandle);
21609
+ if (options.signal) options.signal.removeEventListener("abort", onAbort);
21839
21610
  };
21840
21611
  child.on("error", (error) => {
21841
21612
  cleanup();
@@ -21852,6 +21623,460 @@ async function defaultPiRunner(options) {
21852
21623
  });
21853
21624
  });
21854
21625
  }
21626
+ var piCodingAgentModule = null;
21627
+ var piAiModule = null;
21628
+ async function promptInstall() {
21629
+ if (!process.stdout.isTTY) return false;
21630
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
21631
+ try {
21632
+ return await new Promise((resolve2) => {
21633
+ rl.question(
21634
+ "@mariozechner/pi-coding-agent is not installed. Install it now? (y/N) ",
21635
+ (answer) => resolve2(answer.trim().toLowerCase() === "y")
21636
+ );
21637
+ });
21638
+ } finally {
21639
+ rl.close();
21640
+ }
21641
+ }
21642
+ async function loadSdkModules() {
21643
+ if (!piCodingAgentModule || !piAiModule) {
21644
+ try {
21645
+ [piCodingAgentModule, piAiModule] = await Promise.all([
21646
+ import("@mariozechner/pi-coding-agent"),
21647
+ import("@mariozechner/pi-ai")
21648
+ ]);
21649
+ } catch {
21650
+ if (await promptInstall()) {
21651
+ console.error("Installing @mariozechner/pi-coding-agent...");
21652
+ execSync("bun add @mariozechner/pi-coding-agent", { stdio: "inherit" });
21653
+ [piCodingAgentModule, piAiModule] = await Promise.all([
21654
+ import("@mariozechner/pi-coding-agent"),
21655
+ import("@mariozechner/pi-ai")
21656
+ ]);
21657
+ } else {
21658
+ throw new Error(
21659
+ "pi-coding-agent SDK is not installed. Install it with:\n bun add @mariozechner/pi-coding-agent"
21660
+ );
21661
+ }
21662
+ }
21663
+ }
21664
+ const toolMap = {
21665
+ read: piCodingAgentModule.readTool,
21666
+ bash: piCodingAgentModule.bashTool,
21667
+ edit: piCodingAgentModule.editTool,
21668
+ write: piCodingAgentModule.writeTool,
21669
+ grep: piCodingAgentModule.grepTool,
21670
+ find: piCodingAgentModule.findTool,
21671
+ ls: piCodingAgentModule.lsTool
21672
+ };
21673
+ return {
21674
+ createAgentSession: piCodingAgentModule.createAgentSession,
21675
+ codingTools: piCodingAgentModule.codingTools,
21676
+ toolMap,
21677
+ SessionManager: piCodingAgentModule.SessionManager,
21678
+ getModel: piAiModule.getModel
21679
+ };
21680
+ }
21681
+ var PiCodingAgentProvider = class {
21682
+ id;
21683
+ kind = "pi-coding-agent";
21684
+ targetName;
21685
+ supportsBatch = false;
21686
+ config;
21687
+ constructor(targetName, config) {
21688
+ this.id = `pi-coding-agent:${targetName}`;
21689
+ this.targetName = targetName;
21690
+ this.config = config;
21691
+ }
21692
+ async invoke(request) {
21693
+ if (request.signal?.aborted) {
21694
+ throw new Error("Pi coding agent request was aborted before execution");
21695
+ }
21696
+ const inputFiles = normalizeInputFiles(request.inputFiles);
21697
+ const startTime = (/* @__PURE__ */ new Date()).toISOString();
21698
+ const startMs = Date.now();
21699
+ const sdk = await loadSdkModules();
21700
+ const logger = await this.createStreamLogger(request).catch(() => void 0);
21701
+ try {
21702
+ const cwd = this.resolveCwd(request.cwd);
21703
+ const providerName = this.config.subprovider ?? "google";
21704
+ const modelId = this.config.model ?? "gemini-2.5-flash";
21705
+ this.setApiKeyEnv(providerName);
21706
+ const model = sdk.getModel(providerName, modelId);
21707
+ const tools = this.resolveTools(sdk);
21708
+ const { session } = await sdk.createAgentSession({
21709
+ cwd,
21710
+ model,
21711
+ tools,
21712
+ thinkingLevel: this.config.thinking,
21713
+ sessionManager: sdk.SessionManager.inMemory(cwd)
21714
+ });
21715
+ let tokenUsage;
21716
+ let costUsd;
21717
+ const toolTrackers = /* @__PURE__ */ new Map();
21718
+ const completedToolResults = /* @__PURE__ */ new Map();
21719
+ const unsubscribe = session.subscribe((event) => {
21720
+ logger?.handleEvent(event);
21721
+ switch (event.type) {
21722
+ case "message_end": {
21723
+ const msg = event.message;
21724
+ if (msg && typeof msg === "object" && "role" in msg && msg.role === "assistant" && "usage" in msg) {
21725
+ const usage = msg.usage;
21726
+ if (usage && typeof usage === "object") {
21727
+ const u = usage;
21728
+ const input = toFiniteNumber(u.input);
21729
+ const output = toFiniteNumber(u.output);
21730
+ const cached = toFiniteNumber(u.cacheRead);
21731
+ let callDelta;
21732
+ if (input !== void 0 || output !== void 0) {
21733
+ callDelta = {
21734
+ input: input ?? 0,
21735
+ output: output ?? 0,
21736
+ ...cached !== void 0 ? { cached } : {}
21737
+ };
21738
+ tokenUsage = {
21739
+ input: (tokenUsage?.input ?? 0) + callDelta.input,
21740
+ output: (tokenUsage?.output ?? 0) + callDelta.output,
21741
+ ...cached !== void 0 ? { cached: (tokenUsage?.cached ?? 0) + cached } : tokenUsage?.cached !== void 0 ? { cached: tokenUsage.cached } : {}
21742
+ };
21743
+ }
21744
+ const cost = u.cost;
21745
+ if (cost && typeof cost === "object") {
21746
+ const total = toFiniteNumber(cost.total);
21747
+ if (total !== void 0) {
21748
+ costUsd = (costUsd ?? 0) + total;
21749
+ }
21750
+ }
21751
+ request.streamCallbacks?.onLlmCallEnd?.(modelId, callDelta);
21752
+ }
21753
+ }
21754
+ break;
21755
+ }
21756
+ case "tool_execution_start": {
21757
+ toolTrackers.set(event.toolCallId, {
21758
+ toolCallId: event.toolCallId,
21759
+ toolName: event.toolName,
21760
+ args: event.args,
21761
+ startMs: Date.now(),
21762
+ startTime: (/* @__PURE__ */ new Date()).toISOString()
21763
+ });
21764
+ request.streamCallbacks?.onToolCallStart?.(event.toolName, event.toolCallId);
21765
+ break;
21766
+ }
21767
+ case "tool_execution_end": {
21768
+ const tracker = toolTrackers.get(event.toolCallId);
21769
+ const durationMs = tracker ? Date.now() - tracker.startMs : 0;
21770
+ completedToolResults.set(event.toolCallId, {
21771
+ output: event.result,
21772
+ durationMs
21773
+ });
21774
+ request.streamCallbacks?.onToolCallEnd?.(
21775
+ event.toolName,
21776
+ tracker?.args,
21777
+ event.result,
21778
+ durationMs,
21779
+ event.toolCallId
21780
+ );
21781
+ toolTrackers.delete(event.toolCallId);
21782
+ break;
21783
+ }
21784
+ }
21785
+ });
21786
+ try {
21787
+ const systemPrompt = this.config.systemPrompt;
21788
+ let prompt = request.question;
21789
+ if (systemPrompt) {
21790
+ prompt = `${systemPrompt}
21791
+
21792
+ ${prompt}`;
21793
+ }
21794
+ if (inputFiles && inputFiles.length > 0) {
21795
+ const fileList = inputFiles.map((f) => `@${f}`).join("\n");
21796
+ prompt = `${prompt}
21797
+
21798
+ Files:
21799
+ ${fileList}`;
21800
+ }
21801
+ if (this.config.timeoutMs) {
21802
+ const timeoutMs = this.config.timeoutMs;
21803
+ let timeoutId;
21804
+ const timeoutPromise = new Promise((_, reject) => {
21805
+ timeoutId = setTimeout(
21806
+ () => reject(
21807
+ new Error(`Pi coding agent timed out after ${Math.ceil(timeoutMs / 1e3)}s`)
21808
+ ),
21809
+ timeoutMs
21810
+ );
21811
+ });
21812
+ try {
21813
+ await Promise.race([session.prompt(prompt), timeoutPromise]);
21814
+ } finally {
21815
+ if (timeoutId !== void 0) clearTimeout(timeoutId);
21816
+ }
21817
+ } else {
21818
+ await session.prompt(prompt);
21819
+ }
21820
+ const agentMessages = session.agent.state.messages;
21821
+ const output = [];
21822
+ for (const msg of agentMessages) {
21823
+ output.push(convertAgentMessage(msg, toolTrackers, completedToolResults));
21824
+ }
21825
+ const endTime = (/* @__PURE__ */ new Date()).toISOString();
21826
+ const durationMs = Date.now() - startMs;
21827
+ return {
21828
+ raw: {
21829
+ messages: agentMessages,
21830
+ model: this.config.model,
21831
+ provider: this.config.subprovider
21832
+ },
21833
+ output,
21834
+ tokenUsage,
21835
+ costUsd,
21836
+ durationMs,
21837
+ startTime,
21838
+ endTime
21839
+ };
21840
+ } finally {
21841
+ unsubscribe();
21842
+ session.dispose();
21843
+ }
21844
+ } finally {
21845
+ await logger?.close();
21846
+ }
21847
+ }
21848
+ /** Maps config apiKey to the provider-specific env var the SDK reads. */
21849
+ setApiKeyEnv(providerName) {
21850
+ if (!this.config.apiKey) return;
21851
+ const ENV_KEY_MAP = {
21852
+ google: "GEMINI_API_KEY",
21853
+ gemini: "GEMINI_API_KEY",
21854
+ anthropic: "ANTHROPIC_API_KEY",
21855
+ openai: "OPENAI_API_KEY",
21856
+ groq: "GROQ_API_KEY",
21857
+ xai: "XAI_API_KEY",
21858
+ openrouter: "OPENROUTER_API_KEY"
21859
+ };
21860
+ const envKey = ENV_KEY_MAP[providerName.toLowerCase()];
21861
+ if (envKey) {
21862
+ process.env[envKey] = this.config.apiKey;
21863
+ }
21864
+ }
21865
+ resolveCwd(cwdOverride) {
21866
+ if (cwdOverride) {
21867
+ return path18.resolve(cwdOverride);
21868
+ }
21869
+ if (this.config.cwd) {
21870
+ return path18.resolve(this.config.cwd);
21871
+ }
21872
+ return process.cwd();
21873
+ }
21874
+ resolveTools(sdk) {
21875
+ if (!this.config.tools) {
21876
+ return sdk.codingTools;
21877
+ }
21878
+ const toolNames = this.config.tools.split(",").map((t) => t.trim().toLowerCase());
21879
+ const selected = [];
21880
+ for (const name21 of toolNames) {
21881
+ if (name21 in sdk.toolMap) {
21882
+ selected.push(sdk.toolMap[name21]);
21883
+ }
21884
+ }
21885
+ return selected.length > 0 ? selected : sdk.codingTools;
21886
+ }
21887
+ resolveLogDirectory() {
21888
+ if (this.config.logDir) {
21889
+ return path18.resolve(this.config.logDir);
21890
+ }
21891
+ return path18.join(process.cwd(), ".agentv", "logs", "pi-coding-agent");
21892
+ }
21893
+ async createStreamLogger(request) {
21894
+ const logDir = this.resolveLogDirectory();
21895
+ if (!logDir) {
21896
+ return void 0;
21897
+ }
21898
+ try {
21899
+ await mkdir7(logDir, { recursive: true });
21900
+ } catch (error) {
21901
+ const message = error instanceof Error ? error.message : String(error);
21902
+ console.warn(`Skipping Pi stream logging (could not create ${logDir}): ${message}`);
21903
+ return void 0;
21904
+ }
21905
+ const filePath = path18.join(logDir, buildLogFilename6(request, this.targetName));
21906
+ try {
21907
+ const logger = await PiStreamLogger2.create({
21908
+ filePath,
21909
+ targetName: this.targetName,
21910
+ evalCaseId: request.evalCaseId,
21911
+ attempt: request.attempt,
21912
+ format: this.config.logFormat ?? "summary"
21913
+ });
21914
+ recordPiLogEntry({
21915
+ filePath,
21916
+ targetName: this.targetName,
21917
+ evalCaseId: request.evalCaseId,
21918
+ attempt: request.attempt
21919
+ });
21920
+ return logger;
21921
+ } catch (error) {
21922
+ const message = error instanceof Error ? error.message : String(error);
21923
+ console.warn(`Skipping Pi stream logging for ${filePath}: ${message}`);
21924
+ return void 0;
21925
+ }
21926
+ }
21927
+ };
21928
+ var PiStreamLogger2 = class _PiStreamLogger2 {
21929
+ filePath;
21930
+ stream;
21931
+ startedAt = Date.now();
21932
+ format;
21933
+ constructor(filePath, format) {
21934
+ this.filePath = filePath;
21935
+ this.format = format;
21936
+ this.stream = createWriteStream6(filePath, { flags: "a" });
21937
+ }
21938
+ static async create(options) {
21939
+ const logger = new _PiStreamLogger2(options.filePath, options.format);
21940
+ const header = [
21941
+ "# Pi Coding Agent stream log",
21942
+ `# target: ${options.targetName}`,
21943
+ options.evalCaseId ? `# eval: ${options.evalCaseId}` : void 0,
21944
+ options.attempt !== void 0 ? `# attempt: ${options.attempt + 1}` : void 0,
21945
+ `# started: ${(/* @__PURE__ */ new Date()).toISOString()}`,
21946
+ ""
21947
+ ].filter((line) => Boolean(line));
21948
+ for (const line of header) {
21949
+ logger.stream.write(`${line}
21950
+ `);
21951
+ }
21952
+ return logger;
21953
+ }
21954
+ handleEvent(event) {
21955
+ if (!event || typeof event !== "object") return;
21956
+ const record = event;
21957
+ const type = typeof record.type === "string" ? record.type : void 0;
21958
+ if (!type) return;
21959
+ const message = this.format === "json" ? JSON.stringify(event, null, 2) : summarizeSdkEvent2(event);
21960
+ if (message) {
21961
+ this.stream.write(`[+${formatElapsed6(this.startedAt)}] ${message}
21962
+ `);
21963
+ }
21964
+ }
21965
+ async close() {
21966
+ await new Promise((resolve2, reject) => {
21967
+ this.stream.once("error", reject);
21968
+ this.stream.end(() => resolve2());
21969
+ });
21970
+ }
21971
+ };
21972
+ function summarizeSdkEvent2(event) {
21973
+ if (!event || typeof event !== "object") return void 0;
21974
+ const record = event;
21975
+ const type = typeof record.type === "string" ? record.type : void 0;
21976
+ if (!type) return void 0;
21977
+ switch (type) {
21978
+ case "agent_start":
21979
+ case "agent_end":
21980
+ case "turn_start":
21981
+ case "turn_end":
21982
+ return type;
21983
+ case "message_start":
21984
+ case "message_end": {
21985
+ const msg = record.message;
21986
+ return `${type}: ${msg?.role ?? "unknown"}`;
21987
+ }
21988
+ case "tool_execution_start":
21989
+ return `tool_start: ${record.toolName}`;
21990
+ case "tool_execution_end":
21991
+ return `tool_end: ${record.toolName}`;
21992
+ default:
21993
+ return type;
21994
+ }
21995
+ }
21996
+ function buildLogFilename6(request, targetName) {
21997
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
21998
+ const evalId = sanitizeForFilename6(request.evalCaseId ?? "pi");
21999
+ const attemptSuffix = request.attempt !== void 0 ? `_attempt-${request.attempt + 1}` : "";
22000
+ const target = sanitizeForFilename6(targetName);
22001
+ return `${timestamp}_${target}_${evalId}${attemptSuffix}_${randomUUID8().slice(0, 8)}.log`;
22002
+ }
22003
+ function sanitizeForFilename6(value) {
22004
+ const sanitized = value.replace(/[^A-Za-z0-9._-]+/g, "_");
22005
+ return sanitized.length > 0 ? sanitized : "pi";
22006
+ }
22007
+ function formatElapsed6(startedAt) {
22008
+ const elapsedSeconds = Math.floor((Date.now() - startedAt) / 1e3);
22009
+ const hours = Math.floor(elapsedSeconds / 3600);
22010
+ const minutes = Math.floor(elapsedSeconds % 3600 / 60);
22011
+ const seconds = elapsedSeconds % 60;
22012
+ if (hours > 0) {
22013
+ return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
22014
+ }
22015
+ return `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
22016
+ }
22017
+ function convertAgentMessage(message, toolTrackers, completedToolResults) {
22018
+ if (!message || typeof message !== "object") {
22019
+ return { role: "unknown", content: String(message) };
22020
+ }
22021
+ const msg = message;
22022
+ const role = typeof msg.role === "string" ? msg.role : "unknown";
22023
+ const content = extractPiTextContent(msg.content);
22024
+ const toolCalls = extractToolCalls4(msg.content, toolTrackers, completedToolResults);
22025
+ const startTimeVal = typeof msg.timestamp === "number" ? new Date(msg.timestamp).toISOString() : typeof msg.timestamp === "string" ? msg.timestamp : void 0;
22026
+ let msgTokenUsage;
22027
+ if (msg.usage && typeof msg.usage === "object") {
22028
+ const u = msg.usage;
22029
+ const input = toFiniteNumber(u.input);
22030
+ const output = toFiniteNumber(u.output);
22031
+ if (input !== void 0 || output !== void 0) {
22032
+ msgTokenUsage = {
22033
+ input: input ?? 0,
22034
+ output: output ?? 0,
22035
+ ...toFiniteNumber(u.cacheRead) !== void 0 ? { cached: toFiniteNumber(u.cacheRead) } : {}
22036
+ };
22037
+ }
22038
+ }
22039
+ const metadata = {};
22040
+ if (msg.api) metadata.api = msg.api;
22041
+ if (msg.provider) metadata.provider = msg.provider;
22042
+ if (msg.model) metadata.model = msg.model;
22043
+ if (msg.stopReason) metadata.stopReason = msg.stopReason;
22044
+ return {
22045
+ role,
22046
+ content,
22047
+ toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
22048
+ startTime: startTimeVal,
22049
+ metadata: Object.keys(metadata).length > 0 ? metadata : void 0,
22050
+ tokenUsage: msgTokenUsage
22051
+ };
22052
+ }
22053
+ function extractToolCalls4(content, toolTrackers, completedToolResults) {
22054
+ if (!Array.isArray(content)) {
22055
+ return [];
22056
+ }
22057
+ const toolCalls = [];
22058
+ for (const part of content) {
22059
+ if (!part || typeof part !== "object") {
22060
+ continue;
22061
+ }
22062
+ const p = part;
22063
+ if (p.type === "toolCall" && typeof p.name === "string") {
22064
+ const id = typeof p.id === "string" ? p.id : void 0;
22065
+ const tracker = id ? toolTrackers.get(id) : void 0;
22066
+ const completed = id ? completedToolResults.get(id) : void 0;
22067
+ toolCalls.push({
22068
+ tool: p.name,
22069
+ input: p.arguments,
22070
+ id,
22071
+ output: completed?.output,
22072
+ durationMs: completed?.durationMs,
22073
+ startTime: tracker?.startTime,
22074
+ endTime: tracker?.startTime && completed?.durationMs !== void 0 ? new Date(new Date(tracker.startTime).getTime() + completed.durationMs).toISOString() : void 0
22075
+ });
22076
+ }
22077
+ }
22078
+ return toolCalls;
22079
+ }
21855
22080
  var ProviderRegistry = class {
21856
22081
  factories = /* @__PURE__ */ new Map();
21857
22082
  /** Register a factory function for a provider kind. */
@@ -21894,13 +22119,13 @@ async function pathExists(target) {
21894
22119
  }
21895
22120
  }
21896
22121
  async function ensureDir(target) {
21897
- await mkdir7(target, { recursive: true });
22122
+ await mkdir8(target, { recursive: true });
21898
22123
  }
21899
22124
  async function readDirEntries(target) {
21900
22125
  const entries = await readdir(target, { withFileTypes: true });
21901
22126
  return entries.map((entry) => ({
21902
22127
  name: entry.name,
21903
- absolutePath: path18.join(target, entry.name),
22128
+ absolutePath: path19.join(target, entry.name),
21904
22129
  isDirectory: entry.isDirectory()
21905
22130
  }));
21906
22131
  }
@@ -21914,7 +22139,7 @@ async function removeIfExists(target) {
21914
22139
  }
21915
22140
  }
21916
22141
  function pathToFileUri2(filePath) {
21917
- const absolutePath = path19.isAbsolute(filePath) ? filePath : path19.resolve(filePath);
22142
+ const absolutePath = path20.isAbsolute(filePath) ? filePath : path20.resolve(filePath);
21918
22143
  const normalizedPath = absolutePath.replace(/\\/g, "/");
21919
22144
  if (/^[a-zA-Z]:\//.test(normalizedPath)) {
21920
22145
  return `file:///${normalizedPath}`;
@@ -22006,8 +22231,8 @@ function createBatchRequestPrompt(userQuery, responseFileTmp, responseFileFinal,
22006
22231
  });
22007
22232
  }
22008
22233
  function createBatchOrchestratorPrompt(requestFiles, responseFiles, templateContent) {
22009
- const requestLines = requestFiles.map((file, index) => `${index + 1}. messages/${path20.basename(file)}`).join("\n");
22010
- const responseList = responseFiles.map((file) => `"${path20.basename(file)}"`).join(", ");
22234
+ const requestLines = requestFiles.map((file, index) => `${index + 1}. messages/${path21.basename(file)}`).join("\n");
22235
+ const responseList = responseFiles.map((file) => `"${path21.basename(file)}"`).join(", ");
22011
22236
  return renderTemplate2(templateContent, {
22012
22237
  requestFiles: requestLines,
22013
22238
  responseList
@@ -22067,7 +22292,7 @@ async function waitForResponseOutput(responseFileFinal, pollInterval = 1e3, sile
22067
22292
  }
22068
22293
  async function waitForBatchResponses(responseFilesFinal, pollInterval = 1e3, silent = false, timeoutMs = DEFAULT_TIMEOUT_MS) {
22069
22294
  if (!silent) {
22070
- const fileList = responseFilesFinal.map((file) => path21.basename(file)).join(", ");
22295
+ const fileList = responseFilesFinal.map((file) => path222.basename(file)).join(", ");
22071
22296
  console.error(`waiting for ${responseFilesFinal.length} batch response(s): ${fileList}`);
22072
22297
  }
22073
22298
  const deadline = Date.now() + timeoutMs;
@@ -22076,7 +22301,7 @@ async function waitForBatchResponses(responseFilesFinal, pollInterval = 1e3, sil
22076
22301
  while (pending.size > 0) {
22077
22302
  if (Date.now() >= deadline) {
22078
22303
  if (!silent) {
22079
- const remaining = [...pending].map((f) => path21.basename(f)).join(", ");
22304
+ const remaining = [...pending].map((f) => path222.basename(f)).join(", ");
22080
22305
  console.error(
22081
22306
  `error: timed out after ${Math.round(timeoutMs / 1e3)}s waiting for batch responses. Still pending: ${remaining}`
22082
22307
  );
@@ -22133,25 +22358,25 @@ function getAgentvHome() {
22133
22358
  }
22134
22359
  return envHome;
22135
22360
  }
22136
- return path222.join(os2.homedir(), ".agentv");
22361
+ return path23.join(os2.homedir(), ".agentv");
22137
22362
  }
22138
22363
  function getWorkspacesRoot() {
22139
- return path222.join(getAgentvHome(), "workspaces");
22364
+ return path23.join(getAgentvHome(), "workspaces");
22140
22365
  }
22141
22366
  function getSubagentsRoot() {
22142
- return path222.join(getAgentvHome(), "subagents");
22367
+ return path23.join(getAgentvHome(), "subagents");
22143
22368
  }
22144
22369
  function getTraceStateRoot() {
22145
- return path222.join(getAgentvHome(), "trace-state");
22370
+ return path23.join(getAgentvHome(), "trace-state");
22146
22371
  }
22147
22372
  function getWorkspacePoolRoot() {
22148
- return path222.join(getAgentvHome(), "workspace-pool");
22373
+ return path23.join(getAgentvHome(), "workspace-pool");
22149
22374
  }
22150
22375
  var DEFAULT_LOCK_NAME = "subagent.lock";
22151
22376
  var DEFAULT_ALIVE_FILENAME = ".alive";
22152
22377
  function getDefaultSubagentRoot(vscodeCmd = "code") {
22153
22378
  const folder = vscodeCmd === "code-insiders" ? "vscode-insiders-agents" : "vscode-agents";
22154
- return path23.join(getSubagentsRoot(), folder);
22379
+ return path24.join(getSubagentsRoot(), folder);
22155
22380
  }
22156
22381
  var DEFAULT_SUBAGENT_ROOT = getDefaultSubagentRoot();
22157
22382
  var execAsync2 = promisify2(exec);
@@ -22216,11 +22441,11 @@ async function ensureWorkspaceFocused(workspacePath, workspaceName, subagentDir,
22216
22441
  await raceSpawnError(child);
22217
22442
  return true;
22218
22443
  }
22219
- const aliveFile = path24.join(subagentDir, DEFAULT_ALIVE_FILENAME);
22444
+ const aliveFile = path25.join(subagentDir, DEFAULT_ALIVE_FILENAME);
22220
22445
  await removeIfExists(aliveFile);
22221
- const githubAgentsDir = path24.join(subagentDir, ".github", "agents");
22222
- await mkdir8(githubAgentsDir, { recursive: true });
22223
- const wakeupDst = path24.join(githubAgentsDir, "wakeup.md");
22446
+ const githubAgentsDir = path25.join(subagentDir, ".github", "agents");
22447
+ await mkdir9(githubAgentsDir, { recursive: true });
22448
+ const wakeupDst = path25.join(githubAgentsDir, "wakeup.md");
22224
22449
  await writeFile2(wakeupDst, DEFAULT_WAKEUP_CONTENT, "utf8");
22225
22450
  const workspaceChild = spawnVsCode(vscodeCmd, [workspacePath], {
22226
22451
  label: "open-workspace"
@@ -22233,7 +22458,7 @@ async function ensureWorkspaceFocused(workspacePath, workspaceName, subagentDir,
22233
22458
  "chat",
22234
22459
  "-m",
22235
22460
  wakeupChatId,
22236
- `create a file named .alive in the ${path24.basename(subagentDir)} folder`
22461
+ `create a file named .alive in the ${path25.basename(subagentDir)} folder`
22237
22462
  ];
22238
22463
  const wakeupChild = spawnVsCode(vscodeCmd, chatArgs, { label: "send-wakeup-chat" });
22239
22464
  await raceSpawnError(wakeupChild);
@@ -22248,10 +22473,10 @@ async function ensureWorkspaceFocused(workspacePath, workspaceName, subagentDir,
22248
22473
  return true;
22249
22474
  }
22250
22475
  async function launchVsCodeWithChat(subagentDir, chatId, attachmentPaths, requestInstructions, timestamp, vscodeCmd) {
22251
- const workspacePath = path24.join(subagentDir, `${path24.basename(subagentDir)}.code-workspace`);
22252
- const messagesDir = path24.join(subagentDir, "messages");
22253
- await mkdir8(messagesDir, { recursive: true });
22254
- const reqFile = path24.join(messagesDir, `${timestamp}_req.md`);
22476
+ const workspacePath = path25.join(subagentDir, `${path25.basename(subagentDir)}.code-workspace`);
22477
+ const messagesDir = path25.join(subagentDir, "messages");
22478
+ await mkdir9(messagesDir, { recursive: true });
22479
+ const reqFile = path25.join(messagesDir, `${timestamp}_req.md`);
22255
22480
  await writeFile2(reqFile, requestInstructions, { encoding: "utf8" });
22256
22481
  const reqUri = pathToFileUri2(reqFile);
22257
22482
  const chatArgs = ["-r", "chat", "-m", chatId];
@@ -22259,16 +22484,16 @@ async function launchVsCodeWithChat(subagentDir, chatId, attachmentPaths, reques
22259
22484
  chatArgs.push("-a", attachment);
22260
22485
  }
22261
22486
  chatArgs.push("-a", reqFile);
22262
- chatArgs.push(`Follow instructions in [${path24.basename(reqFile)}](${reqUri})`);
22487
+ chatArgs.push(`Follow instructions in [${path25.basename(reqFile)}](${reqUri})`);
22263
22488
  const workspaceReady = await ensureWorkspaceFocused(
22264
22489
  workspacePath,
22265
- path24.basename(subagentDir),
22490
+ path25.basename(subagentDir),
22266
22491
  subagentDir,
22267
22492
  vscodeCmd
22268
22493
  );
22269
22494
  if (!workspaceReady) {
22270
22495
  throw new Error(
22271
- `VS Code workspace '${path24.basename(subagentDir)}' failed to become ready within the timeout. Check that '${vscodeCmd}' can open workspaces.`
22496
+ `VS Code workspace '${path25.basename(subagentDir)}' failed to become ready within the timeout. Check that '${vscodeCmd}' can open workspaces.`
22272
22497
  );
22273
22498
  }
22274
22499
  await sleep2(500);
@@ -22276,9 +22501,9 @@ async function launchVsCodeWithChat(subagentDir, chatId, attachmentPaths, reques
22276
22501
  await raceSpawnError(child);
22277
22502
  }
22278
22503
  async function launchVsCodeWithBatchChat(subagentDir, chatId, attachmentPaths, chatInstruction, vscodeCmd) {
22279
- const workspacePath = path24.join(subagentDir, `${path24.basename(subagentDir)}.code-workspace`);
22280
- const messagesDir = path24.join(subagentDir, "messages");
22281
- await mkdir8(messagesDir, { recursive: true });
22504
+ const workspacePath = path25.join(subagentDir, `${path25.basename(subagentDir)}.code-workspace`);
22505
+ const messagesDir = path25.join(subagentDir, "messages");
22506
+ await mkdir9(messagesDir, { recursive: true });
22282
22507
  const chatArgs = ["-r", "chat", "-m", chatId];
22283
22508
  for (const attachment of attachmentPaths) {
22284
22509
  chatArgs.push("-a", attachment);
@@ -22286,13 +22511,13 @@ async function launchVsCodeWithBatchChat(subagentDir, chatId, attachmentPaths, c
22286
22511
  chatArgs.push(chatInstruction);
22287
22512
  const workspaceReady = await ensureWorkspaceFocused(
22288
22513
  workspacePath,
22289
- path24.basename(subagentDir),
22514
+ path25.basename(subagentDir),
22290
22515
  subagentDir,
22291
22516
  vscodeCmd
22292
22517
  );
22293
22518
  if (!workspaceReady) {
22294
22519
  throw new Error(
22295
- `VS Code workspace '${path24.basename(subagentDir)}' failed to become ready within the timeout. Check that '${vscodeCmd}' can open workspaces.`
22520
+ `VS Code workspace '${path25.basename(subagentDir)}' failed to become ready within the timeout. Check that '${vscodeCmd}' can open workspaces.`
22296
22521
  );
22297
22522
  }
22298
22523
  await sleep2(500);
@@ -22314,10 +22539,10 @@ function transformWorkspacePaths(workspaceContent, templateDir) {
22314
22539
  }
22315
22540
  const transformedFolders = workspace.folders.map((folder) => {
22316
22541
  const folderPath = folder.path;
22317
- if (path25.isAbsolute(folderPath)) {
22542
+ if (path26.isAbsolute(folderPath)) {
22318
22543
  return folder;
22319
22544
  }
22320
- const absolutePath = path25.resolve(templateDir, folderPath);
22545
+ const absolutePath = path26.resolve(templateDir, folderPath);
22321
22546
  return {
22322
22547
  ...folder,
22323
22548
  path: absolutePath
@@ -22339,19 +22564,19 @@ function transformWorkspacePaths(workspaceContent, templateDir) {
22339
22564
  if (locationMap && typeof locationMap === "object") {
22340
22565
  const transformedMap = {};
22341
22566
  for (const [locationPath, value] of Object.entries(locationMap)) {
22342
- const isAbsolute = path25.isAbsolute(locationPath);
22567
+ const isAbsolute = path26.isAbsolute(locationPath);
22343
22568
  if (isAbsolute) {
22344
22569
  transformedMap[locationPath] = value;
22345
22570
  } else {
22346
22571
  const firstGlobIndex = locationPath.search(/[*]/);
22347
22572
  if (firstGlobIndex === -1) {
22348
- const resolvedPath = path25.resolve(templateDir, locationPath).replace(/\\/g, "/");
22573
+ const resolvedPath = path26.resolve(templateDir, locationPath).replace(/\\/g, "/");
22349
22574
  transformedMap[resolvedPath] = value;
22350
22575
  } else {
22351
22576
  const basePathEnd = locationPath.lastIndexOf("/", firstGlobIndex);
22352
22577
  const basePath = basePathEnd !== -1 ? locationPath.substring(0, basePathEnd) : ".";
22353
22578
  const patternPath = locationPath.substring(basePathEnd !== -1 ? basePathEnd : 0);
22354
- const resolvedPath = (path25.resolve(templateDir, basePath) + patternPath).replace(
22579
+ const resolvedPath = (path26.resolve(templateDir, basePath) + patternPath).replace(
22355
22580
  /\\/g,
22356
22581
  "/"
22357
22582
  );
@@ -22390,7 +22615,7 @@ async function findUnlockedSubagent(subagentRoot) {
22390
22615
  number: Number.parseInt(entry.name.split("-")[1] ?? "", 10)
22391
22616
  })).filter((entry) => Number.isInteger(entry.number)).sort((a, b) => a.number - b.number);
22392
22617
  for (const subagent of subagents) {
22393
- const lockFile = path26.join(subagent.absolutePath, DEFAULT_LOCK_NAME);
22618
+ const lockFile = path27.join(subagent.absolutePath, DEFAULT_LOCK_NAME);
22394
22619
  if (!await pathExists(lockFile)) {
22395
22620
  return subagent.absolutePath;
22396
22621
  }
@@ -22400,7 +22625,7 @@ async function findUnlockedSubagent(subagentRoot) {
22400
22625
  async function copyAgentConfig(subagentDir, workspaceTemplate, cwd) {
22401
22626
  let workspaceContent;
22402
22627
  if (workspaceTemplate) {
22403
- const workspaceSrc = path26.resolve(workspaceTemplate);
22628
+ const workspaceSrc = path27.resolve(workspaceTemplate);
22404
22629
  if (!await pathExists(workspaceSrc)) {
22405
22630
  throw new Error(`workspace template not found: ${workspaceSrc}`);
22406
22631
  }
@@ -22413,13 +22638,13 @@ async function copyAgentConfig(subagentDir, workspaceTemplate, cwd) {
22413
22638
  } else {
22414
22639
  workspaceContent = DEFAULT_WORKSPACE_TEMPLATE;
22415
22640
  }
22416
- const workspaceName = `${path26.basename(subagentDir)}.code-workspace`;
22417
- const workspaceDst = path26.join(subagentDir, workspaceName);
22418
- const templateDir = workspaceTemplate ? path26.dirname(path26.resolve(workspaceTemplate)) : subagentDir;
22641
+ const workspaceName = `${path27.basename(subagentDir)}.code-workspace`;
22642
+ const workspaceDst = path27.join(subagentDir, workspaceName);
22643
+ const templateDir = workspaceTemplate ? path27.dirname(path27.resolve(workspaceTemplate)) : subagentDir;
22419
22644
  const workspaceJson = JSON.stringify(workspaceContent, null, 2);
22420
22645
  let transformedContent = transformWorkspacePaths(workspaceJson, templateDir);
22421
22646
  if (cwd) {
22422
- const absCwd = path26.resolve(cwd);
22647
+ const absCwd = path27.resolve(cwd);
22423
22648
  const parsed = JSON.parse(transformedContent);
22424
22649
  const alreadyPresent = parsed.folders.some((f) => f.path === absCwd);
22425
22650
  if (!alreadyPresent) {
@@ -22428,35 +22653,35 @@ async function copyAgentConfig(subagentDir, workspaceTemplate, cwd) {
22428
22653
  }
22429
22654
  }
22430
22655
  await writeFile3(workspaceDst, transformedContent, "utf8");
22431
- const messagesDir = path26.join(subagentDir, "messages");
22432
- await mkdir9(messagesDir, { recursive: true });
22656
+ const messagesDir = path27.join(subagentDir, "messages");
22657
+ await mkdir10(messagesDir, { recursive: true });
22433
22658
  return { workspace: workspaceDst, messagesDir };
22434
22659
  }
22435
22660
  async function createSubagentLock(subagentDir) {
22436
- const messagesDir = path26.join(subagentDir, "messages");
22661
+ const messagesDir = path27.join(subagentDir, "messages");
22437
22662
  if (await pathExists(messagesDir)) {
22438
22663
  const files = await readdir2(messagesDir);
22439
22664
  await Promise.all(
22440
22665
  files.map(async (file) => {
22441
- const target = path26.join(messagesDir, file);
22666
+ const target = path27.join(messagesDir, file);
22442
22667
  await removeIfExists(target);
22443
22668
  })
22444
22669
  );
22445
22670
  }
22446
- const githubAgentsDir = path26.join(subagentDir, ".github", "agents");
22671
+ const githubAgentsDir = path27.join(subagentDir, ".github", "agents");
22447
22672
  if (await pathExists(githubAgentsDir)) {
22448
22673
  const agentFiles = await readdir2(githubAgentsDir);
22449
22674
  const preservedFiles = /* @__PURE__ */ new Set(["wakeup.md", "subagent.md"]);
22450
22675
  await Promise.all(
22451
- agentFiles.filter((file) => file.endsWith(".md") && !preservedFiles.has(file)).map((file) => removeIfExists(path26.join(githubAgentsDir, file)))
22676
+ agentFiles.filter((file) => file.endsWith(".md") && !preservedFiles.has(file)).map((file) => removeIfExists(path27.join(githubAgentsDir, file)))
22452
22677
  );
22453
22678
  }
22454
- const lockFile = path26.join(subagentDir, DEFAULT_LOCK_NAME);
22679
+ const lockFile = path27.join(subagentDir, DEFAULT_LOCK_NAME);
22455
22680
  await writeFile3(lockFile, "", { encoding: "utf8" });
22456
22681
  return lockFile;
22457
22682
  }
22458
22683
  async function removeSubagentLock(subagentDir) {
22459
- const lockFile = path26.join(subagentDir, DEFAULT_LOCK_NAME);
22684
+ const lockFile = path27.join(subagentDir, DEFAULT_LOCK_NAME);
22460
22685
  await removeIfExists(lockFile);
22461
22686
  }
22462
22687
  async function prepareSubagentDirectory(subagentDir, promptFile, chatId, workspaceTemplate, dryRun, cwd) {
@@ -22476,9 +22701,9 @@ async function prepareSubagentDirectory(subagentDir, promptFile, chatId, workspa
22476
22701
  return 1;
22477
22702
  }
22478
22703
  if (promptFile) {
22479
- const githubAgentsDir = path26.join(subagentDir, ".github", "agents");
22480
- await mkdir9(githubAgentsDir, { recursive: true });
22481
- const agentFile = path26.join(githubAgentsDir, `${chatId}.md`);
22704
+ const githubAgentsDir = path27.join(subagentDir, ".github", "agents");
22705
+ await mkdir10(githubAgentsDir, { recursive: true });
22706
+ const agentFile = path27.join(githubAgentsDir, `${chatId}.md`);
22482
22707
  try {
22483
22708
  await copyFile(promptFile, agentFile);
22484
22709
  } catch (error) {
@@ -22495,7 +22720,7 @@ async function resolvePromptFile(promptFile) {
22495
22720
  if (!promptFile) {
22496
22721
  return void 0;
22497
22722
  }
22498
- const resolvedPrompt = path27.resolve(promptFile);
22723
+ const resolvedPrompt = path28.resolve(promptFile);
22499
22724
  if (!await pathExists(resolvedPrompt)) {
22500
22725
  throw new Error(`Prompt file not found: ${resolvedPrompt}`);
22501
22726
  }
@@ -22511,7 +22736,7 @@ async function resolveAttachments(extraAttachments) {
22511
22736
  }
22512
22737
  const resolved = [];
22513
22738
  for (const attachment of extraAttachments) {
22514
- const resolvedPath = path27.resolve(attachment);
22739
+ const resolvedPath = path28.resolve(attachment);
22515
22740
  if (!await pathExists(resolvedPath)) {
22516
22741
  throw new Error(`Attachment not found: ${resolvedPath}`);
22517
22742
  }
@@ -22553,7 +22778,7 @@ async function dispatchAgentSession(options) {
22553
22778
  error: "No unlocked subagents available. Provision additional subagents with: subagent code provision --subagents <desired_total>"
22554
22779
  };
22555
22780
  }
22556
- const subagentName = path27.basename(subagentDir);
22781
+ const subagentName = path28.basename(subagentDir);
22557
22782
  const chatId = Math.random().toString(16).slice(2, 10);
22558
22783
  const preparationResult = await prepareSubagentDirectory(
22559
22784
  subagentDir,
@@ -22581,9 +22806,9 @@ async function dispatchAgentSession(options) {
22581
22806
  };
22582
22807
  }
22583
22808
  const timestamp = generateTimestamp();
22584
- const messagesDir = path27.join(subagentDir, "messages");
22585
- const responseFileTmp = path27.join(messagesDir, `${timestamp}_res.tmp.md`);
22586
- const responseFileFinal = path27.join(messagesDir, `${timestamp}_res.md`);
22809
+ const messagesDir = path28.join(subagentDir, "messages");
22810
+ const responseFileTmp = path28.join(messagesDir, `${timestamp}_res.tmp.md`);
22811
+ const responseFileFinal = path28.join(messagesDir, `${timestamp}_res.md`);
22587
22812
  const requestInstructions = createRequestPrompt(
22588
22813
  userQuery,
22589
22814
  responseFileTmp,
@@ -22688,7 +22913,7 @@ async function dispatchBatchAgent(options) {
22688
22913
  error: "No unlocked subagents available. Provision additional subagents with: subagent code provision --subagents <desired_total>"
22689
22914
  };
22690
22915
  }
22691
- subagentName = path27.basename(subagentDir);
22916
+ subagentName = path28.basename(subagentDir);
22692
22917
  const chatId = Math.random().toString(16).slice(2, 10);
22693
22918
  const preparationResult = await prepareSubagentDirectory(
22694
22919
  subagentDir,
@@ -22719,17 +22944,17 @@ async function dispatchBatchAgent(options) {
22719
22944
  };
22720
22945
  }
22721
22946
  const timestamp = generateTimestamp();
22722
- const messagesDir = path27.join(subagentDir, "messages");
22947
+ const messagesDir = path28.join(subagentDir, "messages");
22723
22948
  requestFiles = userQueries.map(
22724
- (_, index) => path27.join(messagesDir, `${timestamp}_${index}_req.md`)
22949
+ (_, index) => path28.join(messagesDir, `${timestamp}_${index}_req.md`)
22725
22950
  );
22726
22951
  const responseTmpFiles = userQueries.map(
22727
- (_, index) => path27.join(messagesDir, `${timestamp}_${index}_res.tmp.md`)
22952
+ (_, index) => path28.join(messagesDir, `${timestamp}_${index}_res.tmp.md`)
22728
22953
  );
22729
22954
  responseFilesFinal = userQueries.map(
22730
- (_, index) => path27.join(messagesDir, `${timestamp}_${index}_res.md`)
22955
+ (_, index) => path28.join(messagesDir, `${timestamp}_${index}_res.md`)
22731
22956
  );
22732
- const orchestratorFile = path27.join(messagesDir, `${timestamp}_orchestrator.md`);
22957
+ const orchestratorFile = path28.join(messagesDir, `${timestamp}_orchestrator.md`);
22733
22958
  if (!dryRun) {
22734
22959
  await Promise.all(
22735
22960
  userQueries.map((query, index) => {
@@ -22842,7 +23067,7 @@ async function provisionSubagents(options) {
22842
23067
  if (!Number.isInteger(subagents) || subagents < 1) {
22843
23068
  throw new Error("subagents must be a positive integer");
22844
23069
  }
22845
- const targetPath = path28.resolve(targetRoot);
23070
+ const targetPath = path29.resolve(targetRoot);
22846
23071
  if (!dryRun) {
22847
23072
  await ensureDir(targetPath);
22848
23073
  }
@@ -22862,7 +23087,7 @@ async function provisionSubagents(options) {
22862
23087
  continue;
22863
23088
  }
22864
23089
  highestNumber = Math.max(highestNumber, parsed);
22865
- const lockFile = path28.join(entry.absolutePath, lockName);
23090
+ const lockFile = path29.join(entry.absolutePath, lockName);
22866
23091
  const locked = await pathExists(lockFile);
22867
23092
  if (locked) {
22868
23093
  lockedSubagents.add(entry.absolutePath);
@@ -22879,10 +23104,10 @@ async function provisionSubagents(options) {
22879
23104
  break;
22880
23105
  }
22881
23106
  const subagentDir = subagent.absolutePath;
22882
- const githubAgentsDir = path28.join(subagentDir, ".github", "agents");
22883
- const lockFile = path28.join(subagentDir, lockName);
22884
- const workspaceDst = path28.join(subagentDir, `${path28.basename(subagentDir)}.code-workspace`);
22885
- const wakeupDst = path28.join(githubAgentsDir, "wakeup.md");
23107
+ const githubAgentsDir = path29.join(subagentDir, ".github", "agents");
23108
+ const lockFile = path29.join(subagentDir, lockName);
23109
+ const workspaceDst = path29.join(subagentDir, `${path29.basename(subagentDir)}.code-workspace`);
23110
+ const wakeupDst = path29.join(githubAgentsDir, "wakeup.md");
22886
23111
  const isLocked = await pathExists(lockFile);
22887
23112
  if (isLocked && !force) {
22888
23113
  continue;
@@ -22920,10 +23145,10 @@ async function provisionSubagents(options) {
22920
23145
  let nextIndex = highestNumber;
22921
23146
  while (subagentsProvisioned < subagents) {
22922
23147
  nextIndex += 1;
22923
- const subagentDir = path28.join(targetPath, `subagent-${nextIndex}`);
22924
- const githubAgentsDir = path28.join(subagentDir, ".github", "agents");
22925
- const workspaceDst = path28.join(subagentDir, `${path28.basename(subagentDir)}.code-workspace`);
22926
- const wakeupDst = path28.join(githubAgentsDir, "wakeup.md");
23148
+ const subagentDir = path29.join(targetPath, `subagent-${nextIndex}`);
23149
+ const githubAgentsDir = path29.join(subagentDir, ".github", "agents");
23150
+ const workspaceDst = path29.join(subagentDir, `${path29.basename(subagentDir)}.code-workspace`);
23151
+ const wakeupDst = path29.join(githubAgentsDir, "wakeup.md");
22927
23152
  if (!dryRun) {
22928
23153
  await ensureDir(subagentDir);
22929
23154
  await ensureDir(githubAgentsDir);
@@ -23109,7 +23334,7 @@ var VSCodeProvider = class {
23109
23334
  async function locateVSCodeExecutable(candidate) {
23110
23335
  const includesPathSeparator = candidate.includes("/") || candidate.includes("\\");
23111
23336
  if (includesPathSeparator) {
23112
- const resolved = path29.isAbsolute(candidate) ? candidate : path29.resolve(candidate);
23337
+ const resolved = path30.isAbsolute(candidate) ? candidate : path30.resolve(candidate);
23113
23338
  try {
23114
23339
  await access3(resolved, constants3.F_OK);
23115
23340
  return resolved;
@@ -23138,7 +23363,7 @@ async function resolveWorkspaceTemplateFile(template) {
23138
23363
  return void 0;
23139
23364
  }
23140
23365
  try {
23141
- const stats = await stat4(path29.resolve(template));
23366
+ const stats = await stat4(path30.resolve(template));
23142
23367
  return stats.isFile() ? template : void 0;
23143
23368
  } catch {
23144
23369
  return template;
@@ -23162,7 +23387,7 @@ function buildMandatoryPrereadBlock2(attachmentFiles) {
23162
23387
  return "";
23163
23388
  }
23164
23389
  const buildList = (files) => files.map((absolutePath) => {
23165
- const fileName = path29.basename(absolutePath);
23390
+ const fileName = path30.basename(absolutePath);
23166
23391
  const fileUri = pathToFileUri3(absolutePath);
23167
23392
  return `* [${fileName}](${fileUri})`;
23168
23393
  });
@@ -23183,7 +23408,7 @@ function collectAttachmentFiles(attachments) {
23183
23408
  }
23184
23409
  const unique = /* @__PURE__ */ new Map();
23185
23410
  for (const attachment of attachments) {
23186
- const absolutePath = path29.resolve(attachment);
23411
+ const absolutePath = path30.resolve(attachment);
23187
23412
  if (!unique.has(absolutePath)) {
23188
23413
  unique.set(absolutePath, absolutePath);
23189
23414
  }
@@ -23191,7 +23416,7 @@ function collectAttachmentFiles(attachments) {
23191
23416
  return Array.from(unique.values());
23192
23417
  }
23193
23418
  function pathToFileUri3(filePath) {
23194
- const absolutePath = path29.isAbsolute(filePath) ? filePath : path29.resolve(filePath);
23419
+ const absolutePath = path30.isAbsolute(filePath) ? filePath : path30.resolve(filePath);
23195
23420
  const normalizedPath = absolutePath.replace(/\\/g, "/");
23196
23421
  if (/^[a-zA-Z]:\//.test(normalizedPath)) {
23197
23422
  return `file:///${normalizedPath}`;
@@ -23204,7 +23429,7 @@ function normalizeAttachments(attachments) {
23204
23429
  }
23205
23430
  const deduped = /* @__PURE__ */ new Set();
23206
23431
  for (const attachment of attachments) {
23207
- deduped.add(path29.resolve(attachment));
23432
+ deduped.add(path30.resolve(attachment));
23208
23433
  }
23209
23434
  return Array.from(deduped);
23210
23435
  }
@@ -23213,7 +23438,7 @@ function mergeAttachments(all) {
23213
23438
  for (const list of all) {
23214
23439
  if (!list) continue;
23215
23440
  for (const inputFile of list) {
23216
- deduped.add(path29.resolve(inputFile));
23441
+ deduped.add(path30.resolve(inputFile));
23217
23442
  }
23218
23443
  }
23219
23444
  return deduped.size > 0 ? Array.from(deduped) : void 0;
@@ -23293,7 +23518,7 @@ async function fileExists3(filePath) {
23293
23518
  }
23294
23519
  }
23295
23520
  async function readTargetDefinitions(filePath) {
23296
- const absolutePath = path30.resolve(filePath);
23521
+ const absolutePath = path31.resolve(filePath);
23297
23522
  if (!await fileExists3(absolutePath)) {
23298
23523
  throw new Error(`targets.yaml not found at ${absolutePath}`);
23299
23524
  }
@@ -23314,11 +23539,11 @@ function listTargetNames(definitions) {
23314
23539
  async function discoverProviders(registry, baseDir) {
23315
23540
  const patterns = ["*.ts", "*.js", "*.mts", "*.mjs"];
23316
23541
  const candidateDirs = [];
23317
- let dir = path31.resolve(baseDir);
23318
- const root = path31.parse(dir).root;
23542
+ let dir = path322.resolve(baseDir);
23543
+ const root = path322.parse(dir).root;
23319
23544
  while (dir !== root) {
23320
- candidateDirs.push(path31.join(dir, ".agentv", "providers"));
23321
- dir = path31.dirname(dir);
23545
+ candidateDirs.push(path322.join(dir, ".agentv", "providers"));
23546
+ dir = path322.dirname(dir);
23322
23547
  }
23323
23548
  let files = [];
23324
23549
  for (const providersDir of candidateDirs) {
@@ -23334,7 +23559,7 @@ async function discoverProviders(registry, baseDir) {
23334
23559
  }
23335
23560
  const discoveredKinds = [];
23336
23561
  for (const filePath of files) {
23337
- const basename = path31.basename(filePath);
23562
+ const basename = path322.basename(filePath);
23338
23563
  const kindName = basename.replace(/\.(ts|js|mts|mjs)$/, "");
23339
23564
  if (registry.has(kindName)) {
23340
23565
  continue;
@@ -23350,7 +23575,7 @@ async function discoverProviders(registry, baseDir) {
23350
23575
  }
23351
23576
  function createBuiltinProviderRegistry() {
23352
23577
  const registry = new ProviderRegistry();
23353
- registry.register("openai", (t) => new OpenAIProvider(t.name, t.config)).register("openrouter", (t) => new OpenRouterProvider(t.name, t.config)).register("azure", (t) => new AzureProvider(t.name, t.config)).register("anthropic", (t) => new AnthropicProvider(t.name, t.config)).register("gemini", (t) => new GeminiProvider(t.name, t.config)).register("cli", (t) => new CliProvider(t.name, t.config)).register("codex", (t) => new CodexProvider(t.name, t.config)).register("copilot-sdk", (t) => new CopilotSdkProvider(t.name, t.config)).register("copilot-cli", (t) => new CopilotCliProvider(t.name, t.config)).register("pi-coding-agent", (t) => new PiCodingAgentProvider(t.name, t.config)).register("pi-agent-sdk", (t) => new PiAgentSdkProvider(t.name, t.config)).register("claude-cli", (t) => new ClaudeCliProvider(t.name, t.config)).register("claude", (t) => new ClaudeCliProvider(t.name, t.config)).register("claude-sdk", (t) => new ClaudeSdkProvider(t.name, t.config)).register("mock", (t) => new MockProvider(t.name, t.config)).register("agentv", (t) => new AgentvProvider(t.name, t.config)).register("vscode", (t) => new VSCodeProvider(t.name, t.config, "vscode")).register(
23578
+ registry.register("openai", (t) => new OpenAIProvider(t.name, t.config)).register("openrouter", (t) => new OpenRouterProvider(t.name, t.config)).register("azure", (t) => new AzureProvider(t.name, t.config)).register("anthropic", (t) => new AnthropicProvider(t.name, t.config)).register("gemini", (t) => new GeminiProvider(t.name, t.config)).register("cli", (t) => new CliProvider(t.name, t.config)).register("codex", (t) => new CodexProvider(t.name, t.config)).register("copilot-sdk", (t) => new CopilotSdkProvider(t.name, t.config)).register("copilot-cli", (t) => new CopilotCliProvider(t.name, t.config)).register("pi-coding-agent", (t) => new PiCodingAgentProvider(t.name, t.config)).register("pi-cli", (t) => new PiCliProvider(t.name, t.config)).register("claude-cli", (t) => new ClaudeCliProvider(t.name, t.config)).register("claude", (t) => new ClaudeCliProvider(t.name, t.config)).register("claude-sdk", (t) => new ClaudeSdkProvider(t.name, t.config)).register("mock", (t) => new MockProvider(t.name, t.config)).register("agentv", (t) => new AgentvProvider(t.name, t.config)).register("vscode", (t) => new VSCodeProvider(t.name, t.config, "vscode")).register(
23354
23579
  "vscode-insiders",
23355
23580
  (t) => new VSCodeProvider(t.name, t.config, "vscode-insiders")
23356
23581
  );
@@ -23532,15 +23757,15 @@ async function execFileWithStdinNode(argv, stdinPayload, options) {
23532
23757
  });
23533
23758
  }
23534
23759
  async function execShellWithStdin(command, stdinPayload, options = {}) {
23535
- const { mkdir: mkdir15, readFile: readFile12, rm: rm6, writeFile: writeFile9 } = await import("node:fs/promises");
23760
+ const { mkdir: mkdir16, readFile: readFile12, rm: rm6, writeFile: writeFile9 } = await import("node:fs/promises");
23536
23761
  const { tmpdir: tmpdir3 } = await import("node:os");
23537
- const path44 = await import("node:path");
23538
- const { randomUUID: randomUUID9 } = await import("node:crypto");
23539
- const dir = path44.join(tmpdir3(), `agentv-exec-${randomUUID9()}`);
23540
- await mkdir15(dir, { recursive: true });
23541
- const stdinPath = path44.join(dir, "stdin.txt");
23542
- const stdoutPath = path44.join(dir, "stdout.txt");
23543
- const stderrPath = path44.join(dir, "stderr.txt");
23762
+ const path45 = await import("node:path");
23763
+ const { randomUUID: randomUUID10 } = await import("node:crypto");
23764
+ const dir = path45.join(tmpdir3(), `agentv-exec-${randomUUID10()}`);
23765
+ await mkdir16(dir, { recursive: true });
23766
+ const stdinPath = path45.join(dir, "stdin.txt");
23767
+ const stdoutPath = path45.join(dir, "stdout.txt");
23768
+ const stderrPath = path45.join(dir, "stderr.txt");
23544
23769
  await writeFile9(stdinPath, stdinPayload, "utf8");
23545
23770
  const wrappedCommand = process.platform === "win32" ? `(${command}) < ${shellEscapePath(stdinPath)} > ${shellEscapePath(stdoutPath)} 2> ${shellEscapePath(stderrPath)}` : `(${command}) < ${shellEscapePath(stdinPath)} > ${shellEscapePath(stdoutPath)} 2> ${shellEscapePath(stderrPath)}`;
23546
23771
  const { spawn: spawn5 } = await import("node:child_process");
@@ -24191,7 +24416,7 @@ ${context2.fileChanges}`;
24191
24416
  async evaluateWithRubrics(context2, graderProvider, rubrics) {
24192
24417
  if (!rubrics || rubrics.length === 0) {
24193
24418
  throw new Error(
24194
- `No rubrics found for evaluator "${context2.evaluator?.name ?? "llm-grader"}". Run "agentv generate rubrics" first.`
24419
+ `No rubrics found for evaluator "${context2.evaluator?.name ?? "llm-grader"}". Add rubric criteria under assertions or use the agentv-eval-writer skill for authoring help.`
24195
24420
  );
24196
24421
  }
24197
24422
  const hasScoreRanges = rubrics.some((r) => r.score_ranges && r.score_ranges.length > 0);
@@ -24857,8 +25082,8 @@ function calculateScoreRangeResult(result, rubrics) {
24857
25082
  };
24858
25083
  }
24859
25084
  function resolveSandboxed(basePath, relativePath) {
24860
- const resolved = path322.resolve(basePath, relativePath);
24861
- if (!resolved.startsWith(basePath + path322.sep) && resolved !== basePath) {
25085
+ const resolved = path33.resolve(basePath, relativePath);
25086
+ if (!resolved.startsWith(basePath + path33.sep) && resolved !== basePath) {
24862
25087
  throw new Error(`Path '${relativePath}' is outside the workspace`);
24863
25088
  }
24864
25089
  return resolved;
@@ -24948,11 +25173,11 @@ async function searchDirectory(dirPath, workspacePath, regex, matches) {
24948
25173
  for (const entry of entries) {
24949
25174
  if (matches.length >= MAX_SEARCH_MATCHES) return;
24950
25175
  if (SEARCH_SKIP_DIRS.has(entry.name)) continue;
24951
- const fullPath = path322.join(dirPath, entry.name);
25176
+ const fullPath = path33.join(dirPath, entry.name);
24952
25177
  if (entry.isDirectory()) {
24953
25178
  await searchDirectory(fullPath, workspacePath, regex, matches);
24954
25179
  } else if (entry.isFile()) {
24955
- const ext = path322.extname(entry.name).toLowerCase();
25180
+ const ext = path33.extname(entry.name).toLowerCase();
24956
25181
  if (BINARY_EXTENSIONS.has(ext)) continue;
24957
25182
  try {
24958
25183
  const stat8 = await fs2.stat(fullPath);
@@ -24964,7 +25189,7 @@ async function searchDirectory(dirPath, workspacePath, regex, matches) {
24964
25189
  regex.lastIndex = 0;
24965
25190
  if (regex.test(lines[i])) {
24966
25191
  matches.push({
24967
- file: path322.relative(workspacePath, fullPath),
25192
+ file: path33.relative(workspacePath, fullPath),
24968
25193
  line: i + 1,
24969
25194
  text: lines[i].substring(0, 200)
24970
25195
  });
@@ -25591,115 +25816,115 @@ var FieldAccuracyEvaluator = class {
25591
25816
  * Evaluate a single field against the expected value.
25592
25817
  */
25593
25818
  evaluateField(fieldConfig, candidateData, expectedData) {
25594
- const { path: path44, match, required = true, weight = 1 } = fieldConfig;
25595
- const candidateValue = resolvePath(candidateData, path44);
25596
- const expectedValue = resolvePath(expectedData, path44);
25819
+ const { path: path45, match, required = true, weight = 1 } = fieldConfig;
25820
+ const candidateValue = resolvePath(candidateData, path45);
25821
+ const expectedValue = resolvePath(expectedData, path45);
25597
25822
  if (expectedValue === void 0) {
25598
25823
  return {
25599
- path: path44,
25824
+ path: path45,
25600
25825
  score: 1,
25601
25826
  // No expected value means no comparison needed
25602
25827
  weight,
25603
25828
  hit: true,
25604
- message: `${path44}: no expected value`
25829
+ message: `${path45}: no expected value`
25605
25830
  };
25606
25831
  }
25607
25832
  if (candidateValue === void 0) {
25608
25833
  if (required) {
25609
25834
  return {
25610
- path: path44,
25835
+ path: path45,
25611
25836
  score: 0,
25612
25837
  weight,
25613
25838
  hit: false,
25614
- message: `${path44} (required, missing)`
25839
+ message: `${path45} (required, missing)`
25615
25840
  };
25616
25841
  }
25617
25842
  return {
25618
- path: path44,
25843
+ path: path45,
25619
25844
  score: 1,
25620
25845
  // Don't penalize missing optional fields
25621
25846
  weight: 0,
25622
25847
  // Zero weight means it won't affect the score
25623
25848
  hit: true,
25624
- message: `${path44}: optional field missing`
25849
+ message: `${path45}: optional field missing`
25625
25850
  };
25626
25851
  }
25627
25852
  switch (match) {
25628
25853
  case "exact":
25629
- return this.compareExact(path44, candidateValue, expectedValue, weight);
25854
+ return this.compareExact(path45, candidateValue, expectedValue, weight);
25630
25855
  case "numeric_tolerance":
25631
25856
  return this.compareNumericTolerance(
25632
- path44,
25857
+ path45,
25633
25858
  candidateValue,
25634
25859
  expectedValue,
25635
25860
  fieldConfig,
25636
25861
  weight
25637
25862
  );
25638
25863
  case "date":
25639
- return this.compareDate(path44, candidateValue, expectedValue, fieldConfig, weight);
25864
+ return this.compareDate(path45, candidateValue, expectedValue, fieldConfig, weight);
25640
25865
  default:
25641
25866
  return {
25642
- path: path44,
25867
+ path: path45,
25643
25868
  score: 0,
25644
25869
  weight,
25645
25870
  hit: false,
25646
- message: `${path44}: unknown match type "${match}"`
25871
+ message: `${path45}: unknown match type "${match}"`
25647
25872
  };
25648
25873
  }
25649
25874
  }
25650
25875
  /**
25651
25876
  * Exact equality comparison.
25652
25877
  */
25653
- compareExact(path44, candidateValue, expectedValue, weight) {
25878
+ compareExact(path45, candidateValue, expectedValue, weight) {
25654
25879
  if (deepEqual(candidateValue, expectedValue)) {
25655
25880
  return {
25656
- path: path44,
25881
+ path: path45,
25657
25882
  score: 1,
25658
25883
  weight,
25659
25884
  hit: true,
25660
- message: path44
25885
+ message: path45
25661
25886
  };
25662
25887
  }
25663
25888
  if (typeof candidateValue !== typeof expectedValue) {
25664
25889
  return {
25665
- path: path44,
25890
+ path: path45,
25666
25891
  score: 0,
25667
25892
  weight,
25668
25893
  hit: false,
25669
- message: `${path44} (type mismatch: got ${typeof candidateValue}, expected ${typeof expectedValue})`
25894
+ message: `${path45} (type mismatch: got ${typeof candidateValue}, expected ${typeof expectedValue})`
25670
25895
  };
25671
25896
  }
25672
25897
  return {
25673
- path: path44,
25898
+ path: path45,
25674
25899
  score: 0,
25675
25900
  weight,
25676
25901
  hit: false,
25677
- message: `${path44} (value mismatch)`
25902
+ message: `${path45} (value mismatch)`
25678
25903
  };
25679
25904
  }
25680
25905
  /**
25681
25906
  * Numeric comparison with absolute or relative tolerance.
25682
25907
  */
25683
- compareNumericTolerance(path44, candidateValue, expectedValue, fieldConfig, weight) {
25908
+ compareNumericTolerance(path45, candidateValue, expectedValue, fieldConfig, weight) {
25684
25909
  const { tolerance = 0, relative = false } = fieldConfig;
25685
25910
  const candidateNum = toNumber(candidateValue);
25686
25911
  const expectedNum = toNumber(expectedValue);
25687
25912
  if (candidateNum === null || expectedNum === null) {
25688
25913
  return {
25689
- path: path44,
25914
+ path: path45,
25690
25915
  score: 0,
25691
25916
  weight,
25692
25917
  hit: false,
25693
- message: `${path44} (non-numeric value)`
25918
+ message: `${path45} (non-numeric value)`
25694
25919
  };
25695
25920
  }
25696
25921
  if (!Number.isFinite(candidateNum) || !Number.isFinite(expectedNum)) {
25697
25922
  return {
25698
- path: path44,
25923
+ path: path45,
25699
25924
  score: 0,
25700
25925
  weight,
25701
25926
  hit: false,
25702
- message: `${path44} (invalid numeric value)`
25927
+ message: `${path45} (invalid numeric value)`
25703
25928
  };
25704
25929
  }
25705
25930
  const diff = Math.abs(candidateNum - expectedNum);
@@ -25712,61 +25937,61 @@ var FieldAccuracyEvaluator = class {
25712
25937
  }
25713
25938
  if (withinTolerance) {
25714
25939
  return {
25715
- path: path44,
25940
+ path: path45,
25716
25941
  score: 1,
25717
25942
  weight,
25718
25943
  hit: true,
25719
- message: `${path44} (within tolerance: diff=${diff.toFixed(2)})`
25944
+ message: `${path45} (within tolerance: diff=${diff.toFixed(2)})`
25720
25945
  };
25721
25946
  }
25722
25947
  return {
25723
- path: path44,
25948
+ path: path45,
25724
25949
  score: 0,
25725
25950
  weight,
25726
25951
  hit: false,
25727
- message: `${path44} (outside tolerance: diff=${diff.toFixed(2)}, tolerance=${tolerance})`
25952
+ message: `${path45} (outside tolerance: diff=${diff.toFixed(2)}, tolerance=${tolerance})`
25728
25953
  };
25729
25954
  }
25730
25955
  /**
25731
25956
  * Date comparison with format normalization.
25732
25957
  */
25733
- compareDate(path44, candidateValue, expectedValue, fieldConfig, weight) {
25958
+ compareDate(path45, candidateValue, expectedValue, fieldConfig, weight) {
25734
25959
  const formats = fieldConfig.formats ?? DEFAULT_DATE_FORMATS;
25735
25960
  const candidateDate = parseDate(String(candidateValue), formats);
25736
25961
  const expectedDate = parseDate(String(expectedValue), formats);
25737
25962
  if (candidateDate === null) {
25738
25963
  return {
25739
- path: path44,
25964
+ path: path45,
25740
25965
  score: 0,
25741
25966
  weight,
25742
25967
  hit: false,
25743
- message: `${path44} (unparseable candidate date)`
25968
+ message: `${path45} (unparseable candidate date)`
25744
25969
  };
25745
25970
  }
25746
25971
  if (expectedDate === null) {
25747
25972
  return {
25748
- path: path44,
25973
+ path: path45,
25749
25974
  score: 0,
25750
25975
  weight,
25751
25976
  hit: false,
25752
- message: `${path44} (unparseable expected date)`
25977
+ message: `${path45} (unparseable expected date)`
25753
25978
  };
25754
25979
  }
25755
25980
  if (candidateDate.getFullYear() === expectedDate.getFullYear() && candidateDate.getMonth() === expectedDate.getMonth() && candidateDate.getDate() === expectedDate.getDate()) {
25756
25981
  return {
25757
- path: path44,
25982
+ path: path45,
25758
25983
  score: 1,
25759
25984
  weight,
25760
25985
  hit: true,
25761
- message: path44
25986
+ message: path45
25762
25987
  };
25763
25988
  }
25764
25989
  return {
25765
- path: path44,
25990
+ path: path45,
25766
25991
  score: 0,
25767
25992
  weight,
25768
25993
  hit: false,
25769
- message: `${path44} (date mismatch: got ${formatDateISO(candidateDate)}, expected ${formatDateISO(expectedDate)})`
25994
+ message: `${path45} (date mismatch: got ${formatDateISO(candidateDate)}, expected ${formatDateISO(expectedDate)})`
25770
25995
  };
25771
25996
  }
25772
25997
  /**
@@ -25799,11 +26024,11 @@ var FieldAccuracyEvaluator = class {
25799
26024
  };
25800
26025
  }
25801
26026
  };
25802
- function resolvePath(obj, path44) {
25803
- if (!path44 || !obj) {
26027
+ function resolvePath(obj, path45) {
26028
+ if (!path45 || !obj) {
25804
26029
  return void 0;
25805
26030
  }
25806
- const parts = path44.split(/\.|\[|\]/).filter((p) => p.length > 0);
26031
+ const parts = path45.split(/\.|\[|\]/).filter((p) => p.length > 0);
25807
26032
  let current = obj;
25808
26033
  for (const part of parts) {
25809
26034
  if (current === null || current === void 0) {
@@ -25965,9 +26190,7 @@ var PROVIDER_TOOL_SEMANTICS = {
25965
26190
  "claude-sdk": CLAUDE_MATCHER,
25966
26191
  codex: CODEX_MATCHER,
25967
26192
  "pi-coding-agent": PI_CODING_AGENT_MATCHER,
25968
- // pi-agent-sdk has no tools, so skill detection is a no-op. Kept for completeness.
25969
- // TODO: consider removing pi-agent-sdk provider entirely.
25970
- "pi-agent-sdk": PI_CODING_AGENT_MATCHER,
26193
+ "pi-cli": PI_CODING_AGENT_MATCHER,
25971
26194
  "copilot-cli": COPILOT_MATCHER,
25972
26195
  "copilot-sdk": COPILOT_MATCHER,
25973
26196
  vscode: COPILOT_MATCHER,
@@ -26276,8 +26499,8 @@ var TokenUsageEvaluator = class {
26276
26499
  };
26277
26500
  }
26278
26501
  };
26279
- function getNestedValue(obj, path44) {
26280
- const parts = path44.split(".");
26502
+ function getNestedValue(obj, path45) {
26503
+ const parts = path45.split(".");
26281
26504
  let current = obj;
26282
26505
  for (const part of parts) {
26283
26506
  if (current === null || current === void 0 || typeof current !== "object") {
@@ -27140,7 +27363,7 @@ async function executePromptTemplate(script, context2, config, timeoutMs) {
27140
27363
  };
27141
27364
  const inputJson = JSON.stringify(toSnakeCaseDeep(payload), null, 2);
27142
27365
  const scriptPath = script[script.length - 1];
27143
- const cwd = path33.dirname(scriptPath);
27366
+ const cwd = path34.dirname(scriptPath);
27144
27367
  try {
27145
27368
  const stdout = await executeScript(script, inputJson, timeoutMs, cwd);
27146
27369
  const prompt = stdout.trim();
@@ -27411,11 +27634,11 @@ function createBuiltinRegistry() {
27411
27634
  async function discoverAssertions(registry, baseDir) {
27412
27635
  const patterns = ["*.ts", "*.js", "*.mts", "*.mjs"];
27413
27636
  const candidateDirs = [];
27414
- let dir = path34.resolve(baseDir);
27415
- const root = path34.parse(dir).root;
27637
+ let dir = path35.resolve(baseDir);
27638
+ const root = path35.parse(dir).root;
27416
27639
  while (dir !== root) {
27417
- candidateDirs.push(path34.join(dir, ".agentv", "assertions"));
27418
- dir = path34.dirname(dir);
27640
+ candidateDirs.push(path35.join(dir, ".agentv", "assertions"));
27641
+ dir = path35.dirname(dir);
27419
27642
  }
27420
27643
  let files = [];
27421
27644
  for (const assertionsDir of candidateDirs) {
@@ -27431,7 +27654,7 @@ async function discoverAssertions(registry, baseDir) {
27431
27654
  }
27432
27655
  const discoveredTypes = [];
27433
27656
  for (const filePath of files) {
27434
- const basename = path34.basename(filePath);
27657
+ const basename = path35.basename(filePath);
27435
27658
  const typeName = basename.replace(/\.(ts|js|mts|mjs)$/, "");
27436
27659
  if (registry.has(typeName)) {
27437
27660
  continue;
@@ -27450,12 +27673,12 @@ async function discoverAssertions(registry, baseDir) {
27450
27673
  async function discoverGraders(registry, baseDir) {
27451
27674
  const patterns = ["*.ts", "*.js", "*.mts", "*.mjs"];
27452
27675
  const candidateDirs = [];
27453
- let dir = path35.resolve(baseDir);
27454
- const root = path35.parse(dir).root;
27676
+ let dir = path36.resolve(baseDir);
27677
+ const root = path36.parse(dir).root;
27455
27678
  while (dir !== root) {
27456
- candidateDirs.push(path35.join(dir, ".agentv", "graders"));
27457
- candidateDirs.push(path35.join(dir, ".agentv", "judges"));
27458
- dir = path35.dirname(dir);
27679
+ candidateDirs.push(path36.join(dir, ".agentv", "graders"));
27680
+ candidateDirs.push(path36.join(dir, ".agentv", "judges"));
27681
+ dir = path36.dirname(dir);
27459
27682
  }
27460
27683
  let files = [];
27461
27684
  for (const gradersDir of candidateDirs) {
@@ -27471,7 +27694,7 @@ async function discoverGraders(registry, baseDir) {
27471
27694
  }
27472
27695
  const discoveredTypes = [];
27473
27696
  for (const filePath of files) {
27474
- const basename = path35.basename(filePath);
27697
+ const basename = path36.basename(filePath);
27475
27698
  const typeName = basename.replace(/\.(ts|js|mts|mjs)$/, "");
27476
27699
  if (registry.has(typeName)) {
27477
27700
  continue;
@@ -27657,10 +27880,10 @@ async function stageNestedRepoChanges(workspacePath) {
27657
27880
  }
27658
27881
  for (const entry of entries) {
27659
27882
  if (entry === ".git" || entry === "node_modules") continue;
27660
- const childPath = path36.join(workspacePath, entry);
27883
+ const childPath = path37.join(workspacePath, entry);
27661
27884
  try {
27662
27885
  if (!statSync(childPath).isDirectory()) continue;
27663
- if (!statSync(path36.join(childPath, ".git")).isDirectory()) continue;
27886
+ if (!statSync(path37.join(childPath, ".git")).isDirectory()) continue;
27664
27887
  } catch {
27665
27888
  continue;
27666
27889
  }
@@ -27697,14 +27920,14 @@ async function isDirectory(filePath) {
27697
27920
  }
27698
27921
  function getWorkspacePath(evalRunId, caseId, workspaceRoot) {
27699
27922
  const root = workspaceRoot ?? getWorkspacesRoot();
27700
- return path37.join(root, evalRunId, caseId);
27923
+ return path38.join(root, evalRunId, caseId);
27701
27924
  }
27702
27925
  async function copyDirectoryRecursive(src, dest) {
27703
- await mkdir11(dest, { recursive: true });
27926
+ await mkdir12(dest, { recursive: true });
27704
27927
  const entries = await readdir3(src, { withFileTypes: true });
27705
27928
  for (const entry of entries) {
27706
- const srcPath = path37.join(src, entry.name);
27707
- const destPath = path37.join(dest, entry.name);
27929
+ const srcPath = path38.join(src, entry.name);
27930
+ const destPath = path38.join(dest, entry.name);
27708
27931
  if (entry.name === ".git") {
27709
27932
  continue;
27710
27933
  }
@@ -27716,7 +27939,7 @@ async function copyDirectoryRecursive(src, dest) {
27716
27939
  }
27717
27940
  }
27718
27941
  async function createTempWorkspace(templatePath, evalRunId, caseId, workspaceRoot) {
27719
- const resolvedTemplatePath = path37.resolve(templatePath);
27942
+ const resolvedTemplatePath = path38.resolve(templatePath);
27720
27943
  if (!await fileExists(resolvedTemplatePath)) {
27721
27944
  throw new TemplateNotFoundError(resolvedTemplatePath);
27722
27945
  }
@@ -27765,7 +27988,7 @@ async function cleanupWorkspace(workspacePath) {
27765
27988
  }
27766
27989
  async function cleanupEvalWorkspaces(evalRunId, workspaceRoot) {
27767
27990
  const root = workspaceRoot ?? getWorkspacesRoot();
27768
- const evalDir = path37.join(root, evalRunId);
27991
+ const evalDir = path38.join(root, evalRunId);
27769
27992
  if (await fileExists(evalDir)) {
27770
27993
  await rm4(evalDir, { recursive: true, force: true });
27771
27994
  }
@@ -27819,11 +28042,11 @@ function computeWorkspaceFingerprint(repos) {
27819
28042
  return createHash("sha256").update(JSON.stringify(canonical)).digest("hex");
27820
28043
  }
27821
28044
  async function copyDirectoryRecursive2(src, dest, skipDirs) {
27822
- await mkdir12(dest, { recursive: true });
28045
+ await mkdir13(dest, { recursive: true });
27823
28046
  const entries = await readdir4(src, { withFileTypes: true });
27824
28047
  for (const entry of entries) {
27825
- const srcPath = path38.join(src, entry.name);
27826
- const destPath = path38.join(dest, entry.name);
28048
+ const srcPath = path39.join(src, entry.name);
28049
+ const destPath = path39.join(dest, entry.name);
27827
28050
  if (entry.name === ".git") {
27828
28051
  continue;
27829
28052
  }
@@ -27856,8 +28079,8 @@ var WorkspacePoolManager = class {
27856
28079
  async acquireWorkspace(options) {
27857
28080
  const { templatePath, repos, maxSlots, repoManager, poolReset } = options;
27858
28081
  const fingerprint = computeWorkspaceFingerprint(repos);
27859
- const poolDir = path38.join(this.poolRoot, fingerprint);
27860
- await mkdir12(poolDir, { recursive: true });
28082
+ const poolDir = path39.join(this.poolRoot, fingerprint);
28083
+ await mkdir13(poolDir, { recursive: true });
27861
28084
  const drifted = await this.checkDrift(poolDir, fingerprint);
27862
28085
  if (drifted) {
27863
28086
  console.warn(
@@ -27866,7 +28089,7 @@ var WorkspacePoolManager = class {
27866
28089
  await this.removeAllSlots(poolDir);
27867
28090
  }
27868
28091
  for (let i = 0; i < maxSlots; i++) {
27869
- const slotPath = path38.join(poolDir, `slot-${i}`);
28092
+ const slotPath = path39.join(poolDir, `slot-${i}`);
27870
28093
  const lockPath = `${slotPath}.lock`;
27871
28094
  const locked = await this.tryLock(lockPath);
27872
28095
  if (!locked) {
@@ -27884,7 +28107,7 @@ var WorkspacePoolManager = class {
27884
28107
  poolDir
27885
28108
  };
27886
28109
  }
27887
- await mkdir12(slotPath, { recursive: true });
28110
+ await mkdir13(slotPath, { recursive: true });
27888
28111
  if (templatePath) {
27889
28112
  await copyDirectoryRecursive2(templatePath, slotPath);
27890
28113
  }
@@ -27953,7 +28176,7 @@ var WorkspacePoolManager = class {
27953
28176
  * Returns false (no drift) if metadata.json doesn't exist (first use).
27954
28177
  */
27955
28178
  async checkDrift(poolDir, fingerprint) {
27956
- const metadataPath = path38.join(poolDir, "metadata.json");
28179
+ const metadataPath = path39.join(poolDir, "metadata.json");
27957
28180
  try {
27958
28181
  const raw = await readFile10(metadataPath, "utf-8");
27959
28182
  const metadata = JSON.parse(raw);
@@ -27970,14 +28193,14 @@ var WorkspacePoolManager = class {
27970
28193
  repos,
27971
28194
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
27972
28195
  };
27973
- await writeFile7(path38.join(poolDir, "metadata.json"), JSON.stringify(metadata, null, 2));
28196
+ await writeFile7(path39.join(poolDir, "metadata.json"), JSON.stringify(metadata, null, 2));
27974
28197
  }
27975
28198
  /** Remove all slot directories and their lock files from a pool directory. */
27976
28199
  async removeAllSlots(poolDir) {
27977
28200
  const entries = await readdir4(poolDir);
27978
28201
  for (const entry of entries) {
27979
28202
  if (entry.startsWith("slot-") && !entry.endsWith(".lock")) {
27980
- const lockPath = path38.join(poolDir, `${entry}.lock`);
28203
+ const lockPath = path39.join(poolDir, `${entry}.lock`);
27981
28204
  if (existsSync2(lockPath)) {
27982
28205
  try {
27983
28206
  const pidStr = await readFile10(lockPath, "utf-8");
@@ -27993,12 +28216,12 @@ var WorkspacePoolManager = class {
27993
28216
  } catch {
27994
28217
  }
27995
28218
  }
27996
- await rm5(path38.join(poolDir, entry), { recursive: true, force: true });
28219
+ await rm5(path39.join(poolDir, entry), { recursive: true, force: true });
27997
28220
  await rm5(lockPath, { force: true }).catch(() => {
27998
28221
  });
27999
28222
  }
28000
28223
  }
28001
- await rm5(path38.join(poolDir, "metadata.json"), { force: true }).catch(() => {
28224
+ await rm5(path39.join(poolDir, "metadata.json"), { force: true }).catch(() => {
28002
28225
  });
28003
28226
  }
28004
28227
  /**
@@ -28008,7 +28231,7 @@ var WorkspacePoolManager = class {
28008
28231
  */
28009
28232
  async resetSlot(slotPath, templatePath, repos, poolReset = "fast") {
28010
28233
  for (const repo of repos) {
28011
- const repoDir = path38.join(slotPath, repo.path);
28234
+ const repoDir = path39.join(slotPath, repo.path);
28012
28235
  if (!existsSync2(repoDir)) {
28013
28236
  continue;
28014
28237
  }
@@ -28129,7 +28352,7 @@ ${lines.join("\n")}`;
28129
28352
  * Handles checkout, ref resolution, ancestor walking, shallow clone, sparse checkout.
28130
28353
  */
28131
28354
  async materialize(repo, workspacePath) {
28132
- const targetDir = path39.join(workspacePath, repo.path);
28355
+ const targetDir = path40.join(workspacePath, repo.path);
28133
28356
  const sourceUrl = getSourceUrl(repo.source);
28134
28357
  const startedAt = Date.now();
28135
28358
  if (this.verbose) {
@@ -28220,7 +28443,7 @@ ${lines.join("\n")}`;
28220
28443
  async reset(repos, workspacePath, reset) {
28221
28444
  const cleanFlag = reset === "strict" ? "-fdx" : "-fd";
28222
28445
  for (const repo of repos) {
28223
- const targetDir = path39.join(workspacePath, repo.path);
28446
+ const targetDir = path40.join(workspacePath, repo.path);
28224
28447
  await this.runGit(["reset", "--hard", "HEAD"], { cwd: targetDir });
28225
28448
  await this.runGit(["clean", cleanFlag], { cwd: targetDir });
28226
28449
  }
@@ -28230,11 +28453,11 @@ async function resolveWorkspaceTemplate(templatePath) {
28230
28453
  if (!templatePath) {
28231
28454
  return void 0;
28232
28455
  }
28233
- const resolved = path40.resolve(templatePath);
28456
+ const resolved = path41.resolve(templatePath);
28234
28457
  const stats = await stat6(resolved);
28235
28458
  if (stats.isFile()) {
28236
28459
  return {
28237
- dir: path40.dirname(resolved),
28460
+ dir: path41.dirname(resolved),
28238
28461
  workspaceFile: resolved
28239
28462
  };
28240
28463
  }
@@ -28246,14 +28469,14 @@ async function resolveWorkspaceTemplate(templatePath) {
28246
28469
  if (workspaceFiles.length === 1) {
28247
28470
  return {
28248
28471
  dir: resolved,
28249
- workspaceFile: path40.join(resolved, workspaceFiles[0])
28472
+ workspaceFile: path41.join(resolved, workspaceFiles[0])
28250
28473
  };
28251
28474
  }
28252
28475
  if (workspaceFiles.length > 1) {
28253
28476
  const conventionFile = workspaceFiles.find((f) => f === "template.code-workspace");
28254
28477
  return {
28255
28478
  dir: resolved,
28256
- workspaceFile: conventionFile ? path40.join(resolved, conventionFile) : void 0
28479
+ workspaceFile: conventionFile ? path41.join(resolved, conventionFile) : void 0
28257
28480
  };
28258
28481
  }
28259
28482
  return { dir: resolved };
@@ -28386,7 +28609,7 @@ async function runEvaluation(options) {
28386
28609
  );
28387
28610
  useCache = false;
28388
28611
  }
28389
- const evalRunId = randomUUID8();
28612
+ const evalRunId = randomUUID9();
28390
28613
  const evalCases = preloadedEvalCases ?? await loadTests(evalFilePath, repoRoot, { verbose, filter: filter2 });
28391
28614
  const filteredEvalCases = filterEvalCases(evalCases, filter2);
28392
28615
  if (filteredEvalCases.length === 0) {
@@ -28465,7 +28688,7 @@ async function runEvaluation(options) {
28465
28688
  ];
28466
28689
  const evaluatorRegistry = buildEvaluatorRegistry(evaluators, resolveGraderProvider);
28467
28690
  const typeRegistry = createBuiltinRegistry();
28468
- const discoveryBaseDir = evalFilePath ? path41.dirname(path41.resolve(evalFilePath)) : process.cwd();
28691
+ const discoveryBaseDir = evalFilePath ? path422.dirname(path422.resolve(evalFilePath)) : process.cwd();
28469
28692
  const evalDir = discoveryBaseDir;
28470
28693
  await discoverAssertions(typeRegistry, discoveryBaseDir);
28471
28694
  await discoverGraders(typeRegistry, discoveryBaseDir);
@@ -28612,7 +28835,7 @@ async function runEvaluation(options) {
28612
28835
  const isEmpty = dirExists ? (await readdir6(configuredStaticPath)).length === 0 : false;
28613
28836
  if (isYamlConfiguredPath && (!dirExists || isEmpty)) {
28614
28837
  if (!dirExists) {
28615
- await mkdir13(configuredStaticPath, { recursive: true });
28838
+ await mkdir14(configuredStaticPath, { recursive: true });
28616
28839
  }
28617
28840
  if (workspaceTemplate) {
28618
28841
  await copyDirectoryRecursive(workspaceTemplate, configuredStaticPath);
@@ -28657,12 +28880,12 @@ async function runEvaluation(options) {
28657
28880
  }
28658
28881
  } else if (suiteWorkspace?.hooks || suiteWorkspace?.repos?.length && !isPerTestIsolation) {
28659
28882
  sharedWorkspacePath = getWorkspacePath(evalRunId, "shared");
28660
- await mkdir13(sharedWorkspacePath, { recursive: true });
28883
+ await mkdir14(sharedWorkspacePath, { recursive: true });
28661
28884
  setupLog(`created empty shared workspace at: ${sharedWorkspacePath}`);
28662
28885
  }
28663
28886
  try {
28664
28887
  if (suiteWorkspaceFile && sharedWorkspacePath) {
28665
- const copiedWorkspaceFile = path41.join(sharedWorkspacePath, path41.basename(suiteWorkspaceFile));
28888
+ const copiedWorkspaceFile = path422.join(sharedWorkspacePath, path422.basename(suiteWorkspaceFile));
28666
28889
  try {
28667
28890
  await stat7(copiedWorkspaceFile);
28668
28891
  suiteWorkspaceFile = copiedWorkspaceFile;
@@ -29244,7 +29467,7 @@ async function runEvalCase(options) {
29244
29467
  );
29245
29468
  }
29246
29469
  if (caseWorkspaceFile && workspacePath) {
29247
- const copiedFile = path41.join(workspacePath, path41.basename(caseWorkspaceFile));
29470
+ const copiedFile = path422.join(workspacePath, path422.basename(caseWorkspaceFile));
29248
29471
  try {
29249
29472
  await stat7(copiedFile);
29250
29473
  caseWorkspaceFile = copiedFile;
@@ -29254,7 +29477,7 @@ async function runEvalCase(options) {
29254
29477
  }
29255
29478
  if (!workspacePath && (evalCase.workspace?.hooks || evalCase.workspace?.repos?.length) && evalRunId) {
29256
29479
  workspacePath = getWorkspacePath(evalRunId, evalCase.id);
29257
- await mkdir13(workspacePath, { recursive: true });
29480
+ await mkdir14(workspacePath, { recursive: true });
29258
29481
  }
29259
29482
  if (evalCase.workspace?.repos?.length && workspacePath) {
29260
29483
  const localPathErrors = RepoManager.validateLocalPaths(evalCase.workspace.repos);
@@ -29306,10 +29529,10 @@ async function runEvalCase(options) {
29306
29529
  const files = evalCase.metadata.agent_skills_files;
29307
29530
  if (baseDir && files.length > 0) {
29308
29531
  for (const relPath of files) {
29309
- const srcPath = path41.resolve(baseDir, relPath);
29310
- const destPath = path41.resolve(workspacePath, relPath);
29532
+ const srcPath = path422.resolve(baseDir, relPath);
29533
+ const destPath = path422.resolve(workspacePath, relPath);
29311
29534
  try {
29312
- await mkdir13(path41.dirname(destPath), { recursive: true });
29535
+ await mkdir14(path422.dirname(destPath), { recursive: true });
29313
29536
  await copyFile2(srcPath, destPath);
29314
29537
  } catch (error) {
29315
29538
  const message = error instanceof Error ? error.message : String(error);
@@ -29955,7 +30178,7 @@ async function runEvaluatorList(options) {
29955
30178
  fileChanges,
29956
30179
  workspacePath
29957
30180
  };
29958
- const evalFileDir = evalCase.file_paths[0] ? path41.dirname(evalCase.file_paths[0]) : process.cwd();
30181
+ const evalFileDir = evalCase.file_paths[0] ? path422.dirname(evalCase.file_paths[0]) : process.cwd();
29959
30182
  const dispatchContext = {
29960
30183
  graderProvider,
29961
30184
  targetResolver,
@@ -30318,7 +30541,7 @@ async function evaluate(config) {
30318
30541
  }
30319
30542
  const gitRoot = await findGitRoot(process.cwd());
30320
30543
  const repoRoot = gitRoot ?? process.cwd();
30321
- const testFilePath = config.specFile ? path422.resolve(config.specFile) : path422.join(process.cwd(), "__programmatic__.yaml");
30544
+ const testFilePath = config.specFile ? path43.resolve(config.specFile) : path43.join(process.cwd(), "__programmatic__.yaml");
30322
30545
  await loadEnvHierarchy(repoRoot, testFilePath);
30323
30546
  let resolvedTarget;
30324
30547
  let taskProvider;
@@ -30439,10 +30662,10 @@ function computeSummary(results, durationMs) {
30439
30662
  var TARGET_FILE_CANDIDATES = [".agentv/targets.yaml", ".agentv/targets.yml"];
30440
30663
  async function discoverDefaultTarget(repoRoot) {
30441
30664
  const cwd = process.cwd();
30442
- const chain = buildDirectoryChain(path422.join(cwd, "_placeholder"), repoRoot);
30665
+ const chain = buildDirectoryChain(path43.join(cwd, "_placeholder"), repoRoot);
30443
30666
  for (const dir of chain) {
30444
30667
  for (const candidate of TARGET_FILE_CANDIDATES) {
30445
- const targetsPath = path422.join(dir, candidate);
30668
+ const targetsPath = path43.join(dir, candidate);
30446
30669
  if (!existsSync4(targetsPath)) continue;
30447
30670
  try {
30448
30671
  const definitions = await readTargetDefinitions(targetsPath);
@@ -30459,7 +30682,7 @@ async function loadEnvHierarchy(repoRoot, startPath) {
30459
30682
  const chain = buildDirectoryChain(startPath, repoRoot);
30460
30683
  const envFiles = [];
30461
30684
  for (const dir of chain) {
30462
- const envPath = path422.join(dir, ".env");
30685
+ const envPath = path43.join(dir, ".env");
30463
30686
  if (existsSync4(envPath)) envFiles.push(envPath);
30464
30687
  }
30465
30688
  for (let i = 0; i < envFiles.length; i++) {
@@ -30648,13 +30871,13 @@ var ResponseCache = class {
30648
30871
  }
30649
30872
  async set(key, value) {
30650
30873
  const filePath = this.keyToPath(key);
30651
- const dir = path43.dirname(filePath);
30652
- await mkdir14(dir, { recursive: true });
30874
+ const dir = path44.dirname(filePath);
30875
+ await mkdir15(dir, { recursive: true });
30653
30876
  await writeFile8(filePath, JSON.stringify(value, null, 2), "utf8");
30654
30877
  }
30655
30878
  keyToPath(key) {
30656
30879
  const prefix = key.slice(0, 2);
30657
- return path43.join(this.cachePath, prefix, `${key}.json`);
30880
+ return path44.join(this.cachePath, prefix, `${key}.json`);
30658
30881
  }
30659
30882
  };
30660
30883
  function shouldEnableCache(params) {
@@ -30784,7 +31007,7 @@ var OtelTraceExporter = class {
30784
31007
  );
30785
31008
  }
30786
31009
  if (this.options.traceFilePath) {
30787
- const { SimpleTraceFileExporter: SimpleTraceFileExporter2 } = await import("./simple-trace-file-exporter-S76DMABU-5FCJESD2.js");
31010
+ const { SimpleTraceFileExporter: SimpleTraceFileExporter2 } = await import("./simple-trace-file-exporter-CRIO5HDZ-QYYT2QQT.js");
30788
31011
  processors.push(
30789
31012
  new SimpleSpanProcessor(new SimpleTraceFileExporter2(this.options.traceFilePath))
30790
31013
  );
@@ -30848,6 +31071,17 @@ var OtelTraceExporter = class {
30848
31071
  if (result.durationMs != null)
30849
31072
  rootSpan.setAttribute("agentv.trace.duration_ms", result.durationMs);
30850
31073
  if (result.costUsd != null) rootSpan.setAttribute("agentv.trace.cost_usd", result.costUsd);
31074
+ if (result.tokenUsage) {
31075
+ if (result.tokenUsage.input != null) {
31076
+ rootSpan.setAttribute("agentv.trace.token_input", result.tokenUsage.input);
31077
+ }
31078
+ if (result.tokenUsage.output != null) {
31079
+ rootSpan.setAttribute("agentv.trace.token_output", result.tokenUsage.output);
31080
+ }
31081
+ if (result.tokenUsage.cached != null) {
31082
+ rootSpan.setAttribute("agentv.trace.token_cached", result.tokenUsage.cached);
31083
+ }
31084
+ }
30851
31085
  if (result.trace) {
30852
31086
  const t = result.trace;
30853
31087
  rootSpan.setAttribute("agentv.trace.event_count", t.eventCount);
@@ -30950,6 +31184,7 @@ var OtelTraceExporter = class {
30950
31184
  tracer.startActiveSpan(
30951
31185
  spanName,
30952
31186
  { startTime: startHr },
31187
+ parentCtx,
30953
31188
  (span) => {
30954
31189
  if (isAssistant) {
30955
31190
  span.setAttribute("gen_ai.operation.name", "chat");
@@ -30982,6 +31217,7 @@ var OtelTraceExporter = class {
30982
31217
  tracer.startActiveSpan(
30983
31218
  `execute_tool ${tc.tool}`,
30984
31219
  {},
31220
+ msgCtx,
30985
31221
  (toolSpan) => {
30986
31222
  toolSpan.setAttribute("gen_ai.tool.name", tc.tool);
30987
31223
  if (tc.id) toolSpan.setAttribute("gen_ai.tool.call.id", tc.id);
@@ -31022,8 +31258,12 @@ var OtelStreamingObserver = class {
31022
31258
  rootSpan = null;
31023
31259
  // biome-ignore lint/suspicious/noExplicitAny: OTel context loaded dynamically
31024
31260
  rootCtx = null;
31261
+ observedChildSpans = false;
31262
+ pendingMetrics = null;
31025
31263
  /** Create root eval span immediately (visible in backend right away) */
31026
31264
  startEvalCase(testId, target, evalSet) {
31265
+ this.pendingMetrics = null;
31266
+ this.observedChildSpans = false;
31027
31267
  const ctx = this.parentCtx ?? this.api.context.active();
31028
31268
  this.rootSpan = this.tracer.startSpan("agentv.eval", void 0, ctx);
31029
31269
  this.rootSpan.setAttribute("gen_ai.operation.name", "evaluate");
@@ -31036,8 +31276,9 @@ var OtelStreamingObserver = class {
31036
31276
  /** Create and immediately export a tool span */
31037
31277
  onToolCall(name21, input, output, _durationMs, toolCallId) {
31038
31278
  if (!this.rootCtx) return;
31279
+ this.observedChildSpans = true;
31039
31280
  this.api.context.with(this.rootCtx, () => {
31040
- const span = this.tracer.startSpan(`execute_tool ${name21}`);
31281
+ const span = this.tracer.startSpan(`execute_tool ${name21}`, void 0, this.rootCtx);
31041
31282
  span.setAttribute("gen_ai.tool.name", name21);
31042
31283
  if (toolCallId) span.setAttribute("gen_ai.tool.call.id", toolCallId);
31043
31284
  if (this.captureContent) {
@@ -31058,8 +31299,9 @@ var OtelStreamingObserver = class {
31058
31299
  /** Create and immediately export an LLM span */
31059
31300
  onLlmCall(model, tokenUsage) {
31060
31301
  if (!this.rootCtx) return;
31302
+ this.observedChildSpans = true;
31061
31303
  this.api.context.with(this.rootCtx, () => {
31062
- const span = this.tracer.startSpan(`chat ${model}`);
31304
+ const span = this.tracer.startSpan(`chat ${model}`, void 0, this.rootCtx);
31063
31305
  span.setAttribute("gen_ai.operation.name", "chat");
31064
31306
  span.setAttribute("gen_ai.request.model", model);
31065
31307
  span.setAttribute("gen_ai.response.model", model);
@@ -31074,10 +31316,53 @@ var OtelStreamingObserver = class {
31074
31316
  span.end();
31075
31317
  });
31076
31318
  }
31319
+ /** Record final execution metrics before the root span is finalized. */
31320
+ recordEvalMetrics(result) {
31321
+ this.pendingMetrics = result;
31322
+ }
31077
31323
  /** Finalize root span with score/verdict after evaluation completes */
31078
31324
  finalizeEvalCase(score, error) {
31079
31325
  if (!this.rootSpan) return;
31080
31326
  this.rootSpan.setAttribute("agentv.score", score);
31327
+ if (this.pendingMetrics?.durationMs != null) {
31328
+ this.rootSpan.setAttribute("agentv.trace.duration_ms", this.pendingMetrics.durationMs);
31329
+ }
31330
+ if (this.pendingMetrics?.costUsd != null) {
31331
+ this.rootSpan.setAttribute("agentv.trace.cost_usd", this.pendingMetrics.costUsd);
31332
+ }
31333
+ if (this.pendingMetrics?.tokenUsage) {
31334
+ if (this.pendingMetrics.tokenUsage.input != null) {
31335
+ this.rootSpan.setAttribute(
31336
+ "agentv.trace.token_input",
31337
+ this.pendingMetrics.tokenUsage.input
31338
+ );
31339
+ }
31340
+ if (this.pendingMetrics.tokenUsage.output != null) {
31341
+ this.rootSpan.setAttribute(
31342
+ "agentv.trace.token_output",
31343
+ this.pendingMetrics.tokenUsage.output
31344
+ );
31345
+ }
31346
+ if (this.pendingMetrics.tokenUsage.cached != null) {
31347
+ this.rootSpan.setAttribute(
31348
+ "agentv.trace.token_cached",
31349
+ this.pendingMetrics.tokenUsage.cached
31350
+ );
31351
+ }
31352
+ }
31353
+ if (this.pendingMetrics?.trace) {
31354
+ this.rootSpan.setAttribute("agentv.trace.event_count", this.pendingMetrics.trace.eventCount);
31355
+ this.rootSpan.setAttribute(
31356
+ "agentv.trace.tool_names",
31357
+ Object.keys(this.pendingMetrics.trace.toolCalls).sort().join(",")
31358
+ );
31359
+ if (this.pendingMetrics.trace.llmCallCount != null) {
31360
+ this.rootSpan.setAttribute(
31361
+ "agentv.trace.llm_call_count",
31362
+ this.pendingMetrics.trace.llmCallCount
31363
+ );
31364
+ }
31365
+ }
31081
31366
  if (error) {
31082
31367
  this.rootSpan.setStatus({ code: this.api.SpanStatusCode.ERROR, message: error });
31083
31368
  } else {
@@ -31086,6 +31371,33 @@ var OtelStreamingObserver = class {
31086
31371
  this.rootSpan.end();
31087
31372
  this.rootSpan = null;
31088
31373
  this.rootCtx = null;
31374
+ this.observedChildSpans = false;
31375
+ this.pendingMetrics = null;
31376
+ }
31377
+ /** Backfill child spans from the completed result when the provider emitted no live callbacks. */
31378
+ completeFromResult(result) {
31379
+ this.recordEvalMetrics({
31380
+ durationMs: result.durationMs,
31381
+ costUsd: result.costUsd,
31382
+ tokenUsage: result.tokenUsage,
31383
+ trace: result.trace
31384
+ });
31385
+ if (this.observedChildSpans || !this.rootCtx) {
31386
+ return;
31387
+ }
31388
+ const model = result.output.find((msg) => msg.role === "assistant")?.metadata?.model ?? result.target ?? "unknown";
31389
+ this.onLlmCall(String(model), result.tokenUsage);
31390
+ for (const message of result.output) {
31391
+ for (const toolCall of message.toolCalls ?? []) {
31392
+ this.onToolCall(
31393
+ toolCall.tool,
31394
+ toolCall.input,
31395
+ toolCall.output,
31396
+ toolCall.durationMs ?? 0,
31397
+ toolCall.id
31398
+ );
31399
+ }
31400
+ }
31089
31401
  }
31090
31402
  /** Return the active eval span's trace ID and span ID for Braintrust trace bridging */
31091
31403
  getActiveSpanIds() {
@@ -31276,4 +31588,4 @@ export {
31276
31588
  OtelStreamingObserver,
31277
31589
  createAgentKernel
31278
31590
  };
31279
- //# sourceMappingURL=chunk-EZGWZVVK.js.map
31591
+ //# sourceMappingURL=chunk-UYBLUYHN.js.map