diff --git a/routes/model_routes.py b/routes/model_routes.py index 3f2cb7d4e0..646ac40179 100644 --- a/routes/model_routes.py +++ b/routes/model_routes.py @@ -342,6 +342,10 @@ def _rewrite_loopback_for_docker(base_url: str, *, container_local: bool = False "deepseek": [ "deepseek-chat", "deepseek-reasoner", ], + "atlascloud": [ + "qwen/qwen3.5-flash", + "deepseek-ai/deepseek-v4-pro", + ], "groq": [ "openai/gpt-oss-120b", "openai/gpt-oss-20b", "groq/compound", "groq/compound-mini", @@ -381,6 +385,7 @@ def _rewrite_loopback_for_docker(base_url: str, *, container_local: bool = False # inside an unrelated URL. _HOST_TO_CURATED = ( ("z.ai", "zai"), + ("atlascloud.ai", "atlascloud"), ("deepseek.com", "deepseek"), ("groq.com", "groq"), ("mistral.ai", "mistral"), diff --git a/src/llm_core.py b/src/llm_core.py index af1958f16f..5b5530f27e 100644 --- a/src/llm_core.py +++ b/src/llm_core.py @@ -1001,6 +1001,7 @@ def _provider_label(url: str) -> str: if _host_match(url, "ollama.com"): return "Ollama Cloud" if _host_match(url, "x.ai"): return "xAI" if _host_match(url, "openai.com"): return "OpenAI" + if _host_match(url, "atlascloud.ai"): return "Atlas Cloud" if _host_match(url, "openrouter.ai"): return "OpenRouter" if _host_match(url, "opencode.ai/zen/go"): return "OpenCode Go" if _host_match(url, "opencode.ai/zen"): return "OpenCode Zen" diff --git a/static/js/providers.js b/static/js/providers.js index 54556faebc..ba1bb69d1c 100644 --- a/static/js/providers.js +++ b/static/js/providers.js @@ -110,6 +110,7 @@ const _ENDPOINT_LABELS = [ [/(^|\.)openrouter\.ai$/i, "OpenRouter"], [/(^|\.)anthropic\.com$/i, "Anthropic"], [/(^|\.)openai\.com$/i, "OpenAI"], + [/(^|\.)atlascloud\.ai$/i, "Atlas Cloud"], [/(^|\.)(generativelanguage|aiplatform)\.googleapis\.com$/i, "Google"], [/(^|\.)bedrock[\w.-]*\.amazonaws\.com$/i, "AWS Bedrock"], [/(^|\.)deepseek\.com$/i, "DeepSeek"], diff --git a/static/js/slashCommands.js b/static/js/slashCommands.js index cabb7d32b1..7f68b43ee6 100644 --- a/static/js/slashCommands.js +++ b/static/js/slashCommands.js @@ -56,11 +56,12 @@ const SETUP_PROVIDER_URLS = { groq: { name: 'Groq', url: 'https://api.groq.com/openai/v1' }, gemini: { name: 'Gemini', url: 'https://generativelanguage.googleapis.com/v1beta/openai' }, google: { name: 'Gemini', url: 'https://generativelanguage.googleapis.com/v1beta/openai' }, + atlascloud: { name: 'Atlas Cloud', url: 'https://api.atlascloud.ai/v1' }, 'opencode-zen': { name: 'OpenCode Zen', url: 'https://opencode.ai/zen/v1' }, 'opencode-go': { name: 'OpenCode Go', url: 'https://opencode.ai/zen/go/v1' }, nvidia: { name: 'NVIDIA', url: 'https://integrate.api.nvidia.com/v1' }, }; -const SETUP_PROVIDER_NAMES = ['deepseek', 'openai', 'openrouter', 'ollama', 'xai', 'anthropic', 'groq', 'gemini', 'opencode-zen', 'opencode-go', 'nvidia']; +const SETUP_PROVIDER_NAMES = ['deepseek', 'openai', 'openrouter', 'ollama', 'xai', 'anthropic', 'groq', 'gemini', 'atlascloud', 'opencode-zen', 'opencode-go', 'nvidia']; const SETUP_DEVICE_AUTH_PROVIDERS = [ { key: 'copilot', name: 'GitHub Copilot', aliases: ['github'], command: '/setup copilot' }, { key: 'chatgpt-subscription', name: 'ChatGPT Subscription', aliases: ['chatgptsubscription', 'chatgpt-sub', 'codex'], command: '/setup chatgpt-subscription' }, @@ -100,6 +101,9 @@ function _setupProviderFromInput(input) { google: 'gemini', xai: 'xai', grok: 'xai', + atlas: 'atlascloud', + atlascloud: 'atlascloud', + atlascloudai: 'atlascloud', nvidia: 'nvidia', opencodezen: 'opencode-zen', opencodego: 'opencode-go', @@ -130,6 +134,7 @@ function _extractSetupProviderCredential(input) { ['groq', 'groq'], ['google', 'gemini'], ['gemini', 'gemini'], ['x ai', 'xai'], ['xai', 'xai'], ['grok', 'xai'], + ['atlas cloud', 'atlascloud'], ['atlascloud', 'atlascloud'], ['atlas', 'atlascloud'], ['nvidia', 'nvidia'], ['opencode zen', 'opencode-zen'], ['opencode-zen', 'opencode-zen'], ['opencode go', 'opencode-go'], ['opencode-go', 'opencode-go'], @@ -5864,6 +5869,7 @@ const COMMANDS = { groq: { help: 'Groq', usage: '/setup groq gsk_...', handler: (a, c) => _cmdSetup(['groq', ...a], c) }, gemini: { help: 'Google Gemini', alias: ['google'], usage: '/setup gemini AIza...', handler: (a, c) => _cmdSetup(['gemini', ...a], c) }, xai: { help: 'xAI (Grok)', alias: ['grok'], usage: '/setup xai xai-...', handler: (a, c) => _cmdSetup(['xai', ...a], c) }, + atlascloud: { help: 'Atlas Cloud', alias: ['atlas'], usage: '/setup atlascloud KEY', handler: (a, c) => _cmdSetup(['atlascloud', ...a], c) }, ollama: { help: 'Ollama Cloud', usage: '/setup ollama KEY', handler: (a, c) => _cmdSetup(['ollama', ...a], c) }, copilot: { help: 'GitHub Copilot', usage: '/setup copilot', handler: (a, c) => _cmdSetup(['copilot', ...a], c) }, 'chatgpt-subscription': { help: 'ChatGPT Subscription', alias: ['codex'], usage: '/setup chatgpt-subscription', handler: (a, c) => _cmdSetup(['chatgpt-subscription', ...a], c) }, diff --git a/tests/test_model_routes.py b/tests/test_model_routes.py index d413820c58..3eaec17a5c 100644 --- a/tests/test_model_routes.py +++ b/tests/test_model_routes.py @@ -184,6 +184,9 @@ def test_url_match_overrides_provider(self): def test_deepseek_url(self): assert _match_provider_curated("https://api.deepseek.com/v1", "openai") == "deepseek" + def test_atlascloud_url(self): + assert _match_provider_curated("https://api.atlascloud.ai/v1", "openai") == "atlascloud" + def test_groq_url(self): assert _match_provider_curated("https://api.groq.com/openai/v1", "openai") == "groq" @@ -341,6 +344,12 @@ def test_deepseek_curated(self): assert "deepseek-reasoner" in curated assert "deepseek-coder" in extra + def test_atlascloud_curated(self): + models = ["deepseek-ai/deepseek-v4-pro", "custom-atlas-model", "qwen/qwen3.5-flash"] + curated, extra = _curate_models(models, "atlascloud") + assert curated == ["qwen/qwen3.5-flash", "deepseek-ai/deepseek-v4-pro"] + assert extra == ["custom-atlas-model"] + def test_xai_curated(self): models = ["grok-4", "grok-3-fast", "grok-2"] curated, extra = _curate_models(models, "xai") diff --git a/tests/test_provider_classification.py b/tests/test_provider_classification.py index 62c713e31a..ac890f62d0 100644 --- a/tests/test_provider_classification.py +++ b/tests/test_provider_classification.py @@ -45,6 +45,7 @@ class TestDetectProvider: ("https://api.openai.com/v1", "openai"), ("https://api.x.ai/v1", "openai"), ("https://api.deepseek.com", "openai"), + ("https://api.atlascloud.ai/v1", "openai"), ("https://generativelanguage.googleapis.com/v1beta/openai", "openai"), # Ollama's OpenAI-compatible /v1 surface is generic, not native ollama. ("http://localhost:11434/v1", "openai"), @@ -79,6 +80,7 @@ class TestProviderLabel: ("https://ollama.com", "Ollama Cloud"), ("https://api.x.ai/v1", "xAI"), ("https://api.openai.com/v1", "OpenAI"), + ("https://api.atlascloud.ai/v1", "Atlas Cloud"), ("https://openrouter.ai/api/v1", "OpenRouter"), ("https://api.groq.com/openai/v1", "Groq"), ("https://integrate.api.nvidia.com/v1", "NVIDIA"), diff --git a/tests/test_provider_endpoints_headers.py b/tests/test_provider_endpoints_headers.py index dc7bc5da20..ce73701896 100644 --- a/tests/test_provider_endpoints_headers.py +++ b/tests/test_provider_endpoints_headers.py @@ -24,6 +24,7 @@ def test_headers_anthropic_without_key_still_sends_version(): @pytest.mark.parametrize("base", [ "https://api.openai.com/v1", + "https://api.atlascloud.ai/v1", "https://api.x.ai/v1", "https://api.deepseek.com", "https://api.groq.com/openai/v1", diff --git a/tests/test_provider_endpoints_url_building.py b/tests/test_provider_endpoints_url_building.py index 56d129e1c3..f08c5c2e29 100644 --- a/tests/test_provider_endpoints_url_building.py +++ b/tests/test_provider_endpoints_url_building.py @@ -28,6 +28,9 @@ def no_dns(monkeypatch): ("openai_pathless", "https://api.openai.com", "https://api.openai.com/v1/chat/completions", "https://api.openai.com/v1/models"), + ("atlascloud", "https://api.atlascloud.ai/v1", + "https://api.atlascloud.ai/v1/chat/completions", + "https://api.atlascloud.ai/v1/models"), ("anthropic", "https://api.anthropic.com", "https://api.anthropic.com/v1/messages", "https://api.anthropic.com/v1/models"), diff --git a/tests/test_provider_label_js.py b/tests/test_provider_label_js.py index 39b1a1f5dc..f0e5fac52b 100644 --- a/tests/test_provider_label_js.py +++ b/tests/test_provider_label_js.py @@ -47,6 +47,7 @@ def _provider_label(url: str) -> str | None: ("http://localhost:9999/v1", "Local"), # Known remote provider hosts are still labeled by host suffix. ("https://api.openai.com/v1", "OpenAI"), + ("https://api.atlascloud.ai/v1", "Atlas Cloud"), ("https://api.groq.com/openai/v1","Groq"), ("http://192.168.1.50:8080", "Local"), # private LAN: no port branding ]) diff --git a/tests/test_slash_setup_provider_aliases.py b/tests/test_slash_setup_provider_aliases.py index 0e50c7c48a..a09795b994 100644 --- a/tests/test_slash_setup_provider_aliases.py +++ b/tests/test_slash_setup_provider_aliases.py @@ -25,5 +25,10 @@ def test_opencode_setup_provider_aliases_resolve(): const goCredential = _extractSetupProviderCredential('opencode go sk-test'); assert(goCredential && goCredential.provider.name === 'OpenCode Go', 'opencode go credential provider failed'); assert(goCredential.credential === 'sk-test', 'opencode go credential extraction failed'); -""" +const atlasFromCommand = _setupProviderFromInput('atlas cloud'); +assert(atlasFromCommand && atlasFromCommand.url === 'https://api.atlascloud.ai/v1', 'atlas cloud command alias failed'); +const atlasCredential = _extractSetupProviderCredential('atlascloud sk-test'); +assert(atlasCredential && atlasCredential.provider.name === 'Atlas Cloud', 'atlascloud credential provider failed'); +assert(atlasCredential.credential === 'sk-test', 'atlascloud credential extraction failed'); + """ subprocess.run(["node", "-e", script], check=True)