MCPcopy Index your code
hub / github.com/BlockRunAI/ClawRouter / SpendControl

Class SpendControl

src/spend-control.ts:158–348  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

156}
157
158export class SpendControl {
159 private limits: SpendLimits = {};
160 private history: SpendRecord[] = [];
161 private sessionSpent: number = 0;
162 private sessionCalls: number = 0;
163 private readonly storage: SpendControlStorage;
164 private readonly now: () => number;
165
166 constructor(options?: SpendControlOptions) {
167 this.storage = options?.storage ?? new FileSpendControlStorage();
168 this.now = options?.now ?? (() => Date.now());
169 this.load();
170 }
171
172 setLimit(window: SpendWindow, amount: number): void {
173 if (!Number.isFinite(amount) || amount <= 0) {
174 throw new Error("Limit must be a finite positive number");
175 }
176 this.limits[window] = amount;
177 this.save();
178 }
179
180 clearLimit(window: SpendWindow): void {
181 delete this.limits[window];
182 this.save();
183 }
184
185 getLimits(): SpendLimits {
186 return { ...this.limits };
187 }
188
189 check(estimatedCost: number): CheckResult {
190 const now = this.now();
191
192 if (this.limits.perRequest !== undefined) {
193 if (estimatedCost > this.limits.perRequest) {
194 return {
195 allowed: false,
196 blockedBy: "perRequest",
197 remaining: this.limits.perRequest,
198 reason: `Per-request limit exceeded: $${estimatedCost.toFixed(4)} > $${this.limits.perRequest.toFixed(2)} max`,
199 };
200 }
201 }
202
203 if (this.limits.hourly !== undefined) {
204 const hourlySpent = this.getSpendingInWindow(now - HOUR_MS, now);
205 const remaining = this.limits.hourly - hourlySpent;
206 if (estimatedCost > remaining) {
207 const oldestInWindow = this.history.find((r) => r.timestamp >= now - HOUR_MS);
208 const resetIn = oldestInWindow
209 ? Math.ceil((oldestInWindow.timestamp + HOUR_MS - now) / 1000)
210 : 0;
211 return {
212 allowed: false,
213 blockedBy: "hourly",
214 remaining,
215 reason: `Hourly limit exceeded: $${(hourlySpent + estimatedCost).toFixed(2)} > $${this.limits.hourly.toFixed(2)} max`,

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected