feat(PBI-66): wekelijkse sync van model_prices via Anthropic /v1/models (#167)
Nieuw script `npm run db:sync-model-prices` haalt de actuele Claude 4.x modellijst op bij de Anthropic API en upsert prijzen in `model_prices`. Anthropic biedt geen prijs-API, dus prijzen blijven onderhouden in een PRICE_TABLE constante in het script. Cache-tier-prijzen worden afgeleid via vaste multipliers (read 0.1x, write 1.25x). Nieuwe Claude 4.x modellen worden gedetecteerd en gelogd als warning zodat duidelijk is wanneer de tabel handmatig moet worden bijgewerkt. - scripts/sync-model-prices.ts: idempotent upsert, --dry-run, retry op 5xx - ANTHROPIC_API_KEY als optional env-var (.env.example, lib/env.ts) - scripts/README.md: gebruiksinstructies + edge cases - docs/plans/sync-model-prices.md: ontwerpdocument Verificatie: `npm run lint`, `vitest` (563/563), TypeScript clean. Echt gedraaid tegen DB: 3 created (eerste run) -> 3 unchanged (tweede run). Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8a6b2d2cb3
commit
eaabec8471
7 changed files with 443 additions and 1 deletions
|
|
@ -54,6 +54,7 @@ Auto-generated on 2026-05-08 from front-matter and headings.
|
|||
| [ST-1110 — Demo gebruiker read-only](./plans/ST-1110-demo-readonly.md) | active | 2026-05-03 |
|
||||
| [ST-1111 — Voer uit-knop met Claude Code job queue](./plans/ST-1111-claude-job-trigger.md) | active | 2026-05-03 |
|
||||
| [ST-1114 — Copilot reviews op dashboard](./plans/ST-1114-copilot-reviews.md) | active | 2026-05-03 |
|
||||
| [Plan: wekelijkse sync van `model_prices` (PBI-66 / ST-1296)](./plans/sync-model-prices.md) | — | — |
|
||||
| [Tweede Claude Agent — Planning Agent](./plans/tweede-claude-agent-planning.md) | proposal | 2026-05-03 |
|
||||
| [Scrum4Me — v1.0 readiness](./plans/v1-readiness.md) | active | 2026-05-04 |
|
||||
|
||||
|
|
|
|||
106
docs/plans/sync-model-prices.md
Normal file
106
docs/plans/sync-model-prices.md
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
# Plan: wekelijkse sync van `model_prices` (PBI-66 / ST-1296)
|
||||
|
||||
## Context
|
||||
|
||||
De tabel `model_prices` ([prisma/schema.prisma:465](../../prisma/schema.prisma)) bevat nu 3 hardcoded rijen via [prisma/seed.ts:198](../../prisma/seed.ts) (Opus 4.7, Sonnet 4.6, Haiku 4.5). Die wordt door [lib/insights/token-stats.ts](../../lib/insights/token-stats.ts) en [lib/insights/token-history.ts](../../lib/insights/token-history.ts) ge-`LEFT JOIN`-d voor kostberekening.
|
||||
|
||||
Probleem: prijzen + nieuwe modellen worden alleen bijgewerkt bij een full re-seed. Dat vergeet je. We willen een wekelijks handmatig draaibaar script dat:
|
||||
|
||||
1. De actuele Claude 4.x modellijst ophaalt bij Anthropic (`GET /v1/models`),
|
||||
2. Per model de prijzen bepaalt uit een onderhouden tabel in code,
|
||||
3. Nieuwe modellen detecteert en logt (zodat we weten dat de tabel update nodig heeft),
|
||||
4. Idempotent upsert in `model_prices`.
|
||||
|
||||
**Belangrijke realiteit:** Anthropic biedt geen prijs-API. `/v1/models` levert id, display_name, max_tokens, capabilities — maar **geen pricing**. De prijzen onderhouden we daarom als constanten in het script. De API-call dient om de modellijst te valideren en nieuwe modellen op te merken.
|
||||
|
||||
## Aanpak
|
||||
|
||||
Eén nieuw TypeScript-script `scripts/sync-model-prices.ts` in dezelfde stijl als [scripts/insert-milestone.ts](../../scripts/insert-milestone.ts):
|
||||
|
||||
- dotenv → DATABASE_URL + ANTHROPIC_API_KEY
|
||||
- `pg.Pool` + `PrismaPg` adapter + `PrismaClient` (zelfde patroon als bestaande scripts)
|
||||
- `--dry-run` flag voor preview zonder schrijven
|
||||
- Aangeroepen via `npm run db:sync-model-prices`
|
||||
|
||||
### Datastromen
|
||||
|
||||
```
|
||||
ANTHROPIC API /v1/models
|
||||
│
|
||||
▼ (filter: model_id matcht /^claude-(opus|sonnet|haiku)-4/)
|
||||
API model list ───────────┐
|
||||
│
|
||||
PRICE_TABLE (in script) ──┤── join op model_id
|
||||
│
|
||||
▼
|
||||
Per model:
|
||||
- input_price = PRICE_TABLE[id].input
|
||||
- output_price = PRICE_TABLE[id].output
|
||||
- cache_read_price = input * 0.1
|
||||
- cache_write_price = input * 1.25
|
||||
│
|
||||
▼
|
||||
prisma.modelPrice.upsert
|
||||
```
|
||||
|
||||
### PRICE_TABLE in script
|
||||
|
||||
```ts
|
||||
const PRICE_TABLE: Record<string, { input: number; output: number }> = {
|
||||
'claude-opus-4-7': { input: 15.0, output: 75.0 },
|
||||
'claude-sonnet-4-6': { input: 3.0, output: 15.0 },
|
||||
'claude-haiku-4-5-20251001': { input: 0.8, output: 4.0 },
|
||||
}
|
||||
|
||||
const CACHE_READ_RATIO = 0.1
|
||||
const CACHE_WRITE_RATIO = 1.25 // 5-minute cache write
|
||||
```
|
||||
|
||||
Cache-ratio's komen overeen met de huidige seed: 1.5/15 = 0.1 en 18.75/15 = 1.25 — dus geen waarde-shift voor bestaande rijen.
|
||||
|
||||
### Filter Claude 4.x
|
||||
|
||||
Regex op `id` uit de API: `/^claude-(opus|sonnet|haiku)-4/`. Dit matcht `claude-opus-4-7`, `claude-sonnet-4-6`, `claude-haiku-4-5-20251001` en toekomstige 4.x varianten. Filtert oudere 3.x modellen weg.
|
||||
|
||||
### Detectie nieuwe modellen
|
||||
|
||||
Per Claude 4.x model uit de API:
|
||||
- **In PRICE_TABLE** → upsert met de prijs
|
||||
- **Niet in PRICE_TABLE** → log warning, sla over, exit code blijft 0
|
||||
|
||||
## Bestanden
|
||||
|
||||
| Bestand | Actie |
|
||||
|---|---|
|
||||
| `scripts/sync-model-prices.ts` | **Nieuw** — sync-script |
|
||||
| `package.json` | **Wijzigen** — entry `"db:sync-model-prices"` toevoegen |
|
||||
| `.env.example` | **Wijzigen** — `ANTHROPIC_API_KEY=""` toevoegen |
|
||||
| `lib/env.ts` | **Wijzigen** — `ANTHROPIC_API_KEY` als optional env var |
|
||||
| `scripts/README.md` | **Wijzigen** — sectie "Sync model prices" toevoegen |
|
||||
| `prisma/seed.ts` regels 198–229 | **Behouden** — fallback voor verse DB |
|
||||
|
||||
## Edge cases
|
||||
|
||||
| Geval | Gedrag |
|
||||
|---|---|
|
||||
| `ANTHROPIC_API_KEY` ontbreekt | Error + exit 1 |
|
||||
| API geeft 401 | Error met hint "controleer API key" |
|
||||
| API geeft 5xx | Retry 1× met 2s delay, dan falen |
|
||||
| API levert 0 Claude 4.x modellen | Warning, exit 1 |
|
||||
| Model uit DB staat niet meer in API | Niet verwijderen — alleen loggen |
|
||||
| `--dry-run` | API-call gewoon doen, alleen geen `upsert` |
|
||||
|
||||
## Verificatie
|
||||
|
||||
```bash
|
||||
npm run db:sync-model-prices -- --dry-run
|
||||
npm run db:sync-model-prices
|
||||
psql $DATABASE_URL -c "SELECT model_id, input_price_per_1m, output_price_per_1m, updated_at FROM model_prices ORDER BY model_id"
|
||||
npm run lint && npm test && npm run build
|
||||
```
|
||||
|
||||
## Buiten scope
|
||||
|
||||
- Geen Vercel cron route — bewust gekozen: handmatig draaien geeft moment om PRICE_TABLE bij te werken.
|
||||
- Geen pricing-page scraping — fragiel.
|
||||
- Geen 1-uurs cache write tier — schema heeft één veld.
|
||||
Loading…
Add table
Add a link
Reference in a new issue