Revert "gateway: compact /usage with current-session per-model costs"

This reverts commit 364b93a4b9.
This commit is contained in:
alt-glitch 2026-06-16 19:43:25 +05:30
parent 418ceaf8c1
commit 222126db1d
6 changed files with 7 additions and 416 deletions

View file

@ -243,17 +243,6 @@ def nous_credits_lines(*, markdown: bool = False, timeout: float = 10.0) -> list
renders from that fixture instead of the real portal (so the block + gauge are
testable without a live account). Throwaway scaffolding.
"""
snapshot = _fetch_nous_credits_snapshot(timeout=timeout)
return render_account_usage_lines(snapshot, markdown=markdown)
def _fetch_nous_credits_snapshot(timeout: float = 10.0) -> Optional[AccountUsageSnapshot]:
"""Auth-gate + portal fetch + snapshot build for the Nous credits block.
Shared by ``nous_credits_lines`` (full block) and
``nous_credits_compact_line`` (one-liner). Honors the
HERMES_DEV_CREDITS_FIXTURE dev override. Fail-open None.
"""
# Dev fixture short-circuit — render /usage from the injected state, no portal.
try:
from agent.credits_tracker import dev_fixture_credits_state
@ -262,16 +251,17 @@ def _fetch_nous_credits_snapshot(timeout: float = 10.0) -> Optional[AccountUsage
except Exception:
fixture = None
if fixture is not None:
return _snapshot_from_credits_state(fixture)
snapshot = _snapshot_from_credits_state(fixture)
return render_account_usage_lines(snapshot, markdown=markdown)
try:
from hermes_cli.auth import get_provider_auth_state
tok = (get_provider_auth_state("nous") or {}).get("access_token")
if not (isinstance(tok, str) and tok.strip()):
return None
return []
except Exception:
return None
return []
try:
import concurrent.futures
@ -281,36 +271,13 @@ def _fetch_nous_credits_snapshot(timeout: float = 10.0) -> Optional[AccountUsage
account = pool.submit(
get_nous_portal_account_info, force_fresh=True
).result(timeout=timeout)
return build_nous_credits_snapshot(account)
snapshot = build_nous_credits_snapshot(account)
return render_account_usage_lines(snapshot, markdown=markdown)
except Exception:
# Fail-open (caller shows nothing), but leave a breadcrumb so a dead
# /usage credits block is diagnosable in agent.log without a dev flag.
logger.debug("credits ▸ /usage portal fetch/render failed (fail-open)", exc_info=True)
return None
def nous_credits_compact_line(*, timeout: float = 10.0) -> Optional[str]:
"""One-line Nous credits summary for the compact /usage view, or None.
Condenses the snapshot's own detail strings (stable, locally-built
formats) into ``Nous credits (Plan): Total usable: $X · Renews: ``.
Same gating/fail-open semantics as ``nous_credits_lines``.
"""
snap = _fetch_nous_credits_snapshot(timeout=timeout)
if snap is None or not snap.available:
return None
picked = [
d for d in snap.details
if d.startswith(("Total usable:", "Renews:", "Status:"))
]
if not picked:
picked = [d for d in snap.details if not d.startswith("Manage / top up:")][:2]
if not picked:
return None
title = snap.title
if snap.plan:
title += f" ({snap.plan})"
return f"{title}: " + " · ".join(picked)
return []
def _snapshot_from_credits_state(state) -> Optional[AccountUsageSnapshot]:

View file

@ -1695,36 +1695,6 @@ class SessionDB:
return self._execute_write(_do) or 0
def usage_totals(self, days: int = 30) -> Dict[str, Any]:
"""Aggregate usage for sessions started in the last ``days``.
``reported_cost_usd`` sums only provider-REPORTED ``actual_cost_usd``
(never estimates) and is None when no session in the window has a
reported cost callers must hide cost rather than print $0.00.
"""
cutoff = time.time() - days * 86400
with self._lock:
row = self._conn.execute(
"""SELECT COUNT(*) AS sessions,
COALESCE(SUM(input_tokens), 0)
+ COALESCE(SUM(cache_read_tokens), 0)
+ COALESCE(SUM(cache_write_tokens), 0) AS input_tokens,
COALESCE(SUM(output_tokens), 0) AS output_tokens,
COALESCE(SUM(api_call_count), 0) AS api_calls,
SUM(actual_cost_usd) AS reported_cost_usd
FROM sessions WHERE started_at >= ?""",
(cutoff,),
).fetchone()
result = dict(row) if row else {}
return {
"days": days,
"sessions": int(result.get("sessions") or 0),
"input_tokens": int(result.get("input_tokens") or 0),
"output_tokens": int(result.get("output_tokens") or 0),
"api_calls": int(result.get("api_calls") or 0),
"reported_cost_usd": result.get("reported_cost_usd"),
}
def get_session(self, session_id: str) -> Optional[Dict[str, Any]]:
"""Get a session by ID."""
with self._lock:

View file

@ -184,37 +184,3 @@ class TestOpenRouterUsageParam:
is_openrouter=False,
)
assert "usage" not in (kwargs.get("extra_body") or {})
# ── nous_credits_compact_line — one-liner for the compact /usage page ───────
class TestNousCreditsCompactLine:
def test_condenses_snapshot_details(self, monkeypatch):
import agent.account_usage as au
snap = au.AccountUsageSnapshot(
provider="nous",
source="portal-account",
fetched_at=au._utc_now(),
title="Nous credits",
plan="Ultra",
details=(
"Subscription credits: $-0.79",
"Top-up credits: $988.99",
"Total usable: $988.99",
"Renews: 2026-06-11T08:14:55.000Z",
"Manage / top up: https://portal.nousresearch.com/billing",
),
)
monkeypatch.setattr(au, "_fetch_nous_credits_snapshot", lambda timeout=10.0: snap)
line = au.nous_credits_compact_line()
assert line == (
"Nous credits (Ultra): Total usable: $988.99 · Renews: 2026-06-11T08:14:55.000Z"
)
def test_none_when_no_snapshot(self, monkeypatch):
import agent.account_usage as au
monkeypatch.setattr(au, "_fetch_nous_credits_snapshot", lambda timeout=10.0: None)
assert au.nous_credits_compact_line() is None

View file

@ -158,37 +158,6 @@ class TestSessionLifecycle:
assert session["api_call_count"] == 5
assert session["input_tokens"] == 300
def test_update_token_counts_actual_cost_null_keeps_value(self, db):
"""A NULL actual_cost_usd delta must not touch the stored REAL cost."""
db.create_session(session_id="s1", source="cli")
db.update_token_counts("s1", input_tokens=100, actual_cost_usd=0.25)
db.update_token_counts("s1", input_tokens=100, actual_cost_usd=None)
db.update_token_counts("s1", input_tokens=100, actual_cost_usd=0.10)
session = db.get_session("s1")
assert session["actual_cost_usd"] == pytest.approx(0.35)
def test_usage_totals_reported_cost_none_when_nothing_reported(self, db):
"""usage_totals must distinguish 'no reported cost' (None) from $0."""
db.create_session(session_id="s1", source="cli")
db.update_token_counts("s1", input_tokens=100, output_tokens=50, api_call_count=1)
totals = db.usage_totals(days=30)
assert totals["sessions"] == 1
assert totals["input_tokens"] == 100
assert totals["output_tokens"] == 50
assert totals["reported_cost_usd"] is None
def test_usage_totals_sums_reported_costs(self, db):
db.create_session(session_id="s1", source="cli")
db.create_session(session_id="s2", source="tui")
db.update_token_counts("s1", input_tokens=100, actual_cost_usd=0.20)
db.update_token_counts("s2", input_tokens=300, actual_cost_usd=0.05)
totals = db.usage_totals(days=30)
assert totals["sessions"] == 2
assert totals["reported_cost_usd"] == pytest.approx(0.25)
def test_update_token_counts_backfills_model_when_null(self, db):
db.create_session(session_id="s1", source="telegram")
db.update_token_counts("s1", input_tokens=10, output_tokens=5, model="openai/gpt-5.4")

View file

@ -7848,180 +7848,6 @@ def test_session_list_truncated_false_on_normal_paths(monkeypatch):
assert filtered["result"]["truncated"] is False
# ── /usage: compact in-process page with real-only costs ─────────────────────
def _usage_agent(**overrides):
"""SimpleNamespace agent with realistic session counters for /usage."""
base = dict(
model="anthropic/claude-sonnet-4.6",
provider="openrouter",
base_url="https://openrouter.ai/api/v1",
session_input_tokens=35_000,
session_output_tokens=10_000,
session_cache_read_tokens=5_000,
session_cache_write_tokens=2_000,
session_reasoning_tokens=0,
session_prompt_tokens=40_000,
session_completion_tokens=10_000,
session_total_tokens=50_000,
session_api_calls=5,
session_actual_cost_usd=None,
session_model_usage={},
context_compressor=None,
)
base.update(overrides)
return types.SimpleNamespace(**base)
def _mute_usage_externals(monkeypatch):
import agent.account_usage as account_usage
monkeypatch.setattr(server, "_get_db", lambda: None)
monkeypatch.setattr(account_usage, "nous_credits_compact_line", lambda **kw: None)
def test_get_usage_cost_absent_when_provider_reports_nothing(monkeypatch):
"""No estimation: even a model with known pricing gets NO cost_usd field."""
agent = _usage_agent()
usage = server._get_usage(agent)
assert "cost_usd" not in usage
assert usage["input"] == 35_000
def test_get_usage_cost_present_when_provider_reported(monkeypatch):
agent = _usage_agent(session_actual_cost_usd=0.4321)
usage = server._get_usage(agent)
assert usage["cost_usd"] == pytest.approx(0.4321)
assert usage["cost_status"] == "actual"
def test_get_usage_cost_from_nous_credits_delta(monkeypatch):
agent = _usage_agent(provider="nous")
agent.get_credits_spent_micros = lambda: 250_000 # $0.25 real header delta
usage = server._get_usage(agent)
assert usage["cost_usd"] == pytest.approx(0.25)
def test_compact_usage_per_model_rows_and_real_cost(monkeypatch):
_mute_usage_externals(monkeypatch)
agent = _usage_agent(
session_actual_cost_usd=0.42,
session_model_usage={
"anthropic/claude-sonnet-4.6": {
"calls": 4, "input": 30_000, "output": 9_000,
"cache_read": 5_000, "cache_write": 2_000, "cost_usd": 0.42,
},
"deepseek/deepseek-chat": {
"calls": 1, "input": 5_000, "output": 1_000,
"cache_read": 0, "cache_write": 0, "cost_usd": None,
},
},
)
text = server._compact_usage_text(_session(agent=agent))
assert "Session — anthropic/claude-sonnet-4.6 (openrouter)" in text
sonnet_row = next(l for l in text.splitlines() if "claude-sonnet-4.6" in l and "reqs" in l)
assert "reqs 4" in sonnet_row and "$0.4200" in sonnet_row
deepseek_row = next(l for l in text.splitlines() if "deepseek-chat" in l)
# Cost not reported for this model → no dollar figure on its row.
assert "reqs 1" in deepseek_row and "$" not in deepseek_row
assert "session cost: $0.4200 (provider-reported)" in text
assert "/usage full" in text
def test_compact_usage_absent_cost_never_renders_zero(monkeypatch):
_mute_usage_externals(monkeypatch)
agent = _usage_agent() # nothing reported
text = server._compact_usage_text(_session(agent=agent))
assert "session cost: not reported by provider" in text
assert "$0.00" not in text
def test_compact_usage_no_agent(monkeypatch):
_mute_usage_externals(monkeypatch)
text = server._compact_usage_text(_session(agent=None) | {"agent": None})
assert "no API calls yet" in text
def test_compact_usage_recent_summary_and_credits_line(monkeypatch):
import agent.account_usage as account_usage
class _DB:
def usage_totals(self, days=30):
return {
"days": 30, "sessions": 12, "input_tokens": 1_200_000,
"output_tokens": 90_000, "api_calls": 64,
"reported_cost_usd": 4.5678,
}
monkeypatch.setattr(server, "_get_db", lambda: _DB())
monkeypatch.setattr(
account_usage, "nous_credits_compact_line",
lambda **kw: "Nous credits (Ultra): Total usable: $988.99 · Renews: 2026-06-11",
)
text = server._compact_usage_text(_session(agent=_usage_agent()))
assert "Last 30d: 12 sessions" in text
assert "reported cost $4.57" in text
assert "Nous credits (Ultra)" in text
def test_compact_usage_recent_summary_hides_unreported_cost(monkeypatch):
_mute_usage_externals(monkeypatch)
class _DB:
def usage_totals(self, days=30):
return {
"days": 30, "sessions": 3, "input_tokens": 10_000,
"output_tokens": 2_000, "api_calls": 7,
"reported_cost_usd": None,
}
monkeypatch.setattr(server, "_get_db", lambda: _DB())
text = server._compact_usage_text(_session(agent=_usage_agent()))
assert "Last 30d: 3 sessions" in text
assert "reported cost" not in text
def test_slash_exec_usage_is_answered_in_process(monkeypatch):
"""/usage must not hit the slash worker (it has no live agent)."""
_mute_usage_externals(monkeypatch)
server._sessions["sid-usage"] = _session(agent=_usage_agent())
try:
resp = server.handle_request(
{"id": "1", "method": "slash.exec",
"params": {"session_id": "sid-usage", "command": "usage"}}
)
out = resp["result"]["output"]
assert "Session — anthropic/claude-sonnet-4.6" in out
# Worker untouched.
assert server._sessions["sid-usage"]["slash_worker"] is None
finally:
server._sessions.pop("sid-usage", None)
def test_slash_exec_usage_full_falls_through_to_worker(monkeypatch):
ran = []
class _Worker:
def run(self, cmd):
ran.append(cmd)
return "detailed legacy page"
sess = _session(agent=_usage_agent())
sess["slash_worker"] = _Worker()
server._sessions["sid-usage-full"] = sess
try:
monkeypatch.setattr(server, "_mirror_slash_side_effects", lambda *a: "")
resp = server.handle_request(
{"id": "1", "method": "slash.exec",
"params": {"session_id": "sid-usage-full", "command": "usage full"}}
)
assert resp["result"]["output"] == "detailed legacy page"
assert ran == ["usage full"]
finally:
server._sessions.pop("sid-usage-full", None)
def test_slash_worker_close_reaps_zombie_and_closes_fds():
"""A hung worker is SIGKILLed, the zombie reaped, all pipes closed — once."""
calls = {k: 0 for k in ("terminate", "kill", "wait", "stdin", "stdout", "stderr")}

View file

@ -2321,102 +2321,6 @@ def _get_usage(agent) -> dict:
return usage
def _compact_usage_text(session: dict) -> str:
"""Compact /usage page: current session per-model rows + a tight recent
summary + a one-line Nous credits gauge.
Costs are provider-REPORTED only. When a provider reports nothing the
cost is simply omitted (never rendered as $0.00). The detailed legacy
page stays reachable via `/usage full` (slash-worker CLI path).
"""
from agent.usage_pricing import format_token_count_compact as _fmt
agent = session.get("agent")
lines: list[str] = []
calls = (getattr(agent, "session_api_calls", 0) or 0) if agent is not None else 0
if agent is not None and calls > 0:
u = _get_usage(agent)
header = f"Session — {u['model']}"
provider = getattr(agent, "provider", None)
if provider:
header += f" ({provider})"
lines.append(header)
per_model = getattr(agent, "session_model_usage", None) or {}
rows = list(per_model.items()) or [(
u["model"],
{
"calls": u["calls"], "input": u["input"], "output": u["output"],
"cache_read": u["cache_read"], "cache_write": u["cache_write"],
"cost_usd": None,
},
)]
name_w = max(len(name or "?") for name, _ in rows)
for name, row in rows:
cells = [
f"{(name or '?'):<{name_w}}",
f"reqs {row.get('calls', 0)}",
f"in {_fmt(int(row.get('input', 0) or 0))}",
f"out {_fmt(int(row.get('output', 0) or 0))}",
]
cache_read = int(row.get("cache_read", 0) or 0)
if cache_read:
cells.append(f"cache {_fmt(cache_read)}")
cost = row.get("cost_usd")
if cost is not None:
cells.append(f"${cost:.4f}")
lines.append(" " + " · ".join(cells))
ctx_pct = u.get("context_percent")
tail = [f"total {_fmt(int(u['total'] or 0))} tokens", f"{u['calls']} calls"]
if ctx_pct is not None:
tail.append(f"context {ctx_pct}%")
if u.get("compressions"):
tail.append(f"compressions {u['compressions']}")
lines.append(" " + " · ".join(tail))
cost_usd = u.get("cost_usd")
if cost_usd is not None:
lines.append(f" session cost: ${cost_usd:.4f} (provider-reported)")
else:
lines.append(" session cost: not reported by provider")
else:
lines.append("Session — no API calls yet")
# Tight recent summary from the session DB (real costs only).
try:
db = _get_db()
totals = db.usage_totals(days=30) if db is not None else None
except Exception:
totals = None
if totals and totals.get("sessions"):
from agent.usage_pricing import format_token_count_compact as _fmt30
parts = [
f"{totals['sessions']} sessions",
f"in {_fmt30(totals['input_tokens'])}",
f"out {_fmt30(totals['output_tokens'])}",
]
reported = totals.get("reported_cost_usd")
if reported is not None:
parts.append(f"reported cost ${float(reported):.2f}")
lines.append("Last 30d: " + " · ".join(parts))
# Nous credits one-liner (account-level; independent of the live agent).
try:
from agent.account_usage import nous_credits_compact_line
credits_line = nous_credits_compact_line()
except Exception:
credits_line = None
if credits_line:
lines.append(credits_line)
lines.append("(/usage full — detailed page)")
return "\n".join(lines)
def _probe_credentials(agent) -> str:
"""Light credential check at session creation — returns warning or ''."""
try:
@ -9676,17 +9580,6 @@ def _(rid, params: dict) -> dict:
except Exception as e:
return _ok(rid, {"output": f"Plugin command error: {e}"})
# /usage — answered in-process from the LIVE agent's session counters.
# The slash worker is a separate subprocess that resumes the session
# WITHOUT an agent, so it can never see current-session tokens/costs
# (it only printed the Nous credits block). `/usage full` still falls
# through to the worker for the detailed CLI page.
if _cmd_base == "usage" and _cmd_arg.strip().lower() not in {"full", "--full"}:
try:
return _ok(rid, {"output": _compact_usage_text(session)})
except Exception:
pass # fall through to the slash worker
worker = session.get("slash_worker")
if not worker:
try: