# Maniac Python SDK

The official Python client for the [Maniac Inference Gateway API](https://www.maniac.ai/) — an OpenAI-compatible inference gateway with telemetry, containers, evaluation, and optimization.

## Installation

```bash
pip install maniac
```

## Quick Start

```python
from maniac import Maniac

client = Maniac()  # uses MANIAC_API_KEY env var

completion = client.chat.completions.create(
    model="openai/gpt-4o",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(completion["choices"][0]["message"]["content"])
```

## Chat Completions

### Create a completion

```python
completion = client.chat.completions.create(
    model="openai/gpt-4o",
    messages=[{"role": "user", "content": "What is the capital of France?"}],
)
```

```bash
maniac chat completions create \
  --model openai/gpt-4o \
  --messages '[{"role": "user", "content": "What is the capital of France?"}]'
```

### Stream a completion

```python
for chunk in client.chat.completions.create(
    model="openai/gpt-4o",
    messages=[{"role": "user", "content": "Write a haiku."}],
    stream=True,
):
    print(chunk, end="", flush=True)
```

```bash
maniac chat completions create \
  --model openai/gpt-4o \
  --messages '[{"role": "user", "content": "Write a haiku."}]' \
  --stream
```

### List completions

```python
completions = client.chat.completions.list(limit=10, container="my-container")
```

```bash
maniac chat completions list --limit 10 --container my-container
```

### Retrieve a completion

```python
completion = client.chat.completions.retrieve("completion-id")
```

```bash
maniac chat completions retrieve completion-id
```

### Register examples

```python
client.chat.completions.register(
    container="my-container",
    items=[
        {
            "input": {
                "model": "openai/gpt-4o",
                "messages": [{"role": "user", "content": "Hi"}],
            },
            "output": {
                "choices": [{"message": {"role": "assistant", "content": "Hello!"}}],
            },
        }
    ],
)
```

```bash
maniac chat completions register \
  --container my-container \
  --items '[{"input": {"model": "openai/gpt-4o", "messages": [{"role": "user", "content": "Hi"}]}, "output": {"choices": [{"message": {"role": "assistant", "content": "Hello!"}}]}}]'
```

## Containers

### Create a container

```python
container = client.containers.create(
    label="my-container",
    initial_model="openai/gpt-4o",
)
```

```bash
maniac containers create --label my-container --initial-model openai/gpt-4o
```

### List containers

```python
containers = client.containers.list()
```

```bash
maniac containers list
```

### Retrieve a container

```python
container = client.containers.retrieve("my-container")
```

```bash
maniac containers retrieve my-container
```

### Delete a container

```python
client.containers.delete("my-container")
```

```bash
maniac containers delete my-container
```

## Models

### List models

```python
models = client.models.list()
```

```bash
maniac models list
```

### Add a model to a container

```python
client.models.add(
    container="my-container",
    model="anthropic/claude-sonnet-4.5",
    slug="claude",
)
```

```bash
maniac models add \
  --container my-container \
  --model anthropic/claude-sonnet-4.5 \
  --slug claude
```

## Files

### Upload a file

```python
file = client.files.create(file="data.jsonl", purpose="fine-tune")
```

```bash
maniac files create data.jsonl --purpose fine-tune
```

### List files

```python
files = client.files.list()
```

```bash
maniac files list
```

### Retrieve file metadata

```python
file = client.files.retrieve("file-id")
```

```bash
maniac files retrieve file-id
```

### Download file content

```python
content = client.files.content("file-id")
```

```bash
maniac files content file-id
```

### Delete a file

```python
client.files.delete("file-id")
```

```bash
maniac files delete file-id
```

## Evaluators

### Create an evaluator

```python
evaluator = client.evaluators.create(
    type="judge",
    model="openai/gpt-4o",
    name="quality-judge",
    prompt="Rate the quality of the response from 1-10.",
    container="my-container",
)
```

```bash
maniac evaluators create \
  --type judge \
  --model openai/gpt-4o \
  --name quality-judge \
  --prompt "Rate the quality of the response from 1-10." \
  --container my-container
```

### List evaluators

```python
evaluators = client.evaluators.list(container="my-container")
```

```bash
maniac evaluators list --container my-container
```

### Retrieve an evaluator

```python
evaluator = client.evaluators.retrieve("evaluator-id")
```

```bash
maniac evaluators retrieve evaluator-id
```

### Update an evaluator

```python
client.evaluators.update("evaluator-id", prompt="New prompt text.")
```

```bash
maniac evaluators update evaluator-id --prompt "New prompt text."
```

### Delete an evaluator

```python
client.evaluators.delete("evaluator-id")
```

```bash
maniac evaluators delete evaluator-id
```

## Evaluation Runs

### Create an evaluation run

```python
run = client.evaluation.runs.create(
    container="my-container",
    evaluators=["evaluator-id"],
)
```

```bash
maniac evaluation runs create \
  --container my-container \
  --evaluators '["evaluator-id"]'
```

### List evaluation runs

```python
runs = client.evaluation.runs.list(container="my-container")
```

```bash
maniac evaluation runs list --container my-container
```

### Retrieve an evaluation run

```python
run = client.evaluation.runs.retrieve("run-id")
```

```bash
maniac evaluation runs retrieve run-id
```

## Datasets

### Create a dataset

```python
dataset = client.datasets.create(
    name="my-dataset",
    container="my-container",
    size=100,
)
```

```bash
maniac datasets create \
  --name my-dataset \
  --container my-container \
  --size 100
```

### List datasets

```python
datasets = client.datasets.list(container="my-container")
```

```bash
maniac datasets list --container my-container
```

### Retrieve a dataset

```python
dataset = client.datasets.retrieve("dataset-id")
```

```bash
maniac datasets retrieve dataset-id
```

## Optimization Runs

### Create an optimization run

```python
run = client.optimization.runs.create(
    container="my-container",
    base_models=["openai/gpt-4o"],
    evals=["evaluator-id"],
    methods=[{"type": "sft"}],
)
```

```bash
maniac optimization runs create \
  --container my-container \
  --base-models '["openai/gpt-4o"]' \
  --evals '["evaluator-id"]' \
  --methods '[{"type": "sft"}]'
```

## OpenAI Compatibility

Maniac's inference endpoint is fully compatible with the OpenAI client. Point it at `https://platform.maniac.ai/api/v1` and prefix your container label with `maniac:`:

```python
from openai import OpenAI

client = OpenAI(
    base_url="https://platform.maniac.ai/api/v1",
    api_key=os.getenv("MANIAC_API_KEY"),
)

response = client.chat.completions.create(
    model="maniac:my-container",
    messages=[{"role": "user", "content": "Hello!"}],
)
```

## Async Usage

```python
from maniac import AsyncManiac

async def main():
    async with AsyncManiac() as client:
        completion = await client.chat.completions.create(
            model="openai/gpt-4o",
            messages=[{"role": "user", "content": "Hello!"}],
        )
        print(completion["choices"][0]["message"]["content"])

        # Streaming
        async for chunk in await client.chat.completions.create(
            model="openai/gpt-4o",
            messages=[{"role": "user", "content": "Write a poem."}],
            stream=True,
        ):
            print(chunk, end="", flush=True)
```

## Error Handling

```python
from maniac import Maniac, AuthenticationError, RateLimitError, NotFoundError

client = Maniac()

try:
    client.containers.retrieve("nonexistent")
except NotFoundError:
    print("Container not found")
except AuthenticationError:
    print("Invalid API key")
except RateLimitError as e:
    print(f"Rate limited, retry after {e.retry_after}s")
```

All exceptions inherit from `ManiacError`. The full hierarchy:

- `ManiacError`
  - `APIError` — generic API error (has `status_code` and `code`)
  - `AuthenticationError` — 401/403
  - `RateLimitError` — 429 (has `retry_after`)
  - `NotFoundError` — 404
  - `BadRequestError` — 400/422
  - `APIConnectionError` — network failure

## CLI Global Options

Every command supports `--json` for raw JSON output and `--api-key` / `--base-url` overrides:

```bash
maniac --api-key sk-... containers list --json
```

Run `maniac --help` or `maniac <command> --help` for full option details.
