@runic-labs/ledger
Anhangsbasierte Buchführung über ausgegebene und eingesparte Tokens.
@runic-labs/ledger ist reine Buchführung — es setzt niemals ein Budget durch, lehnt niemals einen Aufruf ab und schätzt niemals Kosten, die du nicht gemeldet hast. Es beantwortet eine Frage: Was hat das Auflösen dieser Entscheidungen tatsächlich gekostet, und wie viel davon wurde durch Wiederverwendung vermieden?
npm install @runic-labs/ledgerpnpm add @runic-labs/ledgeryarn add @runic-labs/ledgerbun add @runic-labs/ledgercreateLedger(store?)
import { createLedger, FileLedgerStore, defaultLedgerFilePath } from "@runic-labs/ledger";
const ledger = createLedger(new FileLedgerStore({ filePath: defaultLedgerFilePath() }));
Verwendet standardmäßig einen FileLedgerStore unter .runic/ledger.json (oder $RUNIC_HOME/ledger.json), wenn kein Store übergeben wird.
recordMiss(signature, tokensSpent)?void
Logs a cache miss — the agent generated its own way and spent tokensSpent.
voidrecordHit(signature)?void
Logs a cache hit, recording the same tokensSpent as the original miss for this signature.
voidsummary()?LedgerSummary
Aggregated totals — see below.
LedgerSummaryall()?LedgerEvent[]
The full raw event log.
LedgerEvent[]clear()?void
Removes all events.
voidLedgerSummary
interface LedgerSummary {
totalSpent: number;
totalSaved: number;
hitsBySignature: Record<string, number>;
}
const summary = ledger.summary();
const totalHits = Object.values(summary.hitsBySignature).reduce((a, b) => a + b, 0);
const tokensWithoutRunic = summary.totalSpent + summary.totalSaved;
const savingsPercent = Math.round((summary.totalSaved / tokensWithoutRunic) * 100);
Dies ist genau die Berechnung, die sowohl benchmarks/openrouter-savings als auch benchmarks/reuse-sweep verwenden, um ihre endgültigen Zahlen auszugeben — siehe Benchmarks.
Warum recordHit kein tokensSpent-Argument annimmt
Der Wert eines Hits ist definiert als was auch immer der ursprüngliche Miss für diese Signatur gekostet hat — das Ledger schlägt ihn selbst nach, statt darauf zu vertrauen, dass der Aufrufer ihn bei jedem Hit korrekt wiederholt. Wenn für eine Signatur, die irgendwie getroffen wird, kein vorheriger Miss existiert (sollte bei normaler Nutzung nicht passieren, aber das Ledger nimmt nicht an, dass es unmöglich ist), zeichnet es 0 auf, statt zu raten.
Speicher-Backends
Dasselbe Muster wie bei @runic-labs/cache: MemoryLedgerStore für Tests und kurzlebige Ausführungen, FileLedgerStore für Persistenz über separate Prozessaufrufe hinweg. Implementiere die Schnittstelle LedgerStore selbst für ein anderes Backend:
interface LedgerStore {
append(event: LedgerEvent): void;
all(): LedgerEvent[];
clear(): void;
}