@agentv/core 0.7.5 → 0.10.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.
- package/dist/{chunk-7XM7HYRS.js → chunk-YQBJAT5I.js} +97 -67
- package/dist/chunk-YQBJAT5I.js.map +1 -0
- package/dist/evaluation/validation/index.cjs +61 -69
- package/dist/evaluation/validation/index.cjs.map +1 -1
- package/dist/evaluation/validation/index.js +51 -58
- package/dist/evaluation/validation/index.js.map +1 -1
- package/dist/index.cjs +538 -192
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +136 -58
- package/dist/index.d.ts +136 -58
- package/dist/index.js +443 -127
- package/dist/index.js.map +1 -1
- package/package.json +1 -2
- package/dist/chunk-7XM7HYRS.js.map +0 -1
|
@@ -6,13 +6,13 @@ import {
|
|
|
6
6
|
buildSearchRoots,
|
|
7
7
|
findGitRoot,
|
|
8
8
|
resolveFileReference
|
|
9
|
-
} from "../../chunk-
|
|
9
|
+
} from "../../chunk-YQBJAT5I.js";
|
|
10
10
|
|
|
11
11
|
// src/evaluation/validation/file-type.ts
|
|
12
12
|
import { readFile } from "node:fs/promises";
|
|
13
13
|
import { parse } from "yaml";
|
|
14
14
|
var SCHEMA_EVAL_V2 = "agentv-eval-v2";
|
|
15
|
-
var SCHEMA_TARGETS_V2 = "agentv-targets-v2.
|
|
15
|
+
var SCHEMA_TARGETS_V2 = "agentv-targets-v2.2";
|
|
16
16
|
var SCHEMA_CONFIG_V2 = "agentv-config-v2";
|
|
17
17
|
async function detectFileType(filePath) {
|
|
18
18
|
try {
|
|
@@ -164,14 +164,14 @@ async function validateEvalFile(filePath) {
|
|
|
164
164
|
validateMessages(inputMessages, `${location}.input_messages`, absolutePath, errors);
|
|
165
165
|
}
|
|
166
166
|
const expectedMessages = evalCase["expected_messages"];
|
|
167
|
-
if (!Array.isArray(expectedMessages)) {
|
|
167
|
+
if (expectedMessages !== void 0 && !Array.isArray(expectedMessages)) {
|
|
168
168
|
errors.push({
|
|
169
169
|
severity: "error",
|
|
170
170
|
filePath: absolutePath,
|
|
171
171
|
location: `${location}.expected_messages`,
|
|
172
|
-
message: "
|
|
172
|
+
message: "Invalid 'expected_messages' field (must be an array if provided)"
|
|
173
173
|
});
|
|
174
|
-
} else {
|
|
174
|
+
} else if (Array.isArray(expectedMessages)) {
|
|
175
175
|
validateMessages(expectedMessages, `${location}.expected_messages`, absolutePath, errors);
|
|
176
176
|
}
|
|
177
177
|
}
|
|
@@ -207,11 +207,13 @@ function validateMessages(messages, location, filePath, errors) {
|
|
|
207
207
|
}
|
|
208
208
|
const content = message["content"];
|
|
209
209
|
if (typeof content === "string") {
|
|
210
|
+
validateContentForRoleMarkers(content, `${msgLocation}.content`, filePath, errors);
|
|
210
211
|
} else if (Array.isArray(content)) {
|
|
211
212
|
for (let j = 0; j < content.length; j++) {
|
|
212
213
|
const contentItem = content[j];
|
|
213
214
|
const contentLocation = `${msgLocation}.content[${j}]`;
|
|
214
215
|
if (typeof contentItem === "string") {
|
|
216
|
+
validateContentForRoleMarkers(contentItem, contentLocation, filePath, errors);
|
|
215
217
|
} else if (isObject(contentItem)) {
|
|
216
218
|
const type = contentItem["type"];
|
|
217
219
|
if (typeof type !== "string") {
|
|
@@ -231,6 +233,8 @@ function validateMessages(messages, location, filePath, errors) {
|
|
|
231
233
|
location: `${contentLocation}.value`,
|
|
232
234
|
message: "Content with type 'text' must have a 'value' field"
|
|
233
235
|
});
|
|
236
|
+
} else {
|
|
237
|
+
validateContentForRoleMarkers(value, `${contentLocation}.value`, filePath, errors);
|
|
234
238
|
}
|
|
235
239
|
}
|
|
236
240
|
} else {
|
|
@@ -252,6 +256,19 @@ function validateMessages(messages, location, filePath, errors) {
|
|
|
252
256
|
}
|
|
253
257
|
}
|
|
254
258
|
}
|
|
259
|
+
function validateContentForRoleMarkers(content, location, filePath, errors) {
|
|
260
|
+
const markers = ["@[System]:", "@[User]:", "@[Assistant]:", "@[Tool]:"];
|
|
261
|
+
for (const marker of markers) {
|
|
262
|
+
if (content.toLowerCase().includes(marker.toLowerCase())) {
|
|
263
|
+
errors.push({
|
|
264
|
+
severity: "warning",
|
|
265
|
+
filePath,
|
|
266
|
+
location,
|
|
267
|
+
message: `Content contains potential role marker '${marker}'. This may confuse agentic providers or cause prompt injection.`
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
255
272
|
|
|
256
273
|
// src/evaluation/validation/targets-validator.ts
|
|
257
274
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
@@ -264,8 +281,21 @@ var COMMON_SETTINGS = /* @__PURE__ */ new Set([
|
|
|
264
281
|
"provider_batching",
|
|
265
282
|
"providerBatching"
|
|
266
283
|
]);
|
|
284
|
+
var RETRY_SETTINGS = /* @__PURE__ */ new Set([
|
|
285
|
+
"max_retries",
|
|
286
|
+
"maxRetries",
|
|
287
|
+
"retry_initial_delay_ms",
|
|
288
|
+
"retryInitialDelayMs",
|
|
289
|
+
"retry_max_delay_ms",
|
|
290
|
+
"retryMaxDelayMs",
|
|
291
|
+
"retry_backoff_factor",
|
|
292
|
+
"retryBackoffFactor",
|
|
293
|
+
"retry_status_codes",
|
|
294
|
+
"retryStatusCodes"
|
|
295
|
+
]);
|
|
267
296
|
var AZURE_SETTINGS = /* @__PURE__ */ new Set([
|
|
268
297
|
...COMMON_SETTINGS,
|
|
298
|
+
...RETRY_SETTINGS,
|
|
269
299
|
"endpoint",
|
|
270
300
|
"resource",
|
|
271
301
|
"resourceName",
|
|
@@ -282,6 +312,7 @@ var AZURE_SETTINGS = /* @__PURE__ */ new Set([
|
|
|
282
312
|
]);
|
|
283
313
|
var ANTHROPIC_SETTINGS = /* @__PURE__ */ new Set([
|
|
284
314
|
...COMMON_SETTINGS,
|
|
315
|
+
...RETRY_SETTINGS,
|
|
285
316
|
"api_key",
|
|
286
317
|
"apiKey",
|
|
287
318
|
"model",
|
|
@@ -295,6 +326,7 @@ var ANTHROPIC_SETTINGS = /* @__PURE__ */ new Set([
|
|
|
295
326
|
]);
|
|
296
327
|
var GEMINI_SETTINGS = /* @__PURE__ */ new Set([
|
|
297
328
|
...COMMON_SETTINGS,
|
|
329
|
+
...RETRY_SETTINGS,
|
|
298
330
|
"api_key",
|
|
299
331
|
"apiKey",
|
|
300
332
|
"model",
|
|
@@ -382,13 +414,14 @@ function getKnownSettings(provider) {
|
|
|
382
414
|
return null;
|
|
383
415
|
}
|
|
384
416
|
}
|
|
385
|
-
function validateUnknownSettings(
|
|
417
|
+
function validateUnknownSettings(target, provider, absolutePath, location, errors) {
|
|
386
418
|
const knownSettings = getKnownSettings(provider);
|
|
387
419
|
if (!knownSettings) {
|
|
388
420
|
return;
|
|
389
421
|
}
|
|
390
|
-
|
|
391
|
-
|
|
422
|
+
const baseFields = /* @__PURE__ */ new Set(["name", "provider", "judge_target", "workers", "$schema", "targets"]);
|
|
423
|
+
for (const key of Object.keys(target)) {
|
|
424
|
+
if (!baseFields.has(key) && !knownSettings.has(key)) {
|
|
392
425
|
errors.push({
|
|
393
426
|
severity: "warning",
|
|
394
427
|
filePath: absolutePath,
|
|
@@ -418,17 +451,8 @@ async function validateTargetsFile(filePath) {
|
|
|
418
451
|
errors
|
|
419
452
|
};
|
|
420
453
|
}
|
|
421
|
-
function validateCliSettings(
|
|
422
|
-
|
|
423
|
-
errors2.push({
|
|
424
|
-
severity: "error",
|
|
425
|
-
filePath: absolutePath2,
|
|
426
|
-
location,
|
|
427
|
-
message: "CLI provider requires a 'settings' object"
|
|
428
|
-
});
|
|
429
|
-
return;
|
|
430
|
-
}
|
|
431
|
-
const commandTemplate = settings["command_template"] ?? settings["commandTemplate"];
|
|
454
|
+
function validateCliSettings(target, absolutePath2, location, errors2) {
|
|
455
|
+
const commandTemplate = target["command_template"] ?? target["commandTemplate"];
|
|
432
456
|
if (typeof commandTemplate !== "string" || commandTemplate.trim().length === 0) {
|
|
433
457
|
errors2.push({
|
|
434
458
|
severity: "error",
|
|
@@ -439,7 +463,7 @@ async function validateTargetsFile(filePath) {
|
|
|
439
463
|
} else {
|
|
440
464
|
recordUnknownPlaceholders(commandTemplate, absolutePath2, `${location}.commandTemplate`, errors2);
|
|
441
465
|
}
|
|
442
|
-
const attachmentsFormat =
|
|
466
|
+
const attachmentsFormat = target["attachments_format"] ?? target["attachmentsFormat"];
|
|
443
467
|
if (attachmentsFormat !== void 0 && typeof attachmentsFormat !== "string") {
|
|
444
468
|
errors2.push({
|
|
445
469
|
severity: "error",
|
|
@@ -448,7 +472,7 @@ async function validateTargetsFile(filePath) {
|
|
|
448
472
|
message: "'attachmentsFormat' must be a string when provided"
|
|
449
473
|
});
|
|
450
474
|
}
|
|
451
|
-
const filesFormat =
|
|
475
|
+
const filesFormat = target["files_format"] ?? target["filesFormat"];
|
|
452
476
|
if (filesFormat !== void 0 && typeof filesFormat !== "string") {
|
|
453
477
|
errors2.push({
|
|
454
478
|
severity: "error",
|
|
@@ -457,7 +481,7 @@ async function validateTargetsFile(filePath) {
|
|
|
457
481
|
message: "'filesFormat' must be a string when provided"
|
|
458
482
|
});
|
|
459
483
|
}
|
|
460
|
-
const cwd =
|
|
484
|
+
const cwd = target["cwd"];
|
|
461
485
|
if (cwd !== void 0 && typeof cwd !== "string") {
|
|
462
486
|
errors2.push({
|
|
463
487
|
severity: "error",
|
|
@@ -466,7 +490,7 @@ async function validateTargetsFile(filePath) {
|
|
|
466
490
|
message: "'cwd' must be a string when provided"
|
|
467
491
|
});
|
|
468
492
|
}
|
|
469
|
-
const timeoutSeconds =
|
|
493
|
+
const timeoutSeconds = target["timeout_seconds"] ?? target["timeoutSeconds"];
|
|
470
494
|
if (timeoutSeconds !== void 0) {
|
|
471
495
|
const numericTimeout = Number(timeoutSeconds);
|
|
472
496
|
if (!Number.isFinite(numericTimeout) || numericTimeout <= 0) {
|
|
@@ -478,29 +502,7 @@ async function validateTargetsFile(filePath) {
|
|
|
478
502
|
});
|
|
479
503
|
}
|
|
480
504
|
}
|
|
481
|
-
const
|
|
482
|
-
if (envOverrides !== void 0) {
|
|
483
|
-
if (!isObject2(envOverrides)) {
|
|
484
|
-
errors2.push({
|
|
485
|
-
severity: "error",
|
|
486
|
-
filePath: absolutePath2,
|
|
487
|
-
location: `${location}.env`,
|
|
488
|
-
message: "'env' must be an object with string values"
|
|
489
|
-
});
|
|
490
|
-
} else {
|
|
491
|
-
for (const [key, value] of Object.entries(envOverrides)) {
|
|
492
|
-
if (typeof value !== "string" || value.trim().length === 0) {
|
|
493
|
-
errors2.push({
|
|
494
|
-
severity: "error",
|
|
495
|
-
filePath: absolutePath2,
|
|
496
|
-
location: `${location}.env.${key}`,
|
|
497
|
-
message: `Environment override '${key}' must be a non-empty string`
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
const healthcheck = settings["healthcheck"];
|
|
505
|
+
const healthcheck = target["healthcheck"];
|
|
504
506
|
if (healthcheck !== void 0) {
|
|
505
507
|
validateCliHealthcheck(healthcheck, absolutePath2, `${location}.healthcheck`, errors2);
|
|
506
508
|
}
|
|
@@ -671,20 +673,11 @@ async function validateTargetsFile(filePath) {
|
|
|
671
673
|
message: `Unknown provider '${provider}'. Known providers: ${knownProviders.join(", ")}`
|
|
672
674
|
});
|
|
673
675
|
}
|
|
674
|
-
const settings = target["settings"];
|
|
675
|
-
if (providerValue !== "cli" && settings !== void 0 && !isObject2(settings)) {
|
|
676
|
-
errors.push({
|
|
677
|
-
severity: "error",
|
|
678
|
-
filePath: absolutePath,
|
|
679
|
-
location: `${location}.settings`,
|
|
680
|
-
message: "Invalid 'settings' field (must be an object)"
|
|
681
|
-
});
|
|
682
|
-
}
|
|
683
676
|
if (providerValue === "cli") {
|
|
684
|
-
validateCliSettings(
|
|
677
|
+
validateCliSettings(target, absolutePath, location, errors);
|
|
685
678
|
}
|
|
686
|
-
if (
|
|
687
|
-
validateUnknownSettings(
|
|
679
|
+
if (typeof provider === "string") {
|
|
680
|
+
validateUnknownSettings(target, provider, absolutePath, location, errors);
|
|
688
681
|
}
|
|
689
682
|
const judgeTarget = target["judge_target"];
|
|
690
683
|
if (judgeTarget !== void 0 && typeof judgeTarget !== "string") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/evaluation/validation/file-type.ts","../../../src/evaluation/validation/eval-validator.ts","../../../src/evaluation/validation/targets-validator.ts","../../../src/evaluation/validation/config-validator.ts","../../../src/evaluation/validation/file-reference-validator.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\r\nimport { parse } from \"yaml\";\r\n\r\nimport type { FileType } from \"./types.js\";\r\n\r\nconst SCHEMA_EVAL_V2 = \"agentv-eval-v2\";\r\nconst SCHEMA_TARGETS_V2 = \"agentv-targets-v2.1\";\r\nconst SCHEMA_CONFIG_V2 = \"agentv-config-v2\";\r\n\r\n/**\r\n * Detect file type by reading $schema field from YAML file.\r\n * Returns \"unknown\" if file cannot be read or $schema is missing/invalid.\r\n */\r\nexport async function detectFileType(filePath: string): Promise<FileType> {\r\n try {\r\n const content = await readFile(filePath, \"utf8\");\r\n const parsed = parse(content) as unknown;\r\n\r\n if (typeof parsed !== \"object\" || parsed === null) {\r\n return \"unknown\";\r\n }\r\n\r\n const record = parsed as Record<string, unknown>;\r\n const schema = record[\"$schema\"];\r\n\r\n if (typeof schema !== \"string\") {\r\n return \"unknown\";\r\n }\r\n\r\n switch (schema) {\r\n case SCHEMA_EVAL_V2:\r\n return \"eval\";\r\n case SCHEMA_TARGETS_V2:\r\n return \"targets\";\r\n case SCHEMA_CONFIG_V2:\r\n return \"config\";\r\n default:\r\n return \"unknown\";\r\n }\r\n } catch {\r\n return \"unknown\";\r\n }\r\n}\r\n\r\n/**\r\n * Check if a schema value is a valid AgentV schema identifier.\r\n */\r\nexport function isValidSchema(schema: unknown): boolean {\r\n return schema === SCHEMA_EVAL_V2 || schema === SCHEMA_TARGETS_V2 || schema === SCHEMA_CONFIG_V2;\r\n}\r\n\r\n/**\r\n * Get the expected schema for a file type.\r\n */\r\nexport function getExpectedSchema(fileType: FileType): string | undefined {\r\n switch (fileType) {\r\n case \"eval\":\r\n return SCHEMA_EVAL_V2;\r\n case \"targets\":\r\n return SCHEMA_TARGETS_V2;\r\n case \"config\":\r\n return SCHEMA_CONFIG_V2;\r\n default:\r\n return undefined;\r\n }\r\n}\r\n","import { readFile } from \"node:fs/promises\";\r\nimport path from \"node:path\";\r\nimport { parse } from \"yaml\";\r\n\r\nimport type { ValidationError, ValidationResult } from \"./types.js\";\r\n\r\nconst SCHEMA_EVAL_V2 = \"agentv-eval-v2\";\r\n\r\ntype JsonValue = string | number | boolean | null | JsonObject | JsonArray;\r\ntype JsonObject = { readonly [key: string]: JsonValue };\r\ntype JsonArray = readonly JsonValue[];\r\n\r\nfunction isObject(value: unknown): value is JsonObject {\r\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\r\n}\r\n\r\n/**\r\n * Validate an eval file (agentv-eval-v2 schema).\r\n */\r\nexport async function validateEvalFile(\r\n filePath: string,\r\n): Promise<ValidationResult> {\r\n const errors: ValidationError[] = [];\r\n const absolutePath = path.resolve(filePath);\r\n\r\n let parsed: unknown;\r\n try {\r\n const content = await readFile(absolutePath, \"utf8\");\r\n parsed = parse(content);\r\n } catch (error) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n message: `Failed to parse YAML: ${(error as Error).message}`,\r\n });\r\n return {\r\n valid: false,\r\n filePath: absolutePath,\r\n fileType: \"eval\",\r\n errors,\r\n };\r\n }\r\n\r\n if (!isObject(parsed)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n message: \"File must contain a YAML object\",\r\n });\r\n return {\r\n valid: false,\r\n filePath: absolutePath,\r\n fileType: \"eval\",\r\n errors,\r\n };\r\n }\r\n\r\n // Validate $schema field\r\n const schema = parsed[\"$schema\"];\r\n if (schema !== SCHEMA_EVAL_V2) {\r\n const message =\r\n typeof schema === \"string\"\r\n ? `Invalid $schema value '${schema}'. Expected '${SCHEMA_EVAL_V2}'`\r\n : `Missing required field '$schema'. Expected '${SCHEMA_EVAL_V2}'`;\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: \"$schema\",\r\n message,\r\n });\r\n }\r\n\r\n // Validate evalcases array\r\n const evalcases = parsed[\"evalcases\"];\r\n if (!Array.isArray(evalcases)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: \"evalcases\",\r\n message: \"Missing or invalid 'evalcases' field (must be an array)\",\r\n });\r\n return {\r\n valid: errors.length === 0,\r\n filePath: absolutePath,\r\n fileType: \"eval\",\r\n errors,\r\n };\r\n }\r\n\r\n // Validate each eval case\r\n for (let i = 0; i < evalcases.length; i++) {\r\n const evalCase = evalcases[i];\r\n const location = `evalcases[${i}]`;\r\n\r\n if (!isObject(evalCase)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location,\r\n message: \"Eval case must be an object\",\r\n });\r\n continue;\r\n }\r\n\r\n // Required fields: id, outcome, input_messages, expected_messages\r\n const id = evalCase[\"id\"];\r\n if (typeof id !== \"string\" || id.trim().length === 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.id`,\r\n message: \"Missing or invalid 'id' field (must be a non-empty string)\",\r\n });\r\n }\r\n\r\n const outcome = evalCase[\"outcome\"];\r\n if (typeof outcome !== \"string\" || outcome.trim().length === 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.outcome`,\r\n message: \"Missing or invalid 'outcome' field (must be a non-empty string)\",\r\n });\r\n }\r\n\r\n const inputMessages = evalCase[\"input_messages\"];\r\n if (!Array.isArray(inputMessages)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.input_messages`,\r\n message: \"Missing or invalid 'input_messages' field (must be an array)\",\r\n });\r\n } else {\r\n validateMessages(inputMessages, `${location}.input_messages`, absolutePath, errors);\r\n }\r\n\r\n const expectedMessages = evalCase[\"expected_messages\"];\r\n if (!Array.isArray(expectedMessages)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.expected_messages`,\r\n message: \"Missing or invalid 'expected_messages' field (must be an array)\",\r\n });\r\n } else {\r\n validateMessages(expectedMessages, `${location}.expected_messages`, absolutePath, errors);\r\n }\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n filePath: absolutePath,\r\n fileType: \"eval\",\r\n errors,\r\n };\r\n}\r\n\r\nfunction validateMessages(\r\n messages: JsonArray,\r\n location: string,\r\n filePath: string,\r\n errors: ValidationError[],\r\n): void {\r\n for (let i = 0; i < messages.length; i++) {\r\n const message = messages[i];\r\n const msgLocation = `${location}[${i}]`;\r\n\r\n if (!isObject(message)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: msgLocation,\r\n message: \"Message must be an object\",\r\n });\r\n continue;\r\n }\r\n\r\n // Validate role field\r\n const role = message[\"role\"];\r\n const validRoles = [\"system\", \"user\", \"assistant\"];\r\n if (!validRoles.includes(role as string)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: `${msgLocation}.role`,\r\n message: `Invalid role '${role}'. Must be one of: ${validRoles.join(\", \")}`,\r\n });\r\n }\r\n\r\n // Validate content field (can be string or array)\r\n const content = message[\"content\"];\r\n if (typeof content === \"string\") {\r\n // String content is valid\r\n } else if (Array.isArray(content)) {\r\n // Array content - validate each element\r\n for (let j = 0; j < content.length; j++) {\r\n const contentItem = content[j];\r\n const contentLocation = `${msgLocation}.content[${j}]`;\r\n\r\n if (typeof contentItem === \"string\") {\r\n // String in array is valid\r\n } else if (isObject(contentItem)) {\r\n const type = contentItem[\"type\"];\r\n if (typeof type !== \"string\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: `${contentLocation}.type`,\r\n message: \"Content object must have a 'type' field\",\r\n });\r\n }\r\n\r\n // For 'file' type, we'll validate existence later in file-reference-validator\r\n // For 'text' type, require 'value' field\r\n if (type === \"text\") {\r\n const value = contentItem[\"value\"];\r\n if (typeof value !== \"string\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: `${contentLocation}.value`,\r\n message: \"Content with type 'text' must have a 'value' field\",\r\n });\r\n }\r\n }\r\n } else {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: contentLocation,\r\n message: \"Content array items must be strings or objects\",\r\n });\r\n }\r\n }\r\n } else {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: `${msgLocation}.content`,\r\n message: \"Missing or invalid 'content' field (must be a string or array)\",\r\n });\r\n }\r\n }\r\n}\r\n","import { readFile } from \"node:fs/promises\";\r\nimport path from \"node:path\";\r\nimport { parse } from \"yaml\";\r\n\r\nimport type { ValidationError, ValidationResult } from \"./types.js\";\r\nimport { KNOWN_PROVIDERS, PROVIDER_ALIASES, TARGETS_SCHEMA_V2 } from \"../providers/types.js\";\r\nimport { CLI_PLACEHOLDERS } from \"../providers/targets.js\";\r\n\r\ntype JsonValue = string | number | boolean | null | JsonObject | JsonArray;\r\ntype JsonObject = { readonly [key: string]: JsonValue };\r\ntype JsonArray = readonly JsonValue[];\r\n\r\nfunction isObject(value: unknown): value is JsonObject {\r\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\r\n}\r\n\r\n// Known settings properties for each provider type\r\nconst COMMON_SETTINGS = new Set([\r\n \"provider_batching\",\r\n \"providerBatching\",\r\n]);\r\n\r\nconst AZURE_SETTINGS = new Set([\r\n ...COMMON_SETTINGS,\r\n \"endpoint\",\r\n \"resource\",\r\n \"resourceName\",\r\n \"api_key\",\r\n \"apiKey\",\r\n \"deployment\",\r\n \"deploymentName\",\r\n \"model\",\r\n \"version\",\r\n \"api_version\",\r\n \"temperature\",\r\n \"max_output_tokens\",\r\n \"maxTokens\",\r\n]);\r\n\r\nconst ANTHROPIC_SETTINGS = new Set([\r\n ...COMMON_SETTINGS,\r\n \"api_key\",\r\n \"apiKey\",\r\n \"model\",\r\n \"deployment\",\r\n \"variant\",\r\n \"temperature\",\r\n \"max_output_tokens\",\r\n \"maxTokens\",\r\n \"thinking_budget\",\r\n \"thinkingBudget\",\r\n]);\r\n\r\nconst GEMINI_SETTINGS = new Set([\r\n ...COMMON_SETTINGS,\r\n \"api_key\",\r\n \"apiKey\",\r\n \"model\",\r\n \"deployment\",\r\n \"variant\",\r\n \"temperature\",\r\n \"max_output_tokens\",\r\n \"maxTokens\",\r\n]);\r\n\r\nconst CODEX_SETTINGS = new Set([\r\n ...COMMON_SETTINGS,\r\n \"executable\",\r\n \"command\",\r\n \"binary\",\r\n \"args\",\r\n \"arguments\",\r\n \"cwd\",\r\n \"timeout_seconds\",\r\n \"timeoutSeconds\",\r\n \"log_dir\",\r\n \"logDir\",\r\n \"log_directory\",\r\n \"logDirectory\",\r\n \"log_format\",\r\n \"logFormat\",\r\n \"log_output_format\",\r\n \"logOutputFormat\",\r\n]);\r\n\r\nconst VSCODE_SETTINGS = new Set([\r\n ...COMMON_SETTINGS,\r\n \"workspace_template\",\r\n \"workspaceTemplate\",\r\n \"vscode_cmd\",\r\n \"command\",\r\n \"wait\",\r\n \"dry_run\",\r\n \"dryRun\",\r\n \"subagent_root\",\r\n \"subagentRoot\",\r\n]);\r\n\r\nconst MOCK_SETTINGS = new Set([\r\n ...COMMON_SETTINGS,\r\n \"response\",\r\n \"delayMs\",\r\n \"delayMinMs\",\r\n \"delayMaxMs\",\r\n]);\r\n\r\nconst CLI_SETTINGS = new Set([\r\n ...COMMON_SETTINGS,\r\n \"command_template\",\r\n \"commandTemplate\",\r\n \"files_format\",\r\n \"filesFormat\",\r\n \"attachments_format\",\r\n \"attachmentsFormat\",\r\n \"cwd\",\r\n \"env\",\r\n \"timeout_seconds\",\r\n \"timeoutSeconds\",\r\n \"healthcheck\",\r\n]);\r\n\r\nfunction getKnownSettings(provider: string): Set<string> | null {\r\n const normalizedProvider = provider.toLowerCase();\r\n switch (normalizedProvider) {\r\n case \"azure\":\r\n case \"azure-openai\":\r\n return AZURE_SETTINGS;\r\n case \"anthropic\":\r\n return ANTHROPIC_SETTINGS;\r\n case \"gemini\":\r\n case \"google\":\r\n case \"google-gemini\":\r\n return GEMINI_SETTINGS;\r\n case \"codex\":\r\n case \"codex-cli\":\r\n return CODEX_SETTINGS;\r\n case \"vscode\":\r\n case \"vscode-insiders\":\r\n return VSCODE_SETTINGS;\r\n case \"mock\":\r\n return MOCK_SETTINGS;\r\n case \"cli\":\r\n return CLI_SETTINGS;\r\n default:\r\n return null; // Unknown provider, can't validate settings\r\n }\r\n}\r\n\r\nfunction validateUnknownSettings(\r\n settings: JsonObject,\r\n provider: string,\r\n absolutePath: string,\r\n location: string,\r\n errors: ValidationError[],\r\n): void {\r\n const knownSettings = getKnownSettings(provider);\r\n if (!knownSettings) {\r\n // Unknown provider, skip settings validation\r\n return;\r\n }\r\n\r\n for (const key of Object.keys(settings)) {\r\n if (!knownSettings.has(key)) {\r\n errors.push({\r\n severity: \"warning\",\r\n filePath: absolutePath,\r\n location: `${location}.${key}`,\r\n message: `Unknown setting '${key}' for ${provider} provider. This property will be ignored.`,\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Validate a targets file (agentv-targets-v2.1 schema).\r\n */\r\nexport async function validateTargetsFile(\r\n filePath: string,\r\n): Promise<ValidationResult> {\r\n const errors: ValidationError[] = [];\r\n const absolutePath = path.resolve(filePath);\r\n\r\n let parsed: unknown;\r\n try {\r\n const content = await readFile(absolutePath, \"utf8\");\r\n parsed = parse(content);\r\n } catch (error) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n message: `Failed to parse YAML: ${(error as Error).message}`,\r\n });\r\n return {\r\n valid: false,\r\n filePath: absolutePath,\r\n fileType: \"targets\",\r\n errors,\r\n};\r\n}\r\n\r\nfunction validateCliSettings(\r\n settings: unknown,\r\n absolutePath: string,\r\n location: string,\r\n errors: ValidationError[],\r\n): void {\r\n if (!isObject(settings)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location,\r\n message: \"CLI provider requires a 'settings' object\",\r\n });\r\n return;\r\n }\r\n\r\n const commandTemplate = settings[\"command_template\"] ?? settings[\"commandTemplate\"];\r\n if (typeof commandTemplate !== \"string\" || commandTemplate.trim().length === 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.commandTemplate`,\r\n message: \"CLI provider requires 'commandTemplate' as a non-empty string\",\r\n });\r\n } else {\r\n recordUnknownPlaceholders(commandTemplate, absolutePath, `${location}.commandTemplate`, errors);\r\n }\r\n\r\n const attachmentsFormat = settings[\"attachments_format\"] ?? settings[\"attachmentsFormat\"];\r\n if (attachmentsFormat !== undefined && typeof attachmentsFormat !== \"string\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.attachmentsFormat`,\r\n message: \"'attachmentsFormat' must be a string when provided\",\r\n });\r\n }\r\n\r\n const filesFormat = settings[\"files_format\"] ?? settings[\"filesFormat\"];\r\n if (filesFormat !== undefined && typeof filesFormat !== \"string\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.filesFormat`,\r\n message: \"'filesFormat' must be a string when provided\",\r\n });\r\n }\r\n\r\n const cwd = settings[\"cwd\"];\r\n if (cwd !== undefined && typeof cwd !== \"string\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.cwd`,\r\n message: \"'cwd' must be a string when provided\",\r\n });\r\n }\r\n\r\n const timeoutSeconds = settings[\"timeout_seconds\"] ?? settings[\"timeoutSeconds\"];\r\n if (timeoutSeconds !== undefined) {\r\n const numericTimeout = Number(timeoutSeconds);\r\n if (!Number.isFinite(numericTimeout) || numericTimeout <= 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.timeoutSeconds`,\r\n message: \"'timeoutSeconds' must be a positive number when provided\",\r\n });\r\n }\r\n }\r\n\r\n const envOverrides = settings[\"env\"];\r\n if (envOverrides !== undefined) {\r\n if (!isObject(envOverrides)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.env`,\r\n message: \"'env' must be an object with string values\",\r\n });\r\n } else {\r\n for (const [key, value] of Object.entries(envOverrides)) {\r\n if (typeof value !== \"string\" || value.trim().length === 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.env.${key}`,\r\n message: `Environment override '${key}' must be a non-empty string`,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n const healthcheck = settings[\"healthcheck\"];\r\n if (healthcheck !== undefined) {\r\n validateCliHealthcheck(healthcheck, absolutePath, `${location}.healthcheck`, errors);\r\n }\r\n}\r\n\r\nfunction validateCliHealthcheck(\r\n healthcheck: unknown,\r\n absolutePath: string,\r\n location: string,\r\n errors: ValidationError[],\r\n): void {\r\n if (!isObject(healthcheck)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location,\r\n message: \"'healthcheck' must be an object when provided\",\r\n });\r\n return;\r\n }\r\n\r\n const type = healthcheck[\"type\"];\r\n if (type !== \"http\" && type !== \"command\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.type`,\r\n message: \"healthcheck.type must be either 'http' or 'command'\",\r\n });\r\n return;\r\n }\r\n\r\n const timeoutSeconds = healthcheck[\"timeout_seconds\"] ?? healthcheck[\"timeoutSeconds\"];\r\n if (timeoutSeconds !== undefined) {\r\n const numericTimeout = Number(timeoutSeconds);\r\n if (!Number.isFinite(numericTimeout) || numericTimeout <= 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.timeoutSeconds`,\r\n message: \"healthcheck.timeoutSeconds must be a positive number when provided\",\r\n });\r\n }\r\n }\r\n\r\n if (type === \"http\") {\r\n const url = healthcheck[\"url\"];\r\n if (typeof url !== \"string\" || url.trim().length === 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.url`,\r\n message: \"healthcheck.url must be a non-empty string for http checks\",\r\n });\r\n }\r\n return;\r\n }\r\n\r\n const commandTemplate = healthcheck[\"command_template\"] ?? healthcheck[\"commandTemplate\"];\r\n if (typeof commandTemplate !== \"string\" || commandTemplate.trim().length === 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.commandTemplate`,\r\n message: \"healthcheck.commandTemplate must be a non-empty string for command checks\",\r\n });\r\n } else {\r\n recordUnknownPlaceholders(commandTemplate, absolutePath, `${location}.commandTemplate`, errors);\r\n }\r\n\r\n const cwd = healthcheck[\"cwd\"];\r\n if (cwd !== undefined && typeof cwd !== \"string\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.cwd`,\r\n message: \"healthcheck.cwd must be a string when provided\",\r\n });\r\n }\r\n}\r\n\r\nfunction recordUnknownPlaceholders(\r\n template: string,\r\n absolutePath: string,\r\n location: string,\r\n errors: ValidationError[],\r\n): void {\r\n const placeholders = extractPlaceholders(template);\r\n for (const placeholder of placeholders) {\r\n if (!CLI_PLACEHOLDERS.has(placeholder)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location,\r\n message: `Unknown CLI placeholder '{${placeholder}}'. Supported placeholders: ${Array.from(CLI_PLACEHOLDERS).join(\", \")}`,\r\n });\r\n }\r\n }\r\n}\r\n\r\nfunction extractPlaceholders(template: string): string[] {\r\n const matches = template.matchAll(/\\{([A-Z_]+)\\}/g);\r\n const result: string[] = [];\r\n for (const match of matches) {\r\n const placeholder = match[1];\r\n if (placeholder) {\r\n result.push(placeholder);\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n if (!isObject(parsed)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n message: \"File must contain a YAML object\",\r\n });\r\n return {\r\n valid: false,\r\n filePath: absolutePath,\r\n fileType: \"targets\",\r\n errors,\r\n };\r\n }\r\n\r\n // Validate $schema field\r\n const schema = parsed[\"$schema\"];\r\n if (schema !== TARGETS_SCHEMA_V2) {\r\n const message =\r\n typeof schema === \"string\"\r\n ? `Invalid $schema value '${schema}'. Expected '${TARGETS_SCHEMA_V2}'`\r\n : `Missing required field '$schema'. Expected '${TARGETS_SCHEMA_V2}'`;\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: \"$schema\",\r\n message,\r\n });\r\n }\r\n\r\n // Validate targets array\r\n const targets = parsed[\"targets\"];\r\n if (!Array.isArray(targets)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: \"targets\",\r\n message: \"Missing or invalid 'targets' field (must be an array)\",\r\n });\r\n return {\r\n valid: errors.length === 0,\r\n filePath: absolutePath,\r\n fileType: \"targets\",\r\n errors,\r\n };\r\n }\r\n\r\n // Validate each target definition\r\n const knownProviders = [...KNOWN_PROVIDERS, ...PROVIDER_ALIASES];\r\n \r\n for (let i = 0; i < targets.length; i++) {\r\n const target = targets[i];\r\n const location = `targets[${i}]`;\r\n\r\n if (!isObject(target)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location,\r\n message: \"Target must be an object\",\r\n });\r\n continue;\r\n }\r\n\r\n // Required field: name\r\n const name = target[\"name\"];\r\n if (typeof name !== \"string\" || name.trim().length === 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.name`,\r\n message: \"Missing or invalid 'name' field (must be a non-empty string)\",\r\n });\r\n }\r\n\r\n // Required field: provider\r\n const provider = target[\"provider\"];\r\n const providerValue = typeof provider === \"string\" ? provider.trim().toLowerCase() : undefined;\r\n if (typeof provider !== \"string\" || provider.trim().length === 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.provider`,\r\n message: \"Missing or invalid 'provider' field (must be a non-empty string)\",\r\n });\r\n } else if (!knownProviders.includes(provider)) {\r\n // Warning for unknown providers (non-fatal)\r\n errors.push({\r\n severity: \"warning\",\r\n filePath: absolutePath,\r\n location: `${location}.provider`,\r\n message: `Unknown provider '${provider}'. Known providers: ${knownProviders.join(\", \")}`,\r\n });\r\n }\r\n\r\n // Optional field: settings (must be object if present)\r\n const settings = target[\"settings\"];\r\n if (providerValue !== \"cli\" && settings !== undefined && !isObject(settings)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.settings`,\r\n message: \"Invalid 'settings' field (must be an object)\",\r\n });\r\n }\r\n\r\n if (providerValue === \"cli\") {\r\n validateCliSettings(settings, absolutePath, `${location}.settings`, errors);\r\n }\r\n\r\n // Check for unknown settings properties\r\n if (settings !== undefined && isObject(settings) && typeof provider === \"string\") {\r\n validateUnknownSettings(settings, provider, absolutePath, `${location}.settings`, errors);\r\n }\r\n\r\n // Optional field: judge_target (must be string if present)\r\n const judgeTarget = target[\"judge_target\"];\r\n if (judgeTarget !== undefined && typeof judgeTarget !== \"string\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.judge_target`,\r\n message: \"Invalid 'judge_target' field (must be a string)\",\r\n });\r\n }\r\n }\r\n\r\n return {\r\n valid: errors.filter((e) => e.severity === \"error\").length === 0,\r\n filePath: absolutePath,\r\n fileType: \"targets\",\r\n errors,\r\n };\r\n}\r\n","import { readFile } from \"node:fs/promises\";\r\nimport { parse } from \"yaml\";\r\n\r\nimport type { ValidationError, ValidationResult } from \"./types.js\";\r\n\r\nconst SCHEMA_CONFIG_V2 = \"agentv-config-v2\";\r\n\r\n/**\r\n * Validate a config.yaml file for schema compliance and structural correctness.\r\n */\r\nexport async function validateConfigFile(filePath: string): Promise<ValidationResult> {\r\n const errors: ValidationError[] = [];\r\n\r\n try {\r\n const content = await readFile(filePath, \"utf8\");\r\n const parsed = parse(content) as unknown;\r\n\r\n // Check if parsed content is an object\r\n if (typeof parsed !== \"object\" || parsed === null) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n message: \"Config file must contain a valid YAML object\",\r\n });\r\n return { valid: false, filePath, fileType: \"config\", errors };\r\n }\r\n\r\n const config = parsed as Record<string, unknown>;\r\n\r\n // Validate $schema field\r\n const schema = config[\"$schema\"];\r\n if (schema !== SCHEMA_CONFIG_V2) {\r\n const message =\r\n typeof schema === \"string\"\r\n ? `Invalid $schema value '${schema}'. Expected '${SCHEMA_CONFIG_V2}'`\r\n : `Missing required field '$schema'. Please add '$schema: ${SCHEMA_CONFIG_V2}' at the top of the file.`;\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: \"$schema\",\r\n message,\r\n });\r\n }\r\n\r\n // Validate guideline_patterns if present\r\n const guidelinePatterns = config[\"guideline_patterns\"];\r\n if (guidelinePatterns !== undefined) {\r\n if (!Array.isArray(guidelinePatterns)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: \"guideline_patterns\",\r\n message: \"Field 'guideline_patterns' must be an array\",\r\n });\r\n } else if (!guidelinePatterns.every((p) => typeof p === \"string\")) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: \"guideline_patterns\",\r\n message: \"All entries in 'guideline_patterns' must be strings\",\r\n });\r\n } else if (guidelinePatterns.length === 0) {\r\n errors.push({\r\n severity: \"warning\",\r\n filePath,\r\n location: \"guideline_patterns\",\r\n message: \"Field 'guideline_patterns' is empty. Consider removing it or adding patterns.\",\r\n });\r\n }\r\n }\r\n\r\n // Check for unexpected fields\r\n const allowedFields = new Set([\"$schema\", \"guideline_patterns\"]);\r\n const unexpectedFields = Object.keys(config).filter((key) => !allowedFields.has(key));\r\n \r\n if (unexpectedFields.length > 0) {\r\n errors.push({\r\n severity: \"warning\",\r\n filePath,\r\n message: `Unexpected fields: ${unexpectedFields.join(\", \")}`,\r\n });\r\n }\r\n\r\n return {\r\n valid: errors.filter((e) => e.severity === \"error\").length === 0,\r\n filePath,\r\n fileType: \"config\",\r\n errors,\r\n };\r\n } catch (error) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n message: `Failed to parse config file: ${(error as Error).message}`,\r\n });\r\n return { valid: false, filePath, fileType: \"config\", errors };\r\n }\r\n}\r\n","import { readFile } from \"node:fs/promises\";\r\nimport path from \"node:path\";\r\nimport { parse } from \"yaml\";\r\n\r\nimport type { ValidationError } from \"./types.js\";\r\nimport { buildSearchRoots, findGitRoot, resolveFileReference } from \"../file-utils.js\";\r\n\r\ntype JsonValue = string | number | boolean | null | JsonObject | JsonArray;\r\ntype JsonObject = { readonly [key: string]: JsonValue };\r\ntype JsonArray = readonly JsonValue[];\r\n\r\nfunction isObject(value: unknown): value is JsonObject {\r\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\r\n}\r\n\r\n/**\r\n * Validate that file references in eval file content exist.\r\n * Checks content blocks with type: \"file\" and validates the referenced file exists.\r\n * Also checks that referenced files are not empty.\r\n */\r\nexport async function validateFileReferences(\r\n evalFilePath: string,\r\n): Promise<readonly ValidationError[]> {\r\n const errors: ValidationError[] = [];\r\n const absolutePath = path.resolve(evalFilePath);\r\n\r\n // Find git root and build search roots (same as yaml-parser does at runtime)\r\n const gitRoot = await findGitRoot(absolutePath);\r\n if (!gitRoot) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n message: \"Cannot validate file references: git repository root not found\",\r\n });\r\n return errors;\r\n }\r\n\r\n const searchRoots = buildSearchRoots(absolutePath, gitRoot);\r\n\r\n let parsed: unknown;\r\n try {\r\n const content = await readFile(absolutePath, \"utf8\");\r\n parsed = parse(content);\r\n } catch {\r\n // Parse errors are already caught by eval-validator\r\n return errors;\r\n }\r\n\r\n if (!isObject(parsed)) {\r\n return errors;\r\n }\r\n\r\n const evalcases = parsed[\"evalcases\"];\r\n if (!Array.isArray(evalcases)) {\r\n return errors;\r\n }\r\n\r\n for (let i = 0; i < evalcases.length; i++) {\r\n const evalCase = evalcases[i];\r\n if (!isObject(evalCase)) {\r\n continue;\r\n }\r\n\r\n // Check input_messages\r\n const inputMessages = evalCase[\"input_messages\"];\r\n if (Array.isArray(inputMessages)) {\r\n await validateMessagesFileRefs(inputMessages, `evalcases[${i}].input_messages`, searchRoots, absolutePath, errors);\r\n }\r\n\r\n // Check expected_messages\r\n const expectedMessages = evalCase[\"expected_messages\"];\r\n if (Array.isArray(expectedMessages)) {\r\n await validateMessagesFileRefs(expectedMessages, `evalcases[${i}].expected_messages`, searchRoots, absolutePath, errors);\r\n }\r\n }\r\n\r\n return errors;\r\n}\r\n\r\nasync function validateMessagesFileRefs(\r\n messages: JsonArray,\r\n location: string,\r\n searchRoots: readonly string[],\r\n filePath: string,\r\n errors: ValidationError[],\r\n): Promise<void> {\r\n for (let i = 0; i < messages.length; i++) {\r\n const message = messages[i];\r\n if (!isObject(message)) {\r\n continue;\r\n }\r\n\r\n const content = message[\"content\"];\r\n if (typeof content === \"string\") {\r\n continue;\r\n }\r\n\r\n if (!Array.isArray(content)) {\r\n continue;\r\n }\r\n\r\n for (let j = 0; j < content.length; j++) {\r\n const contentItem = content[j];\r\n if (!isObject(contentItem)) {\r\n continue;\r\n }\r\n\r\n const type = contentItem[\"type\"];\r\n if (type !== \"file\") {\r\n continue;\r\n }\r\n\r\n const value = contentItem[\"value\"];\r\n if (typeof value !== \"string\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: `${location}[${i}].content[${j}].value`,\r\n message: \"File reference must have a 'value' field with the file path\",\r\n });\r\n continue;\r\n }\r\n\r\n // Use the same file resolution logic as yaml-parser at runtime\r\n const { resolvedPath } = await resolveFileReference(value, searchRoots);\r\n\r\n if (!resolvedPath) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: `${location}[${i}].content[${j}]`,\r\n message: `Referenced file not found: ${value}`,\r\n });\r\n } else {\r\n // Check that file is not empty\r\n try {\r\n const fileContent = await readFile(resolvedPath, \"utf8\");\r\n if (fileContent.trim().length === 0) {\r\n errors.push({\r\n severity: \"warning\",\r\n filePath,\r\n location: `${location}[${i}].content[${j}]`,\r\n message: `Referenced file is empty: ${value}`,\r\n });\r\n }\r\n } catch (error) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: `${location}[${i}].content[${j}]`,\r\n message: `Cannot read referenced file: ${value} (${(error as Error).message})`,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":["readFile","parse","SCHEMA_EVAL_V2","readFile","path","parse","isObject","path","readFile","parse","absolutePath","errors","readFile","parse","SCHEMA_CONFIG_V2","readFile","path","parse","isObject","path","readFile","parse"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/evaluation/validation/file-type.ts","../../../src/evaluation/validation/eval-validator.ts","../../../src/evaluation/validation/targets-validator.ts","../../../src/evaluation/validation/config-validator.ts","../../../src/evaluation/validation/file-reference-validator.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\r\nimport { parse } from \"yaml\";\r\n\r\nimport type { FileType } from \"./types.js\";\r\n\r\nconst SCHEMA_EVAL_V2 = \"agentv-eval-v2\";\r\nconst SCHEMA_TARGETS_V2 = \"agentv-targets-v2.2\";\r\nconst SCHEMA_CONFIG_V2 = \"agentv-config-v2\";\r\n\r\n/**\r\n * Detect file type by reading $schema field from YAML file.\r\n * Returns \"unknown\" if file cannot be read or $schema is missing/invalid.\r\n */\r\nexport async function detectFileType(filePath: string): Promise<FileType> {\r\n try {\r\n const content = await readFile(filePath, \"utf8\");\r\n const parsed = parse(content) as unknown;\r\n\r\n if (typeof parsed !== \"object\" || parsed === null) {\r\n return \"unknown\";\r\n }\r\n\r\n const record = parsed as Record<string, unknown>;\r\n const schema = record[\"$schema\"];\r\n\r\n if (typeof schema !== \"string\") {\r\n return \"unknown\";\r\n }\r\n\r\n switch (schema) {\r\n case SCHEMA_EVAL_V2:\r\n return \"eval\";\r\n case SCHEMA_TARGETS_V2:\r\n return \"targets\";\r\n case SCHEMA_CONFIG_V2:\r\n return \"config\";\r\n default:\r\n return \"unknown\";\r\n }\r\n } catch {\r\n return \"unknown\";\r\n }\r\n}\r\n\r\n/**\r\n * Check if a schema value is a valid AgentV schema identifier.\r\n */\r\nexport function isValidSchema(schema: unknown): boolean {\r\n return schema === SCHEMA_EVAL_V2 || schema === SCHEMA_TARGETS_V2 || schema === SCHEMA_CONFIG_V2;\r\n}\r\n\r\n/**\r\n * Get the expected schema for a file type.\r\n */\r\nexport function getExpectedSchema(fileType: FileType): string | undefined {\r\n switch (fileType) {\r\n case \"eval\":\r\n return SCHEMA_EVAL_V2;\r\n case \"targets\":\r\n return SCHEMA_TARGETS_V2;\r\n case \"config\":\r\n return SCHEMA_CONFIG_V2;\r\n default:\r\n return undefined;\r\n }\r\n}\r\n","import { readFile } from \"node:fs/promises\";\r\nimport path from \"node:path\";\r\nimport { parse } from \"yaml\";\r\n\r\nimport type { ValidationError, ValidationResult } from \"./types.js\";\r\n\r\nconst SCHEMA_EVAL_V2 = \"agentv-eval-v2\";\r\n\r\ntype JsonValue = string | number | boolean | null | JsonObject | JsonArray;\r\ntype JsonObject = { readonly [key: string]: JsonValue };\r\ntype JsonArray = readonly JsonValue[];\r\n\r\nfunction isObject(value: unknown): value is JsonObject {\r\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\r\n}\r\n\r\n/**\r\n * Validate an eval file (agentv-eval-v2 schema).\r\n */\r\nexport async function validateEvalFile(\r\n filePath: string,\r\n): Promise<ValidationResult> {\r\n const errors: ValidationError[] = [];\r\n const absolutePath = path.resolve(filePath);\r\n\r\n let parsed: unknown;\r\n try {\r\n const content = await readFile(absolutePath, \"utf8\");\r\n parsed = parse(content);\r\n } catch (error) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n message: `Failed to parse YAML: ${(error as Error).message}`,\r\n });\r\n return {\r\n valid: false,\r\n filePath: absolutePath,\r\n fileType: \"eval\",\r\n errors,\r\n };\r\n }\r\n\r\n if (!isObject(parsed)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n message: \"File must contain a YAML object\",\r\n });\r\n return {\r\n valid: false,\r\n filePath: absolutePath,\r\n fileType: \"eval\",\r\n errors,\r\n };\r\n }\r\n\r\n // Validate $schema field\r\n const schema = parsed[\"$schema\"];\r\n if (schema !== SCHEMA_EVAL_V2) {\r\n const message =\r\n typeof schema === \"string\"\r\n ? `Invalid $schema value '${schema}'. Expected '${SCHEMA_EVAL_V2}'`\r\n : `Missing required field '$schema'. Expected '${SCHEMA_EVAL_V2}'`;\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: \"$schema\",\r\n message,\r\n });\r\n }\r\n\r\n // Validate evalcases array\r\n const evalcases = parsed[\"evalcases\"];\r\n if (!Array.isArray(evalcases)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: \"evalcases\",\r\n message: \"Missing or invalid 'evalcases' field (must be an array)\",\r\n });\r\n return {\r\n valid: errors.length === 0,\r\n filePath: absolutePath,\r\n fileType: \"eval\",\r\n errors,\r\n };\r\n }\r\n\r\n // Validate each eval case\r\n for (let i = 0; i < evalcases.length; i++) {\r\n const evalCase = evalcases[i];\r\n const location = `evalcases[${i}]`;\r\n\r\n if (!isObject(evalCase)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location,\r\n message: \"Eval case must be an object\",\r\n });\r\n continue;\r\n }\r\n\r\n // Required fields: id, outcome, input_messages, expected_messages\r\n const id = evalCase[\"id\"];\r\n if (typeof id !== \"string\" || id.trim().length === 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.id`,\r\n message: \"Missing or invalid 'id' field (must be a non-empty string)\",\r\n });\r\n }\r\n\r\n const outcome = evalCase[\"outcome\"];\r\n if (typeof outcome !== \"string\" || outcome.trim().length === 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.outcome`,\r\n message: \"Missing or invalid 'outcome' field (must be a non-empty string)\",\r\n });\r\n }\r\n\r\n const inputMessages = evalCase[\"input_messages\"];\r\n if (!Array.isArray(inputMessages)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.input_messages`,\r\n message: \"Missing or invalid 'input_messages' field (must be an array)\",\r\n });\r\n } else {\r\n validateMessages(inputMessages, `${location}.input_messages`, absolutePath, errors);\r\n }\r\n\r\n // expected_messages is optional - for outcome-only evaluation\r\n const expectedMessages = evalCase[\"expected_messages\"];\r\n if (expectedMessages !== undefined && !Array.isArray(expectedMessages)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.expected_messages`,\r\n message: \"Invalid 'expected_messages' field (must be an array if provided)\",\r\n });\r\n } else if (Array.isArray(expectedMessages)) {\r\n validateMessages(expectedMessages, `${location}.expected_messages`, absolutePath, errors);\r\n }\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n filePath: absolutePath,\r\n fileType: \"eval\",\r\n errors,\r\n };\r\n}\r\n\r\nfunction validateMessages(\r\n messages: JsonArray,\r\n location: string,\r\n filePath: string,\r\n errors: ValidationError[],\r\n): void {\r\n for (let i = 0; i < messages.length; i++) {\r\n const message = messages[i];\r\n const msgLocation = `${location}[${i}]`;\r\n\r\n if (!isObject(message)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: msgLocation,\r\n message: \"Message must be an object\",\r\n });\r\n continue;\r\n }\r\n\r\n // Validate role field\r\n const role = message[\"role\"];\r\n const validRoles = [\"system\", \"user\", \"assistant\"];\r\n if (!validRoles.includes(role as string)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: `${msgLocation}.role`,\r\n message: `Invalid role '${role}'. Must be one of: ${validRoles.join(\", \")}`,\r\n });\r\n }\r\n\r\n // Validate content field (can be string or array)\r\n const content = message[\"content\"];\r\n if (typeof content === \"string\") {\r\n validateContentForRoleMarkers(content, `${msgLocation}.content`, filePath, errors);\r\n } else if (Array.isArray(content)) {\r\n // Array content - validate each element\r\n for (let j = 0; j < content.length; j++) {\r\n const contentItem = content[j];\r\n const contentLocation = `${msgLocation}.content[${j}]`;\r\n\r\n if (typeof contentItem === \"string\") {\r\n validateContentForRoleMarkers(contentItem, contentLocation, filePath, errors);\r\n } else if (isObject(contentItem)) {\r\n const type = contentItem[\"type\"];\r\n if (typeof type !== \"string\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: `${contentLocation}.type`,\r\n message: \"Content object must have a 'type' field\",\r\n });\r\n }\r\n\r\n // For 'file' type, we'll validate existence later in file-reference-validator\r\n // For 'text' type, require 'value' field\r\n if (type === \"text\") {\r\n const value = contentItem[\"value\"];\r\n if (typeof value !== \"string\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: `${contentLocation}.value`,\r\n message: \"Content with type 'text' must have a 'value' field\",\r\n });\r\n } else {\r\n validateContentForRoleMarkers(value, `${contentLocation}.value`, filePath, errors);\r\n }\r\n }\r\n } else {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: contentLocation,\r\n message: \"Content array items must be strings or objects\",\r\n });\r\n }\r\n }\r\n } else {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: `${msgLocation}.content`,\r\n message: \"Missing or invalid 'content' field (must be a string or array)\",\r\n });\r\n }\r\n }\r\n}\r\n\r\nfunction validateContentForRoleMarkers(\r\n content: string,\r\n location: string,\r\n filePath: string,\r\n errors: ValidationError[],\r\n): void {\r\n // Check for standard role markers that might confuse agentic providers\r\n const markers = [\"@[System]:\", \"@[User]:\", \"@[Assistant]:\", \"@[Tool]:\"];\r\n for (const marker of markers) {\r\n if (content.toLowerCase().includes(marker.toLowerCase())) {\r\n errors.push({\r\n severity: \"warning\",\r\n filePath,\r\n location,\r\n message: `Content contains potential role marker '${marker}'. This may confuse agentic providers or cause prompt injection.`,\r\n });\r\n }\r\n }\r\n}\r\n","import { readFile } from \"node:fs/promises\";\r\nimport path from \"node:path\";\r\nimport { parse } from \"yaml\";\r\n\r\nimport type { ValidationError, ValidationResult } from \"./types.js\";\r\nimport { CLI_PLACEHOLDERS } from \"../providers/targets.js\";\r\nimport { KNOWN_PROVIDERS, PROVIDER_ALIASES, TARGETS_SCHEMA_V2 } from \"../providers/types.js\";\r\n\r\ntype JsonValue = string | number | boolean | null | JsonObject | JsonArray;\r\ntype JsonObject = { readonly [key: string]: JsonValue };\r\ntype JsonArray = readonly JsonValue[];\r\n\r\nfunction isObject(value: unknown): value is JsonObject {\r\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\r\n}\r\n\r\n// Known settings properties for each provider type\r\nconst COMMON_SETTINGS = new Set([\r\n \"provider_batching\",\r\n \"providerBatching\",\r\n]);\r\n\r\nconst RETRY_SETTINGS = new Set([\r\n \"max_retries\",\r\n \"maxRetries\",\r\n \"retry_initial_delay_ms\",\r\n \"retryInitialDelayMs\",\r\n \"retry_max_delay_ms\",\r\n \"retryMaxDelayMs\",\r\n \"retry_backoff_factor\",\r\n \"retryBackoffFactor\",\r\n \"retry_status_codes\",\r\n \"retryStatusCodes\",\r\n]);\r\n\r\nconst AZURE_SETTINGS = new Set([\r\n ...COMMON_SETTINGS,\r\n ...RETRY_SETTINGS,\r\n \"endpoint\",\r\n \"resource\",\r\n \"resourceName\",\r\n \"api_key\",\r\n \"apiKey\",\r\n \"deployment\",\r\n \"deploymentName\",\r\n \"model\",\r\n \"version\",\r\n \"api_version\",\r\n \"temperature\",\r\n \"max_output_tokens\",\r\n \"maxTokens\",\r\n]);\r\n\r\nconst ANTHROPIC_SETTINGS = new Set([\r\n ...COMMON_SETTINGS,\r\n ...RETRY_SETTINGS,\r\n \"api_key\",\r\n \"apiKey\",\r\n \"model\",\r\n \"deployment\",\r\n \"variant\",\r\n \"temperature\",\r\n \"max_output_tokens\",\r\n \"maxTokens\",\r\n \"thinking_budget\",\r\n \"thinkingBudget\",\r\n]);\r\n\r\nconst GEMINI_SETTINGS = new Set([\r\n ...COMMON_SETTINGS,\r\n ...RETRY_SETTINGS,\r\n \"api_key\",\r\n \"apiKey\",\r\n \"model\",\r\n \"deployment\",\r\n \"variant\",\r\n \"temperature\",\r\n \"max_output_tokens\",\r\n \"maxTokens\",\r\n]);\r\n\r\nconst CODEX_SETTINGS = new Set([\r\n ...COMMON_SETTINGS,\r\n \"executable\",\r\n \"command\",\r\n \"binary\",\r\n \"args\",\r\n \"arguments\",\r\n \"cwd\",\r\n \"timeout_seconds\",\r\n \"timeoutSeconds\",\r\n \"log_dir\",\r\n \"logDir\",\r\n \"log_directory\",\r\n \"logDirectory\",\r\n \"log_format\",\r\n \"logFormat\",\r\n \"log_output_format\",\r\n \"logOutputFormat\",\r\n]);\r\n\r\nconst VSCODE_SETTINGS = new Set([\r\n ...COMMON_SETTINGS,\r\n \"workspace_template\",\r\n \"workspaceTemplate\",\r\n \"vscode_cmd\",\r\n \"command\",\r\n \"wait\",\r\n \"dry_run\",\r\n \"dryRun\",\r\n \"subagent_root\",\r\n \"subagentRoot\",\r\n]);\r\n\r\nconst MOCK_SETTINGS = new Set([\r\n ...COMMON_SETTINGS,\r\n \"response\",\r\n \"delayMs\",\r\n \"delayMinMs\",\r\n \"delayMaxMs\",\r\n]);\r\n\r\nconst CLI_SETTINGS = new Set([\r\n ...COMMON_SETTINGS,\r\n \"command_template\",\r\n \"commandTemplate\",\r\n \"files_format\",\r\n \"filesFormat\",\r\n \"attachments_format\",\r\n \"attachmentsFormat\",\r\n \"cwd\",\r\n \"env\",\r\n \"timeout_seconds\",\r\n \"timeoutSeconds\",\r\n \"healthcheck\",\r\n]);\r\n\r\nfunction getKnownSettings(provider: string): Set<string> | null {\r\n const normalizedProvider = provider.toLowerCase();\r\n switch (normalizedProvider) {\r\n case \"azure\":\r\n case \"azure-openai\":\r\n return AZURE_SETTINGS;\r\n case \"anthropic\":\r\n return ANTHROPIC_SETTINGS;\r\n case \"gemini\":\r\n case \"google\":\r\n case \"google-gemini\":\r\n return GEMINI_SETTINGS;\r\n case \"codex\":\r\n case \"codex-cli\":\r\n return CODEX_SETTINGS;\r\n case \"vscode\":\r\n case \"vscode-insiders\":\r\n return VSCODE_SETTINGS;\r\n case \"mock\":\r\n return MOCK_SETTINGS;\r\n case \"cli\":\r\n return CLI_SETTINGS;\r\n default:\r\n return null; // Unknown provider, can't validate settings\r\n }\r\n}\r\n\r\nfunction validateUnknownSettings(\r\n target: JsonObject,\r\n provider: string,\r\n absolutePath: string,\r\n location: string,\r\n errors: ValidationError[],\r\n): void {\r\n const knownSettings = getKnownSettings(provider);\r\n if (!knownSettings) {\r\n // Unknown provider, skip settings validation\r\n return;\r\n }\r\n\r\n // Known base target fields that aren't settings\r\n const baseFields = new Set([\"name\", \"provider\", \"judge_target\", \"workers\", \"$schema\", \"targets\"]);\r\n\r\n for (const key of Object.keys(target)) {\r\n if (!baseFields.has(key) && !knownSettings.has(key)) {\r\n errors.push({\r\n severity: \"warning\",\r\n filePath: absolutePath,\r\n location: `${location}.${key}`,\r\n message: `Unknown setting '${key}' for ${provider} provider. This property will be ignored.`,\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Validate a targets file (agentv-targets-v2.1 schema).\r\n */\r\nexport async function validateTargetsFile(\r\n filePath: string,\r\n): Promise<ValidationResult> {\r\n const errors: ValidationError[] = [];\r\n const absolutePath = path.resolve(filePath);\r\n\r\n let parsed: unknown;\r\n try {\r\n const content = await readFile(absolutePath, \"utf8\");\r\n parsed = parse(content);\r\n } catch (error) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n message: `Failed to parse YAML: ${(error as Error).message}`,\r\n });\r\n return {\r\n valid: false,\r\n filePath: absolutePath,\r\n fileType: \"targets\",\r\n errors,\r\n};\r\n}\r\n\r\nfunction validateCliSettings(\r\n target: JsonObject,\r\n absolutePath: string,\r\n location: string,\r\n errors: ValidationError[],\r\n): void {\r\n const commandTemplate = target[\"command_template\"] ?? target[\"commandTemplate\"];\r\n if (typeof commandTemplate !== \"string\" || commandTemplate.trim().length === 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.commandTemplate`,\r\n message: \"CLI provider requires 'commandTemplate' as a non-empty string\",\r\n });\r\n } else {\r\n recordUnknownPlaceholders(commandTemplate, absolutePath, `${location}.commandTemplate`, errors);\r\n }\r\n\r\n const attachmentsFormat = target[\"attachments_format\"] ?? target[\"attachmentsFormat\"];\r\n if (attachmentsFormat !== undefined && typeof attachmentsFormat !== \"string\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.attachmentsFormat`,\r\n message: \"'attachmentsFormat' must be a string when provided\",\r\n });\r\n }\r\n\r\n const filesFormat = target[\"files_format\"] ?? target[\"filesFormat\"];\r\n if (filesFormat !== undefined && typeof filesFormat !== \"string\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.filesFormat`,\r\n message: \"'filesFormat' must be a string when provided\",\r\n });\r\n }\r\n\r\n const cwd = target[\"cwd\"];\r\n if (cwd !== undefined && typeof cwd !== \"string\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.cwd`,\r\n message: \"'cwd' must be a string when provided\",\r\n });\r\n }\r\n\r\n const timeoutSeconds = target[\"timeout_seconds\"] ?? target[\"timeoutSeconds\"];\r\n if (timeoutSeconds !== undefined) {\r\n const numericTimeout = Number(timeoutSeconds);\r\n if (!Number.isFinite(numericTimeout) || numericTimeout <= 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.timeoutSeconds`,\r\n message: \"'timeoutSeconds' must be a positive number when provided\",\r\n });\r\n }\r\n }\r\n\r\n const healthcheck = target[\"healthcheck\"];\r\n if (healthcheck !== undefined) {\r\n validateCliHealthcheck(healthcheck, absolutePath, `${location}.healthcheck`, errors);\r\n }\r\n}\r\n\r\nfunction validateCliHealthcheck(\r\n healthcheck: unknown,\r\n absolutePath: string,\r\n location: string,\r\n errors: ValidationError[],\r\n): void {\r\n if (!isObject(healthcheck)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location,\r\n message: \"'healthcheck' must be an object when provided\",\r\n });\r\n return;\r\n }\r\n\r\n const type = healthcheck[\"type\"];\r\n if (type !== \"http\" && type !== \"command\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.type`,\r\n message: \"healthcheck.type must be either 'http' or 'command'\",\r\n });\r\n return;\r\n }\r\n\r\n const timeoutSeconds = healthcheck[\"timeout_seconds\"] ?? healthcheck[\"timeoutSeconds\"];\r\n if (timeoutSeconds !== undefined) {\r\n const numericTimeout = Number(timeoutSeconds);\r\n if (!Number.isFinite(numericTimeout) || numericTimeout <= 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.timeoutSeconds`,\r\n message: \"healthcheck.timeoutSeconds must be a positive number when provided\",\r\n });\r\n }\r\n }\r\n\r\n if (type === \"http\") {\r\n const url = healthcheck[\"url\"];\r\n if (typeof url !== \"string\" || url.trim().length === 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.url`,\r\n message: \"healthcheck.url must be a non-empty string for http checks\",\r\n });\r\n }\r\n return;\r\n }\r\n\r\n const commandTemplate = healthcheck[\"command_template\"] ?? healthcheck[\"commandTemplate\"];\r\n if (typeof commandTemplate !== \"string\" || commandTemplate.trim().length === 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.commandTemplate`,\r\n message: \"healthcheck.commandTemplate must be a non-empty string for command checks\",\r\n });\r\n } else {\r\n recordUnknownPlaceholders(commandTemplate, absolutePath, `${location}.commandTemplate`, errors);\r\n }\r\n\r\n const cwd = healthcheck[\"cwd\"];\r\n if (cwd !== undefined && typeof cwd !== \"string\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.cwd`,\r\n message: \"healthcheck.cwd must be a string when provided\",\r\n });\r\n }\r\n}\r\n\r\nfunction recordUnknownPlaceholders(\r\n template: string,\r\n absolutePath: string,\r\n location: string,\r\n errors: ValidationError[],\r\n): void {\r\n const placeholders = extractPlaceholders(template);\r\n for (const placeholder of placeholders) {\r\n if (!CLI_PLACEHOLDERS.has(placeholder)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location,\r\n message: `Unknown CLI placeholder '{${placeholder}}'. Supported placeholders: ${Array.from(CLI_PLACEHOLDERS).join(\", \")}`,\r\n });\r\n }\r\n }\r\n}\r\n\r\nfunction extractPlaceholders(template: string): string[] {\r\n const matches = template.matchAll(/\\{([A-Z_]+)\\}/g);\r\n const result: string[] = [];\r\n for (const match of matches) {\r\n const placeholder = match[1];\r\n if (placeholder) {\r\n result.push(placeholder);\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n if (!isObject(parsed)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n message: \"File must contain a YAML object\",\r\n });\r\n return {\r\n valid: false,\r\n filePath: absolutePath,\r\n fileType: \"targets\",\r\n errors,\r\n };\r\n }\r\n\r\n // Validate $schema field\r\n const schema = parsed[\"$schema\"];\r\n if (schema !== TARGETS_SCHEMA_V2) {\r\n const message =\r\n typeof schema === \"string\"\r\n ? `Invalid $schema value '${schema}'. Expected '${TARGETS_SCHEMA_V2}'`\r\n : `Missing required field '$schema'. Expected '${TARGETS_SCHEMA_V2}'`;\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: \"$schema\",\r\n message,\r\n });\r\n }\r\n\r\n // Validate targets array\r\n const targets = parsed[\"targets\"];\r\n if (!Array.isArray(targets)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: \"targets\",\r\n message: \"Missing or invalid 'targets' field (must be an array)\",\r\n });\r\n return {\r\n valid: errors.length === 0,\r\n filePath: absolutePath,\r\n fileType: \"targets\",\r\n errors,\r\n };\r\n }\r\n\r\n // Validate each target definition\r\n const knownProviders = [...KNOWN_PROVIDERS, ...PROVIDER_ALIASES];\r\n \r\n for (let i = 0; i < targets.length; i++) {\r\n const target = targets[i];\r\n const location = `targets[${i}]`;\r\n\r\n if (!isObject(target)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location,\r\n message: \"Target must be an object\",\r\n });\r\n continue;\r\n }\r\n\r\n // Required field: name\r\n const name = target[\"name\"];\r\n if (typeof name !== \"string\" || name.trim().length === 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.name`,\r\n message: \"Missing or invalid 'name' field (must be a non-empty string)\",\r\n });\r\n }\r\n\r\n // Required field: provider\r\n const provider = target[\"provider\"];\r\n const providerValue = typeof provider === \"string\" ? provider.trim().toLowerCase() : undefined;\r\n if (typeof provider !== \"string\" || provider.trim().length === 0) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.provider`,\r\n message: \"Missing or invalid 'provider' field (must be a non-empty string)\",\r\n });\r\n } else if (!knownProviders.includes(provider)) {\r\n // Warning for unknown providers (non-fatal)\r\n errors.push({\r\n severity: \"warning\",\r\n filePath: absolutePath,\r\n location: `${location}.provider`,\r\n message: `Unknown provider '${provider}'. Known providers: ${knownProviders.join(\", \")}`,\r\n });\r\n }\r\n\r\n // Validate CLI provider fields\r\n if (providerValue === \"cli\") {\r\n validateCliSettings(target, absolutePath, location, errors);\r\n }\r\n\r\n // Check for unknown settings properties on target object\r\n if (typeof provider === \"string\") {\r\n validateUnknownSettings(target, provider, absolutePath, location, errors);\r\n }\r\n\r\n // Optional field: judge_target (must be string if present)\r\n const judgeTarget = target[\"judge_target\"];\r\n if (judgeTarget !== undefined && typeof judgeTarget !== \"string\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n location: `${location}.judge_target`,\r\n message: \"Invalid 'judge_target' field (must be a string)\",\r\n });\r\n }\r\n }\r\n\r\n return {\r\n valid: errors.filter((e) => e.severity === \"error\").length === 0,\r\n filePath: absolutePath,\r\n fileType: \"targets\",\r\n errors,\r\n };\r\n}\r\n","import { readFile } from \"node:fs/promises\";\r\nimport { parse } from \"yaml\";\r\n\r\nimport type { ValidationError, ValidationResult } from \"./types.js\";\r\n\r\nconst SCHEMA_CONFIG_V2 = \"agentv-config-v2\";\r\n\r\n/**\r\n * Validate a config.yaml file for schema compliance and structural correctness.\r\n */\r\nexport async function validateConfigFile(filePath: string): Promise<ValidationResult> {\r\n const errors: ValidationError[] = [];\r\n\r\n try {\r\n const content = await readFile(filePath, \"utf8\");\r\n const parsed = parse(content) as unknown;\r\n\r\n // Check if parsed content is an object\r\n if (typeof parsed !== \"object\" || parsed === null) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n message: \"Config file must contain a valid YAML object\",\r\n });\r\n return { valid: false, filePath, fileType: \"config\", errors };\r\n }\r\n\r\n const config = parsed as Record<string, unknown>;\r\n\r\n // Validate $schema field\r\n const schema = config[\"$schema\"];\r\n if (schema !== SCHEMA_CONFIG_V2) {\r\n const message =\r\n typeof schema === \"string\"\r\n ? `Invalid $schema value '${schema}'. Expected '${SCHEMA_CONFIG_V2}'`\r\n : `Missing required field '$schema'. Please add '$schema: ${SCHEMA_CONFIG_V2}' at the top of the file.`;\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: \"$schema\",\r\n message,\r\n });\r\n }\r\n\r\n // Validate guideline_patterns if present\r\n const guidelinePatterns = config[\"guideline_patterns\"];\r\n if (guidelinePatterns !== undefined) {\r\n if (!Array.isArray(guidelinePatterns)) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: \"guideline_patterns\",\r\n message: \"Field 'guideline_patterns' must be an array\",\r\n });\r\n } else if (!guidelinePatterns.every((p) => typeof p === \"string\")) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: \"guideline_patterns\",\r\n message: \"All entries in 'guideline_patterns' must be strings\",\r\n });\r\n } else if (guidelinePatterns.length === 0) {\r\n errors.push({\r\n severity: \"warning\",\r\n filePath,\r\n location: \"guideline_patterns\",\r\n message: \"Field 'guideline_patterns' is empty. Consider removing it or adding patterns.\",\r\n });\r\n }\r\n }\r\n\r\n // Check for unexpected fields\r\n const allowedFields = new Set([\"$schema\", \"guideline_patterns\"]);\r\n const unexpectedFields = Object.keys(config).filter((key) => !allowedFields.has(key));\r\n \r\n if (unexpectedFields.length > 0) {\r\n errors.push({\r\n severity: \"warning\",\r\n filePath,\r\n message: `Unexpected fields: ${unexpectedFields.join(\", \")}`,\r\n });\r\n }\r\n\r\n return {\r\n valid: errors.filter((e) => e.severity === \"error\").length === 0,\r\n filePath,\r\n fileType: \"config\",\r\n errors,\r\n };\r\n } catch (error) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n message: `Failed to parse config file: ${(error as Error).message}`,\r\n });\r\n return { valid: false, filePath, fileType: \"config\", errors };\r\n }\r\n}\r\n","import { readFile } from \"node:fs/promises\";\r\nimport path from \"node:path\";\r\nimport { parse } from \"yaml\";\r\n\r\nimport type { ValidationError } from \"./types.js\";\r\nimport { buildSearchRoots, findGitRoot, resolveFileReference } from \"../file-utils.js\";\r\n\r\ntype JsonValue = string | number | boolean | null | JsonObject | JsonArray;\r\ntype JsonObject = { readonly [key: string]: JsonValue };\r\ntype JsonArray = readonly JsonValue[];\r\n\r\nfunction isObject(value: unknown): value is JsonObject {\r\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\r\n}\r\n\r\n/**\r\n * Validate that file references in eval file content exist.\r\n * Checks content blocks with type: \"file\" and validates the referenced file exists.\r\n * Also checks that referenced files are not empty.\r\n */\r\nexport async function validateFileReferences(\r\n evalFilePath: string,\r\n): Promise<readonly ValidationError[]> {\r\n const errors: ValidationError[] = [];\r\n const absolutePath = path.resolve(evalFilePath);\r\n\r\n // Find git root and build search roots (same as yaml-parser does at runtime)\r\n const gitRoot = await findGitRoot(absolutePath);\r\n if (!gitRoot) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath: absolutePath,\r\n message: \"Cannot validate file references: git repository root not found\",\r\n });\r\n return errors;\r\n }\r\n\r\n const searchRoots = buildSearchRoots(absolutePath, gitRoot);\r\n\r\n let parsed: unknown;\r\n try {\r\n const content = await readFile(absolutePath, \"utf8\");\r\n parsed = parse(content);\r\n } catch {\r\n // Parse errors are already caught by eval-validator\r\n return errors;\r\n }\r\n\r\n if (!isObject(parsed)) {\r\n return errors;\r\n }\r\n\r\n const evalcases = parsed[\"evalcases\"];\r\n if (!Array.isArray(evalcases)) {\r\n return errors;\r\n }\r\n\r\n for (let i = 0; i < evalcases.length; i++) {\r\n const evalCase = evalcases[i];\r\n if (!isObject(evalCase)) {\r\n continue;\r\n }\r\n\r\n // Check input_messages\r\n const inputMessages = evalCase[\"input_messages\"];\r\n if (Array.isArray(inputMessages)) {\r\n await validateMessagesFileRefs(inputMessages, `evalcases[${i}].input_messages`, searchRoots, absolutePath, errors);\r\n }\r\n\r\n // Check expected_messages\r\n const expectedMessages = evalCase[\"expected_messages\"];\r\n if (Array.isArray(expectedMessages)) {\r\n await validateMessagesFileRefs(expectedMessages, `evalcases[${i}].expected_messages`, searchRoots, absolutePath, errors);\r\n }\r\n }\r\n\r\n return errors;\r\n}\r\n\r\nasync function validateMessagesFileRefs(\r\n messages: JsonArray,\r\n location: string,\r\n searchRoots: readonly string[],\r\n filePath: string,\r\n errors: ValidationError[],\r\n): Promise<void> {\r\n for (let i = 0; i < messages.length; i++) {\r\n const message = messages[i];\r\n if (!isObject(message)) {\r\n continue;\r\n }\r\n\r\n const content = message[\"content\"];\r\n if (typeof content === \"string\") {\r\n continue;\r\n }\r\n\r\n if (!Array.isArray(content)) {\r\n continue;\r\n }\r\n\r\n for (let j = 0; j < content.length; j++) {\r\n const contentItem = content[j];\r\n if (!isObject(contentItem)) {\r\n continue;\r\n }\r\n\r\n const type = contentItem[\"type\"];\r\n if (type !== \"file\") {\r\n continue;\r\n }\r\n\r\n const value = contentItem[\"value\"];\r\n if (typeof value !== \"string\") {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: `${location}[${i}].content[${j}].value`,\r\n message: \"File reference must have a 'value' field with the file path\",\r\n });\r\n continue;\r\n }\r\n\r\n // Use the same file resolution logic as yaml-parser at runtime\r\n const { resolvedPath } = await resolveFileReference(value, searchRoots);\r\n\r\n if (!resolvedPath) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: `${location}[${i}].content[${j}]`,\r\n message: `Referenced file not found: ${value}`,\r\n });\r\n } else {\r\n // Check that file is not empty\r\n try {\r\n const fileContent = await readFile(resolvedPath, \"utf8\");\r\n if (fileContent.trim().length === 0) {\r\n errors.push({\r\n severity: \"warning\",\r\n filePath,\r\n location: `${location}[${i}].content[${j}]`,\r\n message: `Referenced file is empty: ${value}`,\r\n });\r\n }\r\n } catch (error) {\r\n errors.push({\r\n severity: \"error\",\r\n filePath,\r\n location: `${location}[${i}].content[${j}]`,\r\n message: `Cannot read referenced file: ${value} (${(error as Error).message})`,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":["readFile","parse","SCHEMA_EVAL_V2","readFile","path","parse","isObject","path","readFile","parse","absolutePath","errors","readFile","parse","SCHEMA_CONFIG_V2","readFile","path","parse","isObject","path","readFile","parse"]}
|