Metadata-Version: 2.4
Name: lazysusan
Version: 0.1.0
Summary: The official LazySusan SDK: every leading AI model for chat, images and video through one API key.
Author-email: LazySusan <support@lazysusan.ai>
License: MIT
Project-URL: Homepage, https://www.lazysusan.ai/developers
Project-URL: Documentation, https://www.lazysusan.ai/developers/docs
Keywords: lazysusan,ai,llm,chat,image generation,video generation,api,sdk
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# LazySusan SDK for Python

The official SDK for the [LazySusan API](https://www.lazysusan.ai/developers): chat, image and video models from every major AI lab through one API key and one prepaid balance. Switch models by changing one string.

- Zero dependencies (standard library only). Python 3.9+.
- Typed (`py.typed`).
- Streaming, tool calling, images, async video, usage and cost on every response.

Full reference: https://www.lazysusan.ai/developers/docs

## Install

```bash
pip install https://www.lazysusan.ai/sdk/lazysusan-0.1.0-py3-none-any.whl
```

Get an API key in the [developer console](https://www.lazysusan.ai/developers/console):

```bash
export LAZYSUSAN_API_KEY=lsk_live_...
```

## Chat

```python
from lazysusan import LazySusan

client = LazySusan()  # reads LAZYSUSAN_API_KEY

reply = client.chat.create(
    model="anthropic/claude-sonnet-5-5",
    messages=[{"role": "user", "content": "Summarise this in two lines: ..."}],
)
print(reply.text)
print(reply.usage.cost_credits)
```

### Switch models

```python
for model in ["anthropic/claude-opus-5-5", "deepseek/deepseek-v4-pro", "google/gemini-3.8-flash", "xai/grok-4.7"]:
    r = client.chat.create(model=model, messages=[{"role": "user", "content": "One-line tagline for a coffee shop."}])
    print(model, r.text, r.usage.cost_credits)
```

`client.models.list(type="chat")` returns every model with its price.

### Stream

```python
for event in client.chat.stream(
    model="google/gemini-3.8-flash",
    messages=[{"role": "user", "content": "Write a haiku about deployments."}],
):
    if event.type == "delta":
        print(event.text, end="", flush=True)
    else:
        print("\ncredits:", event.usage.cost_credits if event.usage else None)
```

Parameters use snake_case: `max_tokens`, `temperature`, `top_p`, `stop`, `seed`, `tools`, `tool_choice`, `response_format`, `metadata`.

## Images

```python
img = client.images.generate(
    model="google/nano-banana-2.1",
    prompt="A product photo of a ceramic mug on oak, soft daylight",
    size="1024x1024",
)
print(img.images[0].url)
```

## Video

```python
job = client.videos.create(model="google/veo-3.1-fast", prompt="Slow pan across a misty lake at dawn", seconds=8)
video = client.videos.wait(job.id, on_progress=lambda v: print(v.status))
print(video.video_url)
```

Credits are held when a video starts and charged only if it succeeds. Failed videos are refunded.

## Track usage by project

```python
client.chat.create(
    model="anthropic/claude-haiku-5-5",
    messages=[{"role": "user", "content": "..."}],
    metadata={"project": "support-bot", "feature": "triage", "customer": "acme"},
)
```

Filter usage by these tags, by key, by team member, by model and by environment in the console. Give each developer, service and environment its own key for per-key budgets, model allowlists and expiry dates.

## Errors

```python
from lazysusan import LazySusan, LazySusanError

try:
    client.chat.create(model="anthropic/claude-fable-5-1", messages=messages)
except LazySusanError as e:
    if e.is_insufficient_balance:   # 402: balance or a budget can't cover it; nothing was charged
        print("budget reached" if e.is_budget_reached else "add credits", e.code)
    elif e.is_permission:           # 403: e.g. key not allowed to use that model
        ...
    print(e.status, e.code, e.request_id, e.message)
```

Automatic retries with backoff happen only where they can't cause a second charge: `429` and `503` responses (never charged) and network errors on `GET` requests. Configure with `LazySusan(max_retries=2, timeout=300)`.

## Balance

```python
print(client.credits.get().balance)  # credits; 1 credit = $0.001
```

## License

MIT
