Source code for agenter.runtime.budget

"""Budget tracking for coding sessions."""

from __future__ import annotations

import time
from typing import TYPE_CHECKING

from ..data_models.budget import BudgetLimitType

if TYPE_CHECKING:
    from ..data_models import Budget, UsageDelta


[docs] class BudgetMeter: """Tracks resource usage and checks budget limits. Monitors tokens, cost, time, and iterations against configured limits. Example: tracker = BudgetMeter(Budget(max_tokens=1000)) tracker.add_usage(UsageDelta(tokens=500, cost_usd=0.25)) tracker.add_iteration() exceeded, reason = tracker.exceeded() if exceeded: print(f"Limit hit: {reason.value}") # e.g., "iterations" """
[docs] def __init__(self, budget: Budget): self.budget = budget self.tokens_used = 0 self.cost_usd = 0.0 self.start_time = time.monotonic() # Use monotonic for accurate duration self.iterations = 0
[docs] def add_usage(self, delta: UsageDelta) -> None: """Add usage delta to tracked totals. Args: delta: Usage delta containing tokens and cost to add. """ self.tokens_used += delta.tokens self.cost_usd += delta.cost_usd
[docs] def add_iteration(self) -> None: """Record a completed iteration.""" self.iterations += 1
[docs] def exceeded(self) -> tuple[bool, BudgetLimitType | None]: """Check if any budget limit is exceeded. Returns: Tuple of (exceeded: bool, limit_type: BudgetLimitType | None) """ if self.budget.max_iterations is not None and self.iterations >= self.budget.max_iterations: return True, BudgetLimitType.ITERATIONS if self.budget.max_tokens is not None and self.tokens_used >= self.budget.max_tokens: return True, BudgetLimitType.TOKENS if self.budget.max_cost_usd is not None and self.cost_usd >= self.budget.max_cost_usd: return True, BudgetLimitType.COST if self.budget.max_time_seconds is not None: elapsed = time.monotonic() - self.start_time if elapsed >= self.budget.max_time_seconds: return True, BudgetLimitType.TIME return False, None
[docs] def usage(self) -> dict: """Return current usage statistics.""" return { "tokens_used": self.tokens_used, "cost_usd": self.cost_usd, "elapsed_seconds": time.monotonic() - self.start_time, "iterations": self.iterations, }