Dokümanlar menüsü
Çalıştırma-başına limitler & maliyet tavanı
RunLimits ile çalıştırma-başına token/maliyet/araç-çağrısı tavanında kaçak bir çalıştırmayı durdurun.
Ne işe yarar / ne zaman kullanılır#
Bir çalıştırma kontrolden çıkabilir — pahalı bir model döngüsü, kaçak bir araç-çağrısı zinciri, bütçelemediğiniz bir maliyet. RunLimits, birikimli token'lara, birikimli USD maliyetine ve başarılı araç çağrısı sayısına çalıştırma-başına bir tavan koyar; ayrıca aynı çağrıyı tekrarlayıp duran bir aracı da tespit edebilir. Tüm alanlar opsiyoneldir: bir alanı ayarlamazsanız o koruma çalıştırma için KAPALIdır.
RunLimits alanları#
Her alan opsiyoneldir ve ayarlanmazsa bağımsız olarak kapalıdır:
RunLimits.maxTokensBirikimli toplam token (girdi + çıktı + cache'lenmiş) bu değeri AŞARSA çalıştırmayı durdurur.
RunLimits.maxCostUsdBirikimli USD maliyeti bu değeri AŞARSA çalıştırmayı durdurur.
RunLimits.maxToolCallsBaşarılı araç çağrısı sayısı bu değere ULAŞTIĞINDA (>=) BİR SONRAKİ araç çağrısını bloklar.
RunLimits.loopDetectionOpsiyonel alt-yapılandırma: { maxRepeats?, onRepeat? }. Aynı argsHash ile art arda çağrılan aynı aracı tespit eder.
loopDetection.maxRepeatsKaç ardışık özdeş (araç + argsHash) çağrının cevabı tetikleyeceği.
loopDetection.onRepeat'block' anında ToolLoopDetectedError fırlatır; 'reflect' önce modele bir nudge iletir.
Kurulum / import#
RunLimits @gnldev/durable içinde yaşar ve çalıştırma başına ayarlanır:
import { createGnl, RunLimitExceededError, type RunLimits } from '@gnldev/durable';Adım adım kullanım#
gnl.run'a limits geçin. Bir tavan aşıldığında RunLimitExceededError fırlatılır ve çalıştırma bir sonraki adıma geçmez:
// Checked AFTER each model step is journaled — a single step can OVERSHOOT the ceiling,
// but the run does not proceed to the NEXT step once it is breached.
const limits: RunLimits = { maxTokens: 50_000, maxCostUsd: 0.5, maxToolCalls: 20 };
try {
await gnl.run('asst', { runId: 'r5', prompt: 'do the task', limits });
} catch (e) {
if (e instanceof RunLimitExceededError) {
// e.detail: { kind, value, limit }
console.log('limit exceeded:', e.detail.kind, e.detail.value, e.detail.limit);
}
}Aynı araç çağrısını tekrarlayıp duran bir modeli yakalamak için loopDetection ayarlayın. reflect, hiçbir şey bloklanmadan önce modele toparlanma şansı verir:
// Same tool + identical argsHash repeated 3 times IN A ROW → 'reflect' delivers a nudge
// instead of an immediate block ('block' throws ToolLoopDetectedError right away).
const limits: RunLimits = { loopDetection: { maxRepeats: 3, onRepeat: 'reflect' } };Hata fırlatıldığında journal tutarlı kalır — limiti yükseltin ve çalıştırmanın bıraktığı yerden devam etmek için AYNI runId ile resume edin:
// The journal stays consistent when RunLimitExceededError is thrown.
// Raise the ceiling and resume the SAME runId to continue past the cut-off point:
await gnl.run('asst', { runId: 'r5', prompt: 'continue', limits: { maxTokens: 200_000 } });Streaming: bloklanan/limit ihlallerini yakalamak#
streamDurable / gnl.stream(name, opts), bir loop, maxToolCalls, duplicate ya da tainted BLOCK ateşlendiğinde çağrılan bir onBlocked callback'i kabul eder. Guard'ın ürettiği HAM yapılandırılmış ihlali alır — fırlatılan bir hatanın taşıyacağı bilgiyle aynısını. result.text artık bir block'ta da REDDEDİLİR; bu, gnl.run'dan fırlatılan RunLimitExceededError'ı yansıtır, böylece stream'in doğrudan bir tüketicisi bunu sessizce kaçıramaz.
// onBlocked fires for a loop / maxToolCalls / duplicate / tainted BLOCK — you get the
// RAW breach and decide what (if anything) the user sees. GNL does not invent a
// user-facing message.
const result = await gnl.stream('asst', {
runId: 'r6',
prompt: 'do the task',
limits,
onBlocked: (breach) => {
// breach.kind identifies which guard fired; breach.message is a raw diagnostic
// string; breach.detail carries that guard's own structured payload.
console.log('blocked:', breach.kind, breach.message);
},
});
try {
const text = await result.text;
} catch (e) {
// result.text REJECTS on a block — mirrors runDurable throwing, so a direct
// consumer of the stream cannot silently miss the breach.
}API referansı#
RunLimitExceededErrorBir tavan aşıldığında enforceStepLimits tarafından fırlatılır. detail: { kind, value, limit }; kind bir RunLimitKind'dır.
RunLimitKind'maxCostUsd' | 'maxTokens' | 'maxToolCalls' — RunLimitExceededError.detail içinde hangi tavanın aşıldığını belirtir.
enforceStepLimitsmaxTokens/maxCostUsd'yi her model adımı journal'landıktan SONRA kontrol eder; maxCostUsd ve maxTokens'ın ikisi de null ise erken döner.
RunOptions.limitsRunOptions.limits ile ayarlanır, runDurable/streamDurable'a iletilir ve alt-ajanlar tarafından olduğu gibi devralınır.
onBlockedstreamDurable / gnl.stream(name, opts) üzerinde callback seçeneği: (breach) => void. Bir loop, maxToolCalls, duplicate ya da tainted guard BLOCK olduğunda çağrılır. breach: { kind, message, detail } — kullanıcıya gösterilecek bir metin değil, ham yapılandırılmış payload. Bir block ateşlendiğinde result.text de reddedilir.
RunLimits / RunLimitExceededError tamamen çalıştırma-başınadır — @gnldev/server'daki organizasyon-seviyesi bütçe sisteminden (BudgetExceededError → HTTP 402, budget-quota sayfasında belgelenir) FARKLIDIR; o sistem harcamayı çalıştırmalar boyunca organizasyon başına izler. İkisini birbirine karıştırmayın: bir çalıştırma RunLimits sınırları içinde kalıp yine de organizasyon bütçesi tarafından reddedilebilir, ya da tersi olabilir.enforceStepLimits, maxTokens/maxCostUsd'yi her adım journal'landıktan SONRA kontrol eder; bu yüzden kesme noktası tavanı AŞAN İLK adıma denk gelir — tek bir adım tavanı AŞABİLİR. Garanti 'bir sonraki adıma geçmez'dir, '<= tam olarak limit' değildir. Kaçağı durdurur; bir adımı yarıda kesmez.onBlocked size framework'ün yapılandırılmış ihlalini verir — kind, message, detail — bir son kullanıcı için düşünülmüş bir cümle değil. Kullanıcının ne göreceğine (görecekse) karar vermek uygulamanızın işidir: GNL kullanıcıya gösterilecek bir mesaj icat etmez.budget-quota'ya, RunLimits'in karşılaştırdığı maliyet rakamının nasıl hesaplandığı için cost-observability'ye ve tekrarlanan yan-etkili bir çağrıya karşı kardeş çalıştırma-başına koruma için duplicate-guard'a bakın.