diff --git a/README.md b/README.md index 177187d25..590261471 100644 --- a/README.md +++ b/README.md @@ -307,6 +307,10 @@ codewhale --provider nvidia-nim # AtlasCloud codewhale auth set --provider atlascloud --api-key "YOUR_ATLASCLOUD_API_KEY" codewhale --provider atlascloud +# AtlasCloud provider-hinted resolution also supports the validated Atlas chat +# model pool in the static registry, for example: +codewhale --provider atlascloud --model openai/gpt-5.2-chat +codewhale --provider atlascloud --model qwen/qwen3-vl-235b-a22b-thinking # Wanjie Ark codewhale auth set --provider wanjie-ark --api-key "YOUR_WANJIE_API_KEY" diff --git a/crates/agent/src/lib.rs b/crates/agent/src/lib.rs index 7c3bbdf75..d3cd28bf3 100644 --- a/crates/agent/src/lib.rs +++ b/crates/agent/src/lib.rs @@ -49,10 +49,92 @@ pub struct ModelRegistry { alias_map: HashMap, } +const ATLASCLOUD_VALIDATED_MODELS: &[&str] = &[ + "deepseek-ai/DeepSeek-V3-0324", + "deepseek-ai/deepseek-r1-0528", + "moonshotai/Kimi-K2-Instruct", + "Qwen/Qwen3-Coder", + "Qwen/Qwen3-235B-A22B-Instruct-2507", + "deepseek-ai/DeepSeek-V3.1", + "moonshotai/Kimi-K2-Instruct-0905", + "Qwen/Qwen3-Next-80B-A3B-Instruct", + "Qwen/Qwen3-Next-80B-A3B-Thinking", + "Qwen/Qwen3-30B-A3B-Instruct-2507", + "deepseek-ai/DeepSeek-V3.1-Terminus", + "deepseek-ai/DeepSeek-V3.2-Exp", + "zai-org/GLM-4.6", + "MiniMaxAI/MiniMax-M2", + "Qwen/Qwen3-VL-235B-A22B-Instruct", + "moonshotai/Kimi-K2-Thinking", + "google/gemini-2.5-flash", + "google/gemini-2.5-flash-lite", + "openai/gpt-5.1", + "openai/gpt-5.1-chat", + "openai/gpt-4o", + "openai/gpt-4o-mini", + "openai/gpt-4.1", + "openai/gpt-4.1-mini", + "openai/gpt-4.1-nano", + "openai/o1", + "openai/o3", + "openai/o3-mini", + "openai/o4-mini", + "anthropic/claude-sonnet-4.5-20250929", + "deepseek-ai/deepseek-v3.2", + "openai/gpt-5", + "openai/gpt-5-chat", + "openai/gpt-5-mini", + "openai/gpt-5-nano", + "openai/gpt-5.2", + "openai/gpt-5.2-chat", + "google/gemini-2.5-pro", + "anthropic/claude-opus-4.5-20251101", + "google/gemini-3-flash-preview", + "zai-org/glm-4.7", + "minimaxai/minimax-m2.1", + "google/gemini-2.0-flash", + "qwen/qwen3-8b", + "qwen/qwen3-235b-a22b-thinking-2507", + "qwen/qwen3-vl-235b-a22b-thinking", + "qwen/qwen3-30b-a3b", + "qwen/qwen3-30b-a3b-thinking-2507", + "deepseek-ai/deepseek-ocr", + "xai/grok-4-0709", +]; + +fn atlascloud_model(id: &str, aliases: &[&str]) -> ModelInfo { + ModelInfo { + id: id.to_string(), + provider: ProviderKind::Atlascloud, + aliases: aliases.iter().map(|alias| (*alias).to_string()).collect(), + supports_tools: true, + supports_reasoning: true, + } +} + +fn atlascloud_models() -> Vec { + let mut models = vec![ + atlascloud_model( + "deepseek-ai/deepseek-v4-flash", + &["deepseek-v4-flash", "atlascloud-deepseek-v4-flash"], + ), + atlascloud_model( + "deepseek-ai/deepseek-v4-pro", + &["deepseek-v4-pro", "atlascloud-deepseek-v4-pro"], + ), + ]; + models.extend( + ATLASCLOUD_VALIDATED_MODELS + .iter() + .map(|model_id| atlascloud_model(model_id, &[])), + ); + models +} + /// Creates a registry pre-populated with all built-in models and their aliases. impl Default for ModelRegistry { fn default() -> Self { - let models = vec![ + let mut models = vec![ ModelInfo { id: "deepseek-v4-pro".to_string(), provider: ProviderKind::Deepseek, @@ -111,26 +193,6 @@ impl Default for ModelRegistry { supports_tools: true, supports_reasoning: true, }, - ModelInfo { - id: "deepseek-ai/deepseek-v4-flash".to_string(), - provider: ProviderKind::Atlascloud, - aliases: vec![ - "deepseek-v4-flash".to_string(), - "atlascloud-deepseek-v4-flash".to_string(), - ], - supports_tools: true, - supports_reasoning: true, - }, - ModelInfo { - id: "deepseek-ai/deepseek-v4-pro".to_string(), - provider: ProviderKind::Atlascloud, - aliases: vec![ - "deepseek-v4-pro".to_string(), - "atlascloud-deepseek-v4-pro".to_string(), - ], - supports_tools: true, - supports_reasoning: true, - }, ModelInfo { id: "deepseek-reasoner".to_string(), provider: ProviderKind::WanjieArk, @@ -426,6 +488,7 @@ impl Default for ModelRegistry { supports_reasoning: false, }, ]; + models.splice(6..6, atlascloud_models()); Self::new(models) } } @@ -621,6 +684,28 @@ mod tests { assert_eq!(resolved.resolved.id, "deepseek-ai/deepseek-v4-flash"); } + #[test] + fn atlascloud_validated_model_resolves_when_provider_hinted() { + let registry = ModelRegistry::default(); + let resolved = + registry.resolve(Some("openai/gpt-5.2-chat"), Some(ProviderKind::Atlascloud)); + + assert_eq!(resolved.resolved.provider, ProviderKind::Atlascloud); + assert_eq!(resolved.resolved.id, "openai/gpt-5.2-chat"); + } + + #[test] + fn atlascloud_registry_includes_validated_model_pool() { + let registry = ModelRegistry::default(); + let atlas_count = registry + .list() + .into_iter() + .filter(|model| model.provider == ProviderKind::Atlascloud) + .count(); + + assert!(atlas_count >= ATLASCLOUD_VALIDATED_MODELS.len() + 2); + } + #[test] fn deepseek_v4_pro_alias_resolves_to_atlascloud_when_provider_hinted() { let registry = ModelRegistry::default(); diff --git a/docs/PROVIDERS.md b/docs/PROVIDERS.md index 840474156..96be62a33 100644 --- a/docs/PROVIDERS.md +++ b/docs/PROVIDERS.md @@ -114,7 +114,7 @@ endpoint. | `deepseek` | `[providers.deepseek]` | `DEEPSEEK_API_KEY` | `CODEWHALE_BASE_URL` / `DEEPSEEK_BASE_URL`; default `https://api.deepseek.com/beta` | `deepseek-v4-pro`, `deepseek-v4-flash`; compatibility aliases `deepseek-chat`, `deepseek-reasoner` | First-class default. Beta URL enables strict tool mode, chat prefix completion, and FIM completion. Set `https://api.deepseek.com` or `/v1` explicitly to opt out of beta-only features. | | `nvidia-nim` | `[providers.nvidia_nim]` | `NVIDIA_API_KEY`, `NVIDIA_NIM_API_KEY`, fallback `DEEPSEEK_API_KEY` | `NVIDIA_NIM_BASE_URL`, `NIM_BASE_URL`, `NVIDIA_BASE_URL`; default `https://integrate.api.nvidia.com/v1` | `deepseek-ai/deepseek-v4-pro`, `deepseek-ai/deepseek-v4-flash` | Hosted DeepSeek V4 through NVIDIA NIM. `NVIDIA_NIM_MODEL` is accepted by the TUI config path. | | `openai` | `[providers.openai]` | `OPENAI_API_KEY` | `OPENAI_BASE_URL`; default `https://api.openai.com/v1` | Registry entries: `deepseek-v4-pro`, `deepseek-v4-flash`; default config model `deepseek-v4-pro` | Generic OpenAI-compatible route for gateways and custom endpoints. Use this for explicit third-party OpenAI-compatible routes instead of inventing a new provider ID. `OPENAI_MODEL` is accepted. | -| `atlascloud` | `[providers.atlascloud]` | `ATLASCLOUD_API_KEY` | `ATLASCLOUD_BASE_URL`; default `https://api.atlascloud.ai/v1` | `deepseek-ai/deepseek-v4-flash`, `deepseek-ai/deepseek-v4-pro` | OpenAI-compatible hosted route. `ATLASCLOUD_MODEL` is accepted by the TUI config path, and the static `ModelRegistry` includes AtlasCloud fallback rows for CLI model resolution. | +| `atlascloud` | `[providers.atlascloud]` | `ATLASCLOUD_API_KEY` | `ATLASCLOUD_BASE_URL`; default `https://api.atlascloud.ai/v1` | Default `deepseek-ai/deepseek-v4-flash`; static registry also includes the validated Atlas chat model pool | OpenAI-compatible hosted route. `ATLASCLOUD_MODEL` is accepted by the TUI config path, and the static `ModelRegistry` includes AtlasCloud fallback rows for CLI model resolution and provider-hinted model resolution. | | `wanjie-ark` | `[providers.wanjie_ark]` | `WANJIE_ARK_API_KEY`, `WANJIE_API_KEY`, `WANJIE_MAAS_API_KEY` | `WANJIE_ARK_BASE_URL`, `WANJIE_BASE_URL`, `WANJIE_MAAS_BASE_URL`; default `https://maas-openapi.wanjiedata.com/api/v1` | `deepseek-reasoner` | OpenAI-compatible hosted route. `WANJIE_ARK_MODEL`, `WANJIE_MODEL`, and `WANJIE_MAAS_MODEL` are accepted. | | `volcengine` | `[providers.volcengine]` | `VOLCENGINE_API_KEY`, `VOLCENGINE_ARK_API_KEY`, `ARK_API_KEY` | `VOLCENGINE_BASE_URL`, `VOLCENGINE_ARK_BASE_URL`, `ARK_BASE_URL`; default `https://ark.cn-beijing.volces.com/api/coding/v3` | `DeepSeek-V4-Pro`, `DeepSeek-V4-Flash` | Volcengine/Volcano Engine Ark OpenAI-compatible coding endpoint. `VOLCENGINE_MODEL` and `VOLCENGINE_ARK_MODEL` are accepted. | | `openrouter` | `[providers.openrouter]` | `OPENROUTER_API_KEY` | `OPENROUTER_BASE_URL`; default `https://openrouter.ai/api/v1` | `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash`; recent large IDs include `arcee-ai/trinity-large-thinking`, `minimax/minimax-m3`, `xiaomi/mimo-v2.5-pro`, `qwen/qwen3.6-35b-a3b`, `google/gemma-4-31b-it`, `z-ai/glm-5.1`, `moonshotai/kimi-k2.6` | Additive open-model routing layer. It does not replace DeepSeek; it lets users route supported model IDs through OpenRouter when they choose it. |