# @benvargas/pi-synthetic-provider

[Synthetic](https://synthetic.new) model provider for [pi](https://github.com/badlogic/pi-mono), the AI coding agent.

## Features

- **Dynamic model discovery** -- models fetched live from the Synthetic API at each session start
- **OpenAI Completions API** -- reuses pi's built-in streaming, no custom implementation
- **Tool calling** -- full support via OpenAI-compatible tool use
- **Vision support** -- image input for models that support it (e.g., Kimi-K3)
- **Reasoning support** -- extended thinking for reasoning-capable models
- **Cost tracking** -- accurate per-token pricing parsed from the API
- **Graceful degradation** -- fallback model list if the API is unreachable

## Installation

```bash
pi install npm:@benvargas/pi-synthetic-provider
```

Or try without installing:

```bash
pi -e npm:@benvargas/pi-synthetic-provider
```

## Setup

### Option 1: Environment Variable

```bash
export SYNTHETIC_API_KEY="syn_your_key_here"
pi
```

### Option 2: Auth Storage (persistent)

Add to `~/.pi/agent/auth.json`:

```json
{
  "synthetic": {
    "type": "api_key",
    "key": "syn_your_key_here"
  }
}
```

### Option 3: Runtime CLI Flag

```bash
pi --model synthetic/hf:moonshotai/Kimi-K3 --api-key syn_your_key_here
```

## Usage

```bash
# Interactive model selection
pi /model

# Direct model selection
pi --model synthetic/hf:moonshotai/Kimi-K3

# Or use provider + model flags separately
pi --provider synthetic --model hf:moonshotai/Kimi-K3
```

### Extension Command

- `/synthetic-models` -- display all available models with pricing and capabilities
- `/synthetic-quota` -- display current Synthetic API quota usage, including rolling five-hour, weekly token, and search limits when available

## Available Models

Models are fetched at startup from the [Synthetic models endpoint](https://dev.synthetic.new/docs/api/models). If the startup fetch fails, times out after three seconds, or returns no supported models, the provider falls back to the following hardcoded defaults:

Prices are $ per million tokens, current as of 2026-07-28.

| Model | ID | Reasoning | Vision | Context | Max Output | In / Out / Cache |
|-------|-----|-----------|--------|---------|------------|------------------|
| **Synthetic Large Text** | `syn:large:text` | Yes | No | 524K | 65K | 1.00 / 3.00 / 0.16 |
| **Synthetic Small Text** | `syn:small:text` | Yes | No | 196K | 65K | 0.10 / 0.50 / 0.02 |
| **Synthetic Large Vision** | `syn:large:vision` | Yes | Yes | 524K | 65K | 3.00 / 15.00 / 0.45 |
| **Synthetic Small Vision** | `syn:small:vision` | Yes | Yes | 262K | 65K | 0.45 / 3.60 / 0.09 |
| **GLM 5.2** | `hf:zai-org/GLM-5.2` | Yes | No | 524K | 65K | 1.00 / 3.00 / 0.16 |
| **GPT OSS 120B** | `hf:openai/gpt-oss-120b` | Yes | No | 131K | 65K | 0.10 / 0.10 / 0.02 |
| **Kimi K3** | `hf:moonshotai/Kimi-K3` | Yes | Yes | 524K | 65K | 3.00 / 15.00 / 0.45 |
| **Qwen 3.6 27B** | `hf:Qwen/Qwen3.6-27B` | Yes | Yes | 262K | 65K | 0.45 / 3.60 / 0.09 |
| **MiniMax M3** | `hf:MiniMaxAI/MiniMax-M3` | Yes | Yes | 262K | 65K | 0.60 / 1.20 / 0.12 |
| **GLM 4.7 Flash** | `hf:zai-org/GLM-4.7-Flash` | Yes | No | 196K | 65K | 0.10 / 0.50 / 0.02 |
| **Nemotron 3 Super 120B** | `hf:nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4` | Yes | No | 262K | 65K | 0.30 / 1.00 / 0.06 |

The `syn:*` ids are permalinks that Synthetic re-points as models rotate, so configs using them survive model retirements — `syn:large:vision` moved from Kimi K2.7-Code to Kimi K3 in this release. The `hf:*` ids pin a specific model and break when it is retired.

### Thinking levels on permalinks

When models are discovered live, a `syn:*` permalink inherits its current target's thinking-level support, resolved from the catalog's `hugging_face_id`. Selecting `syn:large:vision` gives you the same levels as `hf:moonshotai/Kimi-K3`.

This follows a re-point automatically **only when the new target is one of the models already in the verified override table**. Those maps come from live probing — which `reasoning_effort` values a model accepts, and which silently disable reasoning — and cannot be derived from the catalog, since `supported_features` reports only that a model reasons, not how it can be steered. If Synthetic re-points a permalink to a model this package has not probed, the permalink stops emitting `reasoning_effort` until a release adds it.

That is the deliberate failure mode: when the target is unrecognized, or the catalog row declares no reasoning support, the permalink emits nothing rather than guessing. A rejected value fails the whole request, while omitting it simply runs at the server-side default.

In the offline fallback list, permalinks never emit `reasoning_effort` at all — with no catalog row there is no way to know what the alias currently points at. Note that pi still *displays* thinking levels `off` through `high` for them, because those entries set `reasoning: true`; the selections just have no effect on the request.

Kimi K3 is at beta launch pricing; Synthetic expects to lower it as engine optimization improves. Run `/synthetic-models` inside pi for the live catalog.

## API Key Priority

When multiple sources are configured, pi checks in this order:

1. CLI runtime flag (`--api-key`)
2. Auth storage (`~/.pi/agent/auth.json`)
3. OAuth credentials (if configured)
4. Environment variable (`SYNTHETIC_API_KEY`)

## Requirements

- pi v0.77.0 or later
- A Synthetic API key from [synthetic.new](https://synthetic.new)

## Notes

- On newer Synthetic accounts, `/synthetic-quota` prefers the current rolling five-hour and weekly token limits over the legacy subscription bucket, while still showing search usage when present.
- The provider refresh path is compatible with current pi releases that expect dynamic provider updates to go through `pi.registerProvider(...)`.

## Uninstall

```bash
pi remove npm:@benvargas/pi-synthetic-provider
```

## License

MIT
