Metadata-Version: 2.4
Name: ryora-atlas-sdk
Version: 1.3.0
Summary: Atlas SDK for Python - Client library for Atlas Control Plane
Author: Atlas Team
License: Proprietary
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.13
Requires-Dist: httpx>=0.28.0
Requires-Dist: pydantic>=2.0.0
Provides-Extra: dev
Requires-Dist: mypy>=1.13.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
Requires-Dist: pytest-cov>=6.0.0; extra == 'dev'
Requires-Dist: pytest-mock>=3.14.0; extra == 'dev'
Requires-Dist: pytest>=8.3.0; extra == 'dev'
Requires-Dist: respx>=0.21.0; extra == 'dev'
Requires-Dist: ruff>=0.8.0; extra == 'dev'
Description-Content-Type: text/markdown

# Atlas SDK for Python

The official Python client library for the Atlas Control Plane API. This SDK enables AI agents to self-report their existence, configuration, and health to the Atlas Control Plane.

## Installation

```bash
pip install ryora-atlas-sdk
```

## Quickstart

### Synchronous Client

```python
from atlas_sdk import ControlPlaneClient, AgentConfiguration

# Create client (reads ATLAS_API_URL and ATLAS_API_KEY from environment)
client = ControlPlaneClient()

# Register your agent
client.register(
    name="my-agent",
    owner="team@company.com",
    configuration=AgentConfiguration(
        model_provider="anthropic",
        model_name="claude-sonnet-4-20250514",
        tools=["file_read", "file_write"],
    ),
)

# Heartbeats are sent automatically in the background
# Do your agent work here...

# Deregister when done
client.deregister()
```

### Using Context Manager

The recommended way to use the client is with a context manager, which ensures proper cleanup:

```python
from atlas_sdk import ControlPlaneClient, AgentConfiguration

with ControlPlaneClient() as client:
    client.register(
        name="my-agent",
        owner="team@company.com",
        configuration=AgentConfiguration(
            model_provider="anthropic",
            model_name="claude-sonnet-4-20250514",
            tools=["file_read"],
        ),
    )
    # Do work...
# Automatic deregistration on exit
```

### Asynchronous Client

```python
import asyncio
from atlas_sdk import AsyncControlPlaneClient, AgentConfiguration

async def main():
    async with AsyncControlPlaneClient() as client:
        await client.register(
            name="my-async-agent",
            owner="team@company.com",
            configuration=AgentConfiguration(
                model_provider="anthropic",
                model_name="claude-sonnet-4-20250514",
                tools=["web_search"],
            ),
        )
        # Do async work...

asyncio.run(main())
```

## Configuration

### Environment Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `ATLAS_API_URL` | Control Plane API base URL | (required) |
| `ATLAS_API_KEY` | API key for authentication | (required) |
| `ATLAS_ENVIRONMENT` | Deployment environment (local, staging, production) | Auto-detected |
| `ATLAS_DISABLED` | Disable SDK entirely (true/1/yes) | `false` |
| `ATLAS_SKIP_CONTEXT_DETECTION` | Skip context auto-detection (true/1/yes) | `false` |

### Client Options

```python
client = ControlPlaneClient(
    base_url="https://api.atlas.example.com",  # Override ATLAS_API_URL
    api_key="your-api-key",                     # Override ATLAS_API_KEY
    timeout=30.0,                               # Request timeout in seconds
    fail_silently=True,                         # Log errors instead of raising (default: True)
    auto_detect_context=True,                   # Auto-detect deployment context (default: True)
    auto_heartbeat=True,                        # Enable background heartbeats (default: True)
    heartbeat_interval_seconds=300,             # Heartbeat interval (default: 5 minutes)
    max_retries=3,                              # Max retry attempts for transient errors
)
```

## Deployment Context

The SDK automatically detects deployment context including:

- **hostname**: Via `socket.gethostname()`
- **environment**: Via `ATLAS_ENVIRONMENT` env var or hostname inference
- **has_internet_access**: Via connectivity check
- **has_filesystem_access**: Via container/sandbox detection

You can also provide explicit context:

```python
from atlas_sdk import ControlPlaneClient, AgentConfiguration, DeploymentContext, ResourceLimits

client.register(
    name="my-agent",
    owner="team@company.com",
    configuration=AgentConfiguration(
        model_provider="anthropic",
        model_name="claude-sonnet-4-20250514",
        tools=["file_read"],
    ),
    deployment_context=DeploymentContext(
        hostname="prod-server-01",
        environment="production",
        has_internet_access=True,
        has_filesystem_access=False,
        resource_limits=ResourceLimits(
            max_memory_mb=4096,
            max_cpu_cores=2,
        ),
    ),
)
```

## Manual Heartbeats

While heartbeats are sent automatically, you can send manual heartbeats with custom status and metrics:

```python
from atlas_sdk import HeartbeatStatus

# Send a heartbeat with custom status
client.heartbeat(
    status=HeartbeatStatus.DEGRADED,
    metrics={
        "requests_processed": 1500,
        "error_rate": 0.02,
        "memory_usage_mb": 512,
    },
)
```

## Updating Configuration

Update your agent's configuration after registration:

```python
from atlas_sdk import AgentConfiguration

client.update_configuration(
    configuration=AgentConfiguration(
        model_provider="anthropic",
        model_name="claude-opus-4-20250514",  # Upgraded model
        tools=["file_read", "file_write", "shell"],
    ),
)
```

## Error Handling

The SDK provides a comprehensive exception hierarchy:

```python
from atlas_sdk import (
    AtlasError,              # Base exception for all SDK errors
    AtlasConnectionError,    # Network/connection errors (retryable)
    AuthenticationError,     # 401 - Invalid API key
    AuthorizationError,      # 403 - Insufficient permissions
    AtlasValidationError,    # 422 - Invalid request data
    RateLimitError,          # 429 - Rate limited (retryable)
    AgentNotFoundError,      # 404 - Agent not registered
    DuplicateAgentError,     # 409 - Agent ID conflict
)

try:
    client.register(...)
except AuthenticationError:
    print("Invalid API key")
except RateLimitError as e:
    print(f"Rate limited, retry after {e.retry_after} seconds")
except AtlasError as e:
    print(f"Atlas error: {e}")
```

### Fail-Safe Mode

By default, the SDK operates in fail-safe mode (`fail_silently=True`), which means:

- Errors are logged but don't crash your agent
- Methods return `None` on failure
- Your agent continues operating even if the Control Plane is unreachable

To receive exceptions instead:

```python
client = ControlPlaneClient(fail_silently=False)
```

## Retry Behavior

The SDK automatically retries transient errors with exponential backoff:

- Connection errors
- Rate limit errors (429)
- Server errors (5xx)

Non-retryable errors (4xx except 429) fail immediately.

## Development

```bash
# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run tests with coverage
pytest --cov=atlas_sdk --cov-report=term-missing

# Type checking
mypy src/

# Linting
ruff check src/ tests/
ruff format src/ tests/
```

## License

Proprietary - Atlas Team
