**English** | **[中文](README-zh.md)**

# pi-opencodego

A lightweight [pi](https://github.com/earendil-works/pi-coding-agent) extension built for the **OpenCode Go / Zen** official API channel, providing three enhancements:

- **① Request compatibility filter** — fixes `400` errors on some models/gateways that reject a `developer` role (rewrites it to `system`).
- **② Multi-key rotation + quota awareness + session affinity** — intelligently rotates across multiple OpenCode keys to survive rate limits / bans; keeps one session pinned to one key to preserve prefix cache.
- **③ Usage / token / cache / cost tracking & visualization** — records every interaction and shows quota/cost in the browser or TUI.

Design principle: **touch only when needed** — only rewrite when there's a compat problem, only rotate when unavailable; otherwise pass requests through untouched.

---

## Install

Requires [pi](https://github.com/earendil-works/pi-coding-agent). Pick one:

```bash
# Option 1: npm (recommended)
pi install npm:pi-opencodego

# Option 2: GitHub
pi install git:github.com/february2015/pi-opencodego
```

> ⚠️ Security: pi extensions run with full system access. Consider reviewing the [source](https://github.com/february2015/pi-opencodego) before installing third-party packages.

## Configure keys

Add your OpenCode Go / Zen keys to the pool and switch to the opencode-go channel:

```bash
/ocgo add main sk-YOUR_KEY      # add a key (multiple allowed: /ocgo add backup sk-...)
/ocgo use 1                     # set the active key (1-based index)
/model opencode-go/deepseek-v4-flash   # switch to an OpenCode Go model
```

Then just chat — the extension injects keys, tracks usage, and rotates to the next available key on rate limit / quota exhaustion (one session always stays pinned to one key to avoid prefix-cache invalidation).

## Commands

| Command | Description |
|---------|-------------|
| `/ocgo status` | List all keys and states (active / cooling / banned) |
| `/ocgo usage` | Show three-window quota percent + reset time |
| `/ocgo cost` | Today's tokens, estimated cost, cache-hit rate |
| `/ocgo add <name> <key>` | Add a key |
| `/ocgo rm <n>` | Remove key (index) |
| `/ocgo use <n>` | Switch to key index |
| `/ocgo next` | Switch to next key |
| `/ocgo reset` | Clear all cooldowns / bans |
| `/ocgo cooldown <min>` | Set cooldown minutes |
| `/ocgo watchdog [on\|off\|ms]` | Watchdog settings |
| `/ocgo web` | Show Web panel status |
| `/ocgo web start` | Start Web panel (usually auto-started) |
| `/ocgo web stop` | Stop Web panel |
| `/ocgo web restart` | Restart Web panel |
| `/ocgo help` | All commands |

## Web quota panel

The extension ships a built-in browser quota panel (default port **8123**) that auto-starts in the background when pi launches — no manual command needed. Open:

```
http://127.0.0.1:8123
```

Control it from inside pi:

```
/ocgo web status     # status + port
/ocgo web start      # manual start (usually not needed)
/ocgo web stop       # stop the panel
/ocgo web restart    # restart the panel
```

> Each key is a card showing rolling / weekly / monthly quota bars, cooldown/ban state, and the key prefix. Two independent dropdowns in the toolbar: **Page refresh** (default 5s, browser rerender rate) and **OpenCode fetch** (default 30s, how often the backend pulls new data upstream).
>
> Disable auto-start with env `OCGO_NO_WEB=1` (e.g. testing / port conflicts).

The pi TUI also renders quota bars + a footer summary in the bottom bar (`ctx.ui.setWidget()` / `setStatus()`, TUI only).

## Features

### Capability A: request compatibility filter (fixes 400)

Intercepts OpenCode Go / Zen provider requests and scans for `role: "developer"` messages:
- Upstream doesn't support `developer` → rewrite to `system` (or merge into adjacent system message).
- Supported or absent → unchanged.
- **Idempotent**: already-rewritten turns are not re-rewritten; unaffected requests pass through with zero overhead. On by default, only active when `developer` exists.

### Capability B: multi-key rotation + quota awareness + session affinity

- **Key pool**: register/switch multiple keys.
- **Quota / state**: track each key's cooldown, quota-ban, and unban time; query usage.
- **Failure rotation**: on 429 / quota exhaustion / silent hang (watchdog), rotate to the next non-banned key, putting the failed key into cooldown/ban; if all banned, stop and report the earliest unban time.
- **Session affinity (key highlight)**: reuse one key within a session; only switch mid-session when that key actually fails or exhausts quota; re-pick on a new session. Goal: **avoid losing the OpenCode prefix cache when switching keys mid-session** (wasteful, degraded).
- Implementation only swaps the `Authorization` header, passing the body through unchanged (role rewrite is Capability A's job).

### Capability C: usage / token / cache / cost tracking

- On each `message_end`, read the standard `usage` from the response (incl. `cached_tokens` / `cache_write_tokens`) and record it automatically.
- Go is flat-rate (`cost` always `"0"`), so cost is **estimated** from a built-in price table (incl. DeepSeek V4 peak/off-peak).
- `/ocgo cost` summarizes today/this-week tokens, estimated cost, and cache-hit rate (= `cached/prompt`, key metric for optimizing DeepSeek cost).

> Verified API return shapes / boundaries: [docs/OPENCODE-API.md](docs/OPENCODE-API.md).

## Project layout

```
src/core/                    # zero-pi business logic (reusable by dsh)
├─ config.ts                 # key pool / cooldown / ban / session-affinity config
├─ keyRouter.ts              # session affinity + failure rotation + quota state machine
├─ usage.ts                  # usage API parsing + display
├─ pricing.ts                # price table + usage/cost estimate
├─ usageStore.ts             # usage records to disk + summary
├─ developerCompat.ts        # developer→system compat filter
├─ webui.ts / portfile.ts    # Web quota panel + port management
└─ index.ts                  # aggregate exports
pi/index.ts                  # pi wrapper: event hooks + /ocgo commands + Web panel auto-start
test/*.test.ts               # unit tests
```

## Docs

| Doc | Content |
|-----|---------|
| [docs/OPENCODE-API.md](docs/OPENCODE-API.md) | Verified official API facts (usage / token / price / peak) |
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Layered design, pi hooks, compatibility with similar extensions |
| [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) | Dev run, tests, acceptance criteria, roadmap |

## License

MIT

