Metadata-Version: 2.5
Name: tokenflow-sdk
Version: 0.1.0
Summary: TokenFlow's official Python client — one API key, any AI model.
Project-URL: Homepage, https://www.tokenflow.co.in
Project-URL: Documentation, https://www.tokenflow.co.in/developers
License: MIT
Requires-Python: >=3.9
Requires-Dist: httpx-sse>=0.4
Requires-Dist: httpx>=0.27
Provides-Extra: tui
Requires-Dist: textual>=0.60; extra == 'tui'
Description-Content-Type: text/markdown

# tokenflow

**One API key, any AI model.** TokenFlow routes your request to whichever underlying
model answers it best — you never need to know or care which AI company is behind the
response, hold separate provider keys, or install another SDK.

```bash
pip install tokenflow-sdk
```

> Distribution name is **`tokenflow-sdk`**; the import name is **`tokenflow`** (`import tokenflow`).

```python
from tokenflow import TokenFlow

client = TokenFlow(api_key="tf-live-...")

response = client.messages.create(
    messages=[{"role": "user", "content": "What is 2+2?"}],
)
print(response.content[0].text)
```

That's it — no `model` required. `model` defaults to `"auto"`, so TokenFlow picks the
model for you. Want control instead? Pin one explicitly:

```python
response = client.messages.create(
    model="claude-haiku-4-5",
    messages=[{"role": "user", "content": "What is 2+2?"}],
)
```

## Quick one-liner

For scripts where you just want text back:

```python
answer = client.chat("What is 2+2?")
```

## Streaming

```python
with client.messages.stream(
    messages=[{"role": "user", "content": "Write a haiku"}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)
```

## Async

```python
from tokenflow import AsyncTokenFlow

client = AsyncTokenFlow(api_key="tf-live-...")
response = await client.messages.create(
    messages=[{"role": "user", "content": "What is 2+2?"}],
)
```

## Wallet balance

Check the balance behind your key (read-only — no wallet mutation, no provider call):

```python
info = client.balance()
print(info["balance_usd"], info["currency"])   # e.g. "12.40" "USD"
print(info["key"]["spent_usd"])                # this key's spend so far
```

## Terminal (CLI)

Installing the package also installs a `tokenflow` command — talk to TokenFlow straight
from your shell, one key, any model, pay per use:

```bash
tokenflow login                          # store your tf-live-… key (once)
tokenflow "explain monads in one line"   # one-shot
echo "summarise this file" | tokenflow   # piped stdin
tokenflow                                # interactive REPL (Ctrl-D to exit)
```

The reply streams to **stdout**; a dim usage line (`model · 5→7 tok · ~$0.00004`) goes to
**stderr**, so redirects stay clean — `tokenflow "…" > answer.txt` captures only the answer.

```bash
tokenflow -m claude-haiku-4-5 "pin a specific model"
tokenflow --max-tokens 4096 --no-stream "wait for the whole reply"
tokenflow help          # same as --help
```

### Full-screen chat (`tokenflow chat`)

A persistent chat *environment* — a header bar, welcome banner, replies rendered as
**markdown with syntax-highlighted code**, and a **warm light/dark theme** (toggle with
**Ctrl-T**). Install the optional UI extra and run `chat`:

```bash
pip install "tokenflow-sdk[tui]"     # adds the terminal UI (textual)
tokenflow chat
```

Every reply carries a **meta line** so you always know what you got and what it cost:

```
● claude-haiku-4-5 · auto → claude-haiku-4-5 · #223b · 15→297 tok · $0.001500
```

model that answered · `pinned` or `auto → <resolved>` · message id · input→output tokens ·
this turn's cost (sub-cent precision). The status bar sums the session cost locally — no extra
API call.

**Commands** (type in the chat; **Esc** cancels a streaming reply):

```
/model [id|auto]    show / switch the model (auto = TokenFlow picks per message)
/models             list available models
/which-model [#id]  which model answered — all turns, or one message id
/usage              every reply this session: #id, model, tokens, cost + total
/lookup on|off      let replies pull in live web results (adds cost, billed server-side)
/system <text>      set a system prompt (/system to view, /system clear to remove)
/retry              re-send your last message for a fresh answer
/context            rough input-token size of the conversation so far
/whoami             active key (masked), base URL, and model
/balance            wallet balance + this key's spend / cap
/save [file]        write the conversation to a markdown file
/clear              forget the conversation so far
/help               list commands
/exit               quit (or Ctrl-D)
```

If you run `tokenflow chat` without the `[tui]` extra installed, it tells you how to add it.

### REPL slash-commands

**In the plain REPL** (`tokenflow` with no args), slash-commands let you change things mid-session:

```
/model              show the current model
/model auto         let TokenFlow pick per message
/model <id>         pin a model (e.g. /model claude-sonnet-5)
/models             list available models
/clear              forget the conversation so far
/help               show commands
/exit               quit (or Ctrl-D)
```

Key resolution order: `--api-key` → `$TOKENFLOW_API_KEY` → the file written by
`tokenflow login` (`~/.config/tokenflow/config.json`, or `%APPDATA%\tokenflow` on Windows;
`chmod 600` on POSIX). `Ctrl-C` cancels a reply mid-stream — you're billed only for the
tokens already produced.

## Configuration

| Setting    | Constructor arg | Environment variable   | CLI flag     |
|------------|------------------|-------------------------|--------------|
| API key    | `api_key=`       | `TOKENFLOW_API_KEY`     | `--api-key`  |
| Base URL   | `base_url=`      | `TOKENFLOW_BASE_URL`    | `--base-url` |

## Errors

Every error raised is a `tokenflow.TokenFlowError` (or a subclass) — nothing else ever
escapes the client:

```python
from tokenflow import TokenFlow, TokenFlowWalletEmptyError, TokenFlowRateLimitError

try:
    client.messages.create(messages=[...])
except TokenFlowWalletEmptyError:
    print("Wallet is empty — top up to keep going.")
except TokenFlowRateLimitError:
    print("Slow down and retry.")
```

| Exception                     | Meaning                                      |
|--------------------------------|-----------------------------------------------|
| `TokenFlowAuthenticationError` | Invalid or missing API key                    |
| `TokenFlowPermissionError`     | Key lacks permission for this request         |
| `TokenFlowNotFoundError`       | Unknown model                                 |
| `TokenFlowWalletEmptyError`    | Wallet empty, or this key hit its spend cap   |
| `TokenFlowRateLimitError`      | Too many requests                             |
| `TokenFlowServerError`         | Something went wrong on TokenFlow's end       |
| `TokenFlowConnectionError`     | Couldn't reach the API                        |

## Known limitations (v1)

- TypeScript package not published yet.
