Dokümanlar menüsü
Saklama (retention) TTL süpürmesi
Belirtilen yaştan eski run'ları/log kayıtlarını/thread'leri toplu temizleyen TTL süpürmesi (sweepRuns/sweepLog/sweepThreads) ve uzun-ömürlü run'lar için dönem devri (rolloverRun) — Studio'daki /retention/sweep ucundan tetiklenir.
Ne işe yarar / ne zaman kullanılır#
Journal append-only olduğu için run'lar zamanla birikir — depolama maliyeti ve okuma yükü büyür. sweepRuns, son aktivitesi belirlenen bir yaştan (olderThanMs) eski run'ları kalıcı olarak siler. Tipik senaryo: "30 günden eski, tamamlanmış run'ları her gece temizle" gibi bir saklama politikasını host'un cron'una bağlamak, ya da Studio'dan POST /retention/sweep ile manuel tetiklemek. Güvenlik varsayılanları bilinçli olarak korumacıdır: askıdaki (onay bekleyen) run'lar ve zaman damgası olmayan run'lar sessizce silinmez.
Kurulum / import#
import { sweepRuns, sweepLog, sweepThreads, rolloverRun } from '@gnldev/durable';Ayrı bir alt-paket yolu yok — sweepRuns, sweepLog, sweepThreads, rolloverRun, purgeRun ve purgeThread doğrudan @gnldev/durable kök export'undan gelir. Süpürme, journal'ın deletePrefix portunu (InMemory/Sqlite/Postgres/Redis adaptörleri sağlar) ve okuma yüzeyini (listRuns/readRun/listKeys) gerektirir; ikisi de yoksa net bir hata fırlatır.
Adım adım kullanım#
1. Doğrudan koddan, belirli bir yaştan eski run'ları süpürün:
import { sweepRuns } from '@gnldev/durable';
const result = await sweepRuns(journal, { olderThanMs: 30 * 86_400_000 }); // 30 days
// result: { scanned, purged, keptSuspended, keptNoTs, deletedEntries }Yaş, run'daki entry'lerin son zaman damgasına (son aktivite) göre ölçülür. keepSuspended varsayılan olarak true'dur; onay bekleyen bir run bu yüzden yaşı ne olursa olsun süpürülmez. Zaman damgası hiç bulunamayan run'lar da güvenli tarafta kalır ve keptNoTs sayacına yansır.
2. Studio üzerinden, aynı süpürmeyi HTTP ile (ör. bir cron job'dan) tetikleyin:
POST /retention/sweep
{ "olderThanMs": 2592000000, "keepSuspended": true }
// or, when createStudioApp was given { retention: { olderThanMs, keepSuspended } },
// the body may be left empty — those defaults are then used.
POST /retention/sweep
{}403 döner. Journal deletePrefix desteklemiyorsa uç 501 ile hata verir.3. Silme öncesi, run bir bütçe sayacına (__usage__) zaten eklenmişse maliyeti otomatik düşülür — süpürme sonrası organizasyon kullanım özeti hayalet maliyet biriktirmez. Her başarılı süpürme Studio audit kaydına retention.sweep olarak (taranan/silinen sayılarıyla) yazılır.
4. sweepRuns, yalnızca run'ları görür — durable-log namespace'leri (ör. Studio'nun __audit__/__alert__ kayıtları) ve BasicMemory thread'leri (mem:<threadId>:*) uzun ömürlü dağıtımlarda sınırsız büyür. sweepLog bu boşluğu kapatır — bir namespace'i kaydın at alanına göre süpürür:
import { sweepLog } from '@gnldev/durable';
const result = await sweepLog(journal, '__audit__', {
olderThanMs: 90 * 86_400_000, // 90 days
// the marker schema is callback-defined — it is not discovered automatically (bkz. @gnldev/queue/@gnldev/events consumeOnce)
markerFor: (item) => `ack:worker1:${item.id}`,
});
// result: { scanned, deleted, keptNoTs, deletedMarkers }5. sweepThreads, son mesajı eşikten eski BasicMemory thread'lerini purgeThread ile toplu siler — ts'i okunamayan (damgasız mesajlı) thread'ler güvenli tarafta kalır, silinmez:
import { sweepThreads } from '@gnldev/durable';
const result = await sweepThreads(journal, { olderThanMs: 180 * 86_400_000 }); // 180 days
// result: { scanned, purged: string[], keptNoTs }Uzun ömürlü run'lar: dönem devri (rolloverRun)#
Journal append-only olduğundan kırpılamaz — haftalarca/aylarca yaşayan TEK bir run'da bu, replay her seferinde baştan okunacağı ve journal'ın sınırsız büyüyeceği anlamına gelir. rolloverRun, bunu run'ı mantıksal dönemlere bölerek çözer: dönem kapanışında eski run'ın materyalize edilmiş son durumu (mesajlar) yeni bir runId'nin :input tohumuna taşınır; yeni dönem sıfır journal'la o bağlamdan devam eder. Bu, in-place compaction'ın (bilinçli olarak yok — append-only sözleşmesi) tasarım-gereği çözümüdür; eski journal'a dokunulmaz, silme ayrı bir karardır (yukarıdaki sweepRuns).
import { rolloverRun, resumeRun } from '@gnldev/durable';
// Period N is complete:
const r = await rolloverRun(journal, 'agent'); // -> { newRunId: 'agent@2', seededMessages, messages }
// Period N+1 continues — the new runId's :input is already seeded, so the prompt is not supplied again:
await resumeRun(r.newRunId, { journal, model, tools });Hedef newRunId (verilmezse `${runId}@2`, sonra @3...) ve tohum (:input) ikisi de claim ile (CAS) yazılır: aynı eski run'ı ikinci kez devretmeye çalışmak MEVCUT hedefi döner (deterministik, idempotent) — eşzamanlı iki çağrıdan yalnız biri hedefi belirler. Uzun konuşmayı özetleyerek taşımak için carry verilebilir (verilmezse mesajlar aynen taşınır):
const r = await rolloverRun(journal, 'agent', {
carry: async (messages) => [{ role: 'system', content: await summarize(messages) }],
});messages vermeyin — :input zaten dolu olduğundan fark journal'a yazılmaz, sonraki resume o mesajları hiç görmez. Askıda (suspended) bir tool'u olan dönemi devretmek yapısal olarak çalışır ama önerilmez; devri askı yokken, dönem kapanışında yapın.API referansı#
sweepRuns(journal, opts: SweepOptions) → Promise<SweepResult>. Son aktivitesi olderThanMs'ten eski run'ları tarayıp kalıcı siler; okuma yüzeyi (listRuns/readRun) ve deletePrefix gerektirir.
SweepOptions{ olderThanMs: number, keepSuspended?: boolean (varsayılan true), now?: number (test için "şimdi") }.
SweepResult{ scanned, purged: string[], keptSuspended, keptNoTs, deletedEntries } — kaç run tarandı, hangileri silindi, kaçı korundu.
purgeRun(journal, runId) → Promise<number>. sweepRuns'ın altında kullandığı tekil run silme yardımcısı: run'ın tüm izini (<runId>:* + memory marker) kalıcı siler; ÖZYİNELEMELİDİR — alt-agent/network çocuklarının journal'larını da (hangi seviyede olursa olsun) kaskad siler.
sweepLog(journal, ns, opts: LogSweepOptions) → Promise<LogSweepResult>. Bir durable-log namespace'ini (ör. Studio __audit__/__alert__) kaydın `at` alanına göre süpürür; listKeys + deletePrefix gerektirir.
LogSweepOptions{ olderThanMs, markerFor?: (item) => string|string[]|undefined, now? } — markerFor consume-marker şeması sabit olmadığından çağıran tarafından bildirilir.
LogSweepResult{ scanned, deleted, keptNoTs, deletedMarkers }.
sweepThreads(journal, opts: ThreadSweepOptions) → Promise<ThreadSweepResult>. Son mesajı eşikten eski BasicMemory thread'lerini purgeThread ile toplu siler; ts'i okunamayan thread silinmez.
ThreadSweepOptions{ olderThanMs, now? }.
ThreadSweepResult{ scanned, purged: string[], keptNoTs }.
rolloverRun(journal, runId, opts?: RolloverOptions) → Promise<RolloverResult>. Uzun-ömürlü bir run'ın son durumunu yeni bir runId'nin :input tohumuna taşır (dönem devri) — deterministik hedef + idempotent seed, hiçbir şey silmez.
RolloverOptions{ newRunId?, carry?: (messages) => messages|Promise<messages> } — carry verilmezse mesajlar aynen taşınır.
RolloverResult{ newRunId, seededMessages, messages } — yeni runId ve ona tohumlanan mesajlar.
sweepRuns/purgeRun çağırmak net bir hata fırlatır; sessizce hiçbir şey silmez.