fix(model-usage): coerce numeric-string costs and ignore non-finite values (#87861)

Merged via squash.

Prepared head SHA: 11bb5719ca
Co-authored-by: coder999999999 <83845889+coder999999999@users.noreply.github.com>
Co-authored-by: vincentkoc <25068+vincentkoc@users.noreply.github.com>
Reviewed-by: @vincentkoc
This commit is contained in:
Coder
2026-06-23 04:16:31 -04:00
committed by GitHub
parent ca5905eb90
commit d63a73a1b8
2 changed files with 146 additions and 9 deletions

View File

@@ -9,6 +9,7 @@ from __future__ import annotations
import argparse
import json
import math
import subprocess
import sys
from dataclasses import dataclass
@@ -107,6 +108,30 @@ def filter_by_days(entries: List[Dict[str, Any]], days: Optional[int]) -> List[D
return filtered
def coerce_finite_cost(value: Any) -> Optional[float]:
"""Coerce a cost field to a finite float, or None if it is not usable.
Accepts native numbers and numeric strings (for example "1.75"), since cost
payloads sometimes serialize numbers as strings. Rejects booleans (they are
ints in Python but never a valid cost) and non-finite values (NaN/Infinity),
which would otherwise silently corrupt aggregated totals.
"""
if isinstance(value, bool):
return None
if isinstance(value, (int, float)):
number = float(value)
elif isinstance(value, str):
try:
number = float(value.strip())
except ValueError:
return None
else:
return None
if not math.isfinite(number):
return None
return number
def aggregate_costs(entries: Iterable[Dict[str, Any]]) -> Dict[str, float]:
totals: Dict[str, float] = {}
for entry in entries:
@@ -119,12 +144,12 @@ def aggregate_costs(entries: Iterable[Dict[str, Any]]) -> Dict[str, float]:
if not isinstance(item, dict):
continue
model = item.get("modelName")
cost = item.get("cost")
if not isinstance(model, str):
continue
if not isinstance(cost, (int, float)):
cost = coerce_finite_cost(item.get("cost"))
if cost is None:
continue
totals[model] = totals.get(model, 0.0) + float(cost)
totals[model] = totals.get(model, 0.0) + cost
return totals
@@ -143,9 +168,9 @@ def pick_current_model(entries: List[Dict[str, Any]]) -> Tuple[Optional[str], Op
if not isinstance(item, dict):
continue
model = item.get("modelName")
cost = item.get("cost")
if isinstance(model, str) and isinstance(cost, (int, float)):
scored.append(ModelCost(model=model, cost=float(cost)))
cost = coerce_finite_cost(item.get("cost"))
if isinstance(model, str) and cost is not None:
scored.append(ModelCost(model=model, cost=cost))
if scored:
scored.sort(key=lambda item: item.cost, reverse=True)
return scored[0].model, entry.get("date") if isinstance(entry.get("date"), str) else None
@@ -178,9 +203,9 @@ def latest_day_cost(entries: List[Dict[str, Any]], model: str) -> Tuple[Optional
if not isinstance(item, dict):
continue
if item.get("modelName") == model:
cost = item.get("cost") if isinstance(item.get("cost"), (int, float)) else None
cost = coerce_finite_cost(item.get("cost"))
day = entry.get("date") if isinstance(entry.get("date"), str) else None
return day, float(cost) if cost is not None else None
return day, cost
return None, None

View File

@@ -7,7 +7,14 @@ import argparse
from datetime import date, timedelta
from unittest import TestCase, main
from model_usage import filter_by_days, positive_int
from model_usage import (
aggregate_costs,
coerce_finite_cost,
filter_by_days,
latest_day_cost,
pick_current_model,
positive_int,
)
class TestModelUsage(TestCase):
@@ -35,6 +42,111 @@ class TestModelUsage(TestCase):
self.assertEqual(filtered[0]["date"], (today - timedelta(days=1)).strftime("%Y-%m-%d"))
self.assertEqual(filtered[1]["date"], today.strftime("%Y-%m-%d"))
def test_coerce_finite_cost_accepts_numbers_and_numeric_strings(self):
self.assertEqual(coerce_finite_cost(2), 2.0)
self.assertEqual(coerce_finite_cost(1.75), 1.75)
self.assertEqual(coerce_finite_cost("1.75"), 1.75)
self.assertEqual(coerce_finite_cost(" 2.5 "), 2.5)
def test_coerce_finite_cost_rejects_booleans(self):
# bool is a subclass of int in Python, but is never a valid cost.
self.assertIsNone(coerce_finite_cost(True))
self.assertIsNone(coerce_finite_cost(False))
def test_coerce_finite_cost_rejects_non_finite(self):
self.assertIsNone(coerce_finite_cost(float("nan")))
self.assertIsNone(coerce_finite_cost(float("inf")))
self.assertIsNone(coerce_finite_cost(float("-inf")))
self.assertIsNone(coerce_finite_cost("NaN"))
self.assertIsNone(coerce_finite_cost("Infinity"))
def test_coerce_finite_cost_rejects_unusable_values(self):
self.assertIsNone(coerce_finite_cost("not-a-number"))
self.assertIsNone(coerce_finite_cost(""))
self.assertIsNone(coerce_finite_cost(None))
self.assertIsNone(coerce_finite_cost({}))
def test_aggregate_costs_includes_numeric_strings(self):
entries = [
{
"date": "2026-05-25",
"modelBreakdowns": [
{"modelName": "claude-sonnet-4-6", "cost": 1.50},
{"modelName": "claude-sonnet-4-6", "cost": "1.75"},
],
}
]
self.assertEqual(aggregate_costs(entries), {"claude-sonnet-4-6": 3.25})
def test_aggregate_costs_ignores_bool_and_non_finite(self):
entries = [
{
"date": "2026-05-25",
"modelBreakdowns": [
{"modelName": "claude-sonnet-4-6", "cost": 1.50},
{"modelName": "claude-sonnet-4-6", "cost": "1.75"},
{"modelName": "claude-sonnet-4-6", "cost": True},
{"modelName": "claude-sonnet-4-6", "cost": float("nan")},
{"modelName": "claude-sonnet-4-6", "cost": float("inf")},
],
}
]
totals = aggregate_costs(entries)
# NaN/Infinity must not poison the total; bool must not add 1.0.
self.assertEqual(totals, {"claude-sonnet-4-6": 3.25})
def test_pick_current_model_scores_numeric_string_costs(self):
# model-b's cost is a numeric string; it must still win on highest cost.
entries = [
{
"date": "2026-05-25",
"modelBreakdowns": [
{"modelName": "model-a", "cost": 1.0},
{"modelName": "model-b", "cost": "5.0"},
],
}
]
model, day = pick_current_model(entries)
self.assertEqual(model, "model-b")
self.assertEqual(day, "2026-05-25")
def test_pick_current_model_ignores_bool_and_non_finite(self):
# Only model-a has a usable cost; bool and NaN must not be scored.
entries = [
{
"date": "2026-05-25",
"modelBreakdowns": [
{"modelName": "model-a", "cost": 2.0},
{"modelName": "model-b", "cost": True},
{"modelName": "model-c", "cost": float("nan")},
],
}
]
model, _day = pick_current_model(entries)
self.assertEqual(model, "model-a")
def test_latest_day_cost_accepts_numeric_string(self):
entries = [
{
"date": "2026-05-25",
"modelBreakdowns": [{"modelName": "model-a", "cost": "2.50"}],
}
]
day, cost = latest_day_cost(entries, "model-a")
self.assertEqual(day, "2026-05-25")
self.assertEqual(cost, 2.50)
def test_latest_day_cost_rejects_non_finite(self):
entries = [
{
"date": "2026-05-25",
"modelBreakdowns": [{"modelName": "model-a", "cost": float("inf")}],
}
]
day, cost = latest_day_cost(entries, "model-a")
self.assertEqual(day, "2026-05-25")
self.assertIsNone(cost)
if __name__ == "__main__":
main()