diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 36b76cb65..e50bc4192 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1478,7 +1478,8 @@ pub fn run() { commands::delete_profile, commands::clear_current_profile, commands::apply_profile, - // model list fetch (OpenAI-compatible /v1/models) + // Fetch OpenAI-compatible and Anthropic model lists. Response data structure: + // data[].id, data[]?.owned_by. Special: supports Zhipu OpenAI Responses models[].slug. commands::fetch_models_for_config, commands::get_opencode_models, // ours: endpoint speed test + custom endpoint management diff --git a/src-tauri/src/services/model_fetch.rs b/src-tauri/src/services/model_fetch.rs index 5963437a7..803b84100 100644 --- a/src-tauri/src/services/model_fetch.rs +++ b/src-tauri/src/services/model_fetch.rs @@ -18,10 +18,14 @@ pub struct FetchedModel { pub owned_by: Option, } -/// OpenAI 兼容的 /v1/models 响应格式 +/// 模型列表响应的兼容格式。 +/// +/// OpenAI 兼容接口和 Anthropic 接口使用 `data` 字段,智谱 OpenAI Responses +/// 接口使用 `models` 字段,此结构同时兼容这两种格式。 #[derive(Debug, Deserialize)] struct ModelsResponse { data: Option>, + models: Option>, } #[derive(Debug, Deserialize)] @@ -30,6 +34,11 @@ struct ModelEntry { owned_by: Option, } +#[derive(Debug, Deserialize)] +struct ZhipuModelEntry { + slug: String, +} + const FETCH_TIMEOUT_SECS: u64 = 15; const MAX_REQUEST_HEADERS: usize = 64; const MAX_HEADER_NAME_BYTES: usize = 256; @@ -98,15 +107,23 @@ pub async fn fetch_models( .await .map_err(|e| format!("Failed to parse response: {e}"))?; - let mut models: Vec = resp - .data - .unwrap_or_default() - .into_iter() - .map(|m| FetchedModel { - id: m.id, - owned_by: m.owned_by, - }) - .collect(); + let mut models: Vec = if let Some(data) = resp.data { + data.into_iter() + .map(|m| FetchedModel { + id: m.id, + owned_by: m.owned_by, + }) + .collect() + } else { + resp.models + .unwrap_or_default() + .into_iter() + .map(|m| FetchedModel { + id: m.slug, + owned_by: None, + }) + .collect() + }; models.sort_by(|a, b| a.id.cmp(&b.id)); return Ok(models); diff --git a/src/lib/api/model-fetch.ts b/src/lib/api/model-fetch.ts index 4f8f3c69c..36c297fbd 100644 --- a/src/lib/api/model-fetch.ts +++ b/src/lib/api/model-fetch.ts @@ -17,6 +17,13 @@ export interface ModelFetchOptions { * * 使用 OpenAI 兼容的 GET /v1/models 端点。优先用 `modelsUrl` 精确覆写; * 否则后端会对 baseURL 生成候选列表并按序尝试(含"剥离 /anthropic 等兼容子路径"兜底)。 + * + * 该接口可以获取数据格式为 + * OpenAI Chat Completion {"data": [{"id": "xxx","owned_by": "xxx"}]} 文档:https://developers.openai.com/api/reference/resources/models/methods/list + * 和 + * Anthropic兼容 {"data":[{"id":"xxx"}]} 文档:https://platform.claude.com/docs/en/api/models/list + * 这两种端点的模型列表 + * 特别支持智谱 OpenAI Responses {"models":[{"slug":"xxx"}]} 端点:https://open.bigmodel.cn/api/v1/models */ export async function fetchModelsForConfig( baseUrl: string,