@@ -56,6 +56,8 @@ const modelConfig = z.object({
5656 . optional ( ) ,
5757 multimodal : z . boolean ( ) . default ( false ) ,
5858 multimodalAcceptedMimetypes : z . array ( z . string ( ) ) . optional ( ) ,
59+ // Aggregated tool-calling capability across providers (HF router)
60+ supportsTools : z . boolean ( ) . default ( false ) ,
5961 unlisted : z . boolean ( ) . default ( false ) ,
6062 embeddingModel : z . never ( ) . optional ( ) ,
6163 /** Used to enable/disable system prompt usage */
@@ -234,6 +236,7 @@ const signatureForModel = (model: ProcessedModel) =>
234236 } ) ?? null ,
235237 multimodal : model . multimodal ,
236238 multimodalAcceptedMimetypes : model . multimodalAcceptedMimetypes ,
239+ supportsTools : ( model as unknown as { supportsTools ?: boolean } ) . supportsTools ?? false ,
237240 isRouter : model . isRouter ,
238241 hasInferenceAPI : model . hasInferenceAPI ,
239242 } ) ;
@@ -329,36 +332,40 @@ const buildModels = async (): Promise<ProcessedModel[]> => {
329332 const parsed = listSchema . parse ( json ) ;
330333 logger . info ( { count : parsed . data . length } , "[models] Parsed models count" ) ;
331334
332- let modelsRaw = parsed . data . map ( ( m ) => {
333- let logoUrl : string | undefined = undefined ;
334- if ( isHFRouter && m . id . includes ( "/" ) ) {
335- const org = m . id . split ( "/" ) [ 0 ] ;
336- logoUrl = `https://huggingface.co/api/organizations/${ encodeURIComponent ( org ) } /avatar?redirect=true` ;
337- }
335+ let modelsRaw = parsed . data . map ( ( m ) => {
336+ let logoUrl : string | undefined = undefined ;
337+ if ( isHFRouter && m . id . includes ( "/" ) ) {
338+ const org = m . id . split ( "/" ) [ 0 ] ;
339+ logoUrl = `https://huggingface.co/api/organizations/${ encodeURIComponent ( org ) } /avatar?redirect=true` ;
340+ }
338341
339- const inputModalities = ( m . architecture ?. input_modalities ?? [ ] ) . map ( ( modality ) =>
340- modality . toLowerCase ( )
341- ) ;
342- const supportsImageInput =
343- inputModalities . includes ( "image" ) || inputModalities . includes ( "vision" ) ;
344- return {
345- id : m . id ,
346- name : m . id ,
347- displayName : m . id ,
348- description : m . description ,
349- logoUrl,
350- providers : m . providers ,
351- multimodal : supportsImageInput ,
352- multimodalAcceptedMimetypes : supportsImageInput ? [ "image/*" ] : undefined ,
353- endpoints : [
354- {
355- type : "openai" as const ,
356- baseURL,
357- // apiKey will be taken from OPENAI_API_KEY or HF_TOKEN automatically
358- } ,
359- ] ,
360- } as ModelConfig ;
361- } ) as ModelConfig [ ] ;
342+ const inputModalities = ( m . architecture ?. input_modalities ?? [ ] ) . map ( ( modality ) =>
343+ modality . toLowerCase ( )
344+ ) ;
345+ const supportsImageInput =
346+ inputModalities . includes ( "image" ) || inputModalities . includes ( "vision" ) ;
347+
348+ // If any provider supports tools, consider the model as supporting tools
349+ const supportsTools = Boolean ( ( m . providers ?? [ ] ) . some ( ( p ) => p ?. supports_tools === true ) ) ;
350+ return {
351+ id : m . id ,
352+ name : m . id ,
353+ displayName : m . id ,
354+ description : m . description ,
355+ logoUrl,
356+ providers : m . providers ,
357+ multimodal : supportsImageInput ,
358+ multimodalAcceptedMimetypes : supportsImageInput ? [ "image/*" ] : undefined ,
359+ supportsTools,
360+ endpoints : [
361+ {
362+ type : "openai" as const ,
363+ baseURL,
364+ // apiKey will be taken from OPENAI_API_KEY or HF_TOKEN automatically
365+ } ,
366+ ] ,
367+ } as ModelConfig ;
368+ } ) as ModelConfig [ ] ;
362369
363370 const overrides = getModelOverrides ( ) ;
364371
0 commit comments