packages/oracle-runtime/src/plugins/credits/
Summary
Owns the full credit lifecycle:- Enforcement — per-request middleware that aborts model calls when the user is out of credits (
createCreditsMiddleware+TokenLimiter). - Settlement — background cron that converts held credits into on-chain claims, shipped via
ClaimProcessingModule.
SubscriptionMiddleware, which gates the HTTP request before the graph even runs.
Environment variables
What it contributes
- Tools: none.
- Sub-agents: none.
- Middleware:
createCreditsMiddleware(aborts the agent run when the user is out of credits). - Nest modules (when Redis is configured at construct time):
ClaimProcessingModule— cron that settles held credits on chain.FileProcessingSinkModule—FILE_PROCESSING_CREDIT_SINKso pre-flight file-processing LLM usage bills the per-user budget.SubscriptionSinkModule—SUBSCRIPTION_CREDIT_SINKso the subscription middleware mirrors per-DID subscription payload + balance into Redis on every authenticated request.
- HTTP routes: none directly.
- Shared state: none.
Production constructor
The bundled singleton is for inspect / test only. Production needs a Redis client and the network:Observing claim settlement
The settlement cron emits structured logs under the[Credits/Claims] prefix — grep for that tag to trace a claim end-to-end.
- Boot — one line at startup with the effective settings, e.g.
Claim processing initialized: network=… denom=… minimumClaimThreshold=… disableCredits=… matrixAccountRoomId=set|MISSING. Use it to confirm the threshold override and required config actually applied. - Per tick — one summary line,
Cron tick: N user(s) at/above threshold T, then auser=… heldAmount=… — evaluatingline per candidate, an explicitSKIP user=… — <reason>for each user the cron drops (below threshold, no subscription payload in Redis, missingoracleClaimsCollectionId, insufficient available credits), and a closingCron tick complete: submitted=X skipped=Y failed=Zcounter. - Per claim — for every settled claim, the 4-step workflow logs
[step 1/4 submitIntent]→[step 2/4 saveToMatrix]→[step 3/4 submitToChain]→[step 4/4 sendToSubsApi], each markedOKorFAILEDand carrying theintentTxHash,claimCid, and on-chainchainTxHashvalues. A successful claim finishes with✔ SUBMITTED user=… claimCid=…. When held credits exceed the oracle’s per-claim ceiling, the split is announced withheldAmount=… exceeds per-claim max … — splitting into N chunks: …. - Pricing source — before submitting, the cron logs
pricing: fetched on-chain oracle pricing list …andcost: claiming heldAmount=… <denom> | per-claim ceiling maxAmount=… <denom>, so you can confirm the chain-side pricing feeding the split.
TokenLimiter.creditsForUsage) also logs a source= marker on every request so you can see which of the three pricing fallbacks priced a call:
Each line includes
costUsd=$… and → N credits (network=…), which makes it easy to spot sub-1-credit charges rounding to 0.
Opt out / Opt in
Where to read next
Add a middleware
The pattern
createCreditsMiddleware uses.Identity and auth
How subscription payloads reach the request.