GNL
Dokümanlar menüsü
Enterprise@gnldev/server

Bütçe & kota (402)

Organizasyon başına token/maliyet limiti zorlar: yazma yolunda limit aşılırsa yeni run/stream/workflow isteği 402 alır (resume serbest); limitler Studio'dan yönetilir.

Ne işe yarar / ne zaman kullanılır#

Birden çok organizasyona aynı agent'ı sunuyorsanız, bir organizasyonun kontrolsüz token/maliyet tüketimi diğerlerini etkilememeli ve faturanızı patlatmamalı. Bütçe/kota bunu yazma yolunda (yeni run/stream/workflow isteklerinde) zorlar: organizasyonun kullanımı journal'dan (recordRunUsage ile artımlı sayılır) tanımlı limiti (token veya USD) aşarsa istek 402 ile reddedilir. Askıdaki işin devamı (resume — ör. bekleyen tool onayı ya da suspend edilmiş workflow) bu kapıdan etkilenmez, aksi halde aşan organizasyonda hiçbir askıdaki iş asla bitirilemezdi. Limitler journal'da (__budget__:*) yaşar — Studio'dan canlı değiştirilebilir, host'u yeniden deploy etmeye gerek kalmaz; host config (RestApiOptions.budgets) yalnız fallback'tir.

Kurulum / import#

Ayrı bir alt-paket gerekmez; kapı @gnldev/server'ın createRestApi'sine gömülüdür, birincil primitifler @gnldev/durable'dan gelir:

import { createGnl } from '@gnldev/durable';
import { createRestApi } from '@gnldev/server';
// To enforce it directly (for non-HTTP paths):
import { checkBudget, assertBudget, getOrgUsage, readBudget, isBudgetExceeded, BudgetExceededError } from '@gnldev/durable';

Adım adım kullanım#

En yaygın kullanım: createRestApi'ye org ile birlikte budgets.default fallback limiti verin — journal'da henüz özel bir __budget__ yoksa bu limit uygulanır:

// org: every organization gets an isolated journal (exactly-once is inherited); budgets: the fallback limit
// the __budget__ document written from Studio OVERRIDES it and returns 402 to the organization that exceeds it.
const DEFAULT_TOKEN_LIMIT = Number(process.env.GNL_DEFAULT_TOKEN_LIMIT ?? 100);

app.route('/api', createRestApi(config, {
  title: 'SWAPI Pro',
  auth,
  org: {},
  budgets: { default: { tokenLimit: DEFAULT_TOKEN_LIMIT } },
}));
// call again with a different runId -> 402 once 100 tokens are exceeded

Organizasyon bazlı farklı limitler için perOrg kullanılır (etkin limit her zaman journal > perOrg[id] > default sırasıyla çözülür):

budgets: {
  default: { tokenLimit: 100_000 },
  perOrg: { 'acme-corp': { usdLimit: 25 } },
}

Aşım anında istemci JSON gövdesiyle 402 alır:

402 gövdesi
{ "error": "budget/quota exceeded — the new run was refused", "usage": { "runs": 3, "tokens": 142, "costUsd": 0 }, "limit": { "tokenLimit": 100 } }

Kalan kotayı/kullanımı sorgulamak için hazır /usage ucu vardır (aynı kapsam çözümlemesini kullanır: organizasyon header'ı ya da bağlı kimlik):

Studio REST
GET /usage
Headers: x-gnl-org: acme-corp
→ { "org": "acme-corp", "usage": { "runs": 3, "tokens": 142, "costUsd": 0 }, "limit": { "tokenLimit": 100 }, "exceeded": true }

@gnldev/server HTTP dışındaki yollarda (@gnldev/queue worker, @gnldev/scheduler cron, @gnldev/a2a, doğrudan runDurable/createGnl gömme) kota otomatik zorlanmaz — kendi run öncesi kontrol noktanızda assertBudget'i çağırmanız gerekir:

import { assertBudget, BudgetExceededError } from '@gnldev/durable';

try {
  await assertBudget(reader, { orgId, fallback: { tokenLimit: 100_000 } });
  // ... start the run here
} catch (e) {
  if (e instanceof BudgetExceededError) {
    // build your own 402 / refusal response from e.check.usage and e.check.limit
  }
  throw e;
}

API referansı#

typeRestApiOptions.budgets

createRestApi'nin bütçe fallback opsiyonu: { default?, perOrg? } — journal'daki __budget__ bunu ezer.

fncheckBudget

Etkin limiti (journal > fallback) okuyup kullanımla kıyaslar; { exceeded, usage, limit } döner (async).

fnassertBudget

checkBudget çağırır, aşımda BudgetExceededError fırlatır — run başlamadan önce host-dışı yollarda çağrılır.

fngetOrgUsage

Organizasyonun (veya paylaşılan kök alanın) toplam runs/tokens/costUsd'unu döner; artımlı __usage__ sayacını kullanır (O(1)).

fnreadBudget

Journal'daki bütçe dokümanını okur: önce __budget__:<orgId>, yoksa __budget__:default.

fnisBudgetExceeded

Saf fonksiyon: OrgUsage ile BudgetLimit karşılaştırıp true/false döner.

typeBudgetLimit

usdLimit? / tokenLimit? alanlarına sahip limit tanımı.

classBudgetExceededError

assertBudget aşımda fırlatır; check (BudgetCheck) alanında usage+limit taşır.

fnrecordRunUsage

Run TAMAMLANINCA maliyetini __usage__ sayacına ekler (idempotent — aynı runId ikinci kez sayılmaz).

fncreateBoundedUsageCache

Sınırlı (LRU) UsageCostCache üretir — çok organizasyonlu kurulumlarda önbelleğin sınırsız büyümesini önler.

Enterprise
Bu özellik ee katmanındadır — üretimde kullanmak için lisans gerekir. Limit yoksa (ne journal'da ne fallback'te) kullanım hiç hesaplanmaz: bütçesiz kurulum ekstra maliyetsiz çalışır.
Not
Bütçe kapısı yalnız yeni iş isteklerini engeller: aynı runId ile gelen bir resume isteği (bekleyen tool onayı veya suspend edilmiş workflow'un devamı) journal'da zaten iz bıraktığından kapıdan otomatik geçer — aşan bir organizasyonda askıdaki iş asla kilitlenmez. Journal listRuns desteklemiyorsa kota zorlanamaz (fail-open) ve host konsola uyarı basar.
İlişkili
Kullanımın nasıl hesaplandığını (token/USD, model başına döküm) görmek için cost-observability sayfasına, organizasyon izolasyonunun temelini anlamak için multi-organization sayfasına, limitleri Studio'dan düzenlemek için studio-inspector sayfasına bakın.