agentv 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/README.md CHANGED
@@ -119,21 +119,28 @@ See [AGENTS.md](AGENTS.md) for development guidelines and design principles.
119
119
 
120
120
  ### Releasing
121
121
 
122
- Stable release:
122
+ Version bump:
123
123
 
124
124
  ```bash
125
125
  bun run release # patch bump
126
126
  bun run release minor
127
127
  bun run release major
128
- bun run publish # publish to npm `latest`
129
128
  ```
130
129
 
131
- Prerelease (`next`) channel:
130
+ Canary rollout (recommended):
131
+
132
+ ```bash
133
+ bun run publish:next # publish current version to npm `next`
134
+ bun run promote:latest # promote same version to npm `latest`
135
+ bun run tag:next 2.18.0 # point npm `next` to an explicit version
136
+ bun run promote:latest 2.18.0 # point npm `latest` to an explicit version
137
+ ```
138
+
139
+ Legacy prerelease flow (still available):
132
140
 
133
141
  ```bash
134
142
  bun run release:next # bump/increment `-next.N`
135
143
  bun run release:next major # start new major prerelease line
136
- bun run publish:next # publish to npm `next`
137
144
  ```
138
145
 
139
146
  ## Core Concepts
@@ -347,7 +354,6 @@ targets:
347
354
 
348
355
  - name: vscode_dev
349
356
  provider: vscode
350
- workspace_template: ${{ WORKSPACE_PATH }}
351
357
  judge_target: azure-base
352
358
 
353
359
  - name: local_agent
@@ -358,6 +364,8 @@ targets:
358
364
 
359
365
  Supports: `azure`, `anthropic`, `gemini`, `codex`, `copilot`, `pi-coding-agent`, `claude`, `vscode`, `vscode-insiders`, `cli`, and `mock`.
360
366
 
367
+ Workspace templates are configured at eval-level under `workspace.template` (not per-target `workspace_template`).
368
+
361
369
  Use `${{ VARIABLE_NAME }}` syntax to reference your `.env` file. See `.agentv/targets.yaml` after `agentv init` for detailed examples and all provider-specific fields.
362
370
 
363
371
  ## Evaluation Features
@@ -148,7 +148,7 @@ var require_dist = __commonJS({
148
148
  }
149
149
  });
150
150
 
151
- // ../../packages/core/dist/chunk-PSYFRPNT.js
151
+ // ../../packages/core/dist/chunk-V42NUK73.js
152
152
  import { constants } from "node:fs";
153
153
  import { access, readFile } from "node:fs/promises";
154
154
  import path from "node:path";
@@ -4195,7 +4195,7 @@ var coerce = {
4195
4195
  };
4196
4196
  var NEVER = INVALID;
4197
4197
 
4198
- // ../../packages/core/dist/chunk-PSYFRPNT.js
4198
+ // ../../packages/core/dist/chunk-V42NUK73.js
4199
4199
  var TEST_MESSAGE_ROLE_VALUES = ["system", "user", "assistant", "tool"];
4200
4200
  var TEST_MESSAGE_ROLES = TEST_MESSAGE_ROLE_VALUES;
4201
4201
  var TEST_MESSAGE_ROLE_SET = new Set(TEST_MESSAGE_ROLE_VALUES);
@@ -4603,6 +4603,11 @@ function resolveRetryConfig(target) {
4603
4603
  }
4604
4604
  function resolveTargetDefinition(definition, env = process.env, evalFilePath) {
4605
4605
  const parsed = BASE_TARGET_SCHEMA.parse(definition);
4606
+ if (parsed.workspace_template !== void 0 || parsed.workspaceTemplate !== void 0) {
4607
+ throw new Error(
4608
+ `${parsed.name}: target-level workspace_template has been removed. Use eval-level workspace.template.`
4609
+ );
4610
+ }
4606
4611
  const provider = parsed.provider.toLowerCase();
4607
4612
  const providerBatching = resolveOptionalBoolean(
4608
4613
  parsed.provider_batching ?? parsed.providerBatching
@@ -33961,7 +33966,7 @@ import { createServer } from "node:http";
33961
33966
  import fs2 from "node:fs/promises";
33962
33967
  import path31 from "node:path";
33963
33968
  import { createHash as createHash2, randomUUID as randomUUID7 } from "node:crypto";
33964
- import { mkdir as mkdir12, stat as stat7 } from "node:fs/promises";
33969
+ import { mkdir as mkdir12, readdir as readdir6, stat as stat7 } from "node:fs/promises";
33965
33970
  import path39 from "node:path";
33966
33971
  import micromatch4 from "micromatch";
33967
33972
  import { readFileSync } from "node:fs";
@@ -37048,11 +37053,13 @@ function parseWorkspaceHookConfig(raw, evalFileDir) {
37048
37053
  function parseWorkspaceHooksConfig(raw, evalFileDir) {
37049
37054
  if (!isJsonObject(raw)) return void 0;
37050
37055
  const obj = raw;
37056
+ const enabled = typeof obj.enabled === "boolean" ? obj.enabled : void 0;
37051
37057
  const beforeAll = parseWorkspaceHookConfig(obj.before_all, evalFileDir);
37052
37058
  const beforeEach = parseWorkspaceHookConfig(obj.before_each, evalFileDir);
37053
37059
  const afterEach = parseWorkspaceHookConfig(obj.after_each, evalFileDir);
37054
37060
  const afterAll = parseWorkspaceHookConfig(obj.after_all, evalFileDir);
37055
37061
  const hooks = {
37062
+ ...enabled !== void 0 && { enabled },
37056
37063
  ...beforeAll !== void 0 && { before_all: beforeAll },
37057
37064
  ...beforeEach !== void 0 && { before_each: beforeEach },
37058
37065
  ...afterEach !== void 0 && { after_each: afterEach },
@@ -37083,6 +37090,17 @@ async function resolveWorkspaceConfig(raw, evalFileDir) {
37083
37090
  function parseWorkspaceConfig(raw, evalFileDir) {
37084
37091
  if (!isJsonObject(raw)) return void 0;
37085
37092
  const obj = raw;
37093
+ if ("static_path" in obj) {
37094
+ throw new Error(
37095
+ "workspace.static_path has been removed. Use workspace.path with workspace.mode=static."
37096
+ );
37097
+ }
37098
+ if ("pool" in obj) {
37099
+ throw new Error("workspace.pool has been removed. Use workspace.mode='pooled' or 'temp'.");
37100
+ }
37101
+ if ("static" in obj) {
37102
+ throw new Error("workspace.static has been removed. Use workspace.mode='static'.");
37103
+ }
37086
37104
  let template = typeof obj.template === "string" ? obj.template : void 0;
37087
37105
  if (template && !path8.isAbsolute(template)) {
37088
37106
  template = path8.resolve(evalFileDir, template);
@@ -37090,19 +37108,17 @@ function parseWorkspaceConfig(raw, evalFileDir) {
37090
37108
  const isolation = obj.isolation === "shared" || obj.isolation === "per_test" ? obj.isolation : void 0;
37091
37109
  const repos = Array.isArray(obj.repos) ? obj.repos.map(parseRepoConfig).filter(Boolean) : void 0;
37092
37110
  const hooks = parseWorkspaceHooksConfig(obj.hooks, evalFileDir);
37093
- const mode = obj.mode === "pooled" || obj.mode === "ephemeral" || obj.mode === "static" ? obj.mode : void 0;
37094
- const staticPath = typeof obj.static_path === "string" ? obj.static_path : void 0;
37095
- const pool = typeof obj.pool === "boolean" ? obj.pool : void 0;
37096
- if (!template && !isolation && !repos && !hooks && !mode && !staticPath && pool === void 0)
37097
- return void 0;
37111
+ const explicitMode = obj.mode === "pooled" || obj.mode === "temp" || obj.mode === "static" ? obj.mode : void 0;
37112
+ const workspacePath = typeof obj.path === "string" ? obj.path : void 0;
37113
+ const mode = explicitMode ?? (workspacePath ? "static" : void 0);
37114
+ if (!template && !isolation && !repos && !hooks && !mode && !workspacePath) return void 0;
37098
37115
  return {
37099
37116
  ...template !== void 0 && { template },
37100
37117
  ...isolation !== void 0 && { isolation },
37101
37118
  ...repos !== void 0 && { repos },
37102
37119
  ...hooks !== void 0 && { hooks },
37103
37120
  ...mode !== void 0 && { mode },
37104
- ...staticPath !== void 0 && { static_path: staticPath },
37105
- ...pool !== void 0 && { pool }
37121
+ ...workspacePath !== void 0 && { path: workspacePath }
37106
37122
  };
37107
37123
  }
37108
37124
  function mergeWorkspaceConfigs(suiteLevel, caseLevel) {
@@ -37116,21 +37132,22 @@ function mergeWorkspaceConfigs(suiteLevel, caseLevel) {
37116
37132
  ...caseHook ?? {}
37117
37133
  };
37118
37134
  };
37135
+ const mergedEnabled = caseLevel.hooks?.enabled ?? suiteLevel.hooks?.enabled;
37119
37136
  const mergedHooks = {
37137
+ ...mergedEnabled !== void 0 && { enabled: mergedEnabled },
37120
37138
  before_all: mergeHook(suiteLevel.hooks?.before_all, caseLevel.hooks?.before_all),
37121
37139
  before_each: mergeHook(suiteLevel.hooks?.before_each, caseLevel.hooks?.before_each),
37122
37140
  after_each: mergeHook(suiteLevel.hooks?.after_each, caseLevel.hooks?.after_each),
37123
37141
  after_all: mergeHook(suiteLevel.hooks?.after_all, caseLevel.hooks?.after_all)
37124
37142
  };
37125
- const hasHooks = Object.values(mergedHooks).some((hook) => hook !== void 0);
37143
+ const hasHooks = mergedEnabled !== void 0 || Object.values(mergedHooks).some((hook) => hook !== void 0 && typeof hook === "object");
37126
37144
  return {
37127
37145
  template: caseLevel.template ?? suiteLevel.template,
37128
37146
  isolation: caseLevel.isolation ?? suiteLevel.isolation,
37129
37147
  repos: caseLevel.repos ?? suiteLevel.repos,
37130
37148
  ...hasHooks && { hooks: mergedHooks },
37131
37149
  mode: caseLevel.mode ?? suiteLevel.mode,
37132
- static_path: caseLevel.static_path ?? suiteLevel.static_path,
37133
- pool: caseLevel.pool ?? suiteLevel.pool
37150
+ path: caseLevel.path ?? suiteLevel.path
37134
37151
  };
37135
37152
  }
37136
37153
  function asString6(value) {
@@ -40000,14 +40017,18 @@ var PiAgentSdkProvider = class {
40000
40017
  }
40001
40018
  });
40002
40019
  try {
40003
- const timeoutMs = this.config.timeoutMs ?? 12e4;
40004
- const timeoutPromise = new Promise((_, reject) => {
40005
- setTimeout(
40006
- () => reject(new Error(`Pi agent SDK timed out after ${timeoutMs}ms`)),
40007
- timeoutMs
40008
- );
40009
- });
40010
- await Promise.race([agent.prompt(request.question), timeoutPromise]);
40020
+ if (this.config.timeoutMs) {
40021
+ const timeoutMs = this.config.timeoutMs;
40022
+ const timeoutPromise = new Promise((_, reject) => {
40023
+ setTimeout(
40024
+ () => reject(new Error(`Pi agent SDK timed out after ${timeoutMs}ms`)),
40025
+ timeoutMs
40026
+ );
40027
+ });
40028
+ await Promise.race([agent.prompt(request.question), timeoutPromise]);
40029
+ } else {
40030
+ await agent.prompt(request.question);
40031
+ }
40011
40032
  await agent.waitForIdle();
40012
40033
  const agentMessages = agent.state.messages;
40013
40034
  for (const msg of agentMessages) {
@@ -47044,6 +47065,9 @@ function toScriptConfig(hook, hookName, context) {
47044
47065
  function hasHookCommand(hook) {
47045
47066
  return !!(hook?.command && hook.command.length > 0 || hook?.script && hook.script.length > 0);
47046
47067
  }
47068
+ function hooksEnabled(workspace) {
47069
+ return workspace?.hooks?.enabled !== false;
47070
+ }
47047
47071
  function getWorkspaceTemplate(target) {
47048
47072
  const config2 = target.config;
47049
47073
  if ("workspaceTemplate" in config2 && typeof config2.workspaceTemplate === "string") {
@@ -47218,19 +47242,27 @@ async function runEvaluation(options) {
47218
47242
  }
47219
47243
  };
47220
47244
  const isPerTestIsolation = suiteWorkspace?.isolation === "per_test";
47221
- const configuredMode = suiteWorkspace?.mode ?? workspaceMode;
47222
- const configuredStaticPath = suiteWorkspace?.static_path ?? workspacePath ?? legacyWorkspacePath;
47223
- const useStaticWorkspace = configuredMode === "static" || !!configuredStaticPath && !configuredMode;
47245
+ const cliWorkspacePath = workspacePath ?? legacyWorkspacePath;
47246
+ const yamlWorkspacePath = suiteWorkspace?.path;
47247
+ if (cliWorkspacePath && workspaceMode && workspaceMode !== "static") {
47248
+ throw new Error("--workspace-path requires --workspace-mode static when both are provided");
47249
+ }
47250
+ const configuredMode = cliWorkspacePath ? "static" : workspaceMode ?? suiteWorkspace?.mode ?? (yamlWorkspacePath ? "static" : "pooled");
47251
+ const configuredStaticPath = cliWorkspacePath ?? yamlWorkspacePath;
47252
+ const useStaticWorkspace = configuredMode === "static";
47224
47253
  if (useStaticWorkspace && isPerTestIsolation) {
47225
47254
  throw new Error(
47226
47255
  "static workspace mode is incompatible with isolation: per_test. Use isolation: shared (default)."
47227
47256
  );
47228
47257
  }
47229
47258
  if (configuredMode === "static" && !configuredStaticPath) {
47230
- throw new Error("workspace.mode=static requires workspace.static_path or --workspace-path");
47259
+ throw new Error("workspace.mode=static requires workspace.path or --workspace-path");
47260
+ }
47261
+ if (configuredMode !== "static" && configuredStaticPath) {
47262
+ throw new Error("workspace.path requires workspace.mode=static");
47231
47263
  }
47232
47264
  const hasSharedWorkspace = !!(useStaticWorkspace || workspaceTemplate || suiteWorkspace?.hooks || suiteWorkspace?.repos?.length && !isPerTestIsolation);
47233
- const poolEnabled = configuredMode === "pooled" ? true : configuredMode === "ephemeral" || useStaticWorkspace ? false : suiteWorkspace?.pool ?? poolWorkspaces ?? true;
47265
+ const poolEnabled = configuredMode === "pooled";
47234
47266
  const usePool = poolEnabled !== false && !!suiteWorkspace?.repos?.length && !isPerTestIsolation && !useStaticWorkspace;
47235
47267
  const resolvedRetainOnSuccess = retainOnSuccess ?? (keepWorkspaces ? "keep" : "cleanup");
47236
47268
  const resolvedRetainOnFailure = retainOnFailure ?? (cleanupWorkspaces ? "cleanup" : "keep");
@@ -47254,9 +47286,28 @@ async function runEvaluation(options) {
47254
47286
  const availablePoolSlots = [];
47255
47287
  const poolSlotBaselines = /* @__PURE__ */ new Map();
47256
47288
  const poolMaxSlots = Math.min(configPoolMaxSlots ?? 10, 50);
47289
+ let staticMaterialised = false;
47257
47290
  if (useStaticWorkspace && configuredStaticPath) {
47291
+ const isYamlConfiguredPath = !cliWorkspacePath && !!yamlWorkspacePath;
47292
+ const dirExists = await stat7(configuredStaticPath).then(
47293
+ (s) => s.isDirectory(),
47294
+ () => false
47295
+ );
47296
+ const isEmpty = dirExists ? (await readdir6(configuredStaticPath)).length === 0 : false;
47297
+ if (isYamlConfiguredPath && (!dirExists || isEmpty)) {
47298
+ if (!dirExists) {
47299
+ await mkdir12(configuredStaticPath, { recursive: true });
47300
+ }
47301
+ if (workspaceTemplate) {
47302
+ await copyDirectoryRecursive(workspaceTemplate, configuredStaticPath);
47303
+ setupLog(`copied template into static workspace: ${configuredStaticPath}`);
47304
+ }
47305
+ staticMaterialised = true;
47306
+ setupLog(`materialised static workspace at: ${configuredStaticPath}`);
47307
+ } else {
47308
+ setupLog(`reusing existing static workspace: ${configuredStaticPath}`);
47309
+ }
47258
47310
  sharedWorkspacePath = configuredStaticPath;
47259
- setupLog(`using static workspace: ${configuredStaticPath}`);
47260
47311
  } else if (usePool && suiteWorkspace?.repos) {
47261
47312
  const slotsNeeded = workers;
47262
47313
  setupLog(`acquiring ${slotsNeeded} workspace pool slot(s) (pool capacity: ${poolMaxSlots})`);
@@ -47302,7 +47353,8 @@ async function runEvaluation(options) {
47302
47353
  } catch {
47303
47354
  }
47304
47355
  }
47305
- const repoManager = suiteWorkspace?.repos?.length && !usePool && !useStaticWorkspace ? new RepoManager(verbose) : void 0;
47356
+ const needsRepoMaterialisation = !!suiteWorkspace?.repos?.length && !usePool && (!useStaticWorkspace || staticMaterialised);
47357
+ const repoManager = needsRepoMaterialisation ? new RepoManager(verbose) : void 0;
47306
47358
  if (repoManager && sharedWorkspacePath && suiteWorkspace?.repos && !isPerTestIsolation) {
47307
47359
  setupLog(
47308
47360
  `materializing ${suiteWorkspace.repos.length} shared repo(s) into ${sharedWorkspacePath}`
@@ -47319,8 +47371,9 @@ async function runEvaluation(options) {
47319
47371
  throw new Error(`Failed to materialize repos: ${message}`);
47320
47372
  }
47321
47373
  }
47374
+ const suiteHooksEnabled = hooksEnabled(suiteWorkspace);
47322
47375
  const suiteBeforeAllHook = suiteWorkspace?.hooks?.before_all;
47323
- if (sharedWorkspacePath && hasHookCommand(suiteBeforeAllHook)) {
47376
+ if (sharedWorkspacePath && suiteHooksEnabled && hasHookCommand(suiteBeforeAllHook)) {
47324
47377
  const beforeAllHook = suiteBeforeAllHook;
47325
47378
  const beforeAllCommand = (beforeAllHook.command ?? beforeAllHook.script ?? []).join(" ");
47326
47379
  setupLog(
@@ -47347,7 +47400,7 @@ async function runEvaluation(options) {
47347
47400
  throw new Error(`before_all script failed: ${message}`);
47348
47401
  }
47349
47402
  }
47350
- if (availablePoolSlots.length > 0 && hasHookCommand(suiteBeforeAllHook)) {
47403
+ if (availablePoolSlots.length > 0 && suiteHooksEnabled && hasHookCommand(suiteBeforeAllHook)) {
47351
47404
  const beforeAllHook = suiteBeforeAllHook;
47352
47405
  for (const slot of availablePoolSlots) {
47353
47406
  setupLog(`running before_all on pool slot ${slot.index}`);
@@ -47589,7 +47642,7 @@ async function runEvaluation(options) {
47589
47642
  }
47590
47643
  const afterAllWorkspaces = poolSlots.length > 1 ? poolSlots.map((s) => s.path) : sharedWorkspacePath ? [sharedWorkspacePath] : [];
47591
47644
  const suiteAfterAllHook = suiteWorkspace?.hooks?.after_all;
47592
- if (afterAllWorkspaces.length > 0 && hasHookCommand(suiteAfterAllHook)) {
47645
+ if (afterAllWorkspaces.length > 0 && suiteHooksEnabled && hasHookCommand(suiteAfterAllHook)) {
47593
47646
  const afterAllHook = suiteAfterAllHook;
47594
47647
  for (const wsPath of afterAllWorkspaces) {
47595
47648
  const scriptContext = {
@@ -47837,6 +47890,7 @@ async function runEvalCase(options) {
47837
47890
  let afterEachOutput;
47838
47891
  const isSharedWorkspace = !!sharedWorkspacePath;
47839
47892
  let caseWorkspaceFile;
47893
+ const caseHooksEnabled = hooksEnabled(evalCase.workspace);
47840
47894
  if (!workspacePath) {
47841
47895
  const rawCaseTemplate = evalCase.workspace?.template ?? getWorkspaceTemplate(target);
47842
47896
  const resolvedCaseTemplate = await resolveWorkspaceTemplate(rawCaseTemplate);
@@ -47898,7 +47952,7 @@ async function runEvalCase(options) {
47898
47952
  }
47899
47953
  }
47900
47954
  const caseBeforeAllHook = evalCase.workspace?.hooks?.before_all;
47901
- if (workspacePath && hasHookCommand(caseBeforeAllHook)) {
47955
+ if (workspacePath && caseHooksEnabled && hasHookCommand(caseBeforeAllHook)) {
47902
47956
  const beforeAllHook = caseBeforeAllHook;
47903
47957
  const beforeAllCommand = (beforeAllHook.command ?? beforeAllHook.script ?? []).join(" ");
47904
47958
  if (setupDebug) {
@@ -47942,7 +47996,7 @@ async function runEvalCase(options) {
47942
47996
  }
47943
47997
  }
47944
47998
  const caseBeforeEachHook = evalCase.workspace?.hooks?.before_each;
47945
- if (workspacePath && hasHookCommand(caseBeforeEachHook)) {
47999
+ if (workspacePath && caseHooksEnabled && hasHookCommand(caseBeforeEachHook)) {
47946
48000
  const beforeEachHook = caseBeforeEachHook;
47947
48001
  const scriptContext = {
47948
48002
  workspacePath,
@@ -48071,7 +48125,7 @@ async function runEvalCase(options) {
48071
48125
  }
48072
48126
  }
48073
48127
  const providerError = extractProviderError(providerResponse);
48074
- if (repoManager && workspacePath && evalCase.workspace?.hooks?.after_each?.reset && evalCase.workspace.hooks.after_each.reset !== "none" && evalCase.workspace.repos) {
48128
+ if (caseHooksEnabled && repoManager && workspacePath && evalCase.workspace?.hooks?.after_each?.reset && evalCase.workspace.hooks.after_each.reset !== "none" && evalCase.workspace.repos) {
48075
48129
  try {
48076
48130
  await repoManager.reset(
48077
48131
  evalCase.workspace.repos,
@@ -48082,7 +48136,7 @@ async function runEvalCase(options) {
48082
48136
  }
48083
48137
  }
48084
48138
  const caseAfterEachHook = evalCase.workspace?.hooks?.after_each;
48085
- if (workspacePath && hasHookCommand(caseAfterEachHook)) {
48139
+ if (workspacePath && caseHooksEnabled && hasHookCommand(caseAfterEachHook)) {
48086
48140
  const afterEachHook = caseAfterEachHook;
48087
48141
  const scriptContext = {
48088
48142
  workspacePath,
@@ -48857,7 +48911,7 @@ async function evaluate(config2) {
48857
48911
  repoRoot,
48858
48912
  target: resolvedTarget,
48859
48913
  maxRetries: config2.maxRetries ?? 2,
48860
- agentTimeoutMs: config2.agentTimeoutMs ?? 12e4,
48914
+ agentTimeoutMs: config2.agentTimeoutMs,
48861
48915
  verbose: config2.verbose,
48862
48916
  maxConcurrency: config2.workers ?? 3,
48863
48917
  filter: config2.filter,
@@ -48957,7 +49011,7 @@ var AgentVConfigSchema = external_exports.object({
48957
49011
  workers: external_exports.number().int().min(1).max(50).optional(),
48958
49012
  /** Maximum retries on failure (default: 2) */
48959
49013
  maxRetries: external_exports.number().int().min(0).optional(),
48960
- /** Agent timeout in milliseconds (default: 120000) */
49014
+ /** Agent timeout in milliseconds. No timeout if not set. */
48961
49015
  agentTimeoutMs: external_exports.number().int().min(0).optional(),
48962
49016
  /** Enable verbose logging */
48963
49017
  verbose: external_exports.boolean().optional(),
@@ -49711,4 +49765,4 @@ export {
49711
49765
  OtelStreamingObserver,
49712
49766
  createAgentKernel
49713
49767
  };
49714
- //# sourceMappingURL=chunk-JSOG3FT6.js.map
49768
+ //# sourceMappingURL=chunk-ID5SDIYE.js.map