feat(dashboard): track real API call count per session

Adds schema v7 'api_call_count' column. run_agent.py increments it by 1
per LLM API call, web_server analytics SQL aggregates it, frontend uses
the real counter instead of summing sessions.

The 'API Calls' card on the analytics dashboard previously displayed
COUNT(*) from the sessions table — the number of conversations, not
LLM requests. Each session makes 10-90 API calls through the tool loop,
so the reported number was ~30x lower than real.

Salvaged from PR #10140 (@kshitijk4poor). The cache-token accuracy
portions of the original PR were deferred — per-provider analytics is
the better path there, since cache_write_tokens and actual_cost_usd
are only reliably available from a subset of providers (Anthropic
native, Codex Responses, OpenRouter with usage.include).

Tests:
- schema_version v7 assertion
- migration v2 -> v7 adds api_call_count column with default 0
- update_token_counts increments api_call_count by provided delta
- absolute=True sets api_call_count directly
- /api/analytics/usage exposes total_api_calls in totals
This commit is contained in:
kshitijk4poor 2026-04-22 05:29:21 -07:00 committed by Teknium
parent be11a75eae
commit 5fb143169b
7 changed files with 61 additions and 10 deletions

View file

@ -93,6 +93,27 @@ class TestSessionLifecycle:
assert session["input_tokens"] == 300
assert session["output_tokens"] == 150
def test_update_token_counts_tracks_api_call_count(self, db):
"""api_call_count increments with each update_token_counts call."""
db.create_session(session_id="s1", source="cli")
db.update_token_counts("s1", input_tokens=100, output_tokens=50, api_call_count=1)
db.update_token_counts("s1", input_tokens=100, output_tokens=50, api_call_count=1)
db.update_token_counts("s1", input_tokens=100, output_tokens=50, api_call_count=1)
session = db.get_session("s1")
assert session["api_call_count"] == 3
def test_update_token_counts_api_call_count_absolute(self, db):
"""absolute mode sets api_call_count directly."""
db.create_session(session_id="s1", source="cli")
db.update_token_counts("s1", input_tokens=100, output_tokens=50, api_call_count=1)
db.update_token_counts("s1", input_tokens=300, output_tokens=150,
api_call_count=5, absolute=True)
session = db.get_session("s1")
assert session["api_call_count"] == 5
assert session["input_tokens"] == 300
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")
@ -1152,7 +1173,7 @@ class TestSchemaInit:
def test_schema_version(self, db):
cursor = db._conn.execute("SELECT version FROM schema_version")
version = cursor.fetchone()[0]
assert version == 7
assert version == 8
def test_title_column_exists(self, db):
"""Verify the title column was created in the sessions table."""
@ -1208,18 +1229,24 @@ class TestSchemaInit:
conn.commit()
conn.close()
# Open with SessionDB — should migrate to v7
# Open with SessionDB — should migrate to v8
migrated_db = SessionDB(db_path=db_path)
# Verify migration
cursor = migrated_db._conn.execute("SELECT version FROM schema_version")
assert cursor.fetchone()[0] == 7
assert cursor.fetchone()[0] == 8
# Verify title column exists and is NULL for existing sessions
session = migrated_db.get_session("existing")
assert session is not None
assert session["title"] is None
# Verify api_call_count column was added with default 0
cursor = migrated_db._conn.execute(
"SELECT api_call_count FROM sessions WHERE id = 'existing'"
)
assert cursor.fetchone()[0] == 0
# Verify we can set title on migrated session
assert migrated_db.set_session_title("existing", "Migrated Title") is True
session = migrated_db.get_session("existing")