@@ -5,74 +5,17 @@ import { v4 as uuidv4 } from 'uuid';
55import logger from './logger.js' ;
66
77class ClientManager {
8- constructor ( clientsDir = './clients' , evalsDir = './evals' ) {
8+ constructor ( clientsDir = './clients' ) {
99 this . clientsDir = path . resolve ( clientsDir ) ;
10- this . evalsDir = path . resolve ( evalsDir ) ;
1110 this . clients = new Map ( ) ;
12- this . evaluations = new Map ( ) ; // clientId -> evaluations array
13- this . configDefaults = null ; // Config.yaml defaults for model precedence
1411 this . activeTabs = new Map ( ) ; // clientId -> Set of { tabId, connection, metadata }
15-
12+
1613 // Ensure directories exist
1714 if ( ! fs . existsSync ( this . clientsDir ) ) {
1815 fs . mkdirSync ( this . clientsDir , { recursive : true } ) ;
1916 }
20- if ( ! fs . existsSync ( this . evalsDir ) ) {
21- fs . mkdirSync ( this . evalsDir , { recursive : true } ) ;
22- }
23-
24- this . loadConfigDefaults ( ) ;
25- this . loadAllClients ( ) ;
26- this . loadAllEvaluations ( ) ;
27- }
28-
29- /**
30- * Load default model configuration from config.yaml
31- */
32- loadConfigDefaults ( ) {
33- try {
34- const configPath = path . resolve ( this . evalsDir , 'config.yaml' ) ;
35- if ( fs . existsSync ( configPath ) ) {
36- const configContent = fs . readFileSync ( configPath , 'utf8' ) ;
37- this . configDefaults = yaml . load ( configContent ) ;
38- logger . info ( 'Loaded config.yaml defaults:' , this . configDefaults ) ;
39- } else {
40- // Don't warn about missing config.yaml - it's optional
41- this . configDefaults = null ;
42- }
43- } catch ( error ) {
44- logger . error ( 'Failed to load config.yaml:' , error ) ;
45- this . configDefaults = null ;
46- }
47- }
48-
49- /**
50- * Apply model precedence: API calls OR test YAML models override config.yaml fallback
51- * Precedence logic:
52- * 1. API calls OR individual test YAML models (highest priority - either overrides everything)
53- * 2. config.yaml defaults (fallback only when neither API nor test YAML specify models)
54- * @param {Object } evaluation - Evaluation object with optional model configuration
55- * @param {import('../types/model-config').ModelConfig } apiModelOverride - Optional API model override
56- * @returns {import('../types/model-config').ModelConfig } Final model configuration
57- */
58- applyModelPrecedence ( evaluation , apiModelOverride = null ) {
59- // Check if API override is provided
60- if ( apiModelOverride ) {
61- // API model override takes precedence over everything
62- // Ensure nested format is used
63- return apiModelOverride ;
64- }
65-
66- // Check if evaluation has its own model config from YAML
67- const testModel = evaluation . model ;
68- if ( testModel && Object . keys ( testModel ) . length > 0 ) {
69- // Test YAML model takes precedence
70- // Ensure nested format is returned
71- return testModel ;
72- }
7317
74- // Neither API nor test YAML specified models, use config.yaml defaults only
75- return this . configDefaults ?. model || { } ;
18+ this . loadAllClients ( ) ;
7619 }
7720
7821 /**
@@ -130,80 +73,11 @@ class ClientManager {
13073 settings : config . settings || { } ,
13174 yamlPath
13275 } ) ;
133-
134- // Note: Evaluations are now loaded separately from the evals directory
135- // Initialize empty evaluations array for this client
136- if ( ! this . evaluations . has ( clientId ) ) {
137- this . evaluations . set ( clientId , [ ] ) ;
138- }
139-
76+
14077 logger . info ( `Loaded client ${ clientId } ` ) ;
14178 return config ;
14279 }
14380
144- /**
145- * Load all evaluations from the evals directory structure
146- */
147- loadAllEvaluations ( ) {
148- try {
149- // Clear existing evaluations to prevent duplicates on reload
150- this . evaluations . clear ( ) ;
151-
152- // Find all category directories
153- const categories = fs . readdirSync ( this . evalsDir )
154- . filter ( dir => fs . statSync ( path . join ( this . evalsDir , dir ) ) . isDirectory ( ) ) ;
155-
156- let totalEvaluations = 0 ;
157-
158- for ( const category of categories ) {
159- const categoryDir = path . join ( this . evalsDir , category ) ;
160- const evalFiles = fs . readdirSync ( categoryDir )
161- . filter ( f => f . endsWith ( '.yaml' ) || f . endsWith ( '.yml' ) ) ;
162-
163- for ( const file of evalFiles ) {
164- try {
165- const evalPath = path . join ( categoryDir , file ) ;
166- const yamlContent = fs . readFileSync ( evalPath , 'utf8' ) ;
167- const evaluation = yaml . load ( yamlContent ) ;
168-
169- if ( evaluation . enabled !== false ) {
170- // Apply model precedence: config.yaml overrides individual test models
171- const resolvedModel = this . applyModelPrecedence ( evaluation ) ;
172-
173- // Add evaluation to all clients for now
174- // In the future, you might want to have client-specific evaluation assignments
175- for ( const [ clientId ] of this . clients ) {
176- const clientEvals = this . evaluations . get ( clientId ) || [ ] ;
177- clientEvals . push ( {
178- ...evaluation ,
179- model : resolvedModel , // Use resolved model with precedence applied
180- clientId,
181- status : 'pending' ,
182- category,
183- filePath : evalPath
184- } ) ;
185- this . evaluations . set ( clientId , clientEvals ) ;
186- }
187- totalEvaluations ++ ;
188- }
189- } catch ( error ) {
190- logger . error ( `Failed to load evaluation ${ file } :` , error ) ;
191- }
192- }
193- }
194-
195- // Update the client evaluation counts
196- for ( const [ clientId ] of this . clients ) {
197- const evalCount = this . evaluations . get ( clientId ) ?. length || 0 ;
198- logger . info ( `Loaded client ${ clientId } with ${ evalCount } evaluations` ) ;
199- }
200-
201- logger . info ( `Loaded ${ totalEvaluations } evaluations from ${ categories . length } categories` ) ;
202- } catch ( error ) {
203- logger . error ( 'Failed to load evaluations:' , error ) ;
204- }
205- }
206-
20781 /**
20882 * Register a new client with authentication
20983 */
@@ -225,8 +99,7 @@ class ClientManager {
22599
226100 return {
227101 success : true ,
228- clientName : client . name ,
229- evaluationsCount : this . evaluations . get ( clientId ) ?. length || 0
102+ clientName : client . name
230103 } ;
231104 }
232105
@@ -237,38 +110,6 @@ class ClientManager {
237110 return this . clients . get ( clientId ) ;
238111 }
239112
240- /**
241- * Get evaluations for a client
242- */
243- getClientEvaluations ( clientId ) {
244- return this . evaluations . get ( clientId ) || [ ] ;
245- }
246-
247- /**
248- * Get next pending evaluation for a client
249- */
250- getNextEvaluation ( clientId ) {
251- const evaluations = this . evaluations . get ( clientId ) || [ ] ;
252- return evaluations . find ( e => e . status === 'pending' ) ;
253- }
254-
255- /**
256- * Update evaluation status
257- */
258- updateEvaluationStatus ( clientId , evaluationId , status , result = null ) {
259- const evaluations = this . evaluations . get ( clientId ) ;
260- if ( ! evaluations ) return ;
261-
262- const evaluation = evaluations . find ( e => e . id === evaluationId ) ;
263- if ( evaluation ) {
264- evaluation . status = status ;
265- evaluation . lastRun = new Date ( ) . toISOString ( ) ;
266- if ( result ) {
267- evaluation . lastResult = result ;
268- }
269- }
270- }
271-
272113 /**
273114 * Create a new client with default configuration
274115 */
@@ -305,13 +146,10 @@ class ClientManager {
305146 // Write YAML file
306147 const yamlContent = yaml . dump ( defaultConfig , { indent : 2 } ) ;
307148 fs . writeFileSync ( yamlPath , yamlContent ) ;
308-
149+
309150 // Load the new client
310151 this . loadClient ( clientId ) ;
311-
312- // Load evaluations for the new client
313- this . loadAllEvaluations ( ) ;
314-
152+
315153 logger . info ( `Created new client: ${ clientId } ` ) ;
316154 return { clientId, yamlPath } ;
317155 }
0 commit comments