Örnek: LLM gateway (SQLite)
examples/llm-gateway: SQLite üzerinde bir LLM gateway. Postpaid; commit bakiyeye bakmaz.
bunx vitest run examples/llm-gateway/** * An LLM gateway on SQLite. * * - Tokens are priced per million with `cumulative` rounding, so a month of tiny calls never drifts. * - Calls are buffered per (account, model) and flushed once a minute as one `observe` (ref type "batch"). * - Output tokens feed a credits pool with a per-model weight; credits are priced by volume with `on_crossing`. * - Every account gets its first 1M input tokens per model free, for life (usedSoFar over all time). * - A CRM discount from the context is applied in getRate. Postpaid: commit never checks balances. */Tarifeler
Bölüm başlığı “Tarifeler”const perMillion = (price: number, id: string): Rate => ({ id, model: "graduated", tiers: [ { from: 0, unitPriceMicroUsd: 0, per: 1_000_000 }, { from: LIFETIME_FREE_INPUT, unitPriceMicroUsd: price, per: 1_000_000 }, ], policy: { rounding: "cumulative", tierPeriod: "lifetime" },});
/** Credits: $0.02 per 1k credits, $0.015 once the month passes 10M credits — for the whole month. */export const CREDIT_RATE: Rate = { id: "credits-2026", model: "volume", tiers: [ { from: 0, unitPriceMicroUsd: 20_000, per: 1000 }, { from: 10_000_000, unitPriceMicroUsd: 15_000, per: 1000 }, ], policy: { adjustmentTiming: "on_crossing", rounding: "cumulative", tierPeriod: "month" },};- Girdi token’ı milyon başına fiyatlanır (
per: 1_000_000) vecumulativeyuvarlanır: tek tek yukarı yuvarlansa her küçük çağrı en az 1 mikro-USD olurdu; kümülatif yuvarlama ayın toplamını kesin tutar (B2). - İlk 1M girdi token’ı model başına ömür boyu ücretsizdir:
usedSoFartüm zamanlar üzerinden sayılır (tierPeriod: "lifetime", B16). - Çıktı token’ı yalnızca sayılır (0 fiyat) ve kredi havuzunu model ağırlığıyla besler (opus 5, sonnet 3, haiku 1). Para krediler üzerinden akar.
- Krediler
volume+on_crossingile fiyatlanır: ay 10M krediyi geçince ayın tamamı ucuz kademeden hesaplanır, önceki kredilerin farkı ayrı bir…:adjkalemidir (B6).
Katalog ve getRate
Bölüm başlığı “Katalog ve getRate”const metering = buildMetering() .context(Context) .refs(["request", "batch"]) .meter("llm/credits") .meter("llm/input", { model: z.enum(MODELS) }) .meter("llm/output", { model: z.enum(MODELS) }, { feeds: { "llm/credits": (d) => CREDIT_WEIGHT[d.model] } }) .getRate(async (meter, dims, ctx, at) => { const discount = (r: Rate) => (ctx.discountPct ? applyDiscount({ rate: r, percent: ctx.discountPct }) : r); if (meter === "llm/input") { // lifetime quota: the counter spans all time const usedSoFar = store.usedSoFar({ account: ctx.accountId, meter, dims }); return { rate: discount(perMillion(INPUT_PRICE[dims.model], `input-${dims.model}`)), usedSoFar }; } if (meter === "llm/output") { // output tokens only count; money flows through credits return { rate: { model: "graduated", tiers: [{ from: 0, unitPriceMicroUsd: 0 }] } }; } const { from, to } = monthWindow({ at }); return { rate: discount(CREDIT_RATE), usedSoFar: store.usedSoFar({ account: ctx.accountId, meter, from, to }) }; }) .commit(store.commit);CRM indirimi bağlamdan gelir ve getRate içinde applyDiscount ile her tarifeye uygulanır (B19). Aylık kredi sayacı monthWindow({ at }) penceresinden okunur.
Dakikalık tampon
Bölüm başlığı “Dakikalık tampon”/** Flush every minute that ended before `now`. Safe to call repeatedly: batch refs are idempotent. */async flush(now: number) { const results = []; for (const b of buffer.drain(now)) { const r = await metering.observe( [ { meter: "llm/input", dims: { model: b.model }, quantity: b.inputTokens }, { meter: "llm/output", dims: { model: b.model }, quantity: b.outputTokens }, ], { type: "batch", id: `${b.ctx.accountId}:${b.model}:${b.minute}` }, b.ctx, { at: b.minute }, ); if (!r.ok) buffer.restore(b); // try again on the next flush results.push({ batch: b, result: r }); } return results;},Çağrılar (hesap, model, dakika) başına tamponlanır ve dakika bitince tek bir çok satırlı observe olarak yazılır. Ref { type: "batch", id: "{hesap}:{model}:{dakika}" } olduğu için flush tekrar çağrılabilir: aynı parti commit’te no-op’tur. Başarısız parti tampona geri konur. Üretimde tampon bir Durable Object ya da Redis’tir; desen aynıdır. Tampon ve zamanlama kütüphanenin değil uygulamanın işidir.