diff --git a/app/main.py b/app/main.py index 2df3f98..e0658cf 100644 --- a/app/main.py +++ b/app/main.py @@ -3068,9 +3068,11 @@ async def admin_overview(request: Request): except Exception as e: logger.warning("admin overview: team/list failed: %s", e) - # All-time spend per member team, from SpendLogs (the team `spend` counter - # is cycle-only and resets at each member's budget_reset_at — the panel - # needs both to avoid the "month change wiped the numbers" confusion). + # All-time spend per team, from SpendLogs (the team `spend` counter is + # cycle-only and resets at each team's budget_reset_at — the panel needs both + # to avoid the "month change wiped the numbers" confusion). + # Covers agent teams as well as members: an agent's cycle counter resets the + # same way, and its all-time spend is the only figure that stays meaningful. all_time_spend: dict[str, float] = {} try: conn = _pg_connect() @@ -3081,7 +3083,7 @@ async def admin_overview(request: Request): SELECT t.team_alias, COALESCE(SUM(s.spend), 0) FROM "LiteLLM_TeamTable" t LEFT JOIN "LiteLLM_SpendLogs" s ON s."team_id" = t.team_id - WHERE t.team_alias LIKE 'member:%' + WHERE t.team_alias LIKE 'member:%' OR t.team_alias LIKE 'agent:%' GROUP BY 1 """ ) @@ -3153,6 +3155,10 @@ async def admin_overview(request: Request): # "agent:" prefix is noise there. `alias` keeps the full string. "name": alias.split(":", 1)[1] if ":" in alias else alias, "spend": float(t.get("spend") or 0.0), + # Cycle counter resets at budget_reset_at (the 1st, for the agents), so + # the panel shows all-time for these accounts instead of a number that + # reads as zeroed every month. + "all_time_spend": round(all_time_spend.get(alias, 0.0), 2), "budget": t.get("max_budget"), "team_members": len(t.get("members_with_roles") or []), }