diff --git a/FEATURE_PARITY.md b/FEATURE_PARITY.md index 3be0f6ca..e53929ca 100644 --- a/FEATURE_PARITY.md +++ b/FEATURE_PARITY.md @@ -245,7 +245,7 @@ This document tracks feature parity between IronClaw (Rust implementation) and O | Ollama (local) | ✅ | ✅ | - | via `rig::providers::ollama` (full support) | | Perplexity | ✅ | ❌ | P3 | Freshness parameter for web_search | | MiniMax | ✅ | ❌ | P3 | Regional endpoint selection | -| GLM-5 | ✅ | ❌ | P3 | | +| GLM-5 | ✅ | ✅ | P3 | Via Z.AI provider (`zai`) using OpenAI-compatible chat completions | | node-llama-cpp | ✅ | ➖ | - | N/A for Rust | | llama.cpp (native) | ❌ | 🔮 | P3 | Rust bindings | diff --git a/providers.json b/providers.json index f7574f4c..3b98af30 100644 --- a/providers.json +++ b/providers.json @@ -238,6 +238,26 @@ "can_list_models": false } }, + { + "id": "zai", + "aliases": [ + "bigmodel" + ], + "protocol": "open_ai_completions", + "default_base_url": "https://api.z.ai/api/paas/v4", + "api_key_env": "ZAI_API_KEY", + "api_key_required": true, + "model_env": "ZAI_MODEL", + "default_model": "glm-5", + "description": "Z.AI GLM inference API", + "setup": { + "kind": "api_key", + "secret_name": "llm_zai_api_key", + "key_url": "https://z.ai/manage-apikey/apikey-list", + "display_name": "Z.AI", + "can_list_models": false + } + }, { "id": "cerebras", "aliases": [], @@ -382,4 +402,4 @@ "can_list_models": false } } -] \ No newline at end of file +] diff --git a/src/config/llm.rs b/src/config/llm.rs index dd2c9563..31b8ff4c 100644 --- a/src/config/llm.rs +++ b/src/config/llm.rs @@ -637,6 +637,31 @@ mod tests { ); } + #[test] + fn registry_provider_alias_resolves_zai() { + let _guard = ENV_MUTEX.lock().expect("env mutex poisoned"); + // SAFETY: Under ENV_MUTEX. + unsafe { + std::env::remove_var("LLM_BACKEND"); + std::env::remove_var("ZAI_API_KEY"); + std::env::remove_var("ZAI_MODEL"); + } + + let settings = Settings { + llm_backend: Some("bigmodel".to_string()), + selected_model: Some("glm-5".to_string()), + ..Default::default() + }; + + let cfg = LlmConfig::resolve(&settings).expect("resolve should succeed"); + assert_eq!(cfg.backend, "zai"); + let provider = cfg.provider.expect("provider config should be present"); + assert_eq!(provider.provider_id, "zai"); + assert_eq!(provider.model, "glm-5"); + assert_eq!(provider.base_url, "https://api.z.ai/api/paas/v4"); + assert_eq!(provider.protocol, ProviderProtocol::OpenAiCompletions); + } + #[test] fn nearai_backend_has_no_registry_provider() { let _guard = ENV_MUTEX.lock().expect("env mutex poisoned");