From bd8de9f3829e9f66e33d36a01464a99adcc42c1d Mon Sep 17 00:00:00 2001
From: Vinay Gupta <58447456+aivinay@users.noreply.github.com>
Date: Mon, 13 Jul 2026 09:09:51 -0500
Subject: [PATCH] fix(proxy): keep recent stats request rows (#1922)
## Description
`/stats.recent_requests` was built from the request-log tail, but then
filtered out any row whose compact token fields were incomplete. That
made the dashboard/API summary diverge from the raw request counters:
`requests.by_model` could show many recent requests for a model while
`recent_requests` only showed the few rows with complete
compression-token accounting.
This fixes the stats payload so the compact `recent_requests` table
mirrors the latest request-log rows without masking unknown token
accounting as measured zero. Missing/non-finite compact numeric fields
now remain `null`, and each row exposes `token_accounting_status` plus
`has_exact_tokens` so API clients and the dashboard can distinguish
complete, partial, and missing token accounting.
Closes #1914
## Type of Change
- [x] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change
- [ ] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring
## Changes Made
- Removed the token-completeness filter from
`_build_recent_request_payload()`.
- Preserved unknown compact recent-request numeric fields as `null`.
- Added `token_accounting_status` and `has_exact_tokens` to compact
recent request rows.
- Updated the dashboard recent-requests table to render unknown
token/latency fields as `unknown`.
- Hardened `build_session_summary()` against token-incomplete
request-log rows and surfaced an `unknown_token_accounting` bucket.
- Added TypeScript SDK fields for the compact recent-request stats
contract.
- Added a regression test covering missing, partial, and complete
token-accounting rows.
## Testing
- [x] Focused stats regression passes
- [x] Adjacent summary/MCP tests pass
- [x] TypeScript SDK typecheck/tests pass
- [x] Ruff check passes
- [x] Ruff format check passes
- [x] Diff whitespace check passes
- [ ] Full suite not run
### Test Output
```text
$ uv run --no-project ... pytest tests/test_proxy_stats_recent_requests.py -q
4 passed, 1 warning
$ uv run --no-project ... pytest tests/test_proxy_dashboard_stats_cache.py::test_session_summary_uses_generic_cli_filtering_keys tests/test_proxy_dashboard_stats_cache.py::test_session_summary_surfaces_codex_ws_counters tests/test_ccr_mcp_server.py -q
19 passed, 1 skipped
$ npm run typecheck
tsc --noEmit
$ npm test
296 passed, 33 skipped
$ uv run --no-project --with ruff ruff check headroom/proxy/server.py headroom/proxy/cost.py headroom/ccr/mcp_server.py tests/test_proxy_stats_recent_requests.py
All checks passed!
$ uv run --no-project --with ruff ruff format --check headroom/proxy/server.py headroom/proxy/cost.py headroom/ccr/mcp_server.py tests/test_proxy_stats_recent_requests.py
4 files already formatted
$ git diff --check
clean
```
## Verification
- Principal engineer review: no blockers after the final
finite-number/accounting-status alignment.
- Senior developer review: no blockers; implementation and focused
coverage look solid for #1914.
- Architect/design review: original API/UI contract blocker resolved;
unknowns remain visible as `null`/`unknown` instead of measured zero.
## Notes
The normal editable `uv run pytest ...` path is blocked locally by the
known native build issue in `esaxx-rs` (`fatal error: 'cstdint' file not
found`) while building the Rust extension on this machine. I validated
the Python-only stats path with a temporary `headroom._core` import stub
and `HEADROOM_REQUIRE_RUST_CORE=false`; no repository files were changed
for that stub.
## Review Readiness
- [x] I have performed a self-review
- [ ] This PR is ready for human review
---
headroom/ccr/mcp_server.py | 1 +
headroom/dashboard/templates/dashboard.html | 32 ++++++---
headroom/proxy/cost.py | 42 +++++++++--
headroom/proxy/server.py | 77 ++++++++++++++------
sdk/typescript/src/types/models.ts | 9 +++
tests/test_proxy_stats_recent_requests.py | 79 +++++++++++++++++++++
6 files changed, 204 insertions(+), 36 deletions(-)
diff --git a/headroom/ccr/mcp_server.py b/headroom/ccr/mcp_server.py
index b1e7ecc37..aa8a2b4d4 100644
--- a/headroom/ccr/mcp_server.py
+++ b/headroom/ccr/mcp_server.py
@@ -130,6 +130,7 @@ def _format_session_summary(
"too_small": "Too small (< 500 tokens)",
"passthrough": "Passthrough (token counting)",
"no_compressible_content": "No compressible content (user/assistant only)",
+ "unknown_token_accounting": "Unknown token accounting",
}
for key, count in uncomp.items():
label = reason_labels.get(key, key)
diff --git a/headroom/dashboard/templates/dashboard.html b/headroom/dashboard/templates/dashboard.html
index 54d04c240..5febf2507 100644
--- a/headroom/dashboard/templates/dashboard.html
+++ b/headroom/dashboard/templates/dashboard.html
@@ -1307,12 +1307,12 @@
-
-
+
+
-
+
-
+
@@ -1321,19 +1321,19 @@
@@ -2054,12 +2054,28 @@
// --- Formatting ---
+ hasNumber(n) {
+ return typeof n === 'number' && Number.isFinite(n);
+ },
+
formatNumber(n) {
if (n >= 1000000) return (n / 1000000).toFixed(1) + 'M';
if (n >= 1000) return (n / 1000).toFixed(1) + 'k';
return n.toString();
},
+ formatOptionalNumber(n) {
+ return this.hasNumber(n) ? this.formatNumber(n) : 'unknown';
+ },
+
+ formatOptionalPercent(n) {
+ return this.hasNumber(n) ? n.toFixed(0) + '%' : 'unknown';
+ },
+
+ formatOptionalMs(n) {
+ return this.hasNumber(n) ? n.toFixed(0) + 'ms' : 'unknown';
+ },
+
formatCurrency(n) {
if (n < 0) return '-' + this.formatCurrency(-n);
if (n >= 1000) return (n / 1000).toFixed(1) + 'k';
diff --git a/headroom/proxy/cost.py b/headroom/proxy/cost.py
index 180be6550..f520d09cb 100644
--- a/headroom/proxy/cost.py
+++ b/headroom/proxy/cost.py
@@ -10,6 +10,7 @@ from __future__ import annotations
import importlib.util
import logging
+import math
from collections import deque
from datetime import datetime, timedelta
from typing import TYPE_CHECKING, Any
@@ -472,23 +473,50 @@ def build_session_summary(
"too_small": 0,
"passthrough": 0,
"no_compressible_content": 0,
+ "unknown_token_accounting": 0,
}
+ def _entry_has_number(entry: Any, attr: str) -> bool:
+ value = getattr(entry, attr, None)
+ return (
+ isinstance(value, (int, float))
+ and not isinstance(value, bool)
+ and math.isfinite(float(value))
+ )
+
+ def _entry_number(entry: Any, attr: str) -> int | float:
+ value = getattr(entry, attr, 0)
+ return value if _entry_has_number(entry, attr) else 0
+
if proxy.logger:
for entry in proxy.logger._logs:
if entry.model and "count_tokens" in entry.model:
uncompressed_reasons["passthrough"] += 1
continue
- if entry.tokens_saved > 0:
+ tokens_saved = _entry_number(entry, "tokens_saved")
+ input_tokens_original = _entry_number(entry, "input_tokens_original")
+ input_tokens_optimized = _entry_number(entry, "input_tokens_optimized")
+ has_complete_token_accounting = all(
+ _entry_has_number(entry, attr)
+ for attr in (
+ "input_tokens_original",
+ "input_tokens_optimized",
+ "tokens_saved",
+ "savings_percent",
+ )
+ )
+ if tokens_saved > 0 and has_complete_token_accounting:
compressed_requests.append(
{
- "savings_pct": round(entry.savings_percent, 1),
- "tokens_saved": entry.tokens_saved,
- "original": entry.input_tokens_original,
- "optimized": entry.input_tokens_optimized,
+ "savings_pct": round(_entry_number(entry, "savings_percent"), 1),
+ "tokens_saved": tokens_saved,
+ "original": input_tokens_original,
+ "optimized": input_tokens_optimized,
}
)
- elif entry.input_tokens_original > 0:
+ elif not has_complete_token_accounting:
+ uncompressed_reasons["unknown_token_accounting"] += 1
+ elif input_tokens_original > 0:
# Categorize why it wasn't compressed
transforms = entry.transforms_applied or []
if not transforms:
@@ -496,7 +524,7 @@ def build_session_summary(
uncompressed_reasons["prefix_frozen"] += 1
elif all("excluded" in t or "protected" in t for t in transforms):
uncompressed_reasons["no_compressible_content"] += 1
- elif entry.input_tokens_original < 500:
+ elif input_tokens_original < 500:
uncompressed_reasons["too_small"] += 1
else:
uncompressed_reasons["prefix_frozen"] += 1
diff --git a/headroom/proxy/server.py b/headroom/proxy/server.py
index 275915947..578556e1c 100644
--- a/headroom/proxy/server.py
+++ b/headroom/proxy/server.py
@@ -30,6 +30,7 @@ import contextlib
import hmac
import json
import logging
+import math
import os
import sys
import threading
@@ -2964,29 +2965,63 @@ def create_app(config: ProxyConfig | None = None) -> FastAPI:
RECENT_REQUEST_LOG_WINDOW = 100
+ def _is_recent_request_number(value: Any) -> bool:
+ return (
+ isinstance(value, (int, float))
+ and not isinstance(value, bool)
+ and math.isfinite(float(value))
+ )
+
+ def _recent_request_optional_number(log: dict[str, Any], key: str) -> int | float | None:
+ value = log.get(key)
+ return value if _is_recent_request_number(value) else None
+
+ def _recent_request_token_accounting_status(log: dict[str, Any]) -> str:
+ token_fields = (
+ "input_tokens_original",
+ "input_tokens_optimized",
+ "tokens_saved",
+ "savings_percent",
+ )
+ present = [_is_recent_request_number(log.get(field)) for field in token_fields]
+ if all(present):
+ return "complete"
+ if any(present):
+ return "partial"
+ return "missing"
+
def _build_recent_request_payload(limit: int = RECENT_REQUEST_LOG_WINDOW) -> dict[str, Any]:
recent_request_logs = proxy.logger.get_recent(limit) if proxy.logger else []
- dashboard_recent_requests = [
- {
- "request_id": log.get("request_id"),
- "timestamp": log.get("timestamp"),
- "provider": log.get("provider"),
- "model": log.get("model"),
- "input_tokens_original": log.get("input_tokens_original"),
- "input_tokens_optimized": log.get("input_tokens_optimized"),
- "output_tokens": log.get("output_tokens"),
- "tokens_saved": log.get("tokens_saved"),
- "savings_percent": log.get("savings_percent"),
- "optimization_latency_ms": log.get("optimization_latency_ms"),
- "total_latency_ms": log.get("total_latency_ms"),
- "transforms_applied": log.get("transforms_applied", []),
- "waste_signals": log.get("waste_signals"),
- "tool_schema_saved_tokens": _tool_schema_saved_from_tags(log.get("tags")),
- }
- for log in recent_request_logs
- if log.get("input_tokens_original") is not None
- and log.get("input_tokens_optimized") is not None
- ][-10:]
+ dashboard_recent_requests = []
+ for log in recent_request_logs:
+ token_accounting_status = _recent_request_token_accounting_status(log)
+ dashboard_recent_requests.append(
+ {
+ "request_id": log.get("request_id"),
+ "timestamp": log.get("timestamp"),
+ "provider": log.get("provider"),
+ "model": log.get("model"),
+ "input_tokens_original": _recent_request_optional_number(
+ log, "input_tokens_original"
+ ),
+ "input_tokens_optimized": _recent_request_optional_number(
+ log, "input_tokens_optimized"
+ ),
+ "output_tokens": _recent_request_optional_number(log, "output_tokens"),
+ "tokens_saved": _recent_request_optional_number(log, "tokens_saved"),
+ "savings_percent": _recent_request_optional_number(log, "savings_percent"),
+ "optimization_latency_ms": _recent_request_optional_number(
+ log, "optimization_latency_ms"
+ ),
+ "total_latency_ms": _recent_request_optional_number(log, "total_latency_ms"),
+ "has_exact_tokens": token_accounting_status == "complete",
+ "token_accounting_status": token_accounting_status,
+ "transforms_applied": log.get("transforms_applied", []),
+ "waste_signals": log.get("waste_signals"),
+ "tool_schema_saved_tokens": _tool_schema_saved_from_tags(log.get("tags")),
+ }
+ )
+ dashboard_recent_requests = dashboard_recent_requests[-10:]
return {
"request_logs": recent_request_logs[-10:],
"recent_requests": dashboard_recent_requests,
diff --git a/sdk/typescript/src/types/models.ts b/sdk/typescript/src/types/models.ts
index 58096733c..240856891 100644
--- a/sdk/typescript/src/types/models.ts
+++ b/sdk/typescript/src/types/models.ts
@@ -72,6 +72,15 @@ export interface RequestMetrics {
model: string;
stream: boolean;
mode: string;
+ inputTokensOriginal?: number | null;
+ inputTokensOptimized?: number | null;
+ outputTokens?: number | null;
+ tokensSaved?: number | null;
+ savingsPercent?: number | null;
+ optimizationLatencyMs?: number | null;
+ totalLatencyMs?: number | null;
+ hasExactTokens?: boolean;
+ tokenAccountingStatus?: "complete" | "partial" | "missing";
tokensInputBefore: number;
tokensInputAfter: number;
tokensOutput?: number | null;
diff --git a/tests/test_proxy_stats_recent_requests.py b/tests/test_proxy_stats_recent_requests.py
index a902a3894..654632e8f 100644
--- a/tests/test_proxy_stats_recent_requests.py
+++ b/tests/test_proxy_stats_recent_requests.py
@@ -85,6 +85,85 @@ def test_stats_refreshes_recent_requests_when_cached() -> None:
assert second_payload["request_logs"][-1]["model"] == "claude-sonnet"
+def test_stats_recent_requests_includes_token_incomplete_requests() -> None:
+ app = create_app(
+ ProxyConfig(
+ optimize=False,
+ cache_enabled=False,
+ rate_limit_enabled=False,
+ cost_tracking_enabled=False,
+ log_requests=False,
+ ccr_inject_tool=False,
+ ccr_handle_responses=False,
+ ccr_context_tracking=False,
+ http2=False,
+ )
+ )
+ logger = FakeRequestLogger()
+ app.state.proxy.logger = logger
+
+ logger.logs = [
+ FakeLogEntry(
+ {
+ "request_id": "req-haiku-1",
+ "timestamp": "2026-07-09T10:00:00Z",
+ "provider": "anthropic",
+ "model": "claude-haiku",
+ "transforms_applied": [],
+ }
+ ),
+ FakeLogEntry(
+ {
+ "request_id": "req-haiku-2",
+ "timestamp": "2026-07-09T10:01:00Z",
+ "provider": "anthropic",
+ "model": "claude-haiku",
+ "input_tokens_original": None,
+ "input_tokens_optimized": None,
+ "output_tokens": None,
+ "tokens_saved": 0,
+ "savings_percent": 0.0,
+ "transforms_applied": [],
+ }
+ ),
+ FakeLogEntry(
+ {
+ "request_id": "req-sonnet-1",
+ "timestamp": "2026-07-09T10:02:00Z",
+ "provider": "anthropic",
+ "model": "claude-sonnet",
+ "input_tokens_original": 200,
+ "input_tokens_optimized": 120,
+ "output_tokens": 40,
+ "tokens_saved": 80,
+ "savings_percent": 40.0,
+ "transforms_applied": ["smart_crusher"],
+ }
+ ),
+ ]
+
+ with TestClient(app, base_url="http://127.0.0.1", client=("127.0.0.1", 12345)) as client:
+ response = client.get("/stats")
+
+ assert response.status_code == 200
+ payload = response.json()
+ assert [req["model"] for req in payload["recent_requests"]] == [
+ "claude-haiku",
+ "claude-haiku",
+ "claude-sonnet",
+ ]
+ assert payload["recent_requests"][0]["input_tokens_optimized"] is None
+ assert payload["recent_requests"][0]["token_accounting_status"] == "missing"
+ assert payload["recent_requests"][0]["has_exact_tokens"] is False
+ assert payload["recent_requests"][1]["output_tokens"] is None
+ assert payload["recent_requests"][1]["token_accounting_status"] == "partial"
+ assert payload["recent_requests"][1]["tokens_saved"] == 0
+ assert payload["recent_requests"][2]["token_accounting_status"] == "complete"
+ assert payload["recent_requests"][2]["has_exact_tokens"] is True
+ assert payload["summary"]["uncompressed_requests"]["unknown_token_accounting"] == 2
+ assert payload["request_logs"][-1]["model"] == "claude-sonnet"
+
+
def test_agent_usage_totals_use_proxy_only_savings(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("HEADROOM_REQUIRE_RUST_CORE", "false")
monkeypatch.setattr(