Skip to content

Rulvar API reference


Rulvar API reference / @rulvar/core / UsageLimits

Interface: UsageLimits

Defined in: packages/core/src/runtime/usage-limits.ts:16

Properties

PropertyTypeDescriptionDefined in
checkpointEveryToolCalls?numberThe mid-batch checkpoint boundary (RV408, the eighth-experiment review): checkpoints normally write once per COMPLETED tool turn, so a kill inside one large parallel batch re-pays every executed call of that batch on resume; with the whole executed-call budget fitting into a single batch (the tool-cap-before-checkpoint preflight warning), the re-paid window is the entire budget. Set to K to bound it: after every K EXECUTED calls within a batch the loop durably writes the same pending state the ask suspension already checkpoints (the executed prefix verbatim, the next call, the remaining tail), so a resume reuses the prefix and re-runs at most the calls since the last boundary. Denied and skipped calls do not advance the cadence, and the batch tail writes no extra boundary (the turn checkpoint follows immediately). Off by default: the boundary writes extra transcript blobs, and enabling it changes no journal bytes and no model requests, only the checkpoint cadence.packages/core/src/runtime/usage-limits.ts:94
finalizationReserve?{ maxOutputTokens?: number; }The guaranteed finalization turn (the experiment-review P1.1): when a TOOL budget limiter (maxToolCalls or toolUnits) expires, the runtime closes the current batch's remaining calls with explicit skipped-call error results instead of dropping them silently, then grants the model exactly ONE summary turn with tools withheld before the invocation settles as status 'limit' with the exact limiter named in the terminal error. The summary text becomes the limit result's output for schema-less calls; a ridden schema validates into typed output when the summary parses (one attempt, no re-prompt). maxOutputTokens bounds the summary turn only; absent, the ordinary per-turn output policy applies. Off by default: the skip results and the summary instruction enter the conversation, so enabling it changes recorded model requests.packages/core/src/runtime/usage-limits.ts:110
finalizationReserve.maxOutputTokens?number-packages/core/src/runtime/usage-limits.ts:110
finalizationTurns?{ allow?: string[]; reserveTurns: number; }The turns-axis finalization reserve (RV1405, the seventeenth comparison experiment: a worker burned maxTurns 28 at 66 of 96 executed tool calls and settled limit with no finalize phase, because every finalization mechanism watched the tool budget). Once the remaining turns against maxTurns drop to reserveTurns, the SAME finalization-window regime engages on the turns dimension: non-allowlisted calls receive the typed window refusal, the model is told once to record its evidence and finish, and the terminal tool stays admitted. The regime has one allowlist: finalizationWindow.allow when declared, else allow here, else the zero-cost tools. Unlike finalizationReserve this grants no turn past the ceiling: the reserved tail lives INSIDE maxTurns, so the ceiling stays a ceiling. Repair-turn grants are deliberately not counted (they exist only for schema-dead terminal exchanges, which already sit inside finalization), keeping the arithmetic conservative. Off by default: the refusals and the notice enter the conversation, so enabling it changes recorded model requests.packages/core/src/runtime/usage-limits.ts:217
finalizationTurns.allow?string[]Tool names allowed inside the reserve; finalizationWindow.allow outranks it.packages/core/src/runtime/usage-limits.ts:221
finalizationTurns.reserveTurnsnumberHow many trailing turns of maxTurns the reserve keeps.packages/core/src/runtime/usage-limits.ts:219
finalizationWindow?{ allow?: string[]; reserveCalls: number; reserveForEvidenceDeficit?: boolean; }The finalization window (RV302, the seventh comparison experiment): once the remaining tool budget (executed calls against the effective maxToolCalls, or remaining weighted units against toolUnits.max, whichever is closer) drops to reserveCalls, only finalization tools may execute. A call outside the window's allowlist receives a typed error tool result naming the window (visible to the model, never terminal, consuming no budget), and the model is told ONCE, via a plain user message, to record its evidence and finish. The allowlist defaults to the tools priced at toolUnits cost 0 (the free bookkeeping tools); the engine terminal tool is always admitted regardless. With toolBudgetExtension configured, remaining money converts into a grant BEFORE any window refusal, so the window binds only when the extension is exhausted or denied. Under the engine, the entry journals a decision entry the moment it fires (RV509), so the summary's finalizationWindowEntered survives resume and replay even when a later grant moved the counts back out of the window. Off by default: the refusals and the notice enter the conversation, so enabling it changes recorded model requests.packages/core/src/runtime/usage-limits.ts:177
finalizationWindow.allow?string[]Tool names allowed inside the window; default: zero-cost tools.packages/core/src/runtime/usage-limits.ts:181
finalizationWindow.reserveCallsnumberHow many trailing executed calls (or units) the window reserves.packages/core/src/runtime/usage-limits.ts:179
finalizationWindow.reserveForEvidenceDeficit?booleanThe evidence-aware reserve (RV1208, the sixteenth comparison run: a worker spent 108 calls and still settled with 10 of 14 declared evidence entries, because the window reserved a FIXED tail the deficit had long outgrown). With this true AND an evidence contract declared on the invocation, the effective reserve is the larger of reserveCalls and the outstanding deficit plus one summary call, recomputed at every boundary from the same successful-record_evidence window the floor refusal reads. So searching stops while the floor is still closable, and the reserve collapses back to reserveCalls as entries land. The one-time notice names the live deficit. Off by default: an earlier window entry changes recorded model requests.packages/core/src/runtime/usage-limits.ts:196
maxCallsPerTool?Record<string, number>Per-tool execution caps by tool NAME (RV-210 close-out): the call that would exceed its tool's cap is denied with a typed error tool result instead of dispatched (visible to the model, never terminal), and the denial does not consume maxToolCalls or tool units. A cap of 0 bans the tool for the invocation; names absent from the record are unlimited. Per layer the whole record replaces (no per-key merge), like every other UsageLimits field.packages/core/src/runtime/usage-limits.ts:66
maxNoNewEvidenceCalls?numberHow many consecutive successful tool executions may return only already-seen result digests before the engine aborts the invocation as status 'limit' with abortClass 'exploration' (RV-210). The executed work is kept and the terminal memoizes. Unlimited by default.packages/core/src/runtime/usage-limits.ts:56
maxOutputTokensPerTurn?numberUnlimited by default (model caps still apply).packages/core/src/runtime/usage-limits.ts:22
maxRepeatedToolSignature?numberHow many times the SAME tool signature (name + canonical JCS args) may execute per invocation (RV-210). The call that would exceed it is denied with a typed error tool result instead of dispatched; the denial is visible to the model and does not consume maxToolCalls. Unlimited by default.packages/core/src/runtime/usage-limits.ts:48
maxToolCalls?numberUnlimited by default.packages/core/src/runtime/usage-limits.ts:20
maxTurns?numberDefault 32.packages/core/src/runtime/usage-limits.ts:18
noProgressTurns?numberThe no-progress detector N (committed at 3): consecutive turns without tool calls or artifact deltas before the engine aborts with the dedicated class (M3-T08).packages/core/src/runtime/usage-limits.ts:32
streamIdleTimeoutMs?numberGap between stream events; default 120000.packages/core/src/runtime/usage-limits.ts:26
timeoutMs?numberPer-agent wall clock; unlimited by default.packages/core/src/runtime/usage-limits.ts:24
toolBudgetExtension?{ coverEvidenceDeficit?: boolean; increment: number; maxExtensions: number; minHeadroomUsd?: number; requireNewEvidence?: boolean; }The adaptive tool budget (RV301, the seventh comparison experiment): when maxToolCalls expires but the run still has money and the agent still makes progress, the runtime grants increment more executed calls instead of ending the invocation, up to maxExtensions grants. A grant is admitted only when the remaining chain budget (the same arithmetic the per-turn output clamp reads) is above zero, or above minHeadroomUsd when declared, and, unless requireNewEvidence is set to false, only when at least one novel tool result digest arrived since the previous grant (the exploration guard's evidence chain). Each grant is announced to the model as a plain user message with the exact new counts, so pacing stays possible. Under the engine, each grant also journals a decision entry the moment it fires (RV509), so a resume restores granted-but-unspent extensions from the journal (the conservative executed-call derivation remains the floor beneath a lost journal tail) and a replayed result reports the grants. Extends maxToolCalls only, never toolUnits. Off by default: the grant notices enter the conversation, so enabling it changes recorded model requests.packages/core/src/runtime/usage-limits.ts:131
toolBudgetExtension.coverEvidenceDeficit?booleanThe evidence-deficit proactive trigger (RV809, the twelfth comparison run: a limited child at 7 of 11 declared evidence entries should convert remaining money into calls BEFORE the cap forces a partial dump through the finalization machinery). With this true AND an evidence contract declared on the invocation, the extension also grants at a tool-turn boundary whenever the remaining call budget cannot cover the declared floor's outstanding deficit (recorded record_evidence entries short of minEntries), under exactly the same admission gates as the at-expiry grant: bounded by maxExtensions, money-gated by minHeadroomUsd, and evidence-gated by requireNewEvidence. The at-expiry site stays the backstop. Off by default: the earlier grant notice changes recorded model requests.packages/core/src/runtime/usage-limits.ts:155
toolBudgetExtension.incrementnumberExecuted calls added per grant.packages/core/src/runtime/usage-limits.ts:133
toolBudgetExtension.maxExtensionsnumberHard bound on grants per invocation.packages/core/src/runtime/usage-limits.ts:135
toolBudgetExtension.minHeadroomUsd?numberGrant only at or above this remaining chain headroom, in USD.packages/core/src/runtime/usage-limits.ts:137
toolBudgetExtension.requireNewEvidence?booleanDefault true: a grant needs new evidence since the last one.packages/core/src/runtime/usage-limits.ts:139
toolBudgetNotices?booleanSoft 50%/80% thresholds over maxToolCalls (RV-210), surfaced to the model as a plain user message carrying the exact remaining count. Inert (with a loud log warning) when maxToolCalls is not set. Off by default: the notice enters the conversation, so enabling it changes recorded model requests.packages/core/src/runtime/usage-limits.ts:40
toolUnits?{ costs?: Record<string, number>; max: number; }The weighted tool budget (RV-210 close-out): every EXECUTED call of tool T costs costs[T] ?? 1 units (a cost of 0 makes bookkeeping tools free), and once the spent units reach max the invocation terminates as status 'limit' exactly like maxToolCalls (paid partial work; executed results stand). Denied calls cost nothing. On resume the spent units rebuild from the restored transcript's successful executions, the same conservative window the exploration guards use.packages/core/src/runtime/usage-limits.ts:76
toolUnits.costs?Record<string, number>-packages/core/src/runtime/usage-limits.ts:76
toolUnits.maxnumber-packages/core/src/runtime/usage-limits.ts:76