import { readFile } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { parse } from "yaml"; import type { CliValidationSpec, EvalCase, EvalCaseRuntimeSpec, EvalMode, EvalValidationSpec, } from "./types"; const REPO_ROOT = fileURLToPath(new URL("../../", import.meta.url)); const CASES_DIR = path.join(REPO_ROOT, "ai_evals", "cases"); interface RawEvalCase { id: string; prompt: string; initial?: string; expected?: string; validate?: EvalValidationSpec; toolExpect?: EvalCase["toolExpect"]; cliExpect?: CliValidationSpec; judgeChecklist?: string[]; skipJudge?: boolean; runtime?: EvalCaseRuntimeSpec; } export function getRepoRoot(): string { return REPO_ROOT; } export function getAiEvalsRoot(): string { return path.join(REPO_ROOT, "ai_evals"); } export async function loadCases(mode: EvalMode): Promise { const filePath = path.join(CASES_DIR, `${mode}.yaml`); const raw = await readFile(filePath, "utf8"); const parsed = parse(raw); if (!Array.isArray(parsed)) { throw new Error(`Expected ${filePath} to contain a YAML list of cases`); } return (parsed as RawEvalCase[]).map((entry) => ({ id: entry.id, prompt: entry.prompt, initialPath: resolveFixturePath(entry.initial), expectedPath: resolveFixturePath(entry.expected), validate: entry.validate, toolExpect: entry.toolExpect, cliExpect: entry.cliExpect, judgeChecklist: entry.judgeChecklist, skipJudge: entry.skipJudge, runtime: entry.runtime, })); } export async function loadSelectedCases( mode: EvalMode, selectedIds: string[] ): Promise { const allCases = await loadCases(mode); if (selectedIds.length === 0) { return allCases; } const caseMap = new Map(allCases.map((entry) => [entry.id, entry])); const missing = selectedIds.filter((id) => !caseMap.has(id)); if (missing.length > 0) { throw new Error( `Unknown ${mode} case${missing.length === 1 ? "" : "s"}: ${missing.join(", ")}` ); } return selectedIds.map((id) => caseMap.get(id)!); } function resolveFixturePath(value: string | undefined): string | undefined { if (!value) { return undefined; } return path.isAbsolute(value) ? value : path.join(REPO_ROOT, value); }