@axlsdk/eval 0.10.4 → 0.11.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/cli.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/compare.ts","../src/runner.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { readdirSync, statSync } from 'node:fs';\nimport { readFile as readFileAsync, writeFile as writeFileAsync, mkdir } from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { evalCompare } from './compare.js';\nimport { runEval } from './runner.js';\nimport type { EvalConfig, EvalResult } from './types.js';\n\nasync function main() {\n const args = process.argv.slice(2);\n\n if (args.length === 0 || args[0] === '--help') {\n console.log(`\nUsage:\n npx axl eval <path> Run eval file(s)\n npx axl eval <path> --output <f> Run eval and save results to JSON\n npx axl eval compare <a> <b> Compare two eval result files\n npx axl eval compare <a> <b> --fail-on-regression Exit 1 if regressions\n`);\n process.exit(0);\n }\n\n if (args[0] === 'compare') {\n await runCompare(args.slice(1));\n return;\n }\n\n await runEvalCommand(args);\n}\n\nasync function runCompare(args: string[]) {\n const failOnRegression = args.includes('--fail-on-regression');\n const files = args.filter((a) => !a.startsWith('--'));\n\n if (files.length !== 2) {\n console.error('Usage: npx axl eval compare <baseline.json> <candidate.json>');\n process.exit(1);\n }\n\n const baseline: EvalResult = JSON.parse(await readFileAsync(files[0], 'utf-8'));\n const candidate: EvalResult = JSON.parse(await readFileAsync(files[1], 'utf-8'));\n const comparison = evalCompare(baseline, candidate);\n\n console.log(\n `\\nCompare: baseline (${comparison.baseline.id.slice(0, 8)}) -> candidate (${comparison.candidate.id.slice(0, 8)})\\n`,\n );\n\n const scorerNames = Object.keys(comparison.scorers);\n const maxNameLen = Math.max(...scorerNames.map((n) => n.length), 6);\n\n console.log(` ${'Scorer'.padEnd(maxNameLen)} Baseline Candidate Delta Change`);\n console.log(` ${''.padEnd(maxNameLen, '-')} -------- --------- -------- ------`);\n\n for (const name of scorerNames) {\n const s = comparison.scorers[name];\n const sign = s.delta > 0 ? '+' : '';\n console.log(\n ` ${name.padEnd(maxNameLen)} ${s.baselineMean.toFixed(3).padStart(8)} ${s.candidateMean.toFixed(3).padStart(9)} ${(sign + s.delta.toFixed(3)).padStart(8)} ${(sign + s.deltaPercent.toFixed(1) + '%').padStart(6)}`,\n );\n }\n\n const stable = Math.max(\n 0,\n baseline.items.length - comparison.regressions.length - comparison.improvements.length,\n );\n console.log(\n `\\n Regressions: ${comparison.regressions.length} | Improvements: ${comparison.improvements.length} | Stable: ${stable}\\n`,\n );\n\n if (failOnRegression && comparison.regressions.length > 0) {\n process.exit(1);\n }\n}\n\nfunction collectEvalFiles(p: string): string[] {\n const resolved = path.resolve(p);\n try {\n const stat = statSync(resolved);\n if (stat.isDirectory()) {\n const entries = readdirSync(resolved);\n return entries\n .filter((e) => e.endsWith('.eval.ts') || e.endsWith('.eval.js'))\n .map((e) => path.join(resolved, e));\n }\n return [resolved];\n } catch {\n return [resolved];\n }\n}\n\nfunction formatTable(result: EvalResult): string {\n const lines: string[] = [];\n const scorerNames = Object.keys(result.summary.scorers);\n const maxNameLen = Math.max(...scorerNames.map((n) => n.length), 'Scorer'.length);\n const colWidth = 8;\n\n lines.push(`Eval: ${result.workflow} x ${result.dataset} (${result.summary.count} items)`);\n lines.push(\n ` ${'Scorer'.padEnd(maxNameLen)} ${'Mean'.padStart(colWidth)} ${'Min'.padStart(colWidth)} ${'Max'.padStart(colWidth)} ${'p50'.padStart(colWidth)} ${'p95'.padStart(colWidth)}`,\n );\n\n const ruleLen = maxNameLen + 2 + (colWidth + 2) * 5;\n lines.push(' ' + '\\u2500'.repeat(ruleLen));\n\n for (const name of scorerNames) {\n const s = result.summary.scorers[name];\n lines.push(\n ` ${name.padEnd(maxNameLen)} ${s.mean.toFixed(2).padStart(colWidth)} ${s.min.toFixed(2).padStart(colWidth)} ${s.max.toFixed(2).padStart(colWidth)} ${s.p50.toFixed(2).padStart(colWidth)} ${s.p95.toFixed(2).padStart(colWidth)}`,\n );\n }\n\n const durationSec = (result.duration / 1000).toFixed(1);\n const costStr = result.totalCost > 0 ? `$${result.totalCost.toFixed(2)}` : '$0.00';\n lines.push('');\n lines.push(\n ` Failures: ${result.summary.failures}/${result.summary.count} | Cost: ${costStr} | Duration: ${durationSec}s`,\n );\n\n return lines.join('\\n');\n}\n\nasync function runEvalCommand(args: string[]) {\n let outputPath: string | undefined;\n const paths: string[] = [];\n for (let i = 0; i < args.length; i++) {\n if (args[i] === '--output' && i + 1 < args.length) {\n outputPath = args[++i];\n } else if (!args[i].startsWith('--')) {\n paths.push(args[i]);\n }\n }\n\n if (paths.length === 0) {\n console.error('Error: No eval file path provided');\n process.exit(1);\n }\n\n const evalFiles: string[] = [];\n for (const p of paths) {\n evalFiles.push(...collectEvalFiles(p));\n }\n\n if (evalFiles.length === 0) {\n console.error('Error: No eval files found');\n process.exit(1);\n }\n\n const results: EvalResult[] = [];\n\n for (const filePath of evalFiles) {\n try {\n const mod = await import(path.resolve(filePath));\n const evalConfig: EvalConfig = mod.default ?? mod.config ?? mod;\n\n if (!evalConfig.workflow || !evalConfig.dataset || !evalConfig.scorers) {\n console.error(\n `Error: ${filePath} does not export a valid eval config (missing workflow, dataset, or scorers)`,\n );\n continue;\n }\n\n const executeWorkflow =\n mod.executeWorkflow ?? (async (input: unknown) => ({ output: input }));\n\n const result = await runEval(evalConfig, executeWorkflow, mod.provider);\n results.push(result);\n\n console.log('\\n' + formatTable(result) + '\\n');\n } catch (err) {\n console.error(\n `Error running eval ${filePath}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n if (outputPath && results.length > 0) {\n const output = results.length === 1 ? results[0] : results;\n // Ensure output directory exists\n const outputDir = path.dirname(path.resolve(outputPath));\n await mkdir(outputDir, { recursive: true });\n await writeFileAsync(outputPath, JSON.stringify(output, null, 2), 'utf-8');\n console.log(`Results saved to ${outputPath}`);\n }\n}\n\nmain().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n","import type { EvalResult, EvalComparison, EvalRegression, EvalImprovement } from './types.js';\n\nfunction round(n: number): number {\n return Math.round(n * 100) / 100;\n}\n\nexport function evalCompare(baseline: EvalResult, candidate: EvalResult): EvalComparison {\n if (baseline.dataset !== candidate.dataset) {\n throw new Error(\n `Cannot compare evals from different datasets: \"${baseline.dataset}\" vs \"${candidate.dataset}\"`,\n );\n }\n\n const baselineScorerNames = Object.keys(baseline.summary.scorers).sort();\n const candidateScorerNames = Object.keys(candidate.summary.scorers).sort();\n if (JSON.stringify(baselineScorerNames) !== JSON.stringify(candidateScorerNames)) {\n throw new Error(`Cannot compare evals with different scorers`);\n }\n\n const scorers: EvalComparison['scorers'] = {};\n for (const name of baselineScorerNames) {\n const bMean = baseline.summary.scorers[name].mean;\n const cMean = candidate.summary.scorers[name].mean;\n const delta = round(cMean - bMean);\n const deltaPercent = bMean > 0 ? round((delta / bMean) * 100) : 0;\n scorers[name] = { baselineMean: bMean, candidateMean: cMean, delta, deltaPercent };\n }\n\n const regressions: EvalRegression[] = [];\n const improvements: EvalImprovement[] = [];\n\n const minLength = Math.min(baseline.items.length, candidate.items.length);\n for (let i = 0; i < minLength; i++) {\n const bItem = baseline.items[i];\n const cItem = candidate.items[i];\n if (bItem.error || cItem.error) continue;\n for (const name of baselineScorerNames) {\n const bScore = bItem.scores[name];\n const cScore = cItem.scores[name];\n if (bScore === undefined || cScore === undefined || bScore < 0 || cScore < 0) continue;\n const delta = round(cScore - bScore);\n if (delta < -0.1)\n regressions.push({\n input: bItem.input,\n scorer: name,\n baselineScore: bScore,\n candidateScore: cScore,\n delta,\n });\n else if (delta > 0.1)\n improvements.push({\n input: bItem.input,\n scorer: name,\n baselineScore: bScore,\n candidateScore: cScore,\n delta,\n });\n }\n }\n\n const parts: string[] = [];\n for (const name of baselineScorerNames) {\n const s = scorers[name];\n if (Math.abs(s.delta) > 0.001) {\n const direction = s.delta > 0 ? 'improves' : 'regresses';\n const sign = s.delta > 0 ? '+' : '';\n parts.push(\n `'${name}' ${direction} by ${sign}${s.deltaPercent.toFixed(1)}% (${s.baselineMean.toFixed(2)} -> ${s.candidateMean.toFixed(2)})`,\n );\n }\n }\n const summaryStr = `candidate ${parts.length > 0 ? parts.join(', ') : 'no significant changes'} with ${regressions.length} regressions and ${improvements.length} improvements`;\n\n return {\n baseline: { id: baseline.id, metadata: baseline.metadata },\n candidate: { id: candidate.id, metadata: candidate.metadata },\n scorers,\n regressions,\n improvements,\n summary: summaryStr,\n };\n}\n","import type { EvalConfig, EvalResult, EvalItem, EvalSummary } from './types.js';\nimport { randomUUID } from 'node:crypto';\n\nfunction computeStats(scores: number[]): {\n mean: number;\n min: number;\n max: number;\n p50: number;\n p95: number;\n} {\n if (scores.length === 0) return { mean: 0, min: 0, max: 0, p50: 0, p95: 0 };\n const sorted = [...scores].sort((a, b) => a - b);\n const mean = sorted.reduce((a, b) => a + b, 0) / sorted.length;\n const min = sorted[0];\n const max = sorted[sorted.length - 1];\n const p50 = sorted[Math.floor(sorted.length * 0.5)];\n const p95 = sorted[Math.floor(sorted.length * 0.95)];\n return { mean: round(mean), min: round(min), max: round(max), p50: round(p50), p95: round(p95) };\n}\n\nfunction round(n: number): number {\n return Math.round(n * 1000) / 1000;\n}\n\nfunction parseCost(cost: string): number {\n const match = cost.match(/^\\$?([\\d.]+)$/);\n if (!match) throw new Error(`Invalid cost format: \"${cost}\"`);\n return parseFloat(match[1]);\n}\n\n/** Minimal provider interface for LLM scoring (avoids depending on core axl package). */\ntype LlmScorerProvider = {\n chat(\n messages: { role: string; content: string }[],\n options: { model: string; temperature?: number },\n ): Promise<{ content: string }>;\n};\n\nexport async function runEval(\n config: EvalConfig,\n executeWorkflow: (\n input: unknown,\n runtime?: unknown,\n ) => Promise<{ output: unknown; cost?: number }>,\n provider?: LlmScorerProvider,\n runtime?: unknown,\n): Promise<EvalResult> {\n const startTime = Date.now();\n const id = randomUUID();\n const items = await config.dataset.getItems();\n const concurrency = config.concurrency ?? 5;\n const budgetLimit = config.budget ? parseCost(config.budget) : undefined;\n\n if (provider) {\n for (const scorer of config.scorers) {\n if (scorer.isLlm) {\n (scorer as unknown as { _provider: LlmScorerProvider })._provider = provider;\n }\n }\n }\n\n const evalItems: EvalItem[] = [];\n let totalCost = 0;\n let budgetExceeded = false;\n\n async function processItem(item: (typeof items)[0]): Promise<void> {\n if (budgetExceeded) {\n evalItems.push({\n input: item.input,\n annotations: item.annotations,\n output: null,\n error: 'Budget exceeded',\n scores: {},\n });\n return;\n }\n\n const evalItem: EvalItem = {\n input: item.input,\n annotations: item.annotations,\n output: null,\n scores: {},\n };\n try {\n const result = await executeWorkflow(item.input, runtime);\n evalItem.output = result.output;\n if (result.cost != null) {\n totalCost += result.cost;\n }\n } catch (err) {\n evalItem.error = err instanceof Error ? err.message : String(err);\n evalItems.push(evalItem);\n return;\n }\n\n if (budgetLimit != null && totalCost > budgetLimit) {\n budgetExceeded = true;\n }\n\n for (const scorer of config.scorers) {\n try {\n const score = await scorer.score(evalItem.output, item.input, item.annotations);\n if (score < 0 || score > 1) {\n if (!evalItem.errors) evalItem.errors = [];\n evalItem.errors.push(\n `Scorer \"${scorer.name}\" returned out-of-range score ${score} for input ${JSON.stringify(item.input)}`,\n );\n evalItem.scores[scorer.name] = -1;\n } else {\n evalItem.scores[scorer.name] = round(score);\n }\n } catch (err) {\n if (!evalItem.errors) evalItem.errors = [];\n evalItem.errors.push(\n `Scorer \"${scorer.name}\" threw: ${err instanceof Error ? err.message : String(err)}`,\n );\n evalItem.scores[scorer.name] = -1;\n }\n }\n evalItems.push(evalItem);\n }\n\n let index = 0;\n async function runNext(): Promise<void> {\n while (index < items.length) {\n const currentIndex = index++;\n await processItem(items[currentIndex]);\n }\n }\n\n const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => runNext());\n await Promise.all(workers);\n\n const failures = evalItems.filter((i) => i.error).length;\n const scorerNames = config.scorers.map((s) => s.name);\n const scorerStats: EvalSummary['scorers'] = {};\n for (const name of scorerNames) {\n const scores = evalItems\n .filter((i) => !i.error && i.scores[name] !== undefined && i.scores[name] >= 0)\n .map((i) => i.scores[name]);\n scorerStats[name] = computeStats(scores);\n }\n\n return {\n id,\n workflow: config.workflow,\n dataset: config.dataset.name,\n metadata: config.metadata ?? {},\n timestamp: new Date().toISOString(),\n totalCost,\n duration: Date.now() - startTime,\n items: evalItems,\n summary: { count: items.length, failures, scorers: scorerStats },\n };\n}\n"],"mappings":"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","names":["round","readFileAsync","writeFileAsync"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/compare.ts","../src/runner.ts","../src/cli-utils.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { readdirSync, statSync } from 'node:fs';\nimport { readFile as readFileAsync, writeFile as writeFileAsync, mkdir } from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { AxlRuntime } from '@axlsdk/axl';\nimport { evalCompare } from './compare.js';\nimport { runEval } from './runner.js';\nimport type { EvalConfig, EvalResult } from './types.js';\nimport {\n findConfig,\n needsEsmForcing,\n needsTsxLoader,\n resolveRuntime,\n ensureTsxLoader,\n forceEsmForConfig,\n registerConditions,\n CONFIG_CANDIDATES,\n} from './cli-utils.js';\n\nconst KNOWN_FLAGS = new Set(['--output', '--config', '--conditions', '--fail-on-regression']);\n\nasync function main() {\n const args = process.argv.slice(2);\n\n if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {\n console.log(`\nUsage:\n axl-eval <path> Run eval file(s)\n axl-eval <path> --output <file> Save results to JSON\n axl-eval <path> --config <file> Use config file for runtime\n axl-eval <path> --conditions <list> Node.js import conditions (comma-separated)\n axl-eval compare <a> <b> Compare two eval result files\n axl-eval compare <a> <b> --fail-on-regression Exit 1 if regressions\n\nConfig auto-detection (when --config is not specified):\n ${CONFIG_CANDIDATES.join(' -> ')}\n\nWhen a config is found, the exported AxlRuntime is passed to executeWorkflow\nand cost is tracked automatically via runtime.trackCost().\nWhen no config is found, a bare AxlRuntime is created (providers from env vars).\n`);\n process.exit(0);\n }\n\n if (args[0] === 'compare') {\n await runCompare(args.slice(1));\n return;\n }\n\n await runEvalCommand(args);\n}\n\nasync function runCompare(args: string[]) {\n const failOnRegression = args.includes('--fail-on-regression');\n const files = args.filter((a) => !a.startsWith('--'));\n\n if (files.length !== 2) {\n console.error('Usage: axl-eval compare <baseline.json> <candidate.json>');\n process.exit(1);\n }\n\n const baseline: EvalResult = JSON.parse(await readFileAsync(files[0], 'utf-8'));\n const candidate: EvalResult = JSON.parse(await readFileAsync(files[1], 'utf-8'));\n const comparison = evalCompare(baseline, candidate);\n\n console.log(\n `\\nCompare: baseline (${comparison.baseline.id.slice(0, 8)}) -> candidate (${comparison.candidate.id.slice(0, 8)})\\n`,\n );\n\n const scorerNames = Object.keys(comparison.scorers);\n const maxNameLen = Math.max(...scorerNames.map((n) => n.length), 6);\n\n console.log(` ${'Scorer'.padEnd(maxNameLen)} Baseline Candidate Delta Change`);\n console.log(` ${''.padEnd(maxNameLen, '-')} -------- --------- -------- ------`);\n\n for (const name of scorerNames) {\n const s = comparison.scorers[name];\n const sign = s.delta > 0 ? '+' : '';\n console.log(\n ` ${name.padEnd(maxNameLen)} ${s.baselineMean.toFixed(3).padStart(8)} ${s.candidateMean.toFixed(3).padStart(9)} ${(sign + s.delta.toFixed(3)).padStart(8)} ${(sign + s.deltaPercent.toFixed(1) + '%').padStart(6)}`,\n );\n }\n\n const stable = Math.max(\n 0,\n baseline.items.length - comparison.regressions.length - comparison.improvements.length,\n );\n console.log(\n `\\n Regressions: ${comparison.regressions.length} | Improvements: ${comparison.improvements.length} | Stable: ${stable}\\n`,\n );\n\n if (failOnRegression && comparison.regressions.length > 0) {\n process.exit(1);\n }\n}\n\nfunction collectEvalFiles(p: string): string[] {\n const resolved = path.resolve(p);\n try {\n const stat = statSync(resolved);\n if (stat.isDirectory()) {\n const entries = readdirSync(resolved);\n return entries\n .filter((e) => /\\.eval\\.[mc]?[jt]sx?$/.test(e))\n .map((e) => path.join(resolved, e));\n }\n return [resolved];\n } catch {\n return [resolved];\n }\n}\n\nfunction formatTable(result: EvalResult): string {\n const lines: string[] = [];\n const scorerNames = Object.keys(result.summary.scorers);\n const maxNameLen = Math.max(...scorerNames.map((n) => n.length), 'Scorer'.length);\n const colWidth = 8;\n\n lines.push(`Eval: ${result.workflow} x ${result.dataset} (${result.summary.count} items)`);\n lines.push(\n ` ${'Scorer'.padEnd(maxNameLen)} ${'Mean'.padStart(colWidth)} ${'Min'.padStart(colWidth)} ${'Max'.padStart(colWidth)} ${'p50'.padStart(colWidth)} ${'p95'.padStart(colWidth)}`,\n );\n\n const ruleLen = maxNameLen + 2 + (colWidth + 2) * 5;\n lines.push(' ' + '\\u2500'.repeat(ruleLen));\n\n for (const name of scorerNames) {\n const s = result.summary.scorers[name];\n lines.push(\n ` ${name.padEnd(maxNameLen)} ${s.mean.toFixed(2).padStart(colWidth)} ${s.min.toFixed(2).padStart(colWidth)} ${s.max.toFixed(2).padStart(colWidth)} ${s.p50.toFixed(2).padStart(colWidth)} ${s.p95.toFixed(2).padStart(colWidth)}`,\n );\n }\n\n const durationSec = (result.duration / 1000).toFixed(1);\n const costStr = result.totalCost > 0 ? `$${result.totalCost.toFixed(2)}` : '$0.00';\n lines.push('');\n lines.push(\n ` Failures: ${result.summary.failures}/${result.summary.count} | Cost: ${costStr} | Duration: ${durationSec}s`,\n );\n\n return lines.join('\\n');\n}\n\n// ── Runtime resolution ─────────────────────────────────────────────\n\nasync function resolveRuntimeFromConfig(configPath: string): Promise<AxlRuntime> {\n // Register tsx loader for TypeScript config files\n if (needsTsxLoader(configPath)) {\n await ensureTsxLoader();\n }\n\n // Force ESM format for .ts/.tsx files so top-level await works\n if (needsEsmForcing(configPath)) {\n await forceEsmForConfig(configPath);\n }\n\n try {\n const mod = await import(pathToFileURL(configPath).href);\n const runtime = resolveRuntime(mod) as AxlRuntime;\n\n if (!runtime || typeof runtime.execute !== 'function') {\n console.error(`Config must export a default AxlRuntime instance.`);\n if (runtime) {\n const keys = Object.keys(runtime as object)\n .slice(0, 5)\n .join(', ');\n console.error(` Got: ${typeof runtime}${keys ? ` with keys: { ${keys} }` : ''}`);\n }\n console.error(\n `Example:\\n import { AxlRuntime } from '@axlsdk/axl';\\n export default new AxlRuntime({ ... });`,\n );\n process.exit(1);\n }\n\n return runtime;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (\n /Cannot use import statement|Unexpected reserved word|top-level await|exports is not defined/.test(\n msg,\n )\n ) {\n const ext = path.extname(configPath);\n console.error(`[axl-eval] Config failed to load due to a CJS/ESM compatibility issue.`);\n if (ext === '.ts' || ext === '.tsx') {\n const mtsPath = configPath.slice(0, -ext.length) + '.mts';\n console.error(\n ` Tip: rename to .mts to force ESM format:\\n` + ` mv ${configPath} ${mtsPath}`,\n );\n } else {\n console.error(` Tip: add \"type\": \"module\" to your package.json.`);\n }\n console.error();\n }\n console.error(`Failed to load config:`, err);\n process.exit(1);\n }\n}\n\nasync function getRuntime(configArg?: string, conditions?: string[]): Promise<AxlRuntime> {\n // Register import conditions before any config loading\n if (conditions && conditions.length > 0) {\n await registerConditions(conditions);\n }\n\n // 1. Explicit --config\n if (configArg) {\n const configPath = path.resolve(process.cwd(), configArg);\n const stat = statSync(configPath, { throwIfNoEntry: false });\n if (!stat?.isFile()) {\n console.error(`Config file not found: ${configPath}`);\n process.exit(1);\n }\n console.error(`[axl-eval] Loading config from ${configPath}`);\n return resolveRuntimeFromConfig(configPath);\n }\n\n // 2. Auto-detect\n const found = findConfig(process.cwd());\n if (found) {\n console.error(`[axl-eval] Auto-detected config: ${found}`);\n return resolveRuntimeFromConfig(found);\n }\n\n // 3. Bare runtime (providers from env vars)\n const { AxlRuntime } = await import('@axlsdk/axl');\n return new AxlRuntime();\n}\n\n// ── Arg parsing ────────────────────────────────────────────────────\n\nfunction parseEvalArgs(args: string[]): {\n outputPath?: string;\n configArg?: string;\n conditions: string[];\n paths: string[];\n} {\n let outputPath: string | undefined;\n let configArg: string | undefined;\n let conditions: string[] = [];\n const paths: string[] = [];\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === '--output' || arg === '--config' || arg === '--conditions') {\n if (i + 1 >= args.length) {\n console.error(`Error: ${arg} requires a value`);\n process.exit(1);\n }\n const value = args[++i];\n if (arg === '--output') outputPath = value;\n else if (arg === '--config') configArg = value;\n else\n conditions = value\n .split(',')\n .map((c) => c.trim())\n .filter(Boolean);\n } else if (arg.startsWith('--')) {\n if (!KNOWN_FLAGS.has(arg)) {\n console.error(`Unknown flag: ${arg}`);\n process.exit(1);\n }\n } else {\n paths.push(arg);\n }\n }\n\n return { outputPath, configArg, conditions, paths };\n}\n\n// ── Main eval command ──────────────────────────────────────────────\n\nasync function runEvalCommand(args: string[]) {\n const { outputPath, configArg, conditions, paths } = parseEvalArgs(args);\n\n if (paths.length === 0) {\n console.error('Error: No eval file path provided');\n process.exit(1);\n }\n\n const evalFiles: string[] = [];\n for (const p of paths) {\n evalFiles.push(...collectEvalFiles(p));\n }\n\n if (evalFiles.length === 0) {\n console.error('Error: No eval files found');\n process.exit(1);\n }\n\n // Register tsx for TypeScript eval files (before config loading, which may also register tsx)\n if (evalFiles.some((f) => /\\.[mc]?tsx?$/.test(f))) {\n await ensureTsxLoader();\n }\n\n const runtime = await getRuntime(configArg, conditions);\n const results: EvalResult[] = [];\n\n try {\n for (const filePath of evalFiles) {\n try {\n const mod = await import(pathToFileURL(path.resolve(filePath)).href);\n const evalConfig: EvalConfig = mod.default ?? mod.config ?? mod;\n\n if (!evalConfig.workflow || !evalConfig.dataset || !evalConfig.scorers) {\n console.error(\n `Error: ${filePath} does not export a valid eval config (missing workflow, dataset, or scorers)`,\n );\n continue;\n }\n\n // Resolve executeWorkflow: custom export > registered workflow > passthrough\n let executeWorkflow: (\n input: unknown,\n rt?: unknown,\n ) => Promise<{ output: unknown; cost?: number }>;\n\n if (mod.executeWorkflow) {\n // Wrap custom executeWorkflow with trackCost for automatic cost attribution\n executeWorkflow = async (input, rt) => {\n const { result, cost: trackedCost } = await runtime.trackCost(async () => {\n return mod.executeWorkflow(input, rt);\n });\n return { output: result.output, cost: result.cost ?? trackedCost };\n };\n } else if (runtime.getWorkflow(evalConfig.workflow)) {\n // No executeWorkflow exported but workflow is registered — use runtime.execute()\n executeWorkflow = async (input) => {\n const { result, cost } = await runtime.trackCost(async () => {\n return runtime.execute(evalConfig.workflow, input);\n });\n return { output: result, cost };\n };\n } else {\n console.warn(\n `[axl-eval] Warning: ${filePath} does not export executeWorkflow — using input passthrough`,\n );\n executeWorkflow = async (input) => ({ output: input });\n }\n\n const result = await runEval(evalConfig, executeWorkflow, mod.provider, runtime);\n results.push(result);\n\n console.log('\\n' + formatTable(result) + '\\n');\n } catch (err) {\n console.error(\n `Error running eval ${filePath}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n if (outputPath && results.length > 0) {\n const output = results.length === 1 ? results[0] : results;\n const outputDir = path.dirname(path.resolve(outputPath));\n await mkdir(outputDir, { recursive: true });\n await writeFileAsync(outputPath, JSON.stringify(output, null, 2), 'utf-8');\n console.log(`Results saved to ${outputPath}`);\n }\n } finally {\n await runtime.shutdown().catch(() => {});\n }\n\n // Exit with non-zero code if no evals succeeded\n if (results.length === 0) {\n process.exit(1);\n }\n}\n\nmain().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n","import type { EvalResult, EvalComparison, EvalRegression, EvalImprovement } from './types.js';\n\nfunction round(n: number): number {\n return Math.round(n * 100) / 100;\n}\n\nexport function evalCompare(baseline: EvalResult, candidate: EvalResult): EvalComparison {\n if (baseline.dataset !== candidate.dataset) {\n throw new Error(\n `Cannot compare evals from different datasets: \"${baseline.dataset}\" vs \"${candidate.dataset}\"`,\n );\n }\n\n const baselineScorerNames = Object.keys(baseline.summary.scorers).sort();\n const candidateScorerNames = Object.keys(candidate.summary.scorers).sort();\n if (JSON.stringify(baselineScorerNames) !== JSON.stringify(candidateScorerNames)) {\n throw new Error(`Cannot compare evals with different scorers`);\n }\n\n const scorers: EvalComparison['scorers'] = {};\n for (const name of baselineScorerNames) {\n const bMean = baseline.summary.scorers[name].mean;\n const cMean = candidate.summary.scorers[name].mean;\n const delta = round(cMean - bMean);\n const deltaPercent = bMean > 0 ? round((delta / bMean) * 100) : 0;\n scorers[name] = { baselineMean: bMean, candidateMean: cMean, delta, deltaPercent };\n }\n\n const regressions: EvalRegression[] = [];\n const improvements: EvalImprovement[] = [];\n\n const minLength = Math.min(baseline.items.length, candidate.items.length);\n for (let i = 0; i < minLength; i++) {\n const bItem = baseline.items[i];\n const cItem = candidate.items[i];\n if (bItem.error || cItem.error) continue;\n for (const name of baselineScorerNames) {\n const bScore = bItem.scores[name];\n const cScore = cItem.scores[name];\n if (bScore === undefined || cScore === undefined || bScore < 0 || cScore < 0) continue;\n const delta = round(cScore - bScore);\n if (delta < -0.1)\n regressions.push({\n input: bItem.input,\n scorer: name,\n baselineScore: bScore,\n candidateScore: cScore,\n delta,\n });\n else if (delta > 0.1)\n improvements.push({\n input: bItem.input,\n scorer: name,\n baselineScore: bScore,\n candidateScore: cScore,\n delta,\n });\n }\n }\n\n const parts: string[] = [];\n for (const name of baselineScorerNames) {\n const s = scorers[name];\n if (Math.abs(s.delta) > 0.001) {\n const direction = s.delta > 0 ? 'improves' : 'regresses';\n const sign = s.delta > 0 ? '+' : '';\n parts.push(\n `'${name}' ${direction} by ${sign}${s.deltaPercent.toFixed(1)}% (${s.baselineMean.toFixed(2)} -> ${s.candidateMean.toFixed(2)})`,\n );\n }\n }\n const summaryStr = `candidate ${parts.length > 0 ? parts.join(', ') : 'no significant changes'} with ${regressions.length} regressions and ${improvements.length} improvements`;\n\n return {\n baseline: { id: baseline.id, metadata: baseline.metadata },\n candidate: { id: candidate.id, metadata: candidate.metadata },\n scorers,\n regressions,\n improvements,\n summary: summaryStr,\n };\n}\n","import type { AxlRuntime } from '@axlsdk/axl';\nimport type { EvalConfig, EvalResult, EvalItem, EvalSummary } from './types.js';\nimport { randomUUID } from 'node:crypto';\n\nfunction computeStats(scores: number[]): {\n mean: number;\n min: number;\n max: number;\n p50: number;\n p95: number;\n} {\n if (scores.length === 0) return { mean: 0, min: 0, max: 0, p50: 0, p95: 0 };\n const sorted = [...scores].sort((a, b) => a - b);\n const mean = sorted.reduce((a, b) => a + b, 0) / sorted.length;\n const min = sorted[0];\n const max = sorted[sorted.length - 1];\n const p50 = sorted[Math.floor(sorted.length * 0.5)];\n const p95 = sorted[Math.floor(sorted.length * 0.95)];\n return { mean: round(mean), min: round(min), max: round(max), p50: round(p50), p95: round(p95) };\n}\n\nfunction round(n: number): number {\n return Math.round(n * 1000) / 1000;\n}\n\nfunction parseCost(cost: string): number {\n const match = cost.match(/^\\$?([\\d.]+)$/);\n if (!match) throw new Error(`Invalid cost format: \"${cost}\"`);\n return parseFloat(match[1]);\n}\n\n/** Minimal provider interface for LLM scoring (avoids depending on core axl package). */\ntype LlmScorerProvider = {\n chat(\n messages: { role: string; content: string }[],\n options: { model: string; temperature?: number },\n ): Promise<{ content: string }>;\n};\n\nexport async function runEval(\n config: EvalConfig,\n executeWorkflow: (\n input: unknown,\n runtime: AxlRuntime,\n ) => Promise<{ output: unknown; cost?: number }>,\n provider: LlmScorerProvider | undefined,\n runtime: AxlRuntime,\n): Promise<EvalResult> {\n const startTime = Date.now();\n const id = randomUUID();\n const items = await config.dataset.getItems();\n const concurrency = config.concurrency ?? 5;\n const budgetLimit = config.budget ? parseCost(config.budget) : undefined;\n\n if (provider) {\n for (const scorer of config.scorers) {\n if (scorer.isLlm) {\n (scorer as unknown as { _provider: LlmScorerProvider })._provider = provider;\n }\n }\n }\n\n const evalItems: EvalItem[] = [];\n let totalCost = 0;\n let budgetExceeded = false;\n\n async function processItem(item: (typeof items)[0]): Promise<void> {\n if (budgetExceeded) {\n evalItems.push({\n input: item.input,\n annotations: item.annotations,\n output: null,\n error: 'Budget exceeded',\n scores: {},\n });\n return;\n }\n\n const evalItem: EvalItem = {\n input: item.input,\n annotations: item.annotations,\n output: null,\n scores: {},\n };\n try {\n const result = await executeWorkflow(item.input, runtime);\n evalItem.output = result.output;\n if (result.cost != null) {\n totalCost += result.cost;\n }\n } catch (err) {\n evalItem.error = err instanceof Error ? err.message : String(err);\n evalItems.push(evalItem);\n return;\n }\n\n if (budgetLimit != null && totalCost > budgetLimit) {\n budgetExceeded = true;\n }\n\n for (const scorer of config.scorers) {\n try {\n const score = await scorer.score(evalItem.output, item.input, item.annotations);\n if (score < 0 || score > 1) {\n if (!evalItem.errors) evalItem.errors = [];\n evalItem.errors.push(\n `Scorer \"${scorer.name}\" returned out-of-range score ${score} for input ${JSON.stringify(item.input)}`,\n );\n evalItem.scores[scorer.name] = -1;\n } else {\n evalItem.scores[scorer.name] = round(score);\n }\n } catch (err) {\n if (!evalItem.errors) evalItem.errors = [];\n evalItem.errors.push(\n `Scorer \"${scorer.name}\" threw: ${err instanceof Error ? err.message : String(err)}`,\n );\n evalItem.scores[scorer.name] = -1;\n }\n }\n evalItems.push(evalItem);\n }\n\n let index = 0;\n async function runNext(): Promise<void> {\n while (index < items.length) {\n const currentIndex = index++;\n await processItem(items[currentIndex]);\n }\n }\n\n const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => runNext());\n await Promise.all(workers);\n\n const failures = evalItems.filter((i) => i.error).length;\n const scorerNames = config.scorers.map((s) => s.name);\n const scorerStats: EvalSummary['scorers'] = {};\n for (const name of scorerNames) {\n const scores = evalItems\n .filter((i) => !i.error && i.scores[name] !== undefined && i.scores[name] >= 0)\n .map((i) => i.scores[name]);\n scorerStats[name] = computeStats(scores);\n }\n\n return {\n id,\n workflow: config.workflow,\n dataset: config.dataset.name,\n metadata: config.metadata ?? {},\n timestamp: new Date().toISOString(),\n totalCost,\n duration: Date.now() - startTime,\n items: evalItems,\n summary: { count: items.length, failures, scorers: scorerStats },\n };\n}\n","/**\n * CLI utilities for config detection, runtime resolution, and loader registration.\n *\n * These are duplicated from @axlsdk/studio (cli-utils.ts, resolve-runtime.ts,\n * eval-loader.ts, cli.ts) because @axlsdk/eval cannot depend on @axlsdk/studio.\n * Keep in sync with the studio versions if either changes.\n */\n\nimport { resolve, extname } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { pathToFileURL } from 'node:url';\n\n// ── Config auto-detection ──────────────────────────────────────────\n\nexport const CONFIG_CANDIDATES = [\n 'axl.config.mts',\n 'axl.config.ts',\n 'axl.config.mjs',\n 'axl.config.js',\n];\n\nexport function findConfig(cwd: string): string | undefined {\n for (const name of CONFIG_CANDIDATES) {\n const p = resolve(cwd, name);\n if (existsSync(p)) return p;\n }\n return undefined;\n}\n\n// ── Extension helpers ──────────────────────────────────────────────\n\n/**\n * Returns true if the config path has an ambiguous TypeScript extension (.ts/.tsx)\n * that needs ESM forcing. Explicit extensions (.mts/.cts) are excluded.\n */\nexport function needsEsmForcing(configPath: string): boolean {\n const ext = extname(configPath);\n return ext === '.ts' || ext === '.tsx';\n}\n\n/** Returns true if the config path is a TypeScript file that needs tsx loader hooks. */\nexport function needsTsxLoader(configPath: string): boolean {\n return /\\.[mc]?tsx?$/.test(configPath);\n}\n\n// ── Runtime resolution ─────────────────────────────────────────────\n\n/**\n * Resolve the AxlRuntime from a dynamically imported config module.\n *\n * Module shapes handled:\n * - ESM `export default runtime` → mod.default is the runtime\n * - CJS compiled from `export default runtime` → mod.default.default is the runtime\n * - CJS `module.exports = runtime` → mod.default is the runtime\n * - Named `export { runtime }` → mod.runtime is the runtime\n */\nexport function resolveRuntime(mod: Record<string, unknown>): unknown {\n const def = mod.default as Record<string, unknown> | undefined;\n return def?.default ?? def ?? mod.runtime;\n}\n\n// ── Loader registration ────────────────────────────────────────────\n\nlet tsxRegistered = false;\n\nexport async function ensureTsxLoader(): Promise<void> {\n if (tsxRegistered) return;\n tsxRegistered = true;\n\n let loaded = false;\n try {\n // @ts-expect-error — tsx is an optional runtime dependency\n const tsxEsm = await import('tsx/esm/api');\n tsxEsm.register();\n loaded = true;\n } catch {\n // ESM hook not available\n }\n try {\n // @ts-expect-error — tsx is an optional runtime dependency\n const tsxCjs = await import('tsx/cjs/api');\n tsxCjs.register();\n loaded = true;\n } catch {\n // CJS hook not available\n }\n if (!loaded) {\n console.warn(\n '[axl-eval] Warning: tsx is not installed. TypeScript files require tsx.\\n' +\n ' Install it with: npm install -D tsx',\n );\n }\n}\n\n/**\n * Force ESM format for a specific config file so top-level await works\n * regardless of the nearest package.json \"type\" field.\n */\nexport async function forceEsmForConfig(configPath: string): Promise<void> {\n try {\n const nodeModule = await import('node:module');\n const configUrl = pathToFileURL(configPath).href;\n const hookCode = [\n `export async function resolve(specifier, context, nextResolve) {`,\n ` const result = await nextResolve(specifier, context);`,\n ` if (result.url === ${JSON.stringify(configUrl)}) result.format = 'module';`,\n ` return result;`,\n `}`,\n ].join('\\n');\n nodeModule.register(`data:text/javascript,${encodeURIComponent(hookCode)}`);\n } catch {\n // module.register() not available (Node < 20.6)\n }\n}\n\nexport async function registerConditions(conditions: string[]): Promise<void> {\n try {\n const nodeModule = await import('node:module');\n const hookCode = [\n `const extra = ${JSON.stringify(conditions)};`,\n `export async function resolve(specifier, context, nextResolve) {`,\n ` return nextResolve(specifier, {`,\n ` ...context,`,\n ` conditions: [...new Set([...context.conditions, ...extra])],`,\n ` });`,\n `}`,\n ].join('\\n');\n nodeModule.register(`data:text/javascript,${encodeURIComponent(hookCode)}`);\n } catch {\n console.warn('[axl-eval] Warning: --conditions requires Node.js 20.6+');\n }\n}\n"],"mappings":"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","names":["import_node_fs","import_node_url","round","readFileAsync","result","writeFileAsync"]}
package/dist/cli.js CHANGED
@@ -2,21 +2,118 @@
2
2
  import {
3
3
  evalCompare,
4
4
  runEval
5
- } from "./chunk-LMQJNZWT.js";
5
+ } from "./chunk-D7KCUS6H.js";
6
6
 
7
7
  // src/cli.ts
8
8
  import { readdirSync, statSync } from "fs";
9
9
  import { readFile as readFileAsync, writeFile as writeFileAsync, mkdir } from "fs/promises";
10
10
  import * as path from "path";
11
+ import { pathToFileURL as pathToFileURL2 } from "url";
12
+
13
+ // src/cli-utils.ts
14
+ import { resolve, extname } from "path";
15
+ import { existsSync } from "fs";
16
+ import { pathToFileURL } from "url";
17
+ var CONFIG_CANDIDATES = [
18
+ "axl.config.mts",
19
+ "axl.config.ts",
20
+ "axl.config.mjs",
21
+ "axl.config.js"
22
+ ];
23
+ function findConfig(cwd) {
24
+ for (const name of CONFIG_CANDIDATES) {
25
+ const p = resolve(cwd, name);
26
+ if (existsSync(p)) return p;
27
+ }
28
+ return void 0;
29
+ }
30
+ function needsEsmForcing(configPath) {
31
+ const ext = extname(configPath);
32
+ return ext === ".ts" || ext === ".tsx";
33
+ }
34
+ function needsTsxLoader(configPath) {
35
+ return /\.[mc]?tsx?$/.test(configPath);
36
+ }
37
+ function resolveRuntime(mod) {
38
+ const def = mod.default;
39
+ return def?.default ?? def ?? mod.runtime;
40
+ }
41
+ var tsxRegistered = false;
42
+ async function ensureTsxLoader() {
43
+ if (tsxRegistered) return;
44
+ tsxRegistered = true;
45
+ let loaded = false;
46
+ try {
47
+ const tsxEsm = await import("tsx/esm/api");
48
+ tsxEsm.register();
49
+ loaded = true;
50
+ } catch {
51
+ }
52
+ try {
53
+ const tsxCjs = await import("tsx/cjs/api");
54
+ tsxCjs.register();
55
+ loaded = true;
56
+ } catch {
57
+ }
58
+ if (!loaded) {
59
+ console.warn(
60
+ "[axl-eval] Warning: tsx is not installed. TypeScript files require tsx.\n Install it with: npm install -D tsx"
61
+ );
62
+ }
63
+ }
64
+ async function forceEsmForConfig(configPath) {
65
+ try {
66
+ const nodeModule = await import("module");
67
+ const configUrl = pathToFileURL(configPath).href;
68
+ const hookCode = [
69
+ `export async function resolve(specifier, context, nextResolve) {`,
70
+ ` const result = await nextResolve(specifier, context);`,
71
+ ` if (result.url === ${JSON.stringify(configUrl)}) result.format = 'module';`,
72
+ ` return result;`,
73
+ `}`
74
+ ].join("\n");
75
+ nodeModule.register(`data:text/javascript,${encodeURIComponent(hookCode)}`);
76
+ } catch {
77
+ }
78
+ }
79
+ async function registerConditions(conditions) {
80
+ try {
81
+ const nodeModule = await import("module");
82
+ const hookCode = [
83
+ `const extra = ${JSON.stringify(conditions)};`,
84
+ `export async function resolve(specifier, context, nextResolve) {`,
85
+ ` return nextResolve(specifier, {`,
86
+ ` ...context,`,
87
+ ` conditions: [...new Set([...context.conditions, ...extra])],`,
88
+ ` });`,
89
+ `}`
90
+ ].join("\n");
91
+ nodeModule.register(`data:text/javascript,${encodeURIComponent(hookCode)}`);
92
+ } catch {
93
+ console.warn("[axl-eval] Warning: --conditions requires Node.js 20.6+");
94
+ }
95
+ }
96
+
97
+ // src/cli.ts
98
+ var KNOWN_FLAGS = /* @__PURE__ */ new Set(["--output", "--config", "--conditions", "--fail-on-regression"]);
11
99
  async function main() {
12
100
  const args = process.argv.slice(2);
13
- if (args.length === 0 || args[0] === "--help") {
101
+ if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
14
102
  console.log(`
15
103
  Usage:
16
- npx axl eval <path> Run eval file(s)
17
- npx axl eval <path> --output <f> Run eval and save results to JSON
18
- npx axl eval compare <a> <b> Compare two eval result files
19
- npx axl eval compare <a> <b> --fail-on-regression Exit 1 if regressions
104
+ axl-eval <path> Run eval file(s)
105
+ axl-eval <path> --output <file> Save results to JSON
106
+ axl-eval <path> --config <file> Use config file for runtime
107
+ axl-eval <path> --conditions <list> Node.js import conditions (comma-separated)
108
+ axl-eval compare <a> <b> Compare two eval result files
109
+ axl-eval compare <a> <b> --fail-on-regression Exit 1 if regressions
110
+
111
+ Config auto-detection (when --config is not specified):
112
+ ${CONFIG_CANDIDATES.join(" -> ")}
113
+
114
+ When a config is found, the exported AxlRuntime is passed to executeWorkflow
115
+ and cost is tracked automatically via runtime.trackCost().
116
+ When no config is found, a bare AxlRuntime is created (providers from env vars).
20
117
  `);
21
118
  process.exit(0);
22
119
  }
@@ -30,7 +127,7 @@ async function runCompare(args) {
30
127
  const failOnRegression = args.includes("--fail-on-regression");
31
128
  const files = args.filter((a) => !a.startsWith("--"));
32
129
  if (files.length !== 2) {
33
- console.error("Usage: npx axl eval compare <baseline.json> <candidate.json>");
130
+ console.error("Usage: axl-eval compare <baseline.json> <candidate.json>");
34
131
  process.exit(1);
35
132
  }
36
133
  const baseline = JSON.parse(await readFileAsync(files[0], "utf-8"));
@@ -71,7 +168,7 @@ function collectEvalFiles(p) {
71
168
  const stat = statSync(resolved);
72
169
  if (stat.isDirectory()) {
73
170
  const entries = readdirSync(resolved);
74
- return entries.filter((e) => e.endsWith(".eval.ts") || e.endsWith(".eval.js")).map((e) => path.join(resolved, e));
171
+ return entries.filter((e) => /\.eval\.[mc]?[jt]sx?$/.test(e)).map((e) => path.join(resolved, e));
75
172
  }
76
173
  return [resolved];
77
174
  } catch {
@@ -103,16 +200,104 @@ function formatTable(result) {
103
200
  );
104
201
  return lines.join("\n");
105
202
  }
106
- async function runEvalCommand(args) {
203
+ async function resolveRuntimeFromConfig(configPath) {
204
+ if (needsTsxLoader(configPath)) {
205
+ await ensureTsxLoader();
206
+ }
207
+ if (needsEsmForcing(configPath)) {
208
+ await forceEsmForConfig(configPath);
209
+ }
210
+ try {
211
+ const mod = await import(pathToFileURL2(configPath).href);
212
+ const runtime = resolveRuntime(mod);
213
+ if (!runtime || typeof runtime.execute !== "function") {
214
+ console.error(`Config must export a default AxlRuntime instance.`);
215
+ if (runtime) {
216
+ const keys = Object.keys(runtime).slice(0, 5).join(", ");
217
+ console.error(` Got: ${typeof runtime}${keys ? ` with keys: { ${keys} }` : ""}`);
218
+ }
219
+ console.error(
220
+ `Example:
221
+ import { AxlRuntime } from '@axlsdk/axl';
222
+ export default new AxlRuntime({ ... });`
223
+ );
224
+ process.exit(1);
225
+ }
226
+ return runtime;
227
+ } catch (err) {
228
+ const msg = err instanceof Error ? err.message : String(err);
229
+ if (/Cannot use import statement|Unexpected reserved word|top-level await|exports is not defined/.test(
230
+ msg
231
+ )) {
232
+ const ext = path.extname(configPath);
233
+ console.error(`[axl-eval] Config failed to load due to a CJS/ESM compatibility issue.`);
234
+ if (ext === ".ts" || ext === ".tsx") {
235
+ const mtsPath = configPath.slice(0, -ext.length) + ".mts";
236
+ console.error(
237
+ ` Tip: rename to .mts to force ESM format:
238
+ mv ${configPath} ${mtsPath}`
239
+ );
240
+ } else {
241
+ console.error(` Tip: add "type": "module" to your package.json.`);
242
+ }
243
+ console.error();
244
+ }
245
+ console.error(`Failed to load config:`, err);
246
+ process.exit(1);
247
+ }
248
+ }
249
+ async function getRuntime(configArg, conditions) {
250
+ if (conditions && conditions.length > 0) {
251
+ await registerConditions(conditions);
252
+ }
253
+ if (configArg) {
254
+ const configPath = path.resolve(process.cwd(), configArg);
255
+ const stat = statSync(configPath, { throwIfNoEntry: false });
256
+ if (!stat?.isFile()) {
257
+ console.error(`Config file not found: ${configPath}`);
258
+ process.exit(1);
259
+ }
260
+ console.error(`[axl-eval] Loading config from ${configPath}`);
261
+ return resolveRuntimeFromConfig(configPath);
262
+ }
263
+ const found = findConfig(process.cwd());
264
+ if (found) {
265
+ console.error(`[axl-eval] Auto-detected config: ${found}`);
266
+ return resolveRuntimeFromConfig(found);
267
+ }
268
+ const { AxlRuntime } = await import("@axlsdk/axl");
269
+ return new AxlRuntime();
270
+ }
271
+ function parseEvalArgs(args) {
107
272
  let outputPath;
273
+ let configArg;
274
+ let conditions = [];
108
275
  const paths = [];
109
276
  for (let i = 0; i < args.length; i++) {
110
- if (args[i] === "--output" && i + 1 < args.length) {
111
- outputPath = args[++i];
112
- } else if (!args[i].startsWith("--")) {
113
- paths.push(args[i]);
277
+ const arg = args[i];
278
+ if (arg === "--output" || arg === "--config" || arg === "--conditions") {
279
+ if (i + 1 >= args.length) {
280
+ console.error(`Error: ${arg} requires a value`);
281
+ process.exit(1);
282
+ }
283
+ const value = args[++i];
284
+ if (arg === "--output") outputPath = value;
285
+ else if (arg === "--config") configArg = value;
286
+ else
287
+ conditions = value.split(",").map((c) => c.trim()).filter(Boolean);
288
+ } else if (arg.startsWith("--")) {
289
+ if (!KNOWN_FLAGS.has(arg)) {
290
+ console.error(`Unknown flag: ${arg}`);
291
+ process.exit(1);
292
+ }
293
+ } else {
294
+ paths.push(arg);
114
295
  }
115
296
  }
297
+ return { outputPath, configArg, conditions, paths };
298
+ }
299
+ async function runEvalCommand(args) {
300
+ const { outputPath, configArg, conditions, paths } = parseEvalArgs(args);
116
301
  if (paths.length === 0) {
117
302
  console.error("Error: No eval file path provided");
118
303
  process.exit(1);
@@ -125,33 +310,65 @@ async function runEvalCommand(args) {
125
310
  console.error("Error: No eval files found");
126
311
  process.exit(1);
127
312
  }
313
+ if (evalFiles.some((f) => /\.[mc]?tsx?$/.test(f))) {
314
+ await ensureTsxLoader();
315
+ }
316
+ const runtime = await getRuntime(configArg, conditions);
128
317
  const results = [];
129
- for (const filePath of evalFiles) {
130
- try {
131
- const mod = await import(path.resolve(filePath));
132
- const evalConfig = mod.default ?? mod.config ?? mod;
133
- if (!evalConfig.workflow || !evalConfig.dataset || !evalConfig.scorers) {
318
+ try {
319
+ for (const filePath of evalFiles) {
320
+ try {
321
+ const mod = await import(pathToFileURL2(path.resolve(filePath)).href);
322
+ const evalConfig = mod.default ?? mod.config ?? mod;
323
+ if (!evalConfig.workflow || !evalConfig.dataset || !evalConfig.scorers) {
324
+ console.error(
325
+ `Error: ${filePath} does not export a valid eval config (missing workflow, dataset, or scorers)`
326
+ );
327
+ continue;
328
+ }
329
+ let executeWorkflow;
330
+ if (mod.executeWorkflow) {
331
+ executeWorkflow = async (input, rt) => {
332
+ const { result: result2, cost: trackedCost } = await runtime.trackCost(async () => {
333
+ return mod.executeWorkflow(input, rt);
334
+ });
335
+ return { output: result2.output, cost: result2.cost ?? trackedCost };
336
+ };
337
+ } else if (runtime.getWorkflow(evalConfig.workflow)) {
338
+ executeWorkflow = async (input) => {
339
+ const { result: result2, cost } = await runtime.trackCost(async () => {
340
+ return runtime.execute(evalConfig.workflow, input);
341
+ });
342
+ return { output: result2, cost };
343
+ };
344
+ } else {
345
+ console.warn(
346
+ `[axl-eval] Warning: ${filePath} does not export executeWorkflow \u2014 using input passthrough`
347
+ );
348
+ executeWorkflow = async (input) => ({ output: input });
349
+ }
350
+ const result = await runEval(evalConfig, executeWorkflow, mod.provider, runtime);
351
+ results.push(result);
352
+ console.log("\n" + formatTable(result) + "\n");
353
+ } catch (err) {
134
354
  console.error(
135
- `Error: ${filePath} does not export a valid eval config (missing workflow, dataset, or scorers)`
355
+ `Error running eval ${filePath}: ${err instanceof Error ? err.message : String(err)}`
136
356
  );
137
- continue;
138
357
  }
139
- const executeWorkflow = mod.executeWorkflow ?? (async (input) => ({ output: input }));
140
- const result = await runEval(evalConfig, executeWorkflow, mod.provider);
141
- results.push(result);
142
- console.log("\n" + formatTable(result) + "\n");
143
- } catch (err) {
144
- console.error(
145
- `Error running eval ${filePath}: ${err instanceof Error ? err.message : String(err)}`
146
- );
147
358
  }
359
+ if (outputPath && results.length > 0) {
360
+ const output = results.length === 1 ? results[0] : results;
361
+ const outputDir = path.dirname(path.resolve(outputPath));
362
+ await mkdir(outputDir, { recursive: true });
363
+ await writeFileAsync(outputPath, JSON.stringify(output, null, 2), "utf-8");
364
+ console.log(`Results saved to ${outputPath}`);
365
+ }
366
+ } finally {
367
+ await runtime.shutdown().catch(() => {
368
+ });
148
369
  }
149
- if (outputPath && results.length > 0) {
150
- const output = results.length === 1 ? results[0] : results;
151
- const outputDir = path.dirname(path.resolve(outputPath));
152
- await mkdir(outputDir, { recursive: true });
153
- await writeFileAsync(outputPath, JSON.stringify(output, null, 2), "utf-8");
154
- console.log(`Results saved to ${outputPath}`);
370
+ if (results.length === 0) {
371
+ process.exit(1);
155
372
  }
156
373
  }
157
374
  main().catch((err) => {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { readdirSync, statSync } from 'node:fs';\nimport { readFile as readFileAsync, writeFile as writeFileAsync, mkdir } from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { evalCompare } from './compare.js';\nimport { runEval } from './runner.js';\nimport type { EvalConfig, EvalResult } from './types.js';\n\nasync function main() {\n const args = process.argv.slice(2);\n\n if (args.length === 0 || args[0] === '--help') {\n console.log(`\nUsage:\n npx axl eval <path> Run eval file(s)\n npx axl eval <path> --output <f> Run eval and save results to JSON\n npx axl eval compare <a> <b> Compare two eval result files\n npx axl eval compare <a> <b> --fail-on-regression Exit 1 if regressions\n`);\n process.exit(0);\n }\n\n if (args[0] === 'compare') {\n await runCompare(args.slice(1));\n return;\n }\n\n await runEvalCommand(args);\n}\n\nasync function runCompare(args: string[]) {\n const failOnRegression = args.includes('--fail-on-regression');\n const files = args.filter((a) => !a.startsWith('--'));\n\n if (files.length !== 2) {\n console.error('Usage: npx axl eval compare <baseline.json> <candidate.json>');\n process.exit(1);\n }\n\n const baseline: EvalResult = JSON.parse(await readFileAsync(files[0], 'utf-8'));\n const candidate: EvalResult = JSON.parse(await readFileAsync(files[1], 'utf-8'));\n const comparison = evalCompare(baseline, candidate);\n\n console.log(\n `\\nCompare: baseline (${comparison.baseline.id.slice(0, 8)}) -> candidate (${comparison.candidate.id.slice(0, 8)})\\n`,\n );\n\n const scorerNames = Object.keys(comparison.scorers);\n const maxNameLen = Math.max(...scorerNames.map((n) => n.length), 6);\n\n console.log(` ${'Scorer'.padEnd(maxNameLen)} Baseline Candidate Delta Change`);\n console.log(` ${''.padEnd(maxNameLen, '-')} -------- --------- -------- ------`);\n\n for (const name of scorerNames) {\n const s = comparison.scorers[name];\n const sign = s.delta > 0 ? '+' : '';\n console.log(\n ` ${name.padEnd(maxNameLen)} ${s.baselineMean.toFixed(3).padStart(8)} ${s.candidateMean.toFixed(3).padStart(9)} ${(sign + s.delta.toFixed(3)).padStart(8)} ${(sign + s.deltaPercent.toFixed(1) + '%').padStart(6)}`,\n );\n }\n\n const stable = Math.max(\n 0,\n baseline.items.length - comparison.regressions.length - comparison.improvements.length,\n );\n console.log(\n `\\n Regressions: ${comparison.regressions.length} | Improvements: ${comparison.improvements.length} | Stable: ${stable}\\n`,\n );\n\n if (failOnRegression && comparison.regressions.length > 0) {\n process.exit(1);\n }\n}\n\nfunction collectEvalFiles(p: string): string[] {\n const resolved = path.resolve(p);\n try {\n const stat = statSync(resolved);\n if (stat.isDirectory()) {\n const entries = readdirSync(resolved);\n return entries\n .filter((e) => e.endsWith('.eval.ts') || e.endsWith('.eval.js'))\n .map((e) => path.join(resolved, e));\n }\n return [resolved];\n } catch {\n return [resolved];\n }\n}\n\nfunction formatTable(result: EvalResult): string {\n const lines: string[] = [];\n const scorerNames = Object.keys(result.summary.scorers);\n const maxNameLen = Math.max(...scorerNames.map((n) => n.length), 'Scorer'.length);\n const colWidth = 8;\n\n lines.push(`Eval: ${result.workflow} x ${result.dataset} (${result.summary.count} items)`);\n lines.push(\n ` ${'Scorer'.padEnd(maxNameLen)} ${'Mean'.padStart(colWidth)} ${'Min'.padStart(colWidth)} ${'Max'.padStart(colWidth)} ${'p50'.padStart(colWidth)} ${'p95'.padStart(colWidth)}`,\n );\n\n const ruleLen = maxNameLen + 2 + (colWidth + 2) * 5;\n lines.push(' ' + '\\u2500'.repeat(ruleLen));\n\n for (const name of scorerNames) {\n const s = result.summary.scorers[name];\n lines.push(\n ` ${name.padEnd(maxNameLen)} ${s.mean.toFixed(2).padStart(colWidth)} ${s.min.toFixed(2).padStart(colWidth)} ${s.max.toFixed(2).padStart(colWidth)} ${s.p50.toFixed(2).padStart(colWidth)} ${s.p95.toFixed(2).padStart(colWidth)}`,\n );\n }\n\n const durationSec = (result.duration / 1000).toFixed(1);\n const costStr = result.totalCost > 0 ? `$${result.totalCost.toFixed(2)}` : '$0.00';\n lines.push('');\n lines.push(\n ` Failures: ${result.summary.failures}/${result.summary.count} | Cost: ${costStr} | Duration: ${durationSec}s`,\n );\n\n return lines.join('\\n');\n}\n\nasync function runEvalCommand(args: string[]) {\n let outputPath: string | undefined;\n const paths: string[] = [];\n for (let i = 0; i < args.length; i++) {\n if (args[i] === '--output' && i + 1 < args.length) {\n outputPath = args[++i];\n } else if (!args[i].startsWith('--')) {\n paths.push(args[i]);\n }\n }\n\n if (paths.length === 0) {\n console.error('Error: No eval file path provided');\n process.exit(1);\n }\n\n const evalFiles: string[] = [];\n for (const p of paths) {\n evalFiles.push(...collectEvalFiles(p));\n }\n\n if (evalFiles.length === 0) {\n console.error('Error: No eval files found');\n process.exit(1);\n }\n\n const results: EvalResult[] = [];\n\n for (const filePath of evalFiles) {\n try {\n const mod = await import(path.resolve(filePath));\n const evalConfig: EvalConfig = mod.default ?? mod.config ?? mod;\n\n if (!evalConfig.workflow || !evalConfig.dataset || !evalConfig.scorers) {\n console.error(\n `Error: ${filePath} does not export a valid eval config (missing workflow, dataset, or scorers)`,\n );\n continue;\n }\n\n const executeWorkflow =\n mod.executeWorkflow ?? (async (input: unknown) => ({ output: input }));\n\n const result = await runEval(evalConfig, executeWorkflow, mod.provider);\n results.push(result);\n\n console.log('\\n' + formatTable(result) + '\\n');\n } catch (err) {\n console.error(\n `Error running eval ${filePath}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n if (outputPath && results.length > 0) {\n const output = results.length === 1 ? results[0] : results;\n // Ensure output directory exists\n const outputDir = path.dirname(path.resolve(outputPath));\n await mkdir(outputDir, { recursive: true });\n await writeFileAsync(outputPath, JSON.stringify(output, null, 2), 'utf-8');\n console.log(`Results saved to ${outputPath}`);\n }\n}\n\nmain().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/cli-utils.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { readdirSync, statSync } from 'node:fs';\nimport { readFile as readFileAsync, writeFile as writeFileAsync, mkdir } from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { AxlRuntime } from '@axlsdk/axl';\nimport { evalCompare } from './compare.js';\nimport { runEval } from './runner.js';\nimport type { EvalConfig, EvalResult } from './types.js';\nimport {\n findConfig,\n needsEsmForcing,\n needsTsxLoader,\n resolveRuntime,\n ensureTsxLoader,\n forceEsmForConfig,\n registerConditions,\n CONFIG_CANDIDATES,\n} from './cli-utils.js';\n\nconst KNOWN_FLAGS = new Set(['--output', '--config', '--conditions', '--fail-on-regression']);\n\nasync function main() {\n const args = process.argv.slice(2);\n\n if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {\n console.log(`\nUsage:\n axl-eval <path> Run eval file(s)\n axl-eval <path> --output <file> Save results to JSON\n axl-eval <path> --config <file> Use config file for runtime\n axl-eval <path> --conditions <list> Node.js import conditions (comma-separated)\n axl-eval compare <a> <b> Compare two eval result files\n axl-eval compare <a> <b> --fail-on-regression Exit 1 if regressions\n\nConfig auto-detection (when --config is not specified):\n ${CONFIG_CANDIDATES.join(' -> ')}\n\nWhen a config is found, the exported AxlRuntime is passed to executeWorkflow\nand cost is tracked automatically via runtime.trackCost().\nWhen no config is found, a bare AxlRuntime is created (providers from env vars).\n`);\n process.exit(0);\n }\n\n if (args[0] === 'compare') {\n await runCompare(args.slice(1));\n return;\n }\n\n await runEvalCommand(args);\n}\n\nasync function runCompare(args: string[]) {\n const failOnRegression = args.includes('--fail-on-regression');\n const files = args.filter((a) => !a.startsWith('--'));\n\n if (files.length !== 2) {\n console.error('Usage: axl-eval compare <baseline.json> <candidate.json>');\n process.exit(1);\n }\n\n const baseline: EvalResult = JSON.parse(await readFileAsync(files[0], 'utf-8'));\n const candidate: EvalResult = JSON.parse(await readFileAsync(files[1], 'utf-8'));\n const comparison = evalCompare(baseline, candidate);\n\n console.log(\n `\\nCompare: baseline (${comparison.baseline.id.slice(0, 8)}) -> candidate (${comparison.candidate.id.slice(0, 8)})\\n`,\n );\n\n const scorerNames = Object.keys(comparison.scorers);\n const maxNameLen = Math.max(...scorerNames.map((n) => n.length), 6);\n\n console.log(` ${'Scorer'.padEnd(maxNameLen)} Baseline Candidate Delta Change`);\n console.log(` ${''.padEnd(maxNameLen, '-')} -------- --------- -------- ------`);\n\n for (const name of scorerNames) {\n const s = comparison.scorers[name];\n const sign = s.delta > 0 ? '+' : '';\n console.log(\n ` ${name.padEnd(maxNameLen)} ${s.baselineMean.toFixed(3).padStart(8)} ${s.candidateMean.toFixed(3).padStart(9)} ${(sign + s.delta.toFixed(3)).padStart(8)} ${(sign + s.deltaPercent.toFixed(1) + '%').padStart(6)}`,\n );\n }\n\n const stable = Math.max(\n 0,\n baseline.items.length - comparison.regressions.length - comparison.improvements.length,\n );\n console.log(\n `\\n Regressions: ${comparison.regressions.length} | Improvements: ${comparison.improvements.length} | Stable: ${stable}\\n`,\n );\n\n if (failOnRegression && comparison.regressions.length > 0) {\n process.exit(1);\n }\n}\n\nfunction collectEvalFiles(p: string): string[] {\n const resolved = path.resolve(p);\n try {\n const stat = statSync(resolved);\n if (stat.isDirectory()) {\n const entries = readdirSync(resolved);\n return entries\n .filter((e) => /\\.eval\\.[mc]?[jt]sx?$/.test(e))\n .map((e) => path.join(resolved, e));\n }\n return [resolved];\n } catch {\n return [resolved];\n }\n}\n\nfunction formatTable(result: EvalResult): string {\n const lines: string[] = [];\n const scorerNames = Object.keys(result.summary.scorers);\n const maxNameLen = Math.max(...scorerNames.map((n) => n.length), 'Scorer'.length);\n const colWidth = 8;\n\n lines.push(`Eval: ${result.workflow} x ${result.dataset} (${result.summary.count} items)`);\n lines.push(\n ` ${'Scorer'.padEnd(maxNameLen)} ${'Mean'.padStart(colWidth)} ${'Min'.padStart(colWidth)} ${'Max'.padStart(colWidth)} ${'p50'.padStart(colWidth)} ${'p95'.padStart(colWidth)}`,\n );\n\n const ruleLen = maxNameLen + 2 + (colWidth + 2) * 5;\n lines.push(' ' + '\\u2500'.repeat(ruleLen));\n\n for (const name of scorerNames) {\n const s = result.summary.scorers[name];\n lines.push(\n ` ${name.padEnd(maxNameLen)} ${s.mean.toFixed(2).padStart(colWidth)} ${s.min.toFixed(2).padStart(colWidth)} ${s.max.toFixed(2).padStart(colWidth)} ${s.p50.toFixed(2).padStart(colWidth)} ${s.p95.toFixed(2).padStart(colWidth)}`,\n );\n }\n\n const durationSec = (result.duration / 1000).toFixed(1);\n const costStr = result.totalCost > 0 ? `$${result.totalCost.toFixed(2)}` : '$0.00';\n lines.push('');\n lines.push(\n ` Failures: ${result.summary.failures}/${result.summary.count} | Cost: ${costStr} | Duration: ${durationSec}s`,\n );\n\n return lines.join('\\n');\n}\n\n// ── Runtime resolution ─────────────────────────────────────────────\n\nasync function resolveRuntimeFromConfig(configPath: string): Promise<AxlRuntime> {\n // Register tsx loader for TypeScript config files\n if (needsTsxLoader(configPath)) {\n await ensureTsxLoader();\n }\n\n // Force ESM format for .ts/.tsx files so top-level await works\n if (needsEsmForcing(configPath)) {\n await forceEsmForConfig(configPath);\n }\n\n try {\n const mod = await import(pathToFileURL(configPath).href);\n const runtime = resolveRuntime(mod) as AxlRuntime;\n\n if (!runtime || typeof runtime.execute !== 'function') {\n console.error(`Config must export a default AxlRuntime instance.`);\n if (runtime) {\n const keys = Object.keys(runtime as object)\n .slice(0, 5)\n .join(', ');\n console.error(` Got: ${typeof runtime}${keys ? ` with keys: { ${keys} }` : ''}`);\n }\n console.error(\n `Example:\\n import { AxlRuntime } from '@axlsdk/axl';\\n export default new AxlRuntime({ ... });`,\n );\n process.exit(1);\n }\n\n return runtime;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (\n /Cannot use import statement|Unexpected reserved word|top-level await|exports is not defined/.test(\n msg,\n )\n ) {\n const ext = path.extname(configPath);\n console.error(`[axl-eval] Config failed to load due to a CJS/ESM compatibility issue.`);\n if (ext === '.ts' || ext === '.tsx') {\n const mtsPath = configPath.slice(0, -ext.length) + '.mts';\n console.error(\n ` Tip: rename to .mts to force ESM format:\\n` + ` mv ${configPath} ${mtsPath}`,\n );\n } else {\n console.error(` Tip: add \"type\": \"module\" to your package.json.`);\n }\n console.error();\n }\n console.error(`Failed to load config:`, err);\n process.exit(1);\n }\n}\n\nasync function getRuntime(configArg?: string, conditions?: string[]): Promise<AxlRuntime> {\n // Register import conditions before any config loading\n if (conditions && conditions.length > 0) {\n await registerConditions(conditions);\n }\n\n // 1. Explicit --config\n if (configArg) {\n const configPath = path.resolve(process.cwd(), configArg);\n const stat = statSync(configPath, { throwIfNoEntry: false });\n if (!stat?.isFile()) {\n console.error(`Config file not found: ${configPath}`);\n process.exit(1);\n }\n console.error(`[axl-eval] Loading config from ${configPath}`);\n return resolveRuntimeFromConfig(configPath);\n }\n\n // 2. Auto-detect\n const found = findConfig(process.cwd());\n if (found) {\n console.error(`[axl-eval] Auto-detected config: ${found}`);\n return resolveRuntimeFromConfig(found);\n }\n\n // 3. Bare runtime (providers from env vars)\n const { AxlRuntime } = await import('@axlsdk/axl');\n return new AxlRuntime();\n}\n\n// ── Arg parsing ────────────────────────────────────────────────────\n\nfunction parseEvalArgs(args: string[]): {\n outputPath?: string;\n configArg?: string;\n conditions: string[];\n paths: string[];\n} {\n let outputPath: string | undefined;\n let configArg: string | undefined;\n let conditions: string[] = [];\n const paths: string[] = [];\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === '--output' || arg === '--config' || arg === '--conditions') {\n if (i + 1 >= args.length) {\n console.error(`Error: ${arg} requires a value`);\n process.exit(1);\n }\n const value = args[++i];\n if (arg === '--output') outputPath = value;\n else if (arg === '--config') configArg = value;\n else\n conditions = value\n .split(',')\n .map((c) => c.trim())\n .filter(Boolean);\n } else if (arg.startsWith('--')) {\n if (!KNOWN_FLAGS.has(arg)) {\n console.error(`Unknown flag: ${arg}`);\n process.exit(1);\n }\n } else {\n paths.push(arg);\n }\n }\n\n return { outputPath, configArg, conditions, paths };\n}\n\n// ── Main eval command ──────────────────────────────────────────────\n\nasync function runEvalCommand(args: string[]) {\n const { outputPath, configArg, conditions, paths } = parseEvalArgs(args);\n\n if (paths.length === 0) {\n console.error('Error: No eval file path provided');\n process.exit(1);\n }\n\n const evalFiles: string[] = [];\n for (const p of paths) {\n evalFiles.push(...collectEvalFiles(p));\n }\n\n if (evalFiles.length === 0) {\n console.error('Error: No eval files found');\n process.exit(1);\n }\n\n // Register tsx for TypeScript eval files (before config loading, which may also register tsx)\n if (evalFiles.some((f) => /\\.[mc]?tsx?$/.test(f))) {\n await ensureTsxLoader();\n }\n\n const runtime = await getRuntime(configArg, conditions);\n const results: EvalResult[] = [];\n\n try {\n for (const filePath of evalFiles) {\n try {\n const mod = await import(pathToFileURL(path.resolve(filePath)).href);\n const evalConfig: EvalConfig = mod.default ?? mod.config ?? mod;\n\n if (!evalConfig.workflow || !evalConfig.dataset || !evalConfig.scorers) {\n console.error(\n `Error: ${filePath} does not export a valid eval config (missing workflow, dataset, or scorers)`,\n );\n continue;\n }\n\n // Resolve executeWorkflow: custom export > registered workflow > passthrough\n let executeWorkflow: (\n input: unknown,\n rt?: unknown,\n ) => Promise<{ output: unknown; cost?: number }>;\n\n if (mod.executeWorkflow) {\n // Wrap custom executeWorkflow with trackCost for automatic cost attribution\n executeWorkflow = async (input, rt) => {\n const { result, cost: trackedCost } = await runtime.trackCost(async () => {\n return mod.executeWorkflow(input, rt);\n });\n return { output: result.output, cost: result.cost ?? trackedCost };\n };\n } else if (runtime.getWorkflow(evalConfig.workflow)) {\n // No executeWorkflow exported but workflow is registered — use runtime.execute()\n executeWorkflow = async (input) => {\n const { result, cost } = await runtime.trackCost(async () => {\n return runtime.execute(evalConfig.workflow, input);\n });\n return { output: result, cost };\n };\n } else {\n console.warn(\n `[axl-eval] Warning: ${filePath} does not export executeWorkflow — using input passthrough`,\n );\n executeWorkflow = async (input) => ({ output: input });\n }\n\n const result = await runEval(evalConfig, executeWorkflow, mod.provider, runtime);\n results.push(result);\n\n console.log('\\n' + formatTable(result) + '\\n');\n } catch (err) {\n console.error(\n `Error running eval ${filePath}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n if (outputPath && results.length > 0) {\n const output = results.length === 1 ? results[0] : results;\n const outputDir = path.dirname(path.resolve(outputPath));\n await mkdir(outputDir, { recursive: true });\n await writeFileAsync(outputPath, JSON.stringify(output, null, 2), 'utf-8');\n console.log(`Results saved to ${outputPath}`);\n }\n } finally {\n await runtime.shutdown().catch(() => {});\n }\n\n // Exit with non-zero code if no evals succeeded\n if (results.length === 0) {\n process.exit(1);\n }\n}\n\nmain().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n","/**\n * CLI utilities for config detection, runtime resolution, and loader registration.\n *\n * These are duplicated from @axlsdk/studio (cli-utils.ts, resolve-runtime.ts,\n * eval-loader.ts, cli.ts) because @axlsdk/eval cannot depend on @axlsdk/studio.\n * Keep in sync with the studio versions if either changes.\n */\n\nimport { resolve, extname } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { pathToFileURL } from 'node:url';\n\n// ── Config auto-detection ──────────────────────────────────────────\n\nexport const CONFIG_CANDIDATES = [\n 'axl.config.mts',\n 'axl.config.ts',\n 'axl.config.mjs',\n 'axl.config.js',\n];\n\nexport function findConfig(cwd: string): string | undefined {\n for (const name of CONFIG_CANDIDATES) {\n const p = resolve(cwd, name);\n if (existsSync(p)) return p;\n }\n return undefined;\n}\n\n// ── Extension helpers ──────────────────────────────────────────────\n\n/**\n * Returns true if the config path has an ambiguous TypeScript extension (.ts/.tsx)\n * that needs ESM forcing. Explicit extensions (.mts/.cts) are excluded.\n */\nexport function needsEsmForcing(configPath: string): boolean {\n const ext = extname(configPath);\n return ext === '.ts' || ext === '.tsx';\n}\n\n/** Returns true if the config path is a TypeScript file that needs tsx loader hooks. */\nexport function needsTsxLoader(configPath: string): boolean {\n return /\\.[mc]?tsx?$/.test(configPath);\n}\n\n// ── Runtime resolution ─────────────────────────────────────────────\n\n/**\n * Resolve the AxlRuntime from a dynamically imported config module.\n *\n * Module shapes handled:\n * - ESM `export default runtime` → mod.default is the runtime\n * - CJS compiled from `export default runtime` → mod.default.default is the runtime\n * - CJS `module.exports = runtime` → mod.default is the runtime\n * - Named `export { runtime }` → mod.runtime is the runtime\n */\nexport function resolveRuntime(mod: Record<string, unknown>): unknown {\n const def = mod.default as Record<string, unknown> | undefined;\n return def?.default ?? def ?? mod.runtime;\n}\n\n// ── Loader registration ────────────────────────────────────────────\n\nlet tsxRegistered = false;\n\nexport async function ensureTsxLoader(): Promise<void> {\n if (tsxRegistered) return;\n tsxRegistered = true;\n\n let loaded = false;\n try {\n // @ts-expect-error — tsx is an optional runtime dependency\n const tsxEsm = await import('tsx/esm/api');\n tsxEsm.register();\n loaded = true;\n } catch {\n // ESM hook not available\n }\n try {\n // @ts-expect-error — tsx is an optional runtime dependency\n const tsxCjs = await import('tsx/cjs/api');\n tsxCjs.register();\n loaded = true;\n } catch {\n // CJS hook not available\n }\n if (!loaded) {\n console.warn(\n '[axl-eval] Warning: tsx is not installed. TypeScript files require tsx.\\n' +\n ' Install it with: npm install -D tsx',\n );\n }\n}\n\n/**\n * Force ESM format for a specific config file so top-level await works\n * regardless of the nearest package.json \"type\" field.\n */\nexport async function forceEsmForConfig(configPath: string): Promise<void> {\n try {\n const nodeModule = await import('node:module');\n const configUrl = pathToFileURL(configPath).href;\n const hookCode = [\n `export async function resolve(specifier, context, nextResolve) {`,\n ` const result = await nextResolve(specifier, context);`,\n ` if (result.url === ${JSON.stringify(configUrl)}) result.format = 'module';`,\n ` return result;`,\n `}`,\n ].join('\\n');\n nodeModule.register(`data:text/javascript,${encodeURIComponent(hookCode)}`);\n } catch {\n // module.register() not available (Node < 20.6)\n }\n}\n\nexport async function registerConditions(conditions: string[]): Promise<void> {\n try {\n const nodeModule = await import('node:module');\n const hookCode = [\n `const extra = ${JSON.stringify(conditions)};`,\n `export async function resolve(specifier, context, nextResolve) {`,\n ` return nextResolve(specifier, {`,\n ` ...context,`,\n ` conditions: [...new Set([...context.conditions, ...extra])],`,\n ` });`,\n `}`,\n ].join('\\n');\n nodeModule.register(`data:text/javascript,${encodeURIComponent(hookCode)}`);\n } catch {\n console.warn('[axl-eval] Warning: --conditions requires Node.js 20.6+');\n }\n}\n"],"mappings":"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","names":["pathToFileURL","pathToFileURL","result"]}