@@ -61,16 +61,19 @@ pub struct LanguageModels {
61
61
model_list : acp_thread:: AgentModelList ,
62
62
refresh_models_rx : watch:: Receiver < ( ) > ,
63
63
refresh_models_tx : watch:: Sender < ( ) > ,
64
+ _authenticate_all_providers_task : Task < ( ) > ,
64
65
}
65
66
66
67
impl LanguageModels {
67
- fn new ( cx : & App ) -> Self {
68
+ fn new ( cx : & mut App ) -> Self {
68
69
let ( refresh_models_tx, refresh_models_rx) = watch:: channel ( ( ) ) ;
70
+
69
71
let mut this = Self {
70
72
models : HashMap :: default ( ) ,
71
73
model_list : acp_thread:: AgentModelList :: Grouped ( IndexMap :: default ( ) ) ,
72
74
refresh_models_rx,
73
75
refresh_models_tx,
76
+ _authenticate_all_providers_task : Self :: authenticate_all_language_model_providers ( cx) ,
74
77
} ;
75
78
this. refresh_list ( cx) ;
76
79
this
@@ -150,6 +153,52 @@ impl LanguageModels {
150
153
fn model_id ( model : & Arc < dyn LanguageModel > ) -> acp_thread:: AgentModelId {
151
154
acp_thread:: AgentModelId ( format ! ( "{}/{}" , model. provider_id( ) . 0 , model. id( ) . 0 ) . into ( ) )
152
155
}
156
+
157
+ fn authenticate_all_language_model_providers ( cx : & mut App ) -> Task < ( ) > {
158
+ let authenticate_all_providers = LanguageModelRegistry :: global ( cx)
159
+ . read ( cx)
160
+ . providers ( )
161
+ . iter ( )
162
+ . map ( |provider| ( provider. id ( ) , provider. name ( ) , provider. authenticate ( cx) ) )
163
+ . collect :: < Vec < _ > > ( ) ;
164
+
165
+ cx. background_spawn ( async move {
166
+ for ( provider_id, provider_name, authenticate_task) in authenticate_all_providers {
167
+ if let Err ( err) = authenticate_task. await {
168
+ if matches ! ( err, language_model:: AuthenticateError :: CredentialsNotFound ) {
169
+ // Since we're authenticating these providers in the
170
+ // background for the purposes of populating the
171
+ // language selector, we don't care about providers
172
+ // where the credentials are not found.
173
+ } else {
174
+ // Some providers have noisy failure states that we
175
+ // don't want to spam the logs with every time the
176
+ // language model selector is initialized.
177
+ //
178
+ // Ideally these should have more clear failure modes
179
+ // that we know are safe to ignore here, like what we do
180
+ // with `CredentialsNotFound` above.
181
+ match provider_id. 0 . as_ref ( ) {
182
+ "lmstudio" | "ollama" => {
183
+ // LM Studio and Ollama both make fetch requests to the local APIs to determine if they are "authenticated".
184
+ //
185
+ // These fail noisily, so we don't log them.
186
+ }
187
+ "copilot_chat" => {
188
+ // Copilot Chat returns an error if Copilot is not enabled, so we don't log those errors.
189
+ }
190
+ _ => {
191
+ log:: error!(
192
+ "Failed to authenticate provider: {}: {err}" ,
193
+ provider_name. 0
194
+ ) ;
195
+ }
196
+ }
197
+ }
198
+ }
199
+ }
200
+ } )
201
+ }
153
202
}
154
203
155
204
pub struct NativeAgent {
0 commit comments