feat(api): limits read unifiedWindows, unknown seven-day windows labelled by model
This commit is contained in:
@@ -737,21 +737,32 @@ def build_app( # noqa: PLR0915
|
|||||||
await require_token(request, runtime, scope=SCOPE)
|
await require_token(request, runtime, scope=SCOPE)
|
||||||
rows = await conversations.rate_limits(limit=200)
|
rows = await conversations.rate_limits(limit=200)
|
||||||
latest: dict[str, RateLimit] = {}
|
latest: dict[str, RateLimit] = {}
|
||||||
|
unified: dict[str, tuple[RateLimit, dict[str, Any]]] = {}
|
||||||
for row in rows:
|
for row in rows:
|
||||||
latest.setdefault(row.window, row)
|
latest.setdefault(row.window, row)
|
||||||
|
for name, info in _unified_windows(row).items():
|
||||||
|
unified.setdefault(name, (row, info))
|
||||||
now = datetime.now(UTC)
|
now = datetime.now(UTC)
|
||||||
windows = []
|
windows = []
|
||||||
for window, row in latest.items():
|
for window in dict.fromkeys([*latest, *unified]):
|
||||||
length = WINDOWS.get(window)
|
row = latest.get(window)
|
||||||
since = (
|
seen = unified.get(window)
|
||||||
_aware(row.resets_at) - length
|
public = _limit_public(row) if row else _limit_blank(window, seen)
|
||||||
if length is not None and row.resets_at is not None
|
resets = row.resets_at if row else None
|
||||||
else _aware(row.ts)
|
if seen and _newer_figure(seen, row):
|
||||||
)
|
carrier, info = seen
|
||||||
|
public["utilization"] = info.get("utilization")
|
||||||
|
public["reported_at"] = _iso(carrier.ts)
|
||||||
|
resets = _unix_dt(info.get("resetsAt")) or resets
|
||||||
|
public["resets_at"] = _iso(resets)
|
||||||
|
length = _window_length(window)
|
||||||
|
anchor = row if row is not None else (seen[0] if seen else None)
|
||||||
|
if length is not None and resets is not None:
|
||||||
|
since = _aware(resets) - length
|
||||||
|
else:
|
||||||
|
since = _aware(anchor.ts) if anchor else now
|
||||||
gateway = _sum_usage(await _usage_rows(runtime, since, now))
|
gateway = _sum_usage(await _usage_rows(runtime, since, now))
|
||||||
gateway["since"] = since.isoformat(timespec="seconds")
|
gateway["since"] = since.isoformat(timespec="seconds")
|
||||||
# The API sends a figure only when a window nears its limit;
|
|
||||||
# the last one inside this window is the best lower bound.
|
|
||||||
known = next(
|
known = next(
|
||||||
(
|
(
|
||||||
r
|
r
|
||||||
@@ -764,13 +775,13 @@ def build_app( # noqa: PLR0915
|
|||||||
)
|
)
|
||||||
windows.append(
|
windows.append(
|
||||||
{
|
{
|
||||||
**_limit_public(row),
|
**public,
|
||||||
"gateway": gateway,
|
"gateway": gateway,
|
||||||
"last_known": _limit_public(known) if known else None,
|
"last_known": _limit_public(known) if known else None,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
windows.sort(
|
windows.sort(
|
||||||
key=lambda w: (WINDOWS.get(w["window"], timedelta.max), w["window"])
|
key=lambda w: (_window_length(w["window"]) or timedelta.max, w["window"])
|
||||||
)
|
)
|
||||||
return {"windows": windows, "history": [_limit_public(r) for r in rows[:50]]}
|
return {"windows": windows, "history": [_limit_public(r) for r in rows[:50]]}
|
||||||
|
|
||||||
@@ -1052,6 +1063,59 @@ def _queue_item(item: InjectQueueItem | None) -> dict[str, Any] | None:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _window_length(name: str) -> timedelta | None:
|
||||||
|
if name.startswith("five_hour"):
|
||||||
|
return timedelta(hours=5)
|
||||||
|
if "seven_day" in name:
|
||||||
|
return timedelta(days=7)
|
||||||
|
return WINDOWS.get(name)
|
||||||
|
|
||||||
|
|
||||||
|
def _unix_dt(value: Any) -> datetime | None:
|
||||||
|
if isinstance(value, int | float) and value > 0:
|
||||||
|
return datetime.fromtimestamp(value, tz=UTC)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _unified_windows(row: RateLimit) -> dict[str, dict[str, Any]]:
|
||||||
|
"""Every window the event carried a figure for, not just the one it was about."""
|
||||||
|
raw = row.raw if isinstance(row.raw, dict) else {}
|
||||||
|
found = raw.get("unifiedWindows")
|
||||||
|
if not isinstance(found, dict):
|
||||||
|
return {}
|
||||||
|
return {
|
||||||
|
str(name): info
|
||||||
|
for name, info in found.items()
|
||||||
|
if isinstance(info, dict) and info.get("utilization") is not None
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _newer_figure(
|
||||||
|
seen: tuple[RateLimit, dict[str, Any]], row: RateLimit | None
|
||||||
|
) -> bool:
|
||||||
|
if row is None or row.utilization is None:
|
||||||
|
return True
|
||||||
|
return seen[0].id != row.id and _aware(seen[0].ts) > _aware(row.ts)
|
||||||
|
|
||||||
|
|
||||||
|
def _limit_blank(
|
||||||
|
window: str, seen: tuple[RateLimit, dict[str, Any]] | None
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
carrier = seen[0] if seen else None
|
||||||
|
return {
|
||||||
|
"id": None,
|
||||||
|
"ts": _iso(carrier.ts) if carrier else None,
|
||||||
|
"window": window,
|
||||||
|
"status": "allowed",
|
||||||
|
"utilization": None,
|
||||||
|
"resets_at": None,
|
||||||
|
"overage_status": None,
|
||||||
|
"overage_resets_at": None,
|
||||||
|
"agent": carrier.agent_name if carrier else None,
|
||||||
|
"session_id": carrier.session_id if carrier else None,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _limit_public(row: RateLimit) -> dict[str, Any]:
|
def _limit_public(row: RateLimit) -> dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"id": row.id,
|
"id": row.id,
|
||||||
|
|||||||
+24
-3
@@ -247,6 +247,7 @@ async def test_usage_groups_by_agent_day_and_model(world: World) -> None:
|
|||||||
async def test_limits_report_latest_window_with_gateway_spend(world: World) -> None:
|
async def test_limits_report_latest_window_with_gateway_spend(world: World) -> None:
|
||||||
api = Api(world)
|
api = Api(world)
|
||||||
now = datetime.now(UTC)
|
now = datetime.now(UTC)
|
||||||
|
resets = int((now + timedelta(hours=4)).timestamp())
|
||||||
async with world.db.session() as session:
|
async with world.db.session() as session:
|
||||||
session.add(
|
session.add(
|
||||||
RateLimit(
|
RateLimit(
|
||||||
@@ -264,7 +265,20 @@ async def test_limits_report_latest_window_with_gateway_spend(world: World) -> N
|
|||||||
resets_at=now + timedelta(hours=4),
|
resets_at=now + timedelta(hours=4),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
session.add(RateLimit(window="seven_day", status="allowed", utilization=0.3))
|
session.add(
|
||||||
|
RateLimit(
|
||||||
|
window="seven_day",
|
||||||
|
status="allowed",
|
||||||
|
utilization=0.3,
|
||||||
|
raw={
|
||||||
|
"unifiedWindows": {
|
||||||
|
"five_hour": {"resetsAt": resets, "utilization": 0.72},
|
||||||
|
"seven_day": {"resetsAt": resets, "utilization": 0.25},
|
||||||
|
"seven_day_fable": {"resetsAt": resets, "utilization": 0.1},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
await seed_usage(
|
await seed_usage(
|
||||||
world,
|
world,
|
||||||
@@ -280,12 +294,19 @@ async def test_limits_report_latest_window_with_gateway_spend(world: World) -> N
|
|||||||
)
|
)
|
||||||
out = await api.get("/limits")
|
out = await api.get("/limits")
|
||||||
windows = {w["window"]: w for w in out["windows"]}
|
windows = {w["window"]: w for w in out["windows"]}
|
||||||
assert windows["five_hour"]["utilization"] == 0.9
|
assert windows["five_hour"]["utilization"] == 0.72
|
||||||
|
assert windows["five_hour"]["reported_at"] is not None
|
||||||
assert windows["five_hour"]["status"] == "allowed_warning"
|
assert windows["five_hour"]["status"] == "allowed_warning"
|
||||||
assert windows["five_hour"]["gateway"]["output"] == 7
|
assert windows["five_hour"]["gateway"]["output"] == 7
|
||||||
assert windows["five_hour"]["gateway"]["cost_usd"] == 0.25
|
assert windows["five_hour"]["gateway"]["cost_usd"] == 0.25
|
||||||
assert windows["seven_day"]["utilization"] == 0.3
|
assert windows["seven_day"]["utilization"] == 0.3
|
||||||
assert [w["window"] for w in out["windows"]] == ["five_hour", "seven_day"]
|
assert windows["seven_day_fable"]["utilization"] == 0.1
|
||||||
|
assert windows["seven_day_fable"]["status"] == "allowed"
|
||||||
|
assert [w["window"] for w in out["windows"]] == [
|
||||||
|
"five_hour",
|
||||||
|
"seven_day",
|
||||||
|
"seven_day_fable",
|
||||||
|
]
|
||||||
assert len(out["history"]) == 3
|
assert len(out["history"]) == 3
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -215,6 +215,8 @@ export interface LimitWindow extends LimitRecord {
|
|||||||
gateway: UsageTotals & { since: string };
|
gateway: UsageTotals & { since: string };
|
||||||
// The last figure reported inside this window, if any: a lower bound.
|
// The last figure reported inside this window, if any: a lower bound.
|
||||||
last_known: LimitRecord | null;
|
last_known: LimitRecord | null;
|
||||||
|
// When the figure came from another event's unified report.
|
||||||
|
reported_at?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LimitsResponse {
|
export interface LimitsResponse {
|
||||||
|
|||||||
+11
-1
@@ -6,8 +6,18 @@ export const LIMIT_LABELS: Record<string, string> = {
|
|||||||
seven_day_sonnet: "7-day · Sonnet",
|
seven_day_sonnet: "7-day · Sonnet",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const SEVEN_DAY = "seven_day_";
|
||||||
|
|
||||||
export function limitLabel(window: string): string {
|
export function limitLabel(window: string): string {
|
||||||
return LIMIT_LABELS[window] ?? window;
|
const known = LIMIT_LABELS[window];
|
||||||
|
if (known) {
|
||||||
|
return known;
|
||||||
|
}
|
||||||
|
if (window.startsWith(SEVEN_DAY)) {
|
||||||
|
const model = window.slice(SEVEN_DAY.length);
|
||||||
|
return `7-day · ${model.charAt(0).toUpperCase()}${model.slice(1)}`;
|
||||||
|
}
|
||||||
|
return window.replaceAll("_", " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
// The status as a word, for the windows the API never puts a figure on.
|
// The status as a word, for the windows the API never puts a figure on.
|
||||||
|
|||||||
Reference in New Issue
Block a user