From 1f37fbd0511fcafd6b39e9de4d6d6db7244453dd Mon Sep 17 00:00:00 2001 From: Umesh Yadav <23421535+imumesh18@users.noreply.github.com> Date: Sat, 6 Sep 2025 11:12:15 +0530 Subject: [PATCH] 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 --- .../src/provider/open_router.rs | 25 +++++++++++++++---- crates/open_router/src/open_router.rs | 8 ++++-- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/crates/language_models/src/provider/open_router.rs b/crates/language_models/src/provider/open_router.rs index 9138f6b82e7e74e9e6a7468306b2f5cf6768987e..f73a97e6426f80e1ad8d1b8214e16bf361d0f0ce 100644 --- a/crates/language_models/src/provider/open_router.rs +++ b/crates/language_models/src/provider/open_router.rs @@ -92,7 +92,7 @@ pub struct State { api_key_from_env: bool, http_client: Arc, available_models: Vec, - fetch_models_task: Option>>, + fetch_models_task: Option>>, settings: OpenRouterSettings, _subscription: Subscription, } @@ -178,20 +178,35 @@ impl State { }) } - fn fetch_models(&mut self, cx: &mut Context) -> Task> { + fn fetch_models( + &mut self, + cx: &mut Context, + ) -> Task> { 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(()) }) } diff --git a/crates/open_router/src/open_router.rs b/crates/open_router/src/open_router.rs index dfaa49746d093810924f744cd1aeb3e8747ddb00..cbc6c243d87c8f9ea3d0186dbecb8f0ac2e10a90 100644 --- a/crates/open_router/src/open_router.rs +++ b/crates/open_router/src/open_router.rs @@ -529,12 +529,16 @@ pub async fn stream_completion( pub async fn list_models( client: &dyn HttpClient, api_url: &str, + api_key: &str, ) -> Result, 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())