@agentv/core 2.17.3 → 2.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -4778,11 +4778,13 @@ function parseWorkspaceHookConfig(raw, evalFileDir) {
4778
4778
  function parseWorkspaceHooksConfig(raw, evalFileDir) {
4779
4779
  if (!isJsonObject(raw)) return void 0;
4780
4780
  const obj = raw;
4781
+ const enabled = typeof obj.enabled === "boolean" ? obj.enabled : void 0;
4781
4782
  const beforeAll = parseWorkspaceHookConfig(obj.before_all, evalFileDir);
4782
4783
  const beforeEach = parseWorkspaceHookConfig(obj.before_each, evalFileDir);
4783
4784
  const afterEach = parseWorkspaceHookConfig(obj.after_each, evalFileDir);
4784
4785
  const afterAll = parseWorkspaceHookConfig(obj.after_all, evalFileDir);
4785
4786
  const hooks = {
4787
+ ...enabled !== void 0 && { enabled },
4786
4788
  ...beforeAll !== void 0 && { before_all: beforeAll },
4787
4789
  ...beforeEach !== void 0 && { before_each: beforeEach },
4788
4790
  ...afterEach !== void 0 && { after_each: afterEach },
@@ -4813,6 +4815,17 @@ async function resolveWorkspaceConfig(raw, evalFileDir) {
4813
4815
  function parseWorkspaceConfig(raw, evalFileDir) {
4814
4816
  if (!isJsonObject(raw)) return void 0;
4815
4817
  const obj = raw;
4818
+ if ("static_path" in obj) {
4819
+ throw new Error(
4820
+ "workspace.static_path has been removed. Use workspace.path with workspace.mode=static."
4821
+ );
4822
+ }
4823
+ if ("pool" in obj) {
4824
+ throw new Error("workspace.pool has been removed. Use workspace.mode='pooled' or 'temp'.");
4825
+ }
4826
+ if ("static" in obj) {
4827
+ throw new Error("workspace.static has been removed. Use workspace.mode='static'.");
4828
+ }
4816
4829
  let template = typeof obj.template === "string" ? obj.template : void 0;
4817
4830
  if (template && !import_node_path8.default.isAbsolute(template)) {
4818
4831
  template = import_node_path8.default.resolve(evalFileDir, template);
@@ -4820,19 +4833,17 @@ function parseWorkspaceConfig(raw, evalFileDir) {
4820
4833
  const isolation = obj.isolation === "shared" || obj.isolation === "per_test" ? obj.isolation : void 0;
4821
4834
  const repos = Array.isArray(obj.repos) ? obj.repos.map(parseRepoConfig).filter(Boolean) : void 0;
4822
4835
  const hooks = parseWorkspaceHooksConfig(obj.hooks, evalFileDir);
4823
- const mode = obj.mode === "pooled" || obj.mode === "ephemeral" || obj.mode === "static" ? obj.mode : void 0;
4824
- const staticPath = typeof obj.static_path === "string" ? obj.static_path : void 0;
4825
- const pool = typeof obj.pool === "boolean" ? obj.pool : void 0;
4826
- if (!template && !isolation && !repos && !hooks && !mode && !staticPath && pool === void 0)
4827
- return void 0;
4836
+ const explicitMode = obj.mode === "pooled" || obj.mode === "temp" || obj.mode === "static" ? obj.mode : void 0;
4837
+ const workspacePath = typeof obj.path === "string" ? obj.path : void 0;
4838
+ const mode = explicitMode ?? (workspacePath ? "static" : void 0);
4839
+ if (!template && !isolation && !repos && !hooks && !mode && !workspacePath) return void 0;
4828
4840
  return {
4829
4841
  ...template !== void 0 && { template },
4830
4842
  ...isolation !== void 0 && { isolation },
4831
4843
  ...repos !== void 0 && { repos },
4832
4844
  ...hooks !== void 0 && { hooks },
4833
4845
  ...mode !== void 0 && { mode },
4834
- ...staticPath !== void 0 && { static_path: staticPath },
4835
- ...pool !== void 0 && { pool }
4846
+ ...workspacePath !== void 0 && { path: workspacePath }
4836
4847
  };
4837
4848
  }
4838
4849
  function mergeWorkspaceConfigs(suiteLevel, caseLevel) {
@@ -4846,21 +4857,22 @@ function mergeWorkspaceConfigs(suiteLevel, caseLevel) {
4846
4857
  ...caseHook ?? {}
4847
4858
  };
4848
4859
  };
4860
+ const mergedEnabled = caseLevel.hooks?.enabled ?? suiteLevel.hooks?.enabled;
4849
4861
  const mergedHooks = {
4862
+ ...mergedEnabled !== void 0 && { enabled: mergedEnabled },
4850
4863
  before_all: mergeHook(suiteLevel.hooks?.before_all, caseLevel.hooks?.before_all),
4851
4864
  before_each: mergeHook(suiteLevel.hooks?.before_each, caseLevel.hooks?.before_each),
4852
4865
  after_each: mergeHook(suiteLevel.hooks?.after_each, caseLevel.hooks?.after_each),
4853
4866
  after_all: mergeHook(suiteLevel.hooks?.after_all, caseLevel.hooks?.after_all)
4854
4867
  };
4855
- const hasHooks = Object.values(mergedHooks).some((hook) => hook !== void 0);
4868
+ const hasHooks = mergedEnabled !== void 0 || Object.values(mergedHooks).some((hook) => hook !== void 0 && typeof hook === "object");
4856
4869
  return {
4857
4870
  template: caseLevel.template ?? suiteLevel.template,
4858
4871
  isolation: caseLevel.isolation ?? suiteLevel.isolation,
4859
4872
  repos: caseLevel.repos ?? suiteLevel.repos,
4860
4873
  ...hasHooks && { hooks: mergedHooks },
4861
4874
  mode: caseLevel.mode ?? suiteLevel.mode,
4862
- static_path: caseLevel.static_path ?? suiteLevel.static_path,
4863
- pool: caseLevel.pool ?? suiteLevel.pool
4875
+ path: caseLevel.path ?? suiteLevel.path
4864
4876
  };
4865
4877
  }
4866
4878
  function asString6(value) {
@@ -7915,14 +7927,18 @@ var PiAgentSdkProvider = class {
7915
7927
  }
7916
7928
  });
7917
7929
  try {
7918
- const timeoutMs = this.config.timeoutMs ?? 12e4;
7919
- const timeoutPromise = new Promise((_, reject) => {
7920
- setTimeout(
7921
- () => reject(new Error(`Pi agent SDK timed out after ${timeoutMs}ms`)),
7922
- timeoutMs
7923
- );
7924
- });
7925
- await Promise.race([agent.prompt(request.question), timeoutPromise]);
7930
+ if (this.config.timeoutMs) {
7931
+ const timeoutMs = this.config.timeoutMs;
7932
+ const timeoutPromise = new Promise((_, reject) => {
7933
+ setTimeout(
7934
+ () => reject(new Error(`Pi agent SDK timed out after ${timeoutMs}ms`)),
7935
+ timeoutMs
7936
+ );
7937
+ });
7938
+ await Promise.race([agent.prompt(request.question), timeoutPromise]);
7939
+ } else {
7940
+ await agent.prompt(request.question);
7941
+ }
7926
7942
  await agent.waitForIdle();
7927
7943
  const agentMessages = agent.state.messages;
7928
7944
  for (const msg of agentMessages) {
@@ -8994,6 +9010,11 @@ function resolveRetryConfig(target) {
8994
9010
  }
8995
9011
  function resolveTargetDefinition(definition, env = process.env, evalFilePath) {
8996
9012
  const parsed = BASE_TARGET_SCHEMA.parse(definition);
9013
+ if (parsed.workspace_template !== void 0 || parsed.workspaceTemplate !== void 0) {
9014
+ throw new Error(
9015
+ `${parsed.name}: target-level workspace_template has been removed. Use eval-level workspace.template.`
9016
+ );
9017
+ }
8997
9018
  const provider = parsed.provider.toLowerCase();
8998
9019
  const providerBatching = resolveOptionalBoolean(
8999
9020
  parsed.provider_batching ?? parsed.providerBatching
@@ -16287,6 +16308,9 @@ function toScriptConfig(hook, hookName, context2) {
16287
16308
  function hasHookCommand(hook) {
16288
16309
  return !!(hook?.command && hook.command.length > 0 || hook?.script && hook.script.length > 0);
16289
16310
  }
16311
+ function hooksEnabled(workspace) {
16312
+ return workspace?.hooks?.enabled !== false;
16313
+ }
16290
16314
  function getWorkspaceTemplate(target) {
16291
16315
  const config = target.config;
16292
16316
  if ("workspaceTemplate" in config && typeof config.workspaceTemplate === "string") {
@@ -16461,19 +16485,27 @@ async function runEvaluation(options) {
16461
16485
  }
16462
16486
  };
16463
16487
  const isPerTestIsolation = suiteWorkspace?.isolation === "per_test";
16464
- const configuredMode = suiteWorkspace?.mode ?? workspaceMode;
16465
- const configuredStaticPath = suiteWorkspace?.static_path ?? workspacePath ?? legacyWorkspacePath;
16466
- const useStaticWorkspace = configuredMode === "static" || !!configuredStaticPath && !configuredMode;
16488
+ const cliWorkspacePath = workspacePath ?? legacyWorkspacePath;
16489
+ const yamlWorkspacePath = suiteWorkspace?.path;
16490
+ if (cliWorkspacePath && workspaceMode && workspaceMode !== "static") {
16491
+ throw new Error("--workspace-path requires --workspace-mode static when both are provided");
16492
+ }
16493
+ const configuredMode = cliWorkspacePath ? "static" : workspaceMode ?? suiteWorkspace?.mode ?? (yamlWorkspacePath ? "static" : "pooled");
16494
+ const configuredStaticPath = cliWorkspacePath ?? yamlWorkspacePath;
16495
+ const useStaticWorkspace = configuredMode === "static";
16467
16496
  if (useStaticWorkspace && isPerTestIsolation) {
16468
16497
  throw new Error(
16469
16498
  "static workspace mode is incompatible with isolation: per_test. Use isolation: shared (default)."
16470
16499
  );
16471
16500
  }
16472
16501
  if (configuredMode === "static" && !configuredStaticPath) {
16473
- throw new Error("workspace.mode=static requires workspace.static_path or --workspace-path");
16502
+ throw new Error("workspace.mode=static requires workspace.path or --workspace-path");
16503
+ }
16504
+ if (configuredMode !== "static" && configuredStaticPath) {
16505
+ throw new Error("workspace.path requires workspace.mode=static");
16474
16506
  }
16475
16507
  const hasSharedWorkspace = !!(useStaticWorkspace || workspaceTemplate || suiteWorkspace?.hooks || suiteWorkspace?.repos?.length && !isPerTestIsolation);
16476
- const poolEnabled = configuredMode === "pooled" ? true : configuredMode === "ephemeral" || useStaticWorkspace ? false : suiteWorkspace?.pool ?? poolWorkspaces ?? true;
16508
+ const poolEnabled = configuredMode === "pooled";
16477
16509
  const usePool = poolEnabled !== false && !!suiteWorkspace?.repos?.length && !isPerTestIsolation && !useStaticWorkspace;
16478
16510
  const resolvedRetainOnSuccess = retainOnSuccess ?? (keepWorkspaces ? "keep" : "cleanup");
16479
16511
  const resolvedRetainOnFailure = retainOnFailure ?? (cleanupWorkspaces ? "cleanup" : "keep");
@@ -16497,9 +16529,28 @@ async function runEvaluation(options) {
16497
16529
  const availablePoolSlots = [];
16498
16530
  const poolSlotBaselines = /* @__PURE__ */ new Map();
16499
16531
  const poolMaxSlots = Math.min(configPoolMaxSlots ?? 10, 50);
16532
+ let staticMaterialised = false;
16500
16533
  if (useStaticWorkspace && configuredStaticPath) {
16534
+ const isYamlConfiguredPath = !cliWorkspacePath && !!yamlWorkspacePath;
16535
+ const dirExists = await (0, import_promises29.stat)(configuredStaticPath).then(
16536
+ (s) => s.isDirectory(),
16537
+ () => false
16538
+ );
16539
+ const isEmpty = dirExists ? (await (0, import_promises29.readdir)(configuredStaticPath)).length === 0 : false;
16540
+ if (isYamlConfiguredPath && (!dirExists || isEmpty)) {
16541
+ if (!dirExists) {
16542
+ await (0, import_promises29.mkdir)(configuredStaticPath, { recursive: true });
16543
+ }
16544
+ if (workspaceTemplate) {
16545
+ await copyDirectoryRecursive(workspaceTemplate, configuredStaticPath);
16546
+ setupLog(`copied template into static workspace: ${configuredStaticPath}`);
16547
+ }
16548
+ staticMaterialised = true;
16549
+ setupLog(`materialised static workspace at: ${configuredStaticPath}`);
16550
+ } else {
16551
+ setupLog(`reusing existing static workspace: ${configuredStaticPath}`);
16552
+ }
16501
16553
  sharedWorkspacePath = configuredStaticPath;
16502
- setupLog(`using static workspace: ${configuredStaticPath}`);
16503
16554
  } else if (usePool && suiteWorkspace?.repos) {
16504
16555
  const slotsNeeded = workers;
16505
16556
  setupLog(`acquiring ${slotsNeeded} workspace pool slot(s) (pool capacity: ${poolMaxSlots})`);
@@ -16545,7 +16596,8 @@ async function runEvaluation(options) {
16545
16596
  } catch {
16546
16597
  }
16547
16598
  }
16548
- const repoManager = suiteWorkspace?.repos?.length && !usePool && !useStaticWorkspace ? new RepoManager(verbose) : void 0;
16599
+ const needsRepoMaterialisation = !!suiteWorkspace?.repos?.length && !usePool && (!useStaticWorkspace || staticMaterialised);
16600
+ const repoManager = needsRepoMaterialisation ? new RepoManager(verbose) : void 0;
16549
16601
  if (repoManager && sharedWorkspacePath && suiteWorkspace?.repos && !isPerTestIsolation) {
16550
16602
  setupLog(
16551
16603
  `materializing ${suiteWorkspace.repos.length} shared repo(s) into ${sharedWorkspacePath}`
@@ -16562,8 +16614,9 @@ async function runEvaluation(options) {
16562
16614
  throw new Error(`Failed to materialize repos: ${message}`);
16563
16615
  }
16564
16616
  }
16617
+ const suiteHooksEnabled = hooksEnabled(suiteWorkspace);
16565
16618
  const suiteBeforeAllHook = suiteWorkspace?.hooks?.before_all;
16566
- if (sharedWorkspacePath && hasHookCommand(suiteBeforeAllHook)) {
16619
+ if (sharedWorkspacePath && suiteHooksEnabled && hasHookCommand(suiteBeforeAllHook)) {
16567
16620
  const beforeAllHook = suiteBeforeAllHook;
16568
16621
  const beforeAllCommand = (beforeAllHook.command ?? beforeAllHook.script ?? []).join(" ");
16569
16622
  setupLog(
@@ -16590,7 +16643,7 @@ async function runEvaluation(options) {
16590
16643
  throw new Error(`before_all script failed: ${message}`);
16591
16644
  }
16592
16645
  }
16593
- if (availablePoolSlots.length > 0 && hasHookCommand(suiteBeforeAllHook)) {
16646
+ if (availablePoolSlots.length > 0 && suiteHooksEnabled && hasHookCommand(suiteBeforeAllHook)) {
16594
16647
  const beforeAllHook = suiteBeforeAllHook;
16595
16648
  for (const slot of availablePoolSlots) {
16596
16649
  setupLog(`running before_all on pool slot ${slot.index}`);
@@ -16832,7 +16885,7 @@ async function runEvaluation(options) {
16832
16885
  }
16833
16886
  const afterAllWorkspaces = poolSlots.length > 1 ? poolSlots.map((s) => s.path) : sharedWorkspacePath ? [sharedWorkspacePath] : [];
16834
16887
  const suiteAfterAllHook = suiteWorkspace?.hooks?.after_all;
16835
- if (afterAllWorkspaces.length > 0 && hasHookCommand(suiteAfterAllHook)) {
16888
+ if (afterAllWorkspaces.length > 0 && suiteHooksEnabled && hasHookCommand(suiteAfterAllHook)) {
16836
16889
  const afterAllHook = suiteAfterAllHook;
16837
16890
  for (const wsPath of afterAllWorkspaces) {
16838
16891
  const scriptContext = {
@@ -17080,6 +17133,7 @@ async function runEvalCase(options) {
17080
17133
  let afterEachOutput;
17081
17134
  const isSharedWorkspace = !!sharedWorkspacePath;
17082
17135
  let caseWorkspaceFile;
17136
+ const caseHooksEnabled = hooksEnabled(evalCase.workspace);
17083
17137
  if (!workspacePath) {
17084
17138
  const rawCaseTemplate = evalCase.workspace?.template ?? getWorkspaceTemplate(target);
17085
17139
  const resolvedCaseTemplate = await resolveWorkspaceTemplate(rawCaseTemplate);
@@ -17141,7 +17195,7 @@ async function runEvalCase(options) {
17141
17195
  }
17142
17196
  }
17143
17197
  const caseBeforeAllHook = evalCase.workspace?.hooks?.before_all;
17144
- if (workspacePath && hasHookCommand(caseBeforeAllHook)) {
17198
+ if (workspacePath && caseHooksEnabled && hasHookCommand(caseBeforeAllHook)) {
17145
17199
  const beforeAllHook = caseBeforeAllHook;
17146
17200
  const beforeAllCommand = (beforeAllHook.command ?? beforeAllHook.script ?? []).join(" ");
17147
17201
  if (setupDebug) {
@@ -17185,7 +17239,7 @@ async function runEvalCase(options) {
17185
17239
  }
17186
17240
  }
17187
17241
  const caseBeforeEachHook = evalCase.workspace?.hooks?.before_each;
17188
- if (workspacePath && hasHookCommand(caseBeforeEachHook)) {
17242
+ if (workspacePath && caseHooksEnabled && hasHookCommand(caseBeforeEachHook)) {
17189
17243
  const beforeEachHook = caseBeforeEachHook;
17190
17244
  const scriptContext = {
17191
17245
  workspacePath,
@@ -17314,7 +17368,7 @@ async function runEvalCase(options) {
17314
17368
  }
17315
17369
  }
17316
17370
  const providerError = extractProviderError(providerResponse);
17317
- if (repoManager && workspacePath && evalCase.workspace?.hooks?.after_each?.reset && evalCase.workspace.hooks.after_each.reset !== "none" && evalCase.workspace.repos) {
17371
+ if (caseHooksEnabled && repoManager && workspacePath && evalCase.workspace?.hooks?.after_each?.reset && evalCase.workspace.hooks.after_each.reset !== "none" && evalCase.workspace.repos) {
17318
17372
  try {
17319
17373
  await repoManager.reset(
17320
17374
  evalCase.workspace.repos,
@@ -17325,7 +17379,7 @@ async function runEvalCase(options) {
17325
17379
  }
17326
17380
  }
17327
17381
  const caseAfterEachHook = evalCase.workspace?.hooks?.after_each;
17328
- if (workspacePath && hasHookCommand(caseAfterEachHook)) {
17382
+ if (workspacePath && caseHooksEnabled && hasHookCommand(caseAfterEachHook)) {
17329
17383
  const afterEachHook = caseAfterEachHook;
17330
17384
  const scriptContext = {
17331
17385
  workspacePath,
@@ -18104,7 +18158,7 @@ async function evaluate(config) {
18104
18158
  repoRoot,
18105
18159
  target: resolvedTarget,
18106
18160
  maxRetries: config.maxRetries ?? 2,
18107
- agentTimeoutMs: config.agentTimeoutMs ?? 12e4,
18161
+ agentTimeoutMs: config.agentTimeoutMs,
18108
18162
  verbose: config.verbose,
18109
18163
  maxConcurrency: config.workers ?? 3,
18110
18164
  filter: config.filter,
@@ -18207,7 +18261,7 @@ var AgentVConfigSchema = import_zod6.z.object({
18207
18261
  workers: import_zod6.z.number().int().min(1).max(50).optional(),
18208
18262
  /** Maximum retries on failure (default: 2) */
18209
18263
  maxRetries: import_zod6.z.number().int().min(0).optional(),
18210
- /** Agent timeout in milliseconds (default: 120000) */
18264
+ /** Agent timeout in milliseconds. No timeout if not set. */
18211
18265
  agentTimeoutMs: import_zod6.z.number().int().min(0).optional(),
18212
18266
  /** Enable verbose logging */
18213
18267
  verbose: import_zod6.z.boolean().optional(),