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
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ windows-use
|--------------|-----------------------------------------------|
| Anthropic | `from windows_use.providers.anthropic import ChatAnthropic` |
| OpenAI | `from windows_use.providers.openai import ChatOpenAI` |
| Atlas Cloud | `from windows_use.providers.atlas_cloud import ChatAtlasCloud` |
| Google | `from windows_use.providers.google import ChatGoogle` |
| Groq | `from windows_use.providers.groq import ChatGroq` |
| Ollama | `from windows_use.providers.ollama import ChatOllama` |
Expand All @@ -161,6 +162,14 @@ windows-use
| NVIDIA | `from windows_use.providers.nvidia import ChatNvidia` |
| vLLM | `from windows_use.providers.vllm import ChatVLLM` |

Atlas Cloud uses its OpenAI-compatible API and reads `ATLAS_CLOUD_API_KEY` by default:

```python
from windows_use.providers.atlas_cloud import ChatAtlasCloud

llm = ChatAtlasCloud(model="openai/gpt-4.1-mini")
```

## 🧰 Agent Configuration

```python
Expand Down
41 changes: 41 additions & 0 deletions tests/unit/providers/test_atlas_cloud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from unittest.mock import patch

from windows_use.cli.registry import (
get_models,
get_provider_display,
get_providers,
provider_requires_api_key,
)
from windows_use.providers.atlas_cloud import ChatAtlasCloud
from windows_use.providers.atlas_cloud.llm import ATLAS_CLOUD_BASE_URL


@patch("windows_use.providers.openai.llm.AsyncOpenAI")
@patch("windows_use.providers.openai.llm.OpenAI")
def test_atlas_cloud_defaults(mock_openai, mock_async_openai, monkeypatch):
monkeypatch.setenv("ATLAS_CLOUD_API_KEY", "atlas-key")

llm = ChatAtlasCloud()

assert llm.provider == "atlas_cloud"
assert llm.model_name == "openai/gpt-4.1-mini"
assert llm.base_url == ATLAS_CLOUD_BASE_URL
mock_openai.assert_called_once_with(
api_key="atlas-key",
base_url=ATLAS_CLOUD_BASE_URL,
timeout=600.0,
max_retries=2,
)
mock_async_openai.assert_called_once_with(
api_key="atlas-key",
base_url=ATLAS_CLOUD_BASE_URL,
timeout=600.0,
max_retries=2,
)


def test_atlas_cloud_is_available_in_cli_registry():
assert ("Atlas Cloud", "atlas_cloud") in get_providers()
assert get_models("atlas_cloud") == [("OpenAI GPT-4.1 mini", "openai/gpt-4.1-mini")]
assert get_provider_display("atlas_cloud") == "Atlas Cloud"
assert provider_requires_api_key("atlas_cloud") is True
6 changes: 6 additions & 0 deletions windows_use/cli/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
PROVIDERS: list[tuple[str, str]] = [
("Groq", "groq"),
("OpenAI", "openai"),
("Atlas Cloud", "atlas_cloud"),
("Anthropic", "anthropic"),
("Google", "google"),
("Ollama", "ollama"),
Expand Down Expand Up @@ -54,6 +55,9 @@
("GPT-4 Turbo", "gpt-4-turbo"),
("GPT-3.5 Turbo", "gpt-3.5-turbo"),
],
"atlas_cloud": [
("OpenAI GPT-4.1 mini", "openai/gpt-4.1-mini"),
],
"perplexity": [
("GPT-5.4 (recommended)", "openai/gpt-5.4"),
("Gemini 3.1 Pro Preview", "google/gemini-3.1-pro-preview"),
Expand Down Expand Up @@ -174,6 +178,7 @@
PROVIDERS_REQUIRING_API_KEY: set[str] = {
"groq",
"openai",
"atlas_cloud",
"anthropic",
"google",
"mistral",
Expand All @@ -196,6 +201,7 @@ def provider_requires_api_key(provider_key: str) -> bool:
PROVIDER_DISPLAY: dict[str, str] = {
"groq": "Groq",
"openai": "OpenAI",
"atlas_cloud": "Atlas Cloud",
"anthropic": "Anthropic",
"google": "Google",
"ollama": "Ollama",
Expand Down
5 changes: 5 additions & 0 deletions windows_use/cli/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,10 @@ def create_llm(provider: str, model: str, api_key: str | None = None, base_url:
from windows_use.providers.openai import ChatOpenAI

return ChatOpenAI(model=model, api_key=key, base_url=base_url)
if provider == "atlas_cloud":
from windows_use.providers.atlas_cloud import ChatAtlasCloud

return ChatAtlasCloud(model=model, api_key=key, base_url=base_url)
if provider == "anthropic":
from windows_use.providers.anthropic import ChatAnthropic

Expand Down Expand Up @@ -751,6 +755,7 @@ def _env_api_key_for_provider(provider: str) -> str | None:
env_map = {
"groq": "GROQ_API_KEY",
"openai": "OPENAI_API_KEY",
"atlas_cloud": "ATLAS_CLOUD_API_KEY",
"anthropic": "ANTHROPIC_API_KEY",
"google": "GEMINI_API_KEY", # or GOOGLE_API_KEY
"mistral": "MISTRAL_API_KEY",
Expand Down
2 changes: 2 additions & 0 deletions windows_use/providers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# Base protocols & data models
# LLM providers
from windows_use.providers.anthropic import ChatAnthropic
from windows_use.providers.atlas_cloud import ChatAtlasCloud
from windows_use.providers.azure_openai import ChatAzureOpenAI
from windows_use.providers.base import BaseChatLLM, BaseSTT, BaseTTS
from windows_use.providers.cerebras import ChatCerebras
Expand Down Expand Up @@ -73,6 +74,7 @@
"ToolCall",
# LLM providers
"ChatAnthropic",
"ChatAtlasCloud",
"ChatGoogle",
"ChatOpenAI",
"ChatOllama",
Expand Down
3 changes: 3 additions & 0 deletions windows_use/providers/atlas_cloud/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from windows_use.providers.atlas_cloud.llm import ChatAtlasCloud

__all__ = ["ChatAtlasCloud"]
37 changes: 37 additions & 0 deletions windows_use/providers/atlas_cloud/llm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""Atlas Cloud LLM provider via its OpenAI-compatible API."""

import os

from windows_use.providers.openai.llm import ChatOpenAI

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


class ChatAtlasCloud(ChatOpenAI):
"""Chat model served through Atlas Cloud's OpenAI-compatible endpoint."""

def __init__(
self,
model: str = "openai/gpt-4.1-mini",
api_key: str | None = None,
base_url: str | None = None,
timeout: float = 600.0,
max_retries: int = 2,
temperature: float | None = None,
**kwargs,
):
api_key = api_key or os.environ.get("ATLAS_CLOUD_API_KEY")
base_url = base_url or os.environ.get("ATLAS_CLOUD_API_BASE") or ATLAS_CLOUD_BASE_URL
super().__init__(
model=model,
api_key=api_key,
base_url=base_url,
timeout=timeout,
max_retries=max_retries,
temperature=temperature,
**kwargs,
)

@property
def provider(self) -> str:
return "atlas_cloud"