From 8a23a22c9b2cbd00d36495d3cb49ea848bafe362 Mon Sep 17 00:00:00 2001 From: ZhenYi <434836402@qq.com> Date: Sun, 26 Apr 2026 15:49:34 +0800 Subject: [PATCH] fix(agent/sync): make OpenRouter fetch optional, fallback to direct sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When OpenRouter's public /api/v1/models endpoint fails (network error, timeout, parse failure), the entire sync was aborted — meaning models accessible from the user's AI endpoint were never synced. Now: if OpenRouter fetch fails, fall back to sync_models_direct for all available models instead of returning an error. Both sync_upstream_models (API) and sync_once (background task) have this fix. --- libs/service/agent/sync.rs | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/libs/service/agent/sync.rs b/libs/service/agent/sync.rs index ed29257..db92a58 100644 --- a/libs/service/agent/sync.rs +++ b/libs/service/agent/sync.rs @@ -726,15 +726,20 @@ impl AppService { available_ids.len() ); - // Step 2: fetch OpenRouter metadata. + // Step 2: fetch OpenRouter metadata (optional — failure falls back to + // direct sync for all available models). let http_client = reqwest::Client::new(); - let or_resp: OpenRouterResponse = fetch_openrouter_models(&http_client) - .await - .map_err(AppError::InternalServerError)?; + let or_models: Vec = match fetch_openrouter_models(&http_client).await { + Ok(resp) => resp.data, + Err(msg) => { + tracing::warn!(error = %msg, "sync_upstream_models: OpenRouter fetch failed, falling back to direct sync"); + let direct_result = sync_models_direct(&self.db, &available_ids).await; + return Ok(direct_result); + } + }; // Step 3: filter to only accessible models. - let filtered: Vec<&OpenRouterModel> = or_resp - .data + let filtered: Vec<&OpenRouterModel> = or_models .iter() .filter(|m| available_ids.contains(&m.id)) .filter(|m| m.id != "openrouter/auto") @@ -927,16 +932,16 @@ impl AppService { }; let http_client = reqwest::Client::new(); - let or_resp = match fetch_openrouter_models(&http_client).await { - Ok(r) => r, + let or_models: Vec = match fetch_openrouter_models(&http_client).await { + Ok(resp) => resp.data, Err(msg) => { - tracing::warn!(error = %msg, "OpenRouter model sync"); + tracing::warn!(error = %msg, "OpenRouter model sync: fetch failed, falling back to direct sync"); + sync_models_direct(db, &available_ids).await; return; } }; - let filtered: Vec<&OpenRouterModel> = or_resp - .data + let filtered: Vec<&OpenRouterModel> = or_models .iter() .filter(|m| available_ids.contains(&m.id)) .filter(|m| m.id != "openrouter/auto")