Metadata-Version: 2.5
Name: superrouter
Version: 0.1.0
Summary: Dual-format FastAPI router that proxies and translates between OpenAI-compatible and Anthropic-compatible chat APIs
Author: Rhytham Negi
License: MIT License
        
        Copyright (c) 2026 Rhytham Negi
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: anthropic,fastapi,llm,openai,proxy,router
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.11
Requires-Dist: fastapi>=0.115
Requires-Dist: pydantic>=2.7
Requires-Dist: requests>=2.31
Provides-Extra: dev
Requires-Dist: httpx>=0.27; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: python-dotenv>=1.0; extra == 'dev'
Requires-Dist: uvicorn>=0.30; extra == 'dev'
Provides-Extra: server
Requires-Dist: uvicorn>=0.30; extra == 'server'
Description-Content-Type: text/markdown

# superrouter

Dual-format FastAPI router that exposes **OpenAI-compatible** and **Anthropic-compatible**
endpoints on the same app, forwarding to OpenAI-compatible and Anthropic-compatible
upstreams and translating request/response formats (including SSE streaming) when needed.

Drop it into any FastAPI app:

```python
from fastapi import FastAPI
from superrouter import SuperRouter

app = FastAPI()

router = SuperRouter(
    providers={
        "openai": {"base_url": "https://api.openai.com/v1", "api_key": "sk-..."},
        "anthropic": {"base_url": "https://api.anthropic.com/v1", "api_key": "sk-ant-..."},
    },
    api_keys=["sk-my-router-key"],  # auth for clients calling YOUR router (optional)
)

app.include_router(router)
```

## Install

With **pip**:

```bash
pip install .
# with server + dev extras
pip install ".[dev,server]"
```

With **uv**:

```bash
uv add superrouter          # from PyPI once published
uv sync                     # install this repo's deps into .venv
uv sync --extra server      # include the server extra
uv build                    # produce dist/*.whl and dist/*.tar.gz
```

For local development (editable + dev tools):

```bash
# uv
uv sync

# pip
pip install -e ".[dev,server]"
# or
pip install -r requirements.txt
```

## Run the example

```bash
cp .env.example .env   # fill in keys
uv run python examples/main.py          # or: python examples/main.py
uv run uvicorn examples.main:app        # alternative
```

Then:

```bash
export OPENAI_BASE_URL=http://localhost:8000/v1
export OPENAI_API_KEY=sk-my-router-key

export ANTHROPIC_BASE_URL=http://localhost:8000/v1
export ANTHROPIC_API_KEY=sk-my-router-key
```

## Endpoints

| Method | Path                        | Upstream                    |
|--------|-----------------------------|-----------------------------|
| POST   | `/v1/chat/completions`      | translated to provider      |
| POST   | `/v1/messages`              | translated to provider      |
| POST   | `/v1/completions`           | openai passthrough          |
| POST   | `/v1/embeddings`            | openai passthrough          |
| POST   | `/v1/messages/count_tokens` | anthropic passthrough       |
| GET    | `/v1/models`                | aggregated from providers   |
| GET    | `/health`                   | local health check          |

Both `/v1/chat/completions` (OpenAI format) and `/v1/messages` (Anthropic format)
accept either wire format — the router detects the source format and translates to
the provider's format, then translates the response (JSON or SSE stream) back.

## Configuration

```python
SuperRouter(
    providers={
        "name": {
            "base_url": "https://api.openai.com/v1",  # required
            "api_key": "sk-...",                      # key sent UPSTREAM
            "kind": "openai",                         # "openai" | "anthropic" (inferred from name if omitted)
        },
    },
    default="openai",                     # provider name used when model doesn't match prefixes
    api_keys=["sk-..."],                  # keys CLIENTS must present (None/[] = open)
    timeout=(10, 600),                    # (connect, read) seconds
    prefix="",                            # mount prefix, e.g. "/api"
    tags=["llm"],                         # OpenAPI tags
)
```

Provider selection per request:

1. `x-super-upstream: <name>` header forces a provider.
2. Model names starting with `claude` route to the first `anthropic` provider.
3. Otherwise the `default` provider (or the first one).

Client auth (`api_keys` set): every endpoint except `/health` requires one of the
keys via `Authorization: Bearer ...`, `x-api-key: ...`, or `?key=...`.

## Development

```bash
uv sync                     # install deps (incl. dev group)
uv run pytest               # run tests
uvx mypy src                # type-check
```

## License

MIT — see [LICENSE](LICENSE).
