@runic-labs/ledger
Comptabilité en ajout seul des jetons dépensés et économisés.
@runic-labs/ledger est un simple outil de comptabilité : il n’applique jamais de budget, ne refuse jamais un appel et n’estime jamais un coût que vous n’avez pas signalé. Il répond à une question : combien la résolution de ces décisions a-t-elle réellement coûté, et quelle part de ce coût a été évitée grâce à la réutilisation ?
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() }));
Utilise par défaut un FileLedgerStore dans .runic/ledger.json (ou $RUNIC_HOME/ledger.json) si aucun stockage n’est fourni.
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);
C’est exactement le calcul utilisé par benchmarks/openrouter-savings et benchmarks/reuse-sweep pour afficher leurs chiffres finaux ; consultez Benchmarks.
Pourquoi recordHit ne prend pas d’argument tokensSpent
La valeur d’un hit est définie comme le coût du miss initial pour cette signature : le registre le recherche lui-même plutôt que de faire confiance à l’appelant pour le répéter correctement à chaque hit. S’il n’existe aucun miss antérieur pour une signature qui est néanmoins touchée (cela ne devrait pas se produire en utilisation normale, mais le registre ne suppose pas que ce soit impossible), il enregistre 0 plutôt que de deviner.
Backends de stockage
Même modèle que @runic-labs/cache : MemoryLedgerStore pour les tests et les exécutions éphémères, FileLedgerStore pour la persistance entre des invocations de processus distinctes. Implémentez vous-même l’interface LedgerStore pour un autre backend :
interface LedgerStore {
append(event: LedgerEvent): void;
all(): LedgerEvent[];
clear(): void;
}