MCPcopy Create free account
hub / github.com/CommonstackAI/UncommonRoute / SpendControl

Class SpendControl

uncommon_route/spend_control.py:125–289  ·  view source on GitHub ↗

Time-windowed spending limiter with persistent storage.

Source from the content-addressed store, hash-verified

123
124
125class SpendControl:
126 """Time-windowed spending limiter with persistent storage."""
127
128 def __init__(
129 self,
130 storage: SpendControlStorage | None = None,
131 now_fn: Any = None,
132 ) -> None:
133 self._storage = storage or FileSpendControlStorage()
134 self._now = now_fn or time.time
135 self._limits = SpendLimits()
136 self._history: list[SpendRecord] = []
137 self._session_spent: float = 0.0
138 self._session_calls: int = 0
139 self._load()
140
141 def set_limit(self, window: SpendWindow, amount: float) -> None:
142 if amount <= 0 or not isinstance(amount, (int, float)):
143 raise ValueError("Limit must be a positive number")
144 setattr(self._limits, window, float(amount))
145 self._save()
146
147 def clear_limit(self, window: SpendWindow) -> None:
148 setattr(self._limits, window, None)
149 self._save()
150
151 @property
152 def limits(self) -> SpendLimits:
153 return self._limits
154
155 def check(self, estimated_cost: float, additional_committed: float = 0.0) -> CheckResult:
156 """Check whether ``estimated_cost`` fits under every configured window.
157
158 ``additional_committed`` covers in-flight reservations (estimated costs of
159 concurrent requests that passed ``check`` but have not yet been settled).
160 It is added to every windowed denominator but NOT to the per-request
161 comparison, which stays strictly about a single call.
162 """
163 now = self._now()
164
165 if self._limits.per_request is not None and estimated_cost > self._limits.per_request:
166 return CheckResult(
167 allowed=False,
168 blocked_by="per_request",
169 remaining=self._limits.per_request,
170 reason=f"Per-request limit: ${estimated_cost:.4f} > ${self._limits.per_request:.2f} max",
171 )
172
173 if self._limits.hourly is not None:
174 hourly_spent = self._window_total(now - HOUR_S, now) + additional_committed
175 remaining = self._limits.hourly - hourly_spent
176 if estimated_cost > remaining:
177 oldest = next((r for r in self._history if r.timestamp >= now - HOUR_S), None)
178 reset_in = int(oldest.timestamp + HOUR_S - now) if oldest else 0
179 return CheckResult(
180 allowed=False, blocked_by="hourly", remaining=remaining,
181 reason=f"Hourly limit: ${hourly_spent + estimated_cost:.2f} > ${self._limits.hourly:.2f}",
182 reset_in_s=max(0, reset_in),

Calls

no outgoing calls