# pi-peak-hours

*Peak/off-peak billing-hours indicator for LLM APIs in the [pi coding agent](https://github.com/earendil-works/pi-coding-agent).*

Some LLM providers bill peak hours at up to 2× the off-peak rate. This extension shows — right above your editor — when the model you're paying for is currently expensive, and how long until it gets cheap.


![pi-peak-hours in action](docs/screenshots/peak.png)

- **Silent when off-peak.** No news, no noise — the widget is hidden entirely.
- **One line during peak.** Names the providers that are in peak and when it ends, in your local timezone.
- **`/peak`** — the full picture on demand: current phase, windows in your timezone, next flip, sources.

## Providers

| Provider | Peak windows (billing calendar, UTC+8) | Off-peak |
|---|---|---|
| DeepSeek API | Mon–Fri 09:00–12:00, 14:00–18:00 | 50% of peak; weekends fully off-peak (since Aug 23, 2026) |
| GLM Coding Plan (Z.AI) | Mon–Fri 14:00–18:00 | Legacy V2: quota burns 3× at peak vs off-peak (GLM-5.3 1×/3×, Flash 0.4×/1.2×); new credit plans: off-peak = 50% of the standard credit rate |

Rules are data, not code (`src/schedules.ts`), each with its source URL and a "verified on" date. The DeepSeek logic is tested against the CC0 conformance vectors from [xyzs996/deepseek-peak-hours](https://github.com/xyzs996/deepseek-peak-hours), including the two subtleties most implementations get wrong: the weekday axis is read on the **billing calendar** (UTC+8), not on UTC, and the weekend rule is **gated on its effective date** so historical instants classify as they were actually billed.

## Install

```bash
pi install npm:pi-peak-hours        # from npm
pi install /path/to/pi-peak-hours   # or a local checkout
pi -e /path/to/pi-peak-hours        # or try it for one run without installing
```

## Config

Read once at startup from `~/.pi/agent/settings.json` under the `peakHours` key (`/reload` to apply). All keys optional; these are the defaults:

```json
{
  "peakHours": {
    "enabled": true,
    "timezone": "auto",
    "show": "peak",
    "providers": ["deepseek", "glm"]
  }
}
```

| Key | Values | Meaning |
|---|---|---|
| `enabled` | `true` / `false` | Turn the extension off entirely |
| `timezone` | `"auto"`, `"UTC"`, or an IANA name (`"Asia/Yekaterinburg"`) | Display timezone. `auto` uses the system clock's zone; override on servers set to UTC |
| `show` | `"peak"` / `"always"` | Hide the widget off-peak (default), or always show both phases |
| `providers` | array of schedule ids | Which rules to track |

## `/peak` output

```
LLM peak/off-peak — local time Asia/Yekaterinburg
⚡ DeepSeek         PEAK until 15:00 · peak 06:00-09:00, 11:00-15:00 Mon-Fri on UTC+08:00
  GLM Coding Plan  off-peak until 15:00 · peak 11:00-15:00 Mon-Fri on UTC+08:00
DeepSeek: off-peak = 50% of peak rates; weekends fully off-peak since Aug 23, 2026. https://api-docs.deepseek.com/quick_start/pricing/
GLM Coding Plan: off-peak usage is charged at 50% of the standard credit rate. https://docs.z.ai/devpack/overview
```

## Notes

- Times come from the system clock; nothing is fetched at runtime.
- The widget lives **above the editor**, not in the footer. Footer replacements (e.g. pi-archimedes) hide `setStatus()` items, while widgets stack independently — so this coexists with any footer.
- Billing windows apply to official provider APIs. Proxies/aggregators set their own flat prices; off-peak discounts generally do not pass through them.
- Rules change. If a provider moves its windows, edit `src/schedules.ts` — and please open an issue or PR here.

## Adding a provider

Add an entry to `SCHEDULES` in `src/schedules.ts`:

```ts
{
  id: "myprovider",
  label: "My Provider",
  shortLabel: "MP",
  calendarOffsetMinutes: 480,          // billing calendar = fixed UTC+8
  windows: [{ start: "14:00", end: "18:00" }],  // wall time on that calendar
  peakWeekdays: [1, 2, 3, 4, 5],       // ISO weekdays on that calendar
  weekendOffPeakFrom: null,            // or "2026-08-22T16:00:00Z"
  offPeakMultiplier: 0.5,
  offPeakNote: "off-peak = 50%",
  source: "https://...",
}
```

## Development

```bash
npm install
npm run check   # typecheck + tests + selfcheck
```

MIT — see [LICENSE](LICENSE).
