language_models: Use /models/user for fetching OpenRouter models (#37534)

This PR switches the OpenRouter integration from fetching all models to
fetching only the models specified in the user's account preferences.
This will help improve the experience

**The Problem**

The previous implementation used the `/models` endpoint, which returned
an exhaustive list of all models supported by OpenRouter. This resulted
in a long and cluttered model selection dropdown in Zed, making it
difficult for users to find the models they actually use.

**The Solution**

We now use the `/models/user` endpoint. This API call returns a curated
list based on the models and providers the user has selected in their
[OpenRouter dashboard](https://openrouter.ai/models).

Ref: [OpenRouter API Docs for User-Filtered
Models](https://openrouter.ai/docs/api-reference/list-models-filtered-by-user-provider-preferences)

Release Notes:

- language_models: Support OpenRouter user preferences for available
models
This commit is contained in:
Umesh Yadav
2025-09-06 07:42:15 +02:00
committed by GitHub
parent 8c9442ad11
commit 1f37fbd051
2 changed files with 26 additions and 7 deletions
@@ -92,7 +92,7 @@ pub struct State {
api_key_from_env: bool,
http_client: Arc<dyn HttpClient>,
available_models: Vec<open_router::Model>,
fetch_models_task: Option<Task<Result<()>>>,
fetch_models_task: Option<Task<Result<(), LanguageModelCompletionError>>>,
settings: OpenRouterSettings,
_subscription: Subscription,
}
@@ -178,20 +178,35 @@ impl State {
})
}
fn fetch_models(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> {
fn fetch_models(
&mut self,
cx: &mut Context<Self>,
) -> Task<Result<(), LanguageModelCompletionError>> {
let settings = &AllLanguageModelSettings::get_global(cx).open_router;
let http_client = self.http_client.clone();
let api_url = settings.api_url.clone();
let Some(api_key) = self.api_key.clone() else {
return Task::ready(Err(LanguageModelCompletionError::NoApiKey {
provider: PROVIDER_NAME,
}));
};
cx.spawn(async move |this, cx| {
let models = list_models(http_client.as_ref(), &api_url)
let models = list_models(http_client.as_ref(), &api_url, &api_key)
.await
.map_err(|e| anyhow::anyhow!("OpenRouter error: {:?}", e))?;
.map_err(|e| {
LanguageModelCompletionError::Other(anyhow::anyhow!(
"OpenRouter error: {:?}",
e
))
})?;
this.update(cx, |this, cx| {
this.available_models = models;
cx.notify();
})
.map_err(|e| LanguageModelCompletionError::Other(e))?;
Ok(())
})
}
+6 -2
View File
@@ -529,12 +529,16 @@ pub async fn stream_completion(
pub async fn list_models(
client: &dyn HttpClient,
api_url: &str,
api_key: &str,
) -> Result<Vec<Model>, OpenRouterError> {
let uri = format!("{api_url}/models");
let uri = format!("{api_url}/models/user");
let request_builder = HttpRequest::builder()
.method(Method::GET)
.uri(uri)
.header("Accept", "application/json");
.header("Accept", "application/json")
.header("Authorization", format!("Bearer {}", api_key))
.header("HTTP-Referer", "https://zed.dev")
.header("X-Title", "Zed Editor");
let request = request_builder
.body(AsyncBody::default())