@@ -82,6 +82,7 @@ describe('EvaluatorBlockHandler', () => {
8282 { name : 'score2' , description : 'Second score' , range : { min : 0 , max : 10 } } ,
8383 ] ,
8484 model : 'gpt-4o' ,
85+ apiKey : 'test-api-key' ,
8586 temperature : 0.1 ,
8687 }
8788
@@ -97,7 +98,6 @@ describe('EvaluatorBlockHandler', () => {
9798 } )
9899 )
99100
100- // Verify the request body contains the expected data
101101 const fetchCallArgs = mockFetch . mock . calls [ 0 ]
102102 const requestBody = JSON . parse ( fetchCallArgs [ 1 ] . body )
103103 expect ( requestBody ) . toMatchObject ( {
@@ -137,6 +137,7 @@ describe('EvaluatorBlockHandler', () => {
137137 const inputs = {
138138 content : JSON . stringify ( contentObj ) ,
139139 metrics : [ { name : 'clarity' , description : 'Clarity score' , range : { min : 1 , max : 5 } } ] ,
140+ apiKey : 'test-api-key' ,
140141 }
141142
142143 mockFetch . mockImplementationOnce ( ( ) => {
@@ -169,6 +170,7 @@ describe('EvaluatorBlockHandler', () => {
169170 metrics : [
170171 { name : 'completeness' , description : 'Data completeness' , range : { min : 0 , max : 1 } } ,
171172 ] ,
173+ apiKey : 'test-api-key' ,
172174 }
173175
174176 mockFetch . mockImplementationOnce ( ( ) => {
@@ -198,6 +200,7 @@ describe('EvaluatorBlockHandler', () => {
198200 const inputs = {
199201 content : 'Test content' ,
200202 metrics : [ { name : 'quality' , description : 'Quality score' , range : { min : 1 , max : 10 } } ] ,
203+ apiKey : 'test-api-key' ,
201204 }
202205
203206 mockFetch . mockImplementationOnce ( ( ) => {
@@ -223,6 +226,7 @@ describe('EvaluatorBlockHandler', () => {
223226 const inputs = {
224227 content : 'Test content' ,
225228 metrics : [ { name : 'score' , description : 'Score' , range : { min : 0 , max : 5 } } ] ,
229+ apiKey : 'test-api-key' ,
226230 }
227231
228232 mockFetch . mockImplementationOnce ( ( ) => {
@@ -251,6 +255,7 @@ describe('EvaluatorBlockHandler', () => {
251255 { name : 'accuracy' , description : 'Acc' , range : { min : 0 , max : 1 } } ,
252256 { name : 'fluency' , description : 'Flu' , range : { min : 0 , max : 1 } } ,
253257 ] ,
258+ apiKey : 'test-api-key' ,
254259 }
255260
256261 mockFetch . mockImplementationOnce ( ( ) => {
@@ -276,6 +281,7 @@ describe('EvaluatorBlockHandler', () => {
276281 const inputs = {
277282 content : 'Test' ,
278283 metrics : [ { name : 'CamelCaseScore' , description : 'Desc' , range : { min : 0 , max : 10 } } ] ,
284+ apiKey : 'test-api-key' ,
279285 }
280286
281287 mockFetch . mockImplementationOnce ( ( ) => {
@@ -304,6 +310,7 @@ describe('EvaluatorBlockHandler', () => {
304310 { name : 'presentScore' , description : 'Desc1' , range : { min : 0 , max : 5 } } ,
305311 { name : 'missingScore' , description : 'Desc2' , range : { min : 0 , max : 5 } } ,
306312 ] ,
313+ apiKey : 'test-api-key' ,
307314 }
308315
309316 mockFetch . mockImplementationOnce ( ( ) => {
@@ -327,7 +334,7 @@ describe('EvaluatorBlockHandler', () => {
327334 } )
328335
329336 it ( 'should handle server error responses' , async ( ) => {
330- const inputs = { content : 'Test error handling.' }
337+ const inputs = { content : 'Test error handling.' , apiKey : 'test-api-key' }
331338
332339 // Override fetch mock to return an error
333340 mockFetch . mockImplementationOnce ( ( ) => {
@@ -340,4 +347,139 @@ describe('EvaluatorBlockHandler', () => {
340347
341348 await expect ( handler . execute ( mockContext , mockBlock , inputs ) ) . rejects . toThrow ( 'Server error' )
342349 } )
350+
351+ it ( 'should handle Azure OpenAI models with endpoint and API version' , async ( ) => {
352+ const inputs = {
353+ content : 'Test content to evaluate' ,
354+ metrics : [ { name : 'quality' , description : 'Quality score' , range : { min : 1 , max : 10 } } ] ,
355+ model : 'gpt-4o' ,
356+ apiKey : 'test-azure-key' ,
357+ azureEndpoint : 'https://test.openai.azure.com' ,
358+ azureApiVersion : '2024-07-01-preview' ,
359+ }
360+
361+ mockGetProviderFromModel . mockReturnValue ( 'azure-openai' )
362+
363+ mockFetch . mockImplementationOnce ( ( ) => {
364+ return Promise . resolve ( {
365+ ok : true ,
366+ json : ( ) =>
367+ Promise . resolve ( {
368+ content : JSON . stringify ( { quality : 8 } ) ,
369+ model : 'gpt-4o' ,
370+ tokens : { } ,
371+ cost : 0 ,
372+ timing : { } ,
373+ } ) ,
374+ } )
375+ } )
376+
377+ await handler . execute ( mockContext , mockBlock , inputs )
378+
379+ const fetchCallArgs = mockFetch . mock . calls [ 0 ]
380+ const requestBody = JSON . parse ( fetchCallArgs [ 1 ] . body )
381+
382+ expect ( requestBody ) . toMatchObject ( {
383+ provider : 'azure-openai' ,
384+ model : 'gpt-4o' ,
385+ apiKey : 'test-azure-key' ,
386+ azureEndpoint : 'https://test.openai.azure.com' ,
387+ azureApiVersion : '2024-07-01-preview' ,
388+ } )
389+ } )
390+
391+ it ( 'should throw error when API key is missing for non-hosted models' , async ( ) => {
392+ const inputs = {
393+ content : 'Test content' ,
394+ metrics : [ { name : 'score' , description : 'Score' , range : { min : 0 , max : 10 } } ] ,
395+ model : 'gpt-4o' ,
396+ // No apiKey provided
397+ }
398+
399+ mockGetProviderFromModel . mockReturnValue ( 'openai' )
400+
401+ await expect ( handler . execute ( mockContext , mockBlock , inputs ) ) . rejects . toThrow (
402+ / A P I k e y i s r e q u i r e d /
403+ )
404+ } )
405+
406+ it ( 'should handle Vertex AI models with OAuth credential' , async ( ) => {
407+ const inputs = {
408+ content : 'Test content to evaluate' ,
409+ metrics : [ { name : 'quality' , description : 'Quality score' , range : { min : 1 , max : 10 } } ] ,
410+ model : 'gemini-2.0-flash-exp' ,
411+ vertexCredential : 'test-vertex-credential-id' ,
412+ vertexProject : 'test-gcp-project' ,
413+ vertexLocation : 'us-central1' ,
414+ }
415+
416+ mockGetProviderFromModel . mockReturnValue ( 'vertex' )
417+
418+ // Mock the database query for Vertex credential
419+ const mockDb = await import ( '@sim/db' )
420+ const mockAccount = {
421+ id : 'test-vertex-credential-id' ,
422+ accessToken : 'mock-access-token' ,
423+ refreshToken : 'mock-refresh-token' ,
424+ expiresAt : new Date ( Date . now ( ) + 3600000 ) , // 1 hour from now
425+ }
426+ vi . spyOn ( mockDb . db . query . account , 'findFirst' ) . mockResolvedValue ( mockAccount as any )
427+
428+ mockFetch . mockImplementationOnce ( ( ) => {
429+ return Promise . resolve ( {
430+ ok : true ,
431+ json : ( ) =>
432+ Promise . resolve ( {
433+ content : JSON . stringify ( { quality : 9 } ) ,
434+ model : 'gemini-2.0-flash-exp' ,
435+ tokens : { } ,
436+ cost : 0 ,
437+ timing : { } ,
438+ } ) ,
439+ } )
440+ } )
441+
442+ await handler . execute ( mockContext , mockBlock , inputs )
443+
444+ const fetchCallArgs = mockFetch . mock . calls [ 0 ]
445+ const requestBody = JSON . parse ( fetchCallArgs [ 1 ] . body )
446+
447+ expect ( requestBody ) . toMatchObject ( {
448+ provider : 'vertex' ,
449+ model : 'gemini-2.0-flash-exp' ,
450+ vertexProject : 'test-gcp-project' ,
451+ vertexLocation : 'us-central1' ,
452+ } )
453+ expect ( requestBody . apiKey ) . toBe ( 'mock-access-token' )
454+ } )
455+
456+ it ( 'should use default model when not provided' , async ( ) => {
457+ const inputs = {
458+ content : 'Test content' ,
459+ metrics : [ { name : 'score' , description : 'Score' , range : { min : 0 , max : 10 } } ] ,
460+ apiKey : 'test-api-key' ,
461+ // No model provided - should use default
462+ }
463+
464+ mockFetch . mockImplementationOnce ( ( ) => {
465+ return Promise . resolve ( {
466+ ok : true ,
467+ json : ( ) =>
468+ Promise . resolve ( {
469+ content : JSON . stringify ( { score : 7 } ) ,
470+ model : 'claude-sonnet-4-5' ,
471+ tokens : { } ,
472+ cost : 0 ,
473+ timing : { } ,
474+ } ) ,
475+ } )
476+ } )
477+
478+ await handler . execute ( mockContext , mockBlock , inputs )
479+
480+ const fetchCallArgs = mockFetch . mock . calls [ 0 ]
481+ const requestBody = JSON . parse ( fetchCallArgs [ 1 ] . body )
482+
483+ expect ( requestBody . model ) . toBe ( 'claude-sonnet-4-5' )
484+ } )
343485} )
0 commit comments