from dataclasses import dataclass, field
from datetime import datetime, timedelta
from aden import instrument, MeterOptions, BeforeRequestResult, MetricEvent
@dataclass
class UserBudget:
limit_usd: float
spent_usd: float = 0.0
period_start: datetime = field(default_factory=datetime.now)
class LocalPolicyEngine:
def __init__(self):
self.budgets: dict[str, UserBudget] = {}
self.model_costs = {
"gpt-4o": {"input": 0.005, "output": 0.015},
"gpt-4o-mini": {"input": 0.00015, "output": 0.0006},
"claude-3-5-sonnet-latest": {"input": 0.003, "output": 0.015},
}
def set_budget(self, user_id: str, limit_usd: float):
self.budgets[user_id] = UserBudget(limit_usd=limit_usd)
def before_request(self, request) -> BeforeRequestResult:
user_id = get_current_user_id()
budget = self.budgets.get(user_id)
if not budget:
return BeforeRequestResult.proceed()
# Reset monthly budget
if datetime.now() - budget.period_start > timedelta(days=30):
budget.spent_usd = 0
budget.period_start = datetime.now()
usage_percent = (budget.spent_usd / budget.limit_usd) * 100
# Block at 100%
if usage_percent >= 100:
return BeforeRequestResult.cancel("Budget exceeded")
# Degrade at 80%
if usage_percent >= 80 and request.model in ["gpt-4o", "claude-3-5-sonnet-latest"]:
return BeforeRequestResult.degrade(
to_model="gpt-4o-mini",
reason=f"Budget at {usage_percent:.0f}%",
)
# Throttle at 50%
if usage_percent >= 50:
return BeforeRequestResult.throttle(delay_ms=500)
return BeforeRequestResult.proceed()
def track_usage(self, event: MetricEvent):
user_id = get_current_user_id()
budget = self.budgets.get(user_id)
if budget and event.usage:
costs = self.model_costs.get(event.model, {"input": 0, "output": 0})
cost = (
event.usage.input_tokens * costs["input"] +
event.usage.output_tokens * costs["output"]
) / 1000
budget.spent_usd += cost
# Usage
engine = LocalPolicyEngine()
engine.set_budget("user_123", limit_usd=10.00)
instrument(MeterOptions(
emit_metric=engine.track_usage,
before_request=engine.before_request,
get_context_id=get_current_user_id,
))