@netlify/axis 1.1.6 → 1.3.1

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.
Files changed (58) hide show
  1. package/README.md +17 -15
  2. package/dist/adapters/base/agent-adapter.d.ts.map +1 -1
  3. package/dist/adapters/base/agent-adapter.js +43 -2
  4. package/dist/adapters/base/agent-adapter.js.map +1 -1
  5. package/dist/adapters/registry.d.ts +2 -0
  6. package/dist/adapters/registry.d.ts.map +1 -1
  7. package/dist/adapters/registry.js +6 -2
  8. package/dist/adapters/registry.js.map +1 -1
  9. package/dist/cli.js +109 -9
  10. package/dist/cli.js.map +1 -1
  11. package/dist/config/loader.d.ts +2 -2
  12. package/dist/config/loader.d.ts.map +1 -1
  13. package/dist/config/loader.js +282 -34
  14. package/dist/config/loader.js.map +1 -1
  15. package/dist/config/validator.d.ts +10 -1
  16. package/dist/config/validator.d.ts.map +1 -1
  17. package/dist/config/validator.js +150 -5
  18. package/dist/config/validator.js.map +1 -1
  19. package/dist/report-ui/index.html +201 -151
  20. package/dist/reports/html.d.ts.map +1 -1
  21. package/dist/reports/html.js +2 -1
  22. package/dist/reports/html.js.map +1 -1
  23. package/dist/reports/writer.d.ts.map +1 -1
  24. package/dist/reports/writer.js +3 -0
  25. package/dist/reports/writer.js.map +1 -1
  26. package/dist/runner/runner.d.ts.map +1 -1
  27. package/dist/runner/runner.js +156 -15
  28. package/dist/runner/runner.js.map +1 -1
  29. package/dist/scoring/index.d.ts.map +1 -1
  30. package/dist/scoring/index.js +4 -1
  31. package/dist/scoring/index.js.map +1 -1
  32. package/dist/scoring/sparse-index.d.ts +6 -1
  33. package/dist/scoring/sparse-index.d.ts.map +1 -1
  34. package/dist/scoring/sparse-index.js +43 -15
  35. package/dist/scoring/sparse-index.js.map +1 -1
  36. package/dist/transcript/extract.d.ts.map +1 -1
  37. package/dist/transcript/extract.js +33 -3
  38. package/dist/transcript/extract.js.map +1 -1
  39. package/dist/types/agent.d.ts +4 -0
  40. package/dist/types/agent.d.ts.map +1 -1
  41. package/dist/types/config.d.ts +27 -1
  42. package/dist/types/config.d.ts.map +1 -1
  43. package/dist/types/output.d.ts +12 -2
  44. package/dist/types/output.d.ts.map +1 -1
  45. package/dist/types/output.js.map +1 -1
  46. package/dist/types/report.d.ts +3 -1
  47. package/dist/types/report.d.ts.map +1 -1
  48. package/dist/types/scenario.d.ts +36 -1
  49. package/dist/types/scenario.d.ts.map +1 -1
  50. package/dist/types/scoring.d.ts +4 -0
  51. package/dist/types/scoring.d.ts.map +1 -1
  52. package/dist/ui/LiveStatus.js +10 -5
  53. package/dist/ui/LiveStatus.js.map +1 -1
  54. package/dist/ui/format.d.ts +4 -0
  55. package/dist/ui/format.d.ts.map +1 -1
  56. package/dist/ui/format.js +34 -18
  57. package/dist/ui/format.js.map +1 -1
  58. package/package.json +2 -1
@@ -1,9 +1,65 @@
1
1
  import * as fs from "node:fs/promises";
2
2
  import * as path from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { createJiti } from "jiti";
3
5
  import { validateConfig, validateScenario } from "./validator.js";
4
6
  import { formatError } from "../types/output.js";
7
+ /** Extensions probed when no explicit config path is given, in priority order. */
8
+ const DEFAULT_CONFIG_EXTENSIONS = [".ts", ".js", ".mjs", ".json"];
9
+ const DEFAULT_CONFIG_BASENAME = "axis.config";
10
+ const JS_EXTENSIONS = new Set([".js", ".mjs", ".cjs"]);
11
+ const TS_EXTENSIONS = new Set([".ts", ".mts", ".cts"]);
5
12
  export async function loadConfig(configPath) {
6
- const resolvedPath = path.resolve(configPath ?? "axis.config.json");
13
+ const resolvedPath = await resolveConfigPath(configPath);
14
+ const ext = path.extname(resolvedPath).toLowerCase();
15
+ let parsed;
16
+ if (ext === ".json" || ext === "") {
17
+ parsed = await loadJsonConfig(resolvedPath);
18
+ }
19
+ else if (JS_EXTENSIONS.has(ext) || TS_EXTENSIONS.has(ext)) {
20
+ parsed = await loadModuleConfig(resolvedPath);
21
+ }
22
+ else {
23
+ throw new Error(`Unsupported config file extension "${ext}" at ${resolvedPath}`);
24
+ }
25
+ // Support a default export that is either the config object or a (sync/async) function returning it.
26
+ if (typeof parsed === "function") {
27
+ parsed = await parsed();
28
+ }
29
+ validateConfig(parsed, resolvedPath);
30
+ normalizeConfigAgents(parsed);
31
+ // Default the scenarios source when omitted; downstream code can assume it is set.
32
+ if (parsed.scenarios === undefined) {
33
+ parsed.scenarios = "./scenarios";
34
+ }
35
+ return {
36
+ config: parsed,
37
+ configDir: path.dirname(resolvedPath),
38
+ };
39
+ }
40
+ async function resolveConfigPath(configPath) {
41
+ if (configPath) {
42
+ return path.resolve(configPath);
43
+ }
44
+ for (const ext of DEFAULT_CONFIG_EXTENSIONS) {
45
+ const candidate = path.resolve(`${DEFAULT_CONFIG_BASENAME}${ext}`);
46
+ if (await fileExists(candidate)) {
47
+ return candidate;
48
+ }
49
+ }
50
+ // Nothing found — fall back to .json so the existing "Could not read" error fires with the expected path.
51
+ return path.resolve(`${DEFAULT_CONFIG_BASENAME}.json`);
52
+ }
53
+ async function fileExists(filePath) {
54
+ try {
55
+ const stat = await fs.stat(filePath);
56
+ return stat.isFile();
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ }
62
+ async function loadJsonConfig(resolvedPath) {
7
63
  let raw;
8
64
  try {
9
65
  raw = await fs.readFile(resolvedPath, "utf-8");
@@ -11,33 +67,79 @@ export async function loadConfig(configPath) {
11
67
  catch (err) {
12
68
  throw new Error(`Could not read config file at ${resolvedPath}: ${formatError(err)}`);
13
69
  }
14
- let parsed;
15
70
  try {
16
- parsed = JSON.parse(raw);
71
+ return JSON.parse(raw);
17
72
  }
18
73
  catch {
19
74
  throw new Error(`Failed to parse JSON in ${resolvedPath}`);
20
75
  }
21
- validateConfig(parsed, resolvedPath);
22
- return {
23
- config: parsed,
24
- configDir: path.dirname(resolvedPath),
25
- };
26
76
  }
27
- export async function discoverScenarios(configDir, scenariosPath, filter) {
28
- const rootDir = path.resolve(configDir, scenariosPath);
29
- let stat;
77
+ async function loadModuleConfig(resolvedPath) {
78
+ if (!(await fileExists(resolvedPath))) {
79
+ throw new Error(`Could not read config file at ${resolvedPath}: file not found`);
80
+ }
81
+ let mod;
30
82
  try {
31
- stat = await fs.stat(rootDir);
83
+ mod = await importModule(resolvedPath);
32
84
  }
33
85
  catch (err) {
34
- throw new Error(`Could not read scenarios directory at ${rootDir}: ${formatError(err)}`);
86
+ throw new Error(`Failed to load config at ${resolvedPath}: ${formatError(err)}`);
87
+ }
88
+ if (!mod || typeof mod !== "object" || !("default" in mod) || mod.default === undefined) {
89
+ throw new Error(`Config at ${resolvedPath} must have a default export`);
35
90
  }
36
- if (!stat.isDirectory()) {
37
- throw new Error(`Scenarios path is not a directory: ${rootDir}`);
91
+ return mod.default;
92
+ }
93
+ /**
94
+ * Imports a JS or TS file by extension. Native dynamic import for `.js`/`.mjs`/`.cjs`,
95
+ * jiti for `.ts`/`.mts`/`.cts`. Returns the module namespace; callers extract `default`.
96
+ */
97
+ async function importModule(filePath) {
98
+ const ext = path.extname(filePath).toLowerCase();
99
+ if (JS_EXTENSIONS.has(ext)) {
100
+ return (await import(pathToFileURL(filePath).href));
38
101
  }
102
+ if (TS_EXTENSIONS.has(ext)) {
103
+ const jiti = createJiti(import.meta.url, { interopDefault: false });
104
+ return (await jiti.import(filePath));
105
+ }
106
+ throw new Error(`Unsupported module extension "${ext}" at ${filePath}`);
107
+ }
108
+ /** Lowercase all agent names in a validated config (mutates in place). */
109
+ function normalizeConfigAgents(config) {
110
+ for (let i = 0; i < config.agents.length; i++) {
111
+ const entry = config.agents[i];
112
+ if (typeof entry === "string") {
113
+ config.agents[i] = entry.toLowerCase();
114
+ }
115
+ else {
116
+ entry.adapter = entry.adapter.toLowerCase();
117
+ }
118
+ }
119
+ }
120
+ export async function discoverScenarios(configDir, scenariosInput, filter) {
121
+ // When omitted, fall back to the default scenarios directory.
122
+ const resolvedInput = scenariosInput ?? "./scenarios";
123
+ const entries = Array.isArray(resolvedInput) ? resolvedInput : [resolvedInput];
39
124
  const scenarios = [];
40
- await walkDir(rootDir, rootDir, scenarios);
125
+ for (const entry of entries) {
126
+ if (typeof entry === "string") {
127
+ await collectFromPath(path.resolve(configDir, entry), scenarios);
128
+ }
129
+ else {
130
+ // Inline scenarios are validated by validateConfig; here we just normalize and expand.
131
+ scenarios.push(...expandInline(entry));
132
+ }
133
+ }
134
+ // Check for duplicate keys (can happen when variant keys collide with other scenario keys
135
+ // or when inline keys collide with on-disk keys)
136
+ const seen = new Set();
137
+ for (const s of scenarios) {
138
+ if (seen.has(s.key)) {
139
+ throw new Error(`Duplicate scenario key "${s.key}". Ensure variant names do not collide with other scenarios.`);
140
+ }
141
+ seen.add(s.key);
142
+ }
41
143
  // Sort by key for deterministic ordering
42
144
  scenarios.sort((a, b) => a.key.localeCompare(b.key));
43
145
  // Filter scenarios if agent specifies a subset
@@ -46,20 +148,80 @@ export async function discoverScenarios(configDir, scenariosPath, filter) {
46
148
  }
47
149
  return scenarios;
48
150
  }
151
+ /** File extensions recognized by the scenarios walker. */
152
+ const SCENARIO_EXTENSIONS = new Set([".json", ".js", ".mjs", ".cjs", ".ts", ".mts", ".cts"]);
153
+ const SCENARIO_EXT_RE = /\.(json|js|mjs|cjs|ts|mts|cts)$/;
154
+ async function collectFromPath(absolutePath, scenarios) {
155
+ let stat;
156
+ try {
157
+ stat = await fs.stat(absolutePath);
158
+ }
159
+ catch (err) {
160
+ throw new Error(`Could not read scenarios path at ${absolutePath}: ${formatError(err)}`);
161
+ }
162
+ if (stat.isDirectory()) {
163
+ await walkDir(absolutePath, absolutePath, scenarios);
164
+ return;
165
+ }
166
+ if (!stat.isFile()) {
167
+ throw new Error(`Scenarios path must be a directory or scenario file: ${absolutePath}`);
168
+ }
169
+ const ext = path.extname(absolutePath).toLowerCase();
170
+ if (!SCENARIO_EXTENSIONS.has(ext)) {
171
+ throw new Error(`Scenario file must end in one of ${[...SCENARIO_EXTENSIONS].join(", ")}: ${absolutePath}`);
172
+ }
173
+ // Single-file entry is explicit, so missing default exports are an error (not silent skip).
174
+ const baseKey = path.basename(absolutePath, ext);
175
+ const loaded = await loadScenarioFromPath(absolutePath, baseKey, false);
176
+ if (loaded)
177
+ scenarios.push(...loaded);
178
+ }
49
179
  async function walkDir(dir, rootDir, scenarios) {
50
180
  const entries = await fs.readdir(dir, { withFileTypes: true });
51
181
  for (const entry of entries) {
52
182
  const fullPath = path.join(dir, entry.name);
53
183
  if (entry.isDirectory()) {
54
184
  await walkDir(fullPath, rootDir, scenarios);
185
+ continue;
55
186
  }
56
- else if (entry.isFile() && entry.name.endsWith(".json")) {
57
- const scenario = await loadScenarioFile(fullPath, rootDir);
58
- scenarios.push(scenario);
59
- }
187
+ if (!entry.isFile())
188
+ continue;
189
+ const ext = path.extname(entry.name).toLowerCase();
190
+ if (!SCENARIO_EXTENSIONS.has(ext))
191
+ continue;
192
+ // Derive key from path relative to the walk root: scenarios/cms/create-post.ts → "cms/create-post"
193
+ const baseKey = path
194
+ .relative(rootDir, fullPath)
195
+ .replace(SCENARIO_EXT_RE, "")
196
+ .split(path.sep)
197
+ .join("/");
198
+ // Walking a directory: silently skip module files that don't default-export a scenario object,
199
+ // so user-authored helpers/utilities can live alongside scenarios without special handling.
200
+ const loaded = await loadScenarioFromPath(fullPath, baseKey, true);
201
+ if (loaded)
202
+ scenarios.push(...loaded);
203
+ }
204
+ }
205
+ /**
206
+ * Loads a single scenario from disk, dispatching by extension.
207
+ *
208
+ * @param silentSkip When true, JS/TS modules without a default object export return null
209
+ * instead of throwing. Used when walking a directory so non-scenario
210
+ * helper modules can coexist with scenario files.
211
+ */
212
+ async function loadScenarioFromPath(filePath, baseKey, silentSkip) {
213
+ const ext = path.extname(filePath).toLowerCase();
214
+ if (ext === ".json") {
215
+ return loadJsonScenario(filePath, baseKey);
216
+ }
217
+ if (JS_EXTENSIONS.has(ext) || TS_EXTENSIONS.has(ext)) {
218
+ return loadModuleScenario(filePath, baseKey, silentSkip);
60
219
  }
220
+ if (silentSkip)
221
+ return null;
222
+ throw new Error(`Unsupported scenario file extension "${ext}" at ${filePath}`);
61
223
  }
62
- async function loadScenarioFile(filePath, rootDir) {
224
+ async function loadJsonScenario(filePath, baseKey) {
63
225
  const raw = await fs.readFile(filePath, "utf-8");
64
226
  let parsed;
65
227
  try {
@@ -68,30 +230,116 @@ async function loadScenarioFile(filePath, rootDir) {
68
230
  catch {
69
231
  throw new Error(`Failed to parse JSON in scenario file ${filePath}`);
70
232
  }
71
- validateScenario(parsed, filePath);
72
- // Derive key from relative path: scenarios/cms/create-post.json → "cms/create-post"
73
- const relativePath = path.relative(rootDir, filePath);
74
- const key = relativePath
75
- .replace(/\.json$/, "")
76
- .split(path.sep)
77
- .join("/");
78
- parsed.key = key;
79
- return parsed;
233
+ return finalizeScenarioObject(parsed, filePath, baseKey);
234
+ }
235
+ async function loadModuleScenario(filePath, baseKey, silentSkip) {
236
+ let mod;
237
+ try {
238
+ mod = await importModule(filePath);
239
+ }
240
+ catch (err) {
241
+ throw new Error(`Failed to load scenario module at ${filePath}: ${formatError(err)}`);
242
+ }
243
+ let def = mod && typeof mod === "object" ? mod.default : undefined;
244
+ if (typeof def === "function") {
245
+ def = await def();
246
+ }
247
+ if (def === undefined || def === null || typeof def !== "object" || Array.isArray(def)) {
248
+ if (silentSkip)
249
+ return null;
250
+ throw new Error(`Scenario module at ${filePath} must default-export an object (or function returning one)`);
251
+ }
252
+ return finalizeScenarioObject(def, filePath, baseKey);
253
+ }
254
+ function finalizeScenarioObject(parsed, filePath, baseKey) {
255
+ validateScenario(parsed, filePath, "file");
256
+ normalizeScenarioAgents(parsed);
257
+ const scenario = parsed;
258
+ // If the file declares a key, it must match the key derived from its path.
259
+ // The path-derived key is always authoritative; this surfaces drift after a rename.
260
+ if (scenario.key !== undefined && scenario.key !== baseKey) {
261
+ throw new Error(`Scenario at ${filePath}: declared key "${scenario.key}" does not match path-derived key "${baseKey}". ` +
262
+ `Either remove the "key" field or set it to "${baseKey}".`);
263
+ }
264
+ if (!scenario.variants || scenario.variants.length === 0) {
265
+ scenario.key = baseKey;
266
+ return [scenario];
267
+ }
268
+ // Expand variants: each becomes a standalone Scenario, base does not run
269
+ return scenario.variants.map((variant) => expandVariant(scenario, variant, baseKey));
270
+ }
271
+ function expandInline(input) {
272
+ // Shallow clone so we don't mutate the caller's config object.
273
+ const scenario = { ...input };
274
+ normalizeScenarioAgents(scenario);
275
+ if (!scenario.variants || scenario.variants.length === 0) {
276
+ return [scenario];
277
+ }
278
+ return scenario.variants.map((variant) => expandVariant(scenario, variant, scenario.key));
279
+ }
280
+ /** Lowercase agent-name entries in a scenario and any variants (mutates in place). */
281
+ function normalizeScenarioAgents(scenario) {
282
+ if (scenario.agents) {
283
+ scenario.agents = scenario.agents.map((a) => a.toLowerCase());
284
+ }
285
+ if (scenario.variants) {
286
+ for (const v of scenario.variants) {
287
+ if (v.agents)
288
+ v.agents = v.agents.map((a) => a.toLowerCase());
289
+ }
290
+ }
291
+ }
292
+ function expandVariant(parent, variant, baseKey) {
293
+ const expanded = {
294
+ key: `${baseKey}@${variant.name}`,
295
+ name: `${parent.name} [${variant.name}]`,
296
+ prompt: variant.prompt ?? parent.prompt,
297
+ rubric: variant.rubric ?? parent.rubric,
298
+ skip: variant.skip ?? parent.skip,
299
+ setup: variant.setup ?? parent.setup,
300
+ teardown: variant.teardown ?? parent.teardown,
301
+ agents: variant.agents ?? parent.agents,
302
+ skills: variant.skills !== undefined ? variant.skills : parent.skills,
303
+ mcp_servers: variant.mcp_servers !== undefined
304
+ ? { ...parent.mcp_servers, ...variant.mcp_servers }
305
+ : parent.mcp_servers,
306
+ limits: variant.limits ?? parent.limits,
307
+ };
308
+ // Strip undefined optional fields to keep objects clean
309
+ if (expanded.skip === undefined)
310
+ delete expanded.skip;
311
+ if (expanded.setup === undefined)
312
+ delete expanded.setup;
313
+ if (expanded.teardown === undefined)
314
+ delete expanded.teardown;
315
+ if (expanded.agents === undefined)
316
+ delete expanded.agents;
317
+ if (expanded.skills === undefined)
318
+ delete expanded.skills;
319
+ if (expanded.mcp_servers === undefined)
320
+ delete expanded.mcp_servers;
321
+ if (expanded.limits === undefined)
322
+ delete expanded.limits;
323
+ return expanded;
80
324
  }
81
325
  function matchesFilter(key, filter) {
326
+ const baseKey = key.includes("@") ? key.split("@")[0] : key;
82
327
  return filter.some((pattern) => {
83
- // Exact match
328
+ // Exact match (full key including variant)
84
329
  if (pattern === key)
85
330
  return true;
86
- // Simple glob: "cms/*" matches "cms/create-post" and "cms/delete-post"
331
+ // Base key match: "cms/create-post" matches all its variants
332
+ if (pattern === baseKey && pattern !== key)
333
+ return true;
334
+ // Simple glob: "cms/*" matches "cms/create-post" and "cms/create-post@variant"
87
335
  if (pattern.endsWith("/*")) {
88
336
  const prefix = pattern.slice(0, -2);
89
- return key.startsWith(prefix + "/");
337
+ return baseKey.startsWith(prefix + "/");
90
338
  }
91
339
  // Prefix glob: "cms/**" matches any depth under cms/
92
340
  if (pattern.endsWith("/**")) {
93
341
  const prefix = pattern.slice(0, -3);
94
- return key.startsWith(prefix + "/");
342
+ return baseKey.startsWith(prefix + "/");
95
343
  }
96
344
  return false;
97
345
  });
@@ -1 +1 @@
1
- {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,16 @@
1
1
  import type { AxisConfig } from "../types/config.js";
2
2
  import type { RubricCriterion, Scenario } from "../types/scenario.js";
3
3
  export declare function validateConfig(data: unknown, filePath: string): asserts data is AxisConfig;
4
- export declare function validateScenario(data: unknown, filePath: string): asserts data is Scenario;
4
+ /**
5
+ * Validates a scenario object.
6
+ *
7
+ * @param mode "file" — loaded from a JSON scenario file; the loader will assign
8
+ * the `key` from the file path and rejects any user-supplied `key`.
9
+ * "inline" — declared inline in `axis.config.*`; the user must
10
+ * provide a non-empty `key` string.
11
+ */
12
+ export declare function validateScenario(data: unknown, filePath: string, mode?: "file" | "inline"): asserts data is Scenario;
13
+ export declare function validateMcpServers(data: unknown, filePath: string): void;
5
14
  /**
6
15
  * Resolve optional weights on rubric entries. Entries with explicit weights
7
16
  * keep them; entries without a weight split the remaining budget equally.
@@ -1 +1 @@
1
- {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/config/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEtE,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,IAAI,UAAU,CAuD1F;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,IAAI,QAAQ,CAwD1F;AA+DD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,eAAe,EAAE,CAajF"}
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/config/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEtE,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,IAAI,UAAU,CAkE1F;AAwBD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,MAAM,GAAG,QAAiB,GAC/B,OAAO,CAAC,IAAI,IAAI,QAAQ,CAmF1B;AA4FD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAqDxE;AAQD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,eAAe,EAAE,CAajF"}
@@ -3,9 +3,7 @@ export function validateConfig(data, filePath) {
3
3
  throw new Error(`Invalid config at ${filePath}: must be a JSON object`);
4
4
  }
5
5
  const obj = data;
6
- if (typeof obj.scenarios !== "string") {
7
- throw new Error(`Invalid config at ${filePath}: "scenarios" must be a string path`);
8
- }
6
+ validateScenariosField(obj.scenarios, filePath);
9
7
  if (!Array.isArray(obj.agents)) {
10
8
  throw new Error(`Invalid config at ${filePath}: "agents" must be an array`);
11
9
  }
@@ -39,6 +37,18 @@ export function validateConfig(data, filePath) {
39
37
  throw new Error(`Invalid config at ${filePath}: "settings.concurrency" must be a positive integer`);
40
38
  }
41
39
  }
40
+ if (settings?.limits !== undefined) {
41
+ const limits = settings.limits;
42
+ if (typeof limits !== "object" || limits === null || Array.isArray(limits)) {
43
+ throw new Error(`Invalid config at ${filePath}: "settings.limits" must be an object`);
44
+ }
45
+ if (limits.run !== undefined) {
46
+ validateLimits(limits.run, filePath, "settings.limits.run");
47
+ }
48
+ if (limits.scenario !== undefined) {
49
+ validateLimits(limits.scenario, filePath, "settings.limits.scenario");
50
+ }
51
+ }
42
52
  if (obj.mcp_servers !== undefined) {
43
53
  validateMcpServers(obj.mcp_servers, filePath);
44
54
  }
@@ -46,11 +56,50 @@ export function validateConfig(data, filePath) {
46
56
  validateSkillsSources(obj.skills, filePath, "skills");
47
57
  }
48
58
  }
49
- export function validateScenario(data, filePath) {
59
+ function validateScenariosField(data, filePath) {
60
+ if (data === undefined)
61
+ return; // optional — loader fills in the default
62
+ if (typeof data === "string")
63
+ return;
64
+ if (!Array.isArray(data)) {
65
+ throw new Error(`Invalid config at ${filePath}: "scenarios" must be a string path or an array of paths and/or scenario objects`);
66
+ }
67
+ for (let i = 0; i < data.length; i++) {
68
+ const entry = data[i];
69
+ if (typeof entry === "string")
70
+ continue;
71
+ if (typeof entry !== "object" || entry === null) {
72
+ throw new Error(`Invalid config at ${filePath}: scenarios[${i}] must be a string path or a scenario object`);
73
+ }
74
+ validateScenario(entry, `${filePath} (scenarios[${i}])`, "inline");
75
+ }
76
+ }
77
+ /**
78
+ * Validates a scenario object.
79
+ *
80
+ * @param mode "file" — loaded from a JSON scenario file; the loader will assign
81
+ * the `key` from the file path and rejects any user-supplied `key`.
82
+ * "inline" — declared inline in `axis.config.*`; the user must
83
+ * provide a non-empty `key` string.
84
+ */
85
+ export function validateScenario(data, filePath, mode = "file") {
50
86
  if (typeof data !== "object" || data === null) {
51
87
  throw new Error(`Invalid scenario at ${filePath}: must be a JSON object`);
52
88
  }
53
89
  const obj = data;
90
+ if (mode === "inline") {
91
+ if (typeof obj.key !== "string" || obj.key.length === 0) {
92
+ throw new Error(`Invalid scenario at ${filePath}: inline scenarios must include a non-empty "key" string`);
93
+ }
94
+ }
95
+ else if (obj.key !== undefined) {
96
+ // File-mode: an explicit `key` is allowed (helpers like `withSharedVariants` may
97
+ // require it on their input), but it must be a non-empty string. The loader
98
+ // verifies it matches the path-derived key — see finalizeScenarioObject in loader.ts.
99
+ if (typeof obj.key !== "string" || obj.key.length === 0) {
100
+ throw new Error(`Invalid scenario at ${filePath}: "key" must be a non-empty string`);
101
+ }
102
+ }
54
103
  if (typeof obj.name !== "string") {
55
104
  throw new Error(`Invalid scenario at ${filePath}: missing required field "name"`);
56
105
  }
@@ -92,14 +141,94 @@ export function validateScenario(data, filePath) {
92
141
  if (obj.skills !== undefined) {
93
142
  validateSkillsSources(obj.skills, filePath, "skills");
94
143
  }
144
+ if (obj.mcp_servers !== undefined) {
145
+ validateMcpServers(obj.mcp_servers, filePath);
146
+ }
147
+ if (obj.limits !== undefined) {
148
+ validateLimits(obj.limits, filePath, "limits");
149
+ }
95
150
  if (obj.setup !== undefined) {
96
151
  validateLifecycleActions(obj.setup, filePath, "setup");
97
152
  }
98
153
  if (obj.teardown !== undefined) {
99
154
  validateLifecycleActions(obj.teardown, filePath, "teardown");
100
155
  }
156
+ if (obj.variants !== undefined) {
157
+ validateVariants(obj.variants, filePath);
158
+ }
159
+ }
160
+ const VARIANT_NAME_RE = /^[a-zA-Z0-9_-]+$/;
161
+ function validateVariants(data, filePath) {
162
+ if (!Array.isArray(data)) {
163
+ throw new Error(`Invalid scenario at ${filePath}: "variants" must be an array`);
164
+ }
165
+ const names = new Set();
166
+ for (let i = 0; i < data.length; i++) {
167
+ const variant = data[i];
168
+ if (typeof variant !== "object" || variant === null) {
169
+ throw new Error(`Invalid scenario at ${filePath}: variants[${i}] must be an object`);
170
+ }
171
+ if (typeof variant.name !== "string" || !VARIANT_NAME_RE.test(variant.name)) {
172
+ throw new Error(`Invalid scenario at ${filePath}: variants[${i}].name must be a string matching /^[a-zA-Z0-9_-]+$/`);
173
+ }
174
+ if (names.has(variant.name)) {
175
+ throw new Error(`Invalid scenario at ${filePath}: duplicate variant name "${variant.name}"`);
176
+ }
177
+ names.add(variant.name);
178
+ if (variant.prompt !== undefined && typeof variant.prompt !== "string") {
179
+ throw new Error(`Invalid scenario at ${filePath}: variants[${i}].prompt must be a string`);
180
+ }
181
+ if (variant.rubric !== undefined) {
182
+ if (typeof variant.rubric === "string") {
183
+ // String rubric — freeform evaluation description
184
+ }
185
+ else if (Array.isArray(variant.rubric)) {
186
+ for (let j = 0; j < variant.rubric.length; j++) {
187
+ const entry = variant.rubric[j];
188
+ if (typeof entry.check !== "string") {
189
+ throw new Error(`Invalid scenario at ${filePath}: variants[${i}].rubric[${j}] missing "check" string`);
190
+ }
191
+ if (entry.weight !== undefined && typeof entry.weight !== "number") {
192
+ throw new Error(`Invalid scenario at ${filePath}: variants[${i}].rubric[${j}].weight must be a number`);
193
+ }
194
+ }
195
+ variant.rubric = resolveRubricWeights(variant.rubric);
196
+ }
197
+ else {
198
+ throw new Error(`Invalid scenario at ${filePath}: variants[${i}].rubric must be a string or array`);
199
+ }
200
+ }
201
+ if (variant.skip !== undefined && typeof variant.skip !== "boolean") {
202
+ throw new Error(`Invalid scenario at ${filePath}: variants[${i}].skip must be a boolean`);
203
+ }
204
+ if (variant.agents !== undefined) {
205
+ if (!Array.isArray(variant.agents) || variant.agents.length === 0) {
206
+ throw new Error(`Invalid scenario at ${filePath}: variants[${i}].agents must be a non-empty array of strings`);
207
+ }
208
+ for (let j = 0; j < variant.agents.length; j++) {
209
+ if (typeof variant.agents[j] !== "string") {
210
+ throw new Error(`Invalid scenario at ${filePath}: variants[${i}].agents[${j}] must be a string`);
211
+ }
212
+ }
213
+ }
214
+ if (variant.skills !== undefined) {
215
+ validateSkillsSources(variant.skills, filePath, `variants[${i}].skills`);
216
+ }
217
+ if (variant.mcp_servers !== undefined) {
218
+ validateMcpServers(variant.mcp_servers, filePath);
219
+ }
220
+ if (variant.setup !== undefined) {
221
+ validateLifecycleActions(variant.setup, filePath, `variants[${i}].setup`);
222
+ }
223
+ if (variant.teardown !== undefined) {
224
+ validateLifecycleActions(variant.teardown, filePath, `variants[${i}].teardown`);
225
+ }
226
+ if (variant.limits !== undefined) {
227
+ validateLimits(variant.limits, filePath, `variants[${i}].limits`);
228
+ }
229
+ }
101
230
  }
102
- function validateMcpServers(data, filePath) {
231
+ export function validateMcpServers(data, filePath) {
103
232
  if (typeof data !== "object" || data === null || Array.isArray(data)) {
104
233
  throw new Error(`Invalid config at ${filePath}: "mcp_servers" must be an object`);
105
234
  }
@@ -171,6 +300,22 @@ export function resolveRubricWeights(rubric) {
171
300
  const share = unspecified.length > 0 ? remaining / unspecified.length : 0;
172
301
  return rubric.map((r) => (r.weight !== undefined ? r : { ...r, weight: share }));
173
302
  }
303
+ function validateLimits(data, filePath, field) {
304
+ if (typeof data !== "object" || data === null || Array.isArray(data)) {
305
+ throw new Error(`Invalid config at ${filePath}: "${field}" must be an object`);
306
+ }
307
+ const obj = data;
308
+ if (obj.time_minutes !== undefined) {
309
+ if (typeof obj.time_minutes !== "number" || obj.time_minutes <= 0) {
310
+ throw new Error(`Invalid config at ${filePath}: "${field}.time_minutes" must be a positive number`);
311
+ }
312
+ }
313
+ if (obj.tokens !== undefined) {
314
+ if (typeof obj.tokens !== "number" || !Number.isInteger(obj.tokens) || obj.tokens <= 0) {
315
+ throw new Error(`Invalid config at ${filePath}: "${field}.tokens" must be a positive integer`);
316
+ }
317
+ }
318
+ }
174
319
  function validateLifecycleActions(data, filePath, field) {
175
320
  if (!Array.isArray(data)) {
176
321
  throw new Error(`Invalid scenario at ${filePath}: "${field}" must be an array`);