Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cascadeflow/providers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

_LAZY_PROVIDERS: dict[str, str] = {
"AnthropicProvider": ".anthropic",
"AtlasCloudProvider": ".atlascloud",
"DeepSeekProvider": ".deepseek",
"GroqProvider": ".groq",
"HuggingFaceProvider": ".huggingface",
Expand Down Expand Up @@ -57,6 +58,7 @@ def _build_provider_registry() -> dict:
registry = {}
_name_to_key = {
"OpenAIProvider": "openai",
"AtlasCloudProvider": "atlascloud",
"AnthropicProvider": "anthropic",
"OllamaProvider": "ollama",
"GroqProvider": "groq",
Expand Down Expand Up @@ -137,6 +139,7 @@ def get_available_providers() -> dict[str, BaseProvider]:
"ModelResponse",
"PROVIDER_CAPABILITIES",
"OpenAIProvider",
"AtlasCloudProvider",
"AnthropicProvider",
"OllamaProvider",
"GroqProvider",
Expand Down
53 changes: 53 additions & 0 deletions cascadeflow/providers/atlascloud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""Atlas Cloud provider implementation.

Atlas Cloud exposes an OpenAI-compatible chat completions API, so the provider
reuses the OpenAI provider implementation with Atlas-specific defaults.

Environment Variables:
ATLASCLOUD_API_KEY: Your Atlas Cloud API key

Models:
- qwen/qwen3.5-flash: Fast default chat model
- deepseek-ai/deepseek-v4-pro: Reasoning-capable chat model
"""

import os
from typing import Optional

from .openai import OpenAIProvider


class AtlasCloudProvider(OpenAIProvider):
"""Atlas Cloud provider using the OpenAI-compatible API."""

BASE_URL = "https://api.atlascloud.ai/v1"

def __init__(
self,
api_key: Optional[str] = None,
base_url: Optional[str] = None,
**kwargs,
):
"""
Initialize Atlas Cloud provider.

Args:
api_key: Atlas Cloud API key (defaults to ATLASCLOUD_API_KEY env var)
base_url: Custom base URL (defaults to Atlas Cloud API)
**kwargs: Additional OpenAI provider options
"""
atlascloud_api_key = api_key or os.getenv("ATLASCLOUD_API_KEY")

if not atlascloud_api_key:
raise ValueError(
"Atlas Cloud API key not found. "
"Set ATLASCLOUD_API_KEY environment variable or pass api_key parameter."
)

super().__init__(api_key=atlascloud_api_key, **kwargs)
self.base_url = base_url or self.BASE_URL

@property
def name(self) -> str:
"""Provider name."""
return "atlascloud"
1 change: 1 addition & 0 deletions cascadeflow/providers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,7 @@ def _get_litellm_prefix(self) -> Optional[str]:
# Map provider class names to LiteLLM prefixes
provider_prefixes = {
"OpenAIProvider": None, # Native format
"AtlasCloudProvider": "openai", # Atlas Cloud uses OpenAI-compatible format
"AnthropicProvider": None, # Native format
"GroqProvider": "groq",
"TogetherProvider": "together_ai",
Expand Down
1 change: 1 addition & 0 deletions docs/INSTALLATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ python examples/multi_provider.py
| pydantic | Core validation | ✅ Always | requirements.txt |
| httpx | Core HTTP client | ✅ Always | requirements.txt |
| openai | OpenAIProvider | ❌ Optional | `[openai]` or `[providers]` or `[all]` |
| atlascloud | AtlasCloudProvider | ❌ Optional | core package + `ATLASCLOUD_API_KEY` |
| anthropic | AnthropicProvider | ❌ Optional | `[anthropic]` or `[providers]` or `[all]` |
| groq | GroqProvider | ❌ Optional | `[groq]` or `[providers]` or `[all]` |
| huggingface-hub | HuggingFaceProvider | ❌ Optional | `[huggingface]` or `[all]` |
Expand Down
46 changes: 46 additions & 0 deletions tests/test_atlascloud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""Tests for Atlas Cloud provider."""

import os
from unittest.mock import patch

import pytest

from cascadeflow.providers import PROVIDER_REGISTRY
from cascadeflow.providers.atlascloud import AtlasCloudProvider


def test_init_with_api_key():
"""Test initialization with explicit API key."""
provider = AtlasCloudProvider(api_key="atlas-test-key")

assert provider.api_key == "atlas-test-key"
assert provider.base_url == "https://api.atlascloud.ai/v1"
assert provider.name == "atlascloud"


def test_init_from_env():
"""Test initialization from ATLASCLOUD_API_KEY."""
with patch.dict(os.environ, {"ATLASCLOUD_API_KEY": "atlas-env-key"}, clear=True):
provider = AtlasCloudProvider()

assert provider.api_key == "atlas-env-key"
assert provider.base_url == "https://api.atlascloud.ai/v1"


def test_init_no_api_key():
"""Test initialization fails without Atlas Cloud API key."""
with patch.dict(os.environ, {}, clear=True):
with pytest.raises(ValueError, match="Atlas Cloud API key not found"):
AtlasCloudProvider()


def test_custom_base_url():
"""Test custom Atlas Cloud-compatible base URL."""
provider = AtlasCloudProvider(api_key="atlas-test-key", base_url="https://proxy.test/v1")

assert provider.base_url == "https://proxy.test/v1"


def test_registered_provider():
"""Test Atlas Cloud is registered for cascade agents."""
assert PROVIDER_REGISTRY["atlascloud"] is AtlasCloudProvider