Dokümanlar menüsü
Storage adaptörleri
Journal + memory + vektör + iş kuyruğu için takılabilir depolama arka uçları: SqliteStorage, PostgresStorage, RedisStorage, InMemoryStorage; capability matrisi ve composite ile karışık backend.
Ne işe yarar / ne zaman kullanılır#
GNL'nin dayanıklılık çekirdeği (run journal, exactly-once, replay) hep aynı Storage sözleşmesiyle konuşur; hangi arka ucu takacağın ortama göre değişir. Geliştirirken veya tek dosyalık bir demo kurarken SqliteStorage, prod'da PostgresStorage, testte ise InMemoryStorage kullanılır — hiçbiri agent/tool/workflow kodunu değiştirmez, sadece createGnl'e verdiğin storage alanı değişir.
Tek bir storage her port'u (runs/memory/vectors/work/cache) aynı kalitede sağlamayabilir — bu yüzden her adaptör bir capability matrisi taşır ve gerektiğinde composite() ile port bazında farklı bir storage'e (ör. cache için Redis) yönlendirilebilir.
Kurulum / import#
Somut implementasyonlar çekirdek paketi şişirmesin diye alt-export'larda yaşar; ana @gnldev/durable girişi sadece arayüzleri ve composite/toJournal gibi saf yardımcıları taşır.
import { SqliteStorage } from '@gnldev/durable/sqlite';
import { PostgresStorage } from '@gnldev/durable/postgres';
import { RedisStorage } from '@gnldev/durable/redis';
import { InMemoryStorage, toJournal, composite } from '@gnldev/durable';Adım adım kullanım#
1) Bir storage örneği oluştur ve createGnl yapılandırmasına ver (swapi-free örneğinden birebir):
import { SqliteStorage } from '@gnldev/durable/sqlite';
import { createGnl, toJournal } from '@gnldev/durable';
import type { CreateGnlConfig } from '@gnldev/durable';
const storage = new SqliteStorage(process.env.DB_PATH ?? 'swapi-free.db');
const config: CreateGnlConfig = {
storage,
agents: {
starwars: { model: buildModel(), system: SYSTEM, tools: makeSwapiTools(), maxSteps: 4 },
},
};2) Studio veya başka bir sayfasız (non-paged) tüketici Journal & JournalReader beklediğinde, toJournal() ile storage.runs'u köprüle:
app.route('/studio', createStudioApp({
reader: toJournal(storage.runs),
apiBase: '/studio',
gnl: createStudioRunner(gnl, config, { toJsonSchema: aiToolSchema }),
auth,
}));3) Prod'a geçerken tek satır değişir — SqliteStorage yerine PostgresStorage:
import { PostgresStorage } from '@gnldev/durable/postgres';
const storage = new PostgresStorage({ connectionString: process.env.DATABASE_URL });
// or inject an existing pg.Pool / pg-mem:
const storage2 = new PostgresStorage({ pool: myPgPool });4) Testte kalıcılık istemiyorsan InMemoryStorage — hiçbir kurulum/dosya gerektirmez, tüm port'lar tam kapasiteli (full):
import { InMemoryStorage } from '@gnldev/durable';
const storage = new InMemoryStorage();5) Redis ağır eşzamanlılık altında atomik CAS ve native TTL istediğinde RedisStorage — runs ve work port'larını 'full' (SET NX ile atomik putIfAbsent/exactly-once ack, toplu okumada mget), cache'i native 'ttl' (Redis PX) ile sağlar:
import { RedisStorage } from '@gnldev/durable/redis';
const storage = new RedisStorage({ connectionString: process.env.REDIS_URL });
// or inject your own ioredis client: new RedisStorage({ client: myIoredis })RedisStorage, capability matrisinde dürüst davranır: memory='none' ve vectors='none' döner — Redis (RediSearch/RedisJSON modülleri olmadan) sorgulanabilir hafıza/vektör recall için uygun değildir (index yok, brute-force tüm ağı uygulamaya çeker). Bu yüzden RedisStorage tek başına değil, tipik olarak composite() içinde runs/work/cache'in default'u ya da yalnızca cache override'ı olarak kullanılır.
6) Yalnızca tek bir port'u (ör. cache) farklı bir storage'e devretmek istersen composite() kullan — runs ve meta her zaman default'tan gelir (replay tek journal'da kalmalı):
import { composite } from '@gnldev/durable';
import { SqliteStorage } from '@gnldev/durable/sqlite';
import { RedisStorage } from '@gnldev/durable/redis';
const storage = composite({
default: new SqliteStorage('app.db'),
overrides: { cache: new RedisStorage({ connectionString: process.env.REDIS_URL }) },
});RAG için kalıcı bir vektör deposu gerekiyorsa @gnldev/rag paketindeki PostgresVectorStore (pgvector, HNSW/ivfflat index) InMemoryVectorStore ile birebir aynı VectorStore arayüzünü sağlar — composite()'ın vectors port'una drop-in bağlanır (ayrı bir @gnldev/durable adaptörü değildir, createRagTool içinde durable-wrapped çalıştığı için sorgu sonucu da journal'lanır — resume'da tekrar pg sorgusu atılmaz):
import { PostgresVectorStore } from '@gnldev/rag';
const vectors = new PostgresVectorStore({ connectionString: process.env.DATABASE_URL, index: 'hnsw' });API referansı#
SqliteStoragenode:sqlite tabanlı tüm port'ların implementasyonu — dev/tek-dosya default (@gnldev/durable/sqlite).
PostgresStoragepg tabanlı prod storage; connectionString veya enjekte pool (pg-mem dahil) kabul eder (@gnldev/durable/postgres).
PostgresStorageOptions{ connectionString?, pool? } — PostgresStorage kurucu seçenekleri.
RedisStorageioredis tabanlı storage (@gnldev/durable/redis): runs/work='full' (SET NX atomik CAS, mget), cache='ttl' (native PX); memory/vectors='none' (dürüst — composite ile override edilir).
RedisStorageOptions{ connectionString?, client?, keyPrefix?, replicationWarning?, waitReplicas? } — RedisStorage girdisi. Son ikisi dayanıklılık ayarlarıdır: 'replicationWarning' sunucunun replikasyon kurulumunu bir kez kontrol edip uyarır (tavsiye niteliğinde, fail-open); 'waitReplicas: { replicas, timeoutMs, onTimeout }' başarılı her claim'in o kadar replikanın onayını BEKLEMESİNİ sağlar — hiçbir replikanın doğrulamadığı bir yazım, failover'da kaybedilen yazımdır.
InMemoryStorageKalıcılık olmadan tüm port'ları 'full' capability ile sağlayan test/örnek storage.
StorageTüm store port’larını (runs/memory/vectors/work/cache/meta) + capabilities taşıyan birim arayüz.
toJournalRunJournal'ı eski Journal & JournalReader sözleşmesine sarar — sayfasız tüketiciler (ör. Studio) için köprü.
compositeVarsayılan storage + port bazında override alan bir Storage üretir; capability matrisini yeniden hesaplar.
CompositeConfig{ default, overrides? } — composite() girdisi.
requireCapabilityBir port'un en az 'scan' düzeyinde mevcut olmasını zorunlu kılar; yoksa CapabilityError fırlatır.
CapabilityMatrix{ runs, memory, vectors, work, cache } — her port için 'full' | 'scan' | 'ttl' | 'none'.
RunJournalKORUNAN append-only journal port'u — get/put/putIfAbsent (CAS)/listKeys/readRun/listRuns (sayfalı).
MemoryStoreThread/mesaj/working-memory/observation port'u — konuşma artefaktları (replay state değil).
VectorStoreRAG korpusu port'u — upsert/query (embedding tabanlı benzerlik).
WorkStoreKuyruk/olay/scheduler port'u — kendi namespace'inde, RunJournal'ı kirletmez.
runs ve meta port'ları composite()'ta her zaman default'tan gelir ve override edilemez — replay/exactly-once tek bir RunJournal'a bağlı kalmalı. Vektör arama @gnldev/durable'ın iki somut adaptöründe (Sqlite/Postgres) hâlâ 'scan' (brute-force cosine) seviyesinde; kalıcı/ölçekli RAG için @gnldev/rag'ın PostgresVectorStore'u (pgvector) kullanılır. RedisStorage ise memory/vectors için 'none' döner — tek başına kullanılmaz, composite ile tamamlanır.