Metadata-Version: 2.4
Name: openmodex-sdk
Version: 0.1.0
Summary: The official Python SDK for the OpenModex AI Gateway API
Project-URL: Homepage, https://openmodex.com
Project-URL: Documentation, https://docs.openmodex.com
Project-URL: Repository, https://github.com/openmodexlabs/openmodex-sdk-python
Project-URL: Changelog, https://github.com/openmodexlabs/openmodex-sdk-python/releases
Author-email: OpenModex <sdk@openmodex.com>
License-Expression: MIT
License-File: LICENSE
Keywords: ai,anthropic,gateway,llm,openai,openmodex,sdk
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.8
Requires-Dist: httpx>=0.24.0
Description-Content-Type: text/markdown

# OpenModex Python SDK

The official Python SDK for the [OpenModex](https://openmodex.com) AI Gateway API. Access 100+ LLM models from OpenAI, Anthropic, Google, DeepSeek, Mistral, and Qwen through a single unified API with intelligent routing, automatic fallbacks, and built-in cost tracking.

## Features

- **Unified API** -- One client for all major LLM providers
- **Smart Routing** -- Automatic model selection optimized for cost, latency, or quality
- **Client-Side Fallbacks** -- Automatic retry with backup models on failure
- **Streaming** -- First-class SSE streaming with sync and async iterators
- **Async Support** -- Full `asyncio` support via `httpx`
- **Lightweight** -- Zero dependencies beyond `httpx` (no Pydantic required)
- **Type Safe** -- Fully typed with dataclasses and type hints
- **OpenAI Compatible** -- Drop-in replacement by changing `base_url`

## Requirements

- Python 3.8+

## Installation

```bash
pip install openmodex
```

## Quick Start

```python
import os
from openmodex import OpenModex

client = OpenModex(api_key=os.environ["OPENMODEX_API_KEY"])

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "user", "content": "What is OpenModex?"},
    ],
)

print(response.choices[0].message.content)
```

## Usage

### Chat Completions

```python
response = client.chat.completions.create(
    model="claude-3-5-sonnet",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Explain quantum computing in simple terms."},
    ],
    temperature=0.7,
    max_tokens=1000,
)

print(response.choices[0].message.content)
```

### Streaming

```python
stream = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "user", "content": "Write a short story."},
    ],
    stream=True,
)

with stream:
    for chunk in stream:
        if chunk.choices[0].delta.content:
            print(chunk.choices[0].delta.content, end="", flush=True)
```

### Async Usage

```python
import asyncio
from openmodex import AsyncOpenModex

async def main():
    client = AsyncOpenModex(api_key="omx_sk_...")

    # Non-streaming
    response = await client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": "Hello!"}],
    )
    print(response.choices[0].message.content)

    # Streaming
    stream = await client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": "Hello!"}],
        stream=True,
    )
    async with stream:
        async for chunk in stream:
            if chunk.choices[0].delta.content:
                print(chunk.choices[0].delta.content, end="")

    await client.close()

asyncio.run(main())
```

### Smart Routing (OpenModex Extension)

Let the gateway pick the best model or optimize for cost/latency:

```python
from openmodex import OpenModex, MODEL_AUTO, MODEL_CHEAPEST

# Use model aliases
response = client.chat.completions.create(
    model=MODEL_AUTO,  # "@auto" -- balanced selection
    # model=MODEL_CHEAPEST,  # "@cheapest" -- lowest cost
    messages=[{"role": "user", "content": "Hello!"}],
)

# Or configure routing strategy per-request
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello!"}],
    routing={"strategy": "cost_optimized", "allow_upgrade": True},
)
```

### OpenModex Metadata

Every response includes OpenModex-specific metadata:

```python
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello!"}],
)

if response.openmodex:
    print(f"Provider: {response.openmodex.provider}")
    print(f"Model used: {response.openmodex.model_used}")
    print(f"Cache hit: {response.openmodex.cache_hit}")
    print(f"Routing: {response.openmodex.routing_strategy}")
    print(f"Latency: {response.openmodex.latency_ms}ms")
    print(f"Request ID: {response.openmodex.request_id}")
```

### Cache Control

```python
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "What is 2+2?"}],
    cache={"enabled": True, "ttl": 3600},
)
```

### Client-Side Fallbacks

Automatically retry with backup models on failure:

```python
client = OpenModex(
    api_key="omx_sk_...",
    fallback_models=["gpt-4o", "claude-3-5-sonnet", "gemini-1.5-pro"],
)

# If gpt-4o fails (5xx/timeout), automatically tries the next model
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello!"}],
)
```

### Embeddings

```python
response = client.embeddings.create(
    model="text-embedding-3-small",
    input="The quick brown fox jumps over the lazy dog.",
)

print(f"Dimensions: {len(response.data[0].embedding)}")
```

### Models

```python
# List all available models
models = client.models.list()
for m in models.data:
    print(f"{m.id} ({m.provider})")

# Get a specific model
model = client.models.retrieve("openai/gpt-4o")
print(f"{model.name}: {model.description}")

# Compare models side by side
comparison = client.models.compare(["openai/gpt-4o", "anthropic/claude-3-5-sonnet"])
print(f"Cheapest: {comparison.highlights.cheapest}")
print(f"Best quality: {comparison.highlights.best_quality}")
```

### Legacy Completions

```python
response = client.completions.create(
    model="gpt-3.5-turbo-instruct",
    prompt="Once upon a time",
    max_tokens=100,
)

print(response.choices[0].text)
```

### Error Handling

```python
from openmodex import OpenModex, APIError, AllFallbacksFailedError

try:
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": "Hello!"}],
    )
except APIError as e:
    print(f"API error: {e.message} (status: {e.status_code}, code: {e.code})")
    if e.is_rate_limited:
        print("Rate limited -- back off and retry")
    if e.is_auth_error:
        print("Check your API key")
except AllFallbacksFailedError:
    print("All fallback models failed")
```

## Configuration

| Parameter | Description | Default |
|-----------|-------------|---------|
| `api_key` | Your OpenModex API key | `OPENMODEX_API_KEY` env var |
| `base_url` | API base URL | `https://api.openmodex.com/v1` |
| `timeout` | Request timeout (seconds) | `30.0` |
| `max_retries` | Max retry attempts on transient errors | `2` |
| `default_headers` | Headers sent with every request | `{}` |
| `default_model` | Default model when none specified | `None` |
| `fallback_models` | Ordered fallback model chain | `[]` |
| `http_client` | Custom `httpx.Client` / `httpx.AsyncClient` | Auto-created |

## OpenAI SDK Compatibility

OpenModex Gateway supports drop-in compatibility. If you are already using the OpenAI Python SDK, you can route through OpenModex by changing just the `base_url`:

```python
from openai import OpenAI

# Just change the base URL and API key
client = OpenAI(
    base_url="https://api.openmodex.com/compat/openai/v1",
    api_key="omx_sk_live_...",
)

# Everything else works exactly the same
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello!"}],
)
```

## Examples

See the [examples/](examples/) directory for runnable examples:

- [chat_completion.py](examples/chat_completion.py) -- Basic chat completion with routing
- [streaming.py](examples/streaming.py) -- Sync and async SSE streaming
- [models.py](examples/models.py) -- List, retrieve, and compare models

## Version

```python
import openmodex
print(openmodex.__version__)  # "0.1.0"
```

## License

[MIT](LICENSE)
