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>
4.5 KiB
Plan: wekelijkse sync van model_prices (PBI-66 / ST-1296)
Context
De tabel model_prices (prisma/schema.prisma:465) bevat nu 3 hardcoded rijen via prisma/seed.ts:198 (Opus 4.7, Sonnet 4.6, Haiku 4.5). Die wordt door lib/insights/token-stats.ts en 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:
- De actuele Claude 4.x modellijst ophaalt bij Anthropic (
GET /v1/models), - Per model de prijzen bepaalt uit een onderhouden tabel in code,
- Nieuwe modellen detecteert en logt (zodat we weten dat de tabel update nodig heeft),
- 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:
- dotenv → DATABASE_URL + ANTHROPIC_API_KEY
pg.Pool+PrismaPgadapter +PrismaClient(zelfde patroon als bestaande scripts)--dry-runflag 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
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
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.