Fix credit model: allowance is a floor, credits add on top (max_budget = allowance + credits, not reduced by cycle overspend)
This commit is contained in:
1 parent
563881d63c
commit
052a109040
1 file changed
+10
-14
+10
-14
@@ -584,32 +584,28 @@ def add_credits(email: str, delta: float, reason: str, reference: str | None = N
|
|||||||
def compute_max_budget(allowance: float, credit_balance: float, team_spend: float | None) -> dict:
|
def compute_max_budget(allowance: float, credit_balance: float, team_spend: float | None) -> dict:
|
||||||
"""Compute the effective LiteLLM max_budget from the two buckets.
|
"""Compute the effective LiteLLM max_budget from the two buckets.
|
||||||
|
|
||||||
Model: the member has a monthly ALLOWANCE (resets via LiteLLM's
|
Model: the member has a monthly ALLOWANCE (renews on each membership
|
||||||
budget_duration) plus a NON-EXPIRING credit balance. Spend draws the
|
payment) plus a credit balance that adds spendable headroom ON TOP of the
|
||||||
allowance first; once spend exceeds the allowance within a cycle, credits
|
allowance. The total spendable cap is simply `allowance + credit_balance`
|
||||||
cover the overflow.
|
— credits never shrink the allowance; they extend it.
|
||||||
|
|
||||||
`team_spend` is the member's spend so far this cycle (from LiteLLM).
|
`team_spend` is the member's spend so far this cycle (from LiteLLM). It is
|
||||||
Credits already consumed this cycle are excluded from the available pool
|
used only to split the spend between allowance vs credits for display, NOT
|
||||||
so the pushed max_budget reflects exactly what's left:
|
to reduce the cap.
|
||||||
|
|
||||||
max_budget = allowance + credits_remaining
|
|
||||||
|
|
||||||
Returns {"max_budget", "allowance_used", "credits_used"} for dashboards.
|
Returns {"max_budget", "allowance_used", "credits_used"} for dashboards.
|
||||||
"""
|
"""
|
||||||
|
max_budget = allowance + credit_balance
|
||||||
if team_spend is None:
|
if team_spend is None:
|
||||||
# Unknown spend: be permissive (full allowance + full credits) so we
|
|
||||||
# never wrongly block a member over a metrics gap.
|
|
||||||
return {
|
return {
|
||||||
"max_budget": allowance + credit_balance,
|
"max_budget": max_budget,
|
||||||
"allowance_used": 0.0,
|
"allowance_used": 0.0,
|
||||||
"credits_used": 0.0,
|
"credits_used": 0.0,
|
||||||
}
|
}
|
||||||
allowance_used = min(max(team_spend, 0.0), allowance)
|
allowance_used = min(max(team_spend, 0.0), allowance)
|
||||||
credits_used = max(0.0, team_spend - allowance)
|
credits_used = max(0.0, team_spend - allowance)
|
||||||
credits_remaining = max(0.0, credit_balance - credits_used)
|
|
||||||
return {
|
return {
|
||||||
"max_budget": allowance + credits_remaining,
|
"max_budget": max_budget,
|
||||||
"allowance_used": allowance_used,
|
"allowance_used": allowance_used,
|
||||||
"credits_used": credits_used,
|
"credits_used": credits_used,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user