diff --git a/.env.example b/.env.example index 4c011b0..246b821 100644 --- a/.env.example +++ b/.env.example @@ -24,7 +24,8 @@ OLLAMA_URL="http://localhost:11434" # Chinese providers # DEEPSEEK_API_KEY="" # DeepSeek # DASHSCOPE_API_KEY="" # Alibaba Qwen (DashScope) -# ZHIPU_API_KEY="" # Zhipu AI (GLM) +# ZHIPU_API_KEY="" # Zhipu AI (GLM, mainland BigModel) +# ZAI_API_KEY="" # Z.AI (Zhipu international, GLM) # MOONSHOT_API_KEY="" # Moonshot AI (Kimi) # QIANFAN_API_KEY="" # Baidu ERNIE (Qianfan) # MINIMAX_API_KEY="" # MiniMax diff --git a/backend/gateway/Cargo.toml b/backend/gateway/Cargo.toml index 59fd227..272568a 100644 --- a/backend/gateway/Cargo.toml +++ b/backend/gateway/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] anyhow.workspace = true axum = { workspace = true, features = ["ws"] } +tower-http = { version = "0.6", features = ["cors"] } serde = { workspace = true, features = ["derive"] } serde_json.workspace = true tokio = { workspace = true, features = ["full", "signal"] } diff --git a/backend/planner/src/providers/catalog.rs b/backend/planner/src/providers/catalog.rs index f4624a6..0a85e2a 100644 --- a/backend/planner/src/providers/catalog.rs +++ b/backend/planner/src/providers/catalog.rs @@ -113,9 +113,13 @@ pub const CATALOG: &[ProviderInfo] = &[ ProviderInfo { id: "qwen", display_name: "Alibaba Qwen (DashScope)", region: Region::China, base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1", env_var: "DASHSCOPE_API_KEY", wire: Wire::OpenAiCompatible, example_models: &["qwen-max", "qwen-plus", "qwen2.5-72b-instruct"], data_residency: "China-hosted; an international endpoint is also available" }, - ProviderInfo { id: "zhipu", display_name: "Zhipu AI (GLM)", region: Region::China, + ProviderInfo { id: "zhipu", display_name: "Zhipu AI (GLM, BigModel)", region: Region::China, base_url: "https://open.bigmodel.cn/api/paas/v4", env_var: "ZHIPU_API_KEY", wire: Wire::OpenAiCompatible, - example_models: &["glm-4.6", "glm-4-plus"], data_residency: "China-hosted" }, + example_models: &["glm-4.6", "glm-4-plus"], data_residency: "China-hosted (mainland BigModel endpoint)" }, + ProviderInfo { id: "zai", display_name: "Z.AI (Zhipu international, GLM)", region: Region::China, + base_url: "https://api.z.ai/api/paas/v4", env_var: "ZAI_API_KEY", wire: Wire::OpenAiCompatible, + example_models: &["glm-4.6", "glm-4.5", "glm-4.5-air"], + data_residency: "Zhipu's international GLM endpoint; coding-plan keys use /api/coding/paas/v4" }, ProviderInfo { id: "moonshot", display_name: "Moonshot AI (Kimi)", region: Region::China, base_url: "https://api.moonshot.cn/v1", env_var: "MOONSHOT_API_KEY", wire: Wire::OpenAiCompatible, example_models: &["moonshot-v1-128k", "kimi-k2-0905-preview"], data_residency: "China-hosted; a global endpoint is also available" }, @@ -205,12 +209,20 @@ mod tests { #[test] fn covers_major_chinese_providers() { - for id in ["deepseek", "qwen", "zhipu", "moonshot", "baidu", "minimax", "tencent", "yi"] { + for id in ["deepseek", "qwen", "zhipu", "zai", "moonshot", "baidu", "minimax", "tencent", "yi"] { assert!(get(id).is_some(), "missing Chinese provider {id}"); } assert!(chinese().len() >= 10, "expected at least 10 China-hosted providers"); } + #[test] + fn zai_is_openai_compatible_with_z_ai_base() { + let z = get("zai").unwrap(); + assert_eq!(z.wire, Wire::OpenAiCompatible); + assert!(z.base_url.contains("api.z.ai")); + assert_eq!(z.env_var, "ZAI_API_KEY"); + } + #[test] fn anthropic_uses_native_wire() { assert_eq!(get("anthropic").unwrap().wire, Wire::Anthropic); diff --git a/docs/model-providers.md b/docs/model-providers.md index c164708..bf8cdd4 100644 --- a/docs/model-providers.md +++ b/docs/model-providers.md @@ -48,7 +48,8 @@ cargo run -p clawforge-cli -- serve |----|----------|--------|------|---------| | `deepseek` | DeepSeek | China | OpenAI-compatible | `DEEPSEEK_API_KEY` | | `qwen` | Alibaba Qwen (DashScope) | China | OpenAI-compatible | `DASHSCOPE_API_KEY` | -| `zhipu` | Zhipu AI (GLM) | China | OpenAI-compatible | `ZHIPU_API_KEY` | +| `zhipu` | Zhipu AI (GLM, mainland BigModel) | China | OpenAI-compatible | `ZHIPU_API_KEY` | +| `zai` | Z.AI (Zhipu international, GLM) | China | OpenAI-compatible | `ZAI_API_KEY` | | `moonshot` | Moonshot AI (Kimi) | China | OpenAI-compatible | `MOONSHOT_API_KEY` | | `baidu` | Baidu ERNIE (Qianfan) | China | OpenAI-compatible | `QIANFAN_API_KEY` | | `minimax` | MiniMax | China | OpenAI-compatible | `MINIMAX_API_KEY` |