@@ -16,22 +16,30 @@ local M = {}
1616--- @field formatted_name string ?
1717--- @field opts { can_use_tools : boolean , has_vision : boolean }
1818
19- --- @alias MistralModelCache table<string , MistralModelInfo>
20-
21- --- @type MistralModelCache
19+ --- @class MistralApiCapabilities
20+ --- @field completion_chat boolean
21+ --- @field vision boolean
22+ --- @field function_calling boolean
23+
24+ --- @class MistralApiModel
25+ --- @field id string
26+ --- @field name string
27+ --- @field aliases string[]
28+ --- @field deprecation any ?
29+ --- @field capabilities MistralApiCapabilities
30+
31+ --- @type table<string , MistralModelInfo>
2232local _cached_models = {}
2333
24- --- @return MistralModelCache
34+ --- @return table<string , MistralModelInfo>
2535local function get_cached_models ()
26- assert (_cached_models ~= nil , " Model info is not available in the cache." )
27- local models = _cached_models
28- return models
36+ return _cached_models
2937end
3038
3139--- When given a list of names that are aliases for the same model, returns the preferred name.
3240--- The preference order is: names ending with '-latest' (highest priority),
3341--- then names ending with four digits (e.g., '-2023'), and finally other names.
34- --- @param names table List of names, should at least contain 1 entry
42+ --- @param names string[] List of names, should at least contain 1 entry
3543--- @return string ?
3644local function preferred_model_name (names )
3745 local high_score = - 1
5563
5664--- Multiple id can refer to the same Model,
5765--- This function removes duplicates, only using preferred model name
58- --- @param models table [] Table as returned by Mistral API response
59- --- @return table []
66+ --- @param models MistralApiModel [] Table as returned by Mistral API response
67+ --- @return MistralApiModel []
6068local function dedup_models (models )
6169 local preferred_names = {}
6270 for _ , model in ipairs (models ) do
6371 if model .id then
64- local aliases = {}
65- if model .aliases then
66- aliases = model .aliases
67- end
72+ local aliases = model .aliases
6873 table.insert (aliases , model .id )
6974
7075 if preferred_names [model .id ] then
9297
9398--- Fetch model list and model info.
9499--- Aborts if there's another fetch job running.
95- --- Returns the number of models if the fetches are fired.
100+ --- @return boolean cache was successful updated
96101--- @param adapter CodeCompanion.HTTPAdapter Mistral adapter with env var replaced.
97102local function fetch_async (adapter )
98103 assert (adapter ~= nil )
104+
105+ utils .get_env_vars (adapter )
99106 if running then
100- return
107+ return false
101108 end
102109
103110 running = true
104111
105- _cached_models = _cached_models or {} -- TODO: this has the side effect models are never removed
112+ _cached_models = _cached_models or {}
106113
107114 local models_endpoint = " /v1/models"
108115 local headers = {
109116 [" content-type" ] = " application/json" ,
110117 [" Authorization" ] = " Bearer " .. adapter .env_replaced .api_key ,
111118 }
112119 local url = adapter .env_replaced .url
113- pcall (function ()
120+ local ok , err = pcall (function ()
114121 Curl .get (url .. models_endpoint , {
115122 headers = headers ,
116123 insecure = config .adapters .http .opts .allow_insecure ,
@@ -120,18 +127,19 @@ local function fetch_async(adapter)
120127 -- This can happen wen you update vim ui in curl callback.
121128 callback = vim .schedule_wrap (function (response )
122129 if response .status ~= 200 then
123- running = false
124- return log :error (
130+ log :error (
125131 " Could not get Mistral models from " .. url .. models_endpoint .. " . Error: %s" ,
126132 response .body
127133 )
134+ running = false
135+ return false
128136 end
129137
130138 local ok , json = pcall (vim .json .decode , response .body )
131139 if not ok then
132- running = false
133140 log :error (" Could not parse the response from " .. url .. models_endpoint )
134- return {}
141+ running = false
142+ return false
135143 end
136144
137145 for _ , model_obj in ipairs (dedup_models (json .data )) do
@@ -150,39 +158,29 @@ local function fetch_async(adapter)
150158 running = false
151159 end ),
152160 })
153- if adapter .opts .cache_adapter == false then
154- vim .wait (CONSTANTS .TIMEOUT , function ()
155- local models = _cached_models
156- return models ~= nil and not vim .tbl_isempty (models ) and not running
157- end )
158- end
159161 end )
162+
163+ if not ok then
164+ log :error (" Could not fetch fetch Mistral Copilot models: %s" , err )
165+ running = false
166+ return false
167+ end
168+ return true
160169end
161170
162171--- @param self CodeCompanion.HTTPAdapter
163- --- @return MistralModelCache
164- function M .choices (self , opts )
165- local adapter = require (" codecompanion.adapters.http" ).resolve (self )
172+ --- @return table<string , MistralModelInfo>
173+ function M .choices (self )
166174
167- if not adapter then
168- log : error ( " Could not resolve Mistral adapter in the `choices` function " )
169- return {}
175+ local models = get_cached_models ()
176+ if models ~= nil and next ( models ) then
177+ return models
170178 end
171- opts = opts or { async = true }
172-
173- utils .get_env_vars (adapter )
174- local is_uninitialised = _cached_models == nil or next (_cached_models )
175-
176- local should_block = (adapter .opts .cache_adapter == false ) or is_uninitialised or not opts .async
177179
178- fetch_async (adapter )
179-
180- if should_block and running then
181- vim .wait (CONSTANTS .TIMEOUT , function ()
182- return not running
183- end )
184- end
180+ fetch_async (self )
181+ vim .wait (CONSTANTS .TIMEOUT , function ()
182+ return not running
183+ end )
185184 return get_cached_models ()
186185end
187-
188186return M
0 commit comments