@@ -61,16 +61,19 @@ pub struct LanguageModels {
model_list: acp_thread::AgentModelList,
refresh_models_rx: watch::Receiver<()>,
refresh_models_tx: watch::Sender<()>,
+ _authenticate_all_providers_task: Task<()>,
}
impl LanguageModels {
- fn new(cx: &App) -> Self {
+ fn new(cx: &mut App) -> Self {
let (refresh_models_tx, refresh_models_rx) = watch::channel(());
+
let mut this = Self {
models: HashMap::default(),
model_list: acp_thread::AgentModelList::Grouped(IndexMap::default()),
refresh_models_rx,
refresh_models_tx,
+ _authenticate_all_providers_task: Self::authenticate_all_language_model_providers(cx),
};
this.refresh_list(cx);
this
@@ -150,6 +153,52 @@ impl LanguageModels {
fn model_id(model: &Arc<dyn LanguageModel>) -> acp_thread::AgentModelId {
acp_thread::AgentModelId(format!("{}/{}", model.provider_id().0, model.id().0).into())
}
+
+ fn authenticate_all_language_model_providers(cx: &mut App) -> Task<()> {
+ let authenticate_all_providers = LanguageModelRegistry::global(cx)
+ .read(cx)
+ .providers()
+ .iter()
+ .map(|provider| (provider.id(), provider.name(), provider.authenticate(cx)))
+ .collect::<Vec<_>>();
+
+ cx.background_spawn(async move {
+ for (provider_id, provider_name, authenticate_task) in authenticate_all_providers {
+ if let Err(err) = authenticate_task.await {
+ if matches!(err, language_model::AuthenticateError::CredentialsNotFound) {
+ // Since we're authenticating these providers in the
+ // background for the purposes of populating the
+ // language selector, we don't care about providers
+ // where the credentials are not found.
+ } else {
+ // Some providers have noisy failure states that we
+ // don't want to spam the logs with every time the
+ // language model selector is initialized.
+ //
+ // Ideally these should have more clear failure modes
+ // that we know are safe to ignore here, like what we do
+ // with `CredentialsNotFound` above.
+ match provider_id.0.as_ref() {
+ "lmstudio" | "ollama" => {
+ // LM Studio and Ollama both make fetch requests to the local APIs to determine if they are "authenticated".
+ //
+ // These fail noisily, so we don't log them.
+ }
+ "copilot_chat" => {
+ // Copilot Chat returns an error if Copilot is not enabled, so we don't log those errors.
+ }
+ _ => {
+ log::error!(
+ "Failed to authenticate provider: {}: {err}",
+ provider_name.0
+ );
+ }
+ }
+ }
+ }
+ }
+ })
+ }
}
pub struct NativeAgent {