@@ -31,6 +31,31 @@ describe("Ollama Fetcher", () => {
3131 description : "Family: qwen3, Context: 40960, Size: 32.8B" ,
3232 } )
3333 } )
34+
35+ it ( "should handle models with null families field" , ( ) => {
36+ const modelDataWithNullFamilies = {
37+ ...ollamaModelsData [ "qwen3-2to16:latest" ] ,
38+ details : {
39+ ...ollamaModelsData [ "qwen3-2to16:latest" ] . details ,
40+ families : null ,
41+ } ,
42+ }
43+
44+ const parsedModel = parseOllamaModel ( modelDataWithNullFamilies as any )
45+
46+ expect ( parsedModel ) . toEqual ( {
47+ maxTokens : 40960 ,
48+ contextWindow : 40960 ,
49+ supportsImages : false ,
50+ supportsComputerUse : false ,
51+ supportsPromptCache : true ,
52+ inputPrice : 0 ,
53+ outputPrice : 0 ,
54+ cacheWritesPrice : 0 ,
55+ cacheReadsPrice : 0 ,
56+ description : "Family: qwen3, Context: 40960, Size: 32.8B" ,
57+ } )
58+ } )
3459 } )
3560
3661 describe ( "getOllamaModels" , ( ) => {
@@ -129,5 +154,69 @@ describe("Ollama Fetcher", () => {
129154
130155 consoleInfoSpy . mockRestore ( ) // Restore original console.info
131156 } )
157+
158+ it ( "should handle models with null families field in API response" , async ( ) => {
159+ const baseUrl = "http://localhost:11434"
160+ const modelName = "test-model:latest"
161+
162+ const mockApiTagsResponse = {
163+ models : [
164+ {
165+ name : modelName ,
166+ model : modelName ,
167+ modified_at : "2025-06-03T09:23:22.610222878-04:00" ,
168+ size : 14333928010 ,
169+ digest : "6a5f0c01d2c96c687d79e32fdd25b87087feb376bf9838f854d10be8cf3c10a5" ,
170+ details : {
171+ family : "llama" ,
172+ families : null , // This is the case we're testing
173+ format : "gguf" ,
174+ parameter_size : "23.6B" ,
175+ parent_model : "" ,
176+ quantization_level : "Q4_K_M" ,
177+ } ,
178+ } ,
179+ ] ,
180+ }
181+ const mockApiShowResponse = {
182+ license : "Mock License" ,
183+ modelfile : "FROM /path/to/blob\nTEMPLATE {{ .Prompt }}" ,
184+ parameters : "num_ctx 4096\nstop_token <eos>" ,
185+ template : "{{ .System }}USER: {{ .Prompt }}ASSISTANT:" ,
186+ modified_at : "2025-06-03T09:23:22.610222878-04:00" ,
187+ details : {
188+ parent_model : "" ,
189+ format : "gguf" ,
190+ family : "llama" ,
191+ families : null , // This is the case we're testing
192+ parameter_size : "23.6B" ,
193+ quantization_level : "Q4_K_M" ,
194+ } ,
195+ model_info : {
196+ "ollama.context_length" : 4096 ,
197+ "some.other.info" : "value" ,
198+ } ,
199+ capabilities : [ "completion" ] ,
200+ }
201+
202+ mockedAxios . get . mockResolvedValueOnce ( { data : mockApiTagsResponse } )
203+ mockedAxios . post . mockResolvedValueOnce ( { data : mockApiShowResponse } )
204+
205+ const result = await getOllamaModels ( baseUrl )
206+
207+ expect ( mockedAxios . get ) . toHaveBeenCalledTimes ( 1 )
208+ expect ( mockedAxios . get ) . toHaveBeenCalledWith ( `${ baseUrl } /api/tags` )
209+
210+ expect ( mockedAxios . post ) . toHaveBeenCalledTimes ( 1 )
211+ expect ( mockedAxios . post ) . toHaveBeenCalledWith ( `${ baseUrl } /api/show` , { model : modelName } )
212+
213+ expect ( typeof result ) . toBe ( "object" )
214+ expect ( result ) . not . toBeInstanceOf ( Array )
215+ expect ( Object . keys ( result ) . length ) . toBe ( 1 )
216+ expect ( result [ modelName ] ) . toBeDefined ( )
217+
218+ // Verify the model was parsed correctly despite null families
219+ expect ( result [ modelName ] . description ) . toBe ( "Family: llama, Context: 4096, Size: 23.6B" )
220+ } )
132221 } )
133222} )
0 commit comments