@@ -2,11 +2,8 @@ import chalk from "chalk";
22import { Command } from "commander" ;
33import ora from "ora" ;
44import { loadConfig } from "../config/loader.js" ;
5- import { executeTasks } from "../eval/executor.js" ;
6- import { scoreResults } from "../eval/scorer.js" ;
7- import { generateTasks } from "../eval/task-generator.js" ;
8- import { createAdapter } from "../protocols/factory.js" ;
9- import { buildReport , printReport , saveReport } from "../report/generator.js" ;
5+ import { runEvaluation } from "../eval/engine.js" ;
6+ import { printReport } from "../report/generator.js" ;
107
118/**
129 * Load API key from environment.
@@ -50,106 +47,42 @@ export const runCommand = new Command("run")
5047 )
5148 . action ( async ( options ) => {
5249 try {
53- await runEval ( options ) ;
50+ // Load config
51+ const config = loadConfig ( options . config ) ;
52+ const apiKey = await getApiKey ( ) ;
53+
54+ const runsPerTask = options . runs
55+ ? Number . parseInt ( options . runs , 10 )
56+ : config . eval . runs ;
57+ const tasksPerTool = Number . parseInt ( options . tasksPerTool , 10 ) ;
58+
59+ // Run evaluation with spinner progress
60+ const spinner = ora ( ) . start ( ) ;
61+ const result = await runEvaluation ( {
62+ config,
63+ apiKey,
64+ tasksPerTool,
65+ runsPerTask,
66+ outputDir : options . output ,
67+ onProgress : ( _step , detail ) => {
68+ spinner . text = detail ;
69+ } ,
70+ } ) ;
71+ spinner . succeed ( "Evaluation complete" ) ;
72+
73+ // Display results
74+ if ( options . json ) {
75+ console . log ( JSON . stringify ( result . report , null , 2 ) ) ;
76+ } else {
77+ printReport ( result . report ) ;
78+ if ( result . reportPath ) {
79+ console . log ( chalk . dim ( ` Full report: ${ result . reportPath } ` ) ) ;
80+ console . log ( "" ) ;
81+ }
82+ }
5483 } catch ( err ) {
5584 const message = err instanceof Error ? err . message : String ( err ) ;
5685 console . error ( chalk . red ( `\nError: ${ message } ` ) ) ;
5786 process . exit ( 1 ) ;
5887 }
5988 } ) ;
60-
61- async function runEval ( options : {
62- config : string ;
63- runs ?: string ;
64- tasksPerTool : string ;
65- json ?: boolean ;
66- output : string ;
67- } ) {
68- // Step 1: Load config
69- const spinner = ora ( "Loading config..." ) . start ( ) ;
70- const config = loadConfig ( options . config ) ;
71- const runsPerTask = options . runs
72- ? Number . parseInt ( options . runs , 10 )
73- : config . eval . runs ;
74- const tasksPerTool = Number . parseInt ( options . tasksPerTool , 10 ) ;
75- spinner . succeed (
76- `Config loaded: ${ config . agent . name } (${ config . agent . protocol . toUpperCase ( ) } )` ,
77- ) ;
78-
79- // Step 2: Get API key
80- const apiKey = await getApiKey ( ) ;
81-
82- // Step 3: Connect and discover tools.
83- // We keep one connection open for the entire eval — discovery, task gen, and execution.
84- spinner . start (
85- `Connecting to agent via ${ config . agent . protocol . toUpperCase ( ) } ...` ,
86- ) ;
87- const adapter = createAdapter ( config . agent . protocol , config . agent . endpoint ) ;
88- await adapter . connect ( ) ;
89- const tools = await adapter . listTools ( ) ;
90- spinner . succeed ( `Discovered ${ tools . length } tool(s)` ) ;
91-
92- if ( tools . length === 0 ) {
93- console . log ( chalk . yellow ( "No tools found. Nothing to evaluate." ) ) ;
94- await adapter . disconnect ( ) . catch ( ( ) => { } ) ;
95- return ;
96- }
97-
98- // Step 4: Generate test tasks using Claude API
99- spinner . start (
100- `Generating ${ tasksPerTool } test tasks per tool (${ tools . length } tools)...` ,
101- ) ;
102- const tasks = await generateTasks ( tools , config . agent . capabilities , {
103- tasksPerTool,
104- apiKey,
105- } ) ;
106- spinner . succeed ( `Generated ${ tasks . length } test tasks` ) ;
107-
108- // Step 5: Execute tasks (reuse the same connection)
109- const totalRuns = tasks . length * runsPerTask ;
110- spinner . start (
111- `Executing ${ totalRuns } runs (${ tasks . length } tasks x ${ runsPerTask } runs)...` ,
112- ) ;
113- const execution = await executeTasks ( adapter , tasks , runsPerTask , {
114- onRunComplete : ( completed , total ) => {
115- spinner . text = `Executing runs... ${ completed } /${ total } ` ;
116- } ,
117- } ) ;
118- spinner . succeed (
119- `Executed ${ execution . totalRuns } runs (${ execution . totalSuccessful } successful)` ,
120- ) ;
121-
122- // Step 6: Disconnect
123- await adapter . disconnect ( ) . catch ( ( ) => { } ) ;
124-
125- // Step 8: Score results with LLM-as-judge
126- spinner . start ( "Scoring results with LLM-as-judge..." ) ;
127- const weights = {
128- capability : config . eval . dimensions . capability . weight ,
129- reliability : config . eval . dimensions . reliability . weight ,
130- efficiency : config . eval . dimensions . efficiency . weight ,
131- safety : config . eval . dimensions . safety . weight ,
132- developer_experience : config . eval . dimensions . developer_experience . weight ,
133- } ;
134- const scores = await scoreResults ( execution . taskResults , {
135- apiKey,
136- weights,
137- onTaskScored : ( completed , total ) => {
138- spinner . text = `Scoring tasks... ${ completed } /${ total } ` ;
139- } ,
140- } ) ;
141- spinner . succeed ( "Scoring complete" ) ;
142-
143- // Step 9: Generate and save report
144- const report = buildReport ( config , tools , execution , scores ) ;
145- const reportPath = saveReport ( report , options . output ) ;
146-
147- // Step 10: Display results
148- if ( options . json ) {
149- console . log ( JSON . stringify ( report , null , 2 ) ) ;
150- } else {
151- printReport ( report ) ;
152- console . log ( chalk . dim ( ` Full report: ${ reportPath } ` ) ) ;
153- console . log ( "" ) ;
154- }
155- }
0 commit comments