feat(gui): add Session Insights panel with token history tracking

This commit is contained in:
2026-03-07 11:17:51 -05:00
parent d6cdbf21d7
commit 9aea9b6210
2 changed files with 47 additions and 0 deletions

View File

@@ -147,6 +147,8 @@ class AppController:
self._tool_log: List[Dict[str, Any]] = []
self._tool_stats: Dict[str, Dict[str, Any]] = {} # {tool_name: {"count": 0, "total_time_ms": 0.0, "failures": 0}}
self._cached_cache_stats: Dict[str, Any] = {} # Pre-computed cache stats for GUI
self._token_history: List[Dict[str, Any]] = [] # Token usage over time [{"time": t, "input": n, "output": n, "model": s}, ...]
self._session_start_time: float = time.time() # For calculating burn rate
self._comms_log: List[Dict[str, Any]] = []
self.session_usage: Dict[str, Any] = {
"input_tokens": 0,
@@ -961,6 +963,15 @@ class AppController:
for k in ["input_tokens", "output_tokens", "cache_read_input_tokens", "cache_creation_input_tokens", "total_tokens"]:
if k in u:
self.session_usage[k] += u.get(k, 0) or 0
input_t = u.get("input_tokens", 0)
output_t = u.get("output_tokens", 0)
model = payload.get("model", "unknown")
self._token_history.append({
"time": time.time(),
"input": input_t,
"output": output_t,
"model": model
})
if kind in ("tool_result", "tool_call"):
role = "Tool" if kind == "tool_result" else "Vendor API"
@@ -1753,6 +1764,28 @@ class AppController:
ai_client.cleanup()
self._update_cached_stats()
def get_session_insights(self) -> Dict[str, Any]:
import cost_tracker
total_input = sum(e["input"] for e in self._token_history)
total_output = sum(e["output"] for e in self._token_history)
total_tokens = total_input + total_output
elapsed_min = (time.time() - self._session_start_time) / 60.0 if self._token_history else 0
burn_rate = total_tokens / elapsed_min if elapsed_min > 0 else 0
session_cost = cost_tracker.estimate_cost("gemini-2.5-flash", total_input, total_output)
completed = sum(1 for t in self.active_tickets if t.get("status") == "complete")
efficiency = total_tokens / completed if completed > 0 else 0
return {
"total_tokens": total_tokens,
"total_input": total_input,
"total_output": total_output,
"elapsed_min": elapsed_min,
"burn_rate": burn_rate,
"session_cost": session_cost,
"completed_tickets": completed,
"efficiency": efficiency,
"call_count": len(self._token_history)
}
def _flush_to_project(self) -> None:
proj = self.project
proj.setdefault("output", {})["output_dir"] = self.ui_output_dir

View File

@@ -333,6 +333,7 @@ class App:
self._render_token_budget_panel()
self._render_cache_panel()
self._render_tool_analytics_panel()
self._render_session_insights_panel()
if imgui.collapsing_header("System Prompts"):
self._render_system_prompts_panel()
@@ -1509,6 +1510,19 @@ class App:
imgui.text("0%")
imgui.end_table()
def _render_session_insights_panel(self) -> None:
if not imgui.collapsing_header("Session Insights"):
return
insights = self.controller.get_session_insights()
imgui.text(f"Total Tokens: {insights.get('total_tokens', 0):,}")
imgui.text(f"API Calls: {insights.get('call_count', 0)}")
imgui.text(f"Burn Rate: {insights.get('burn_rate', 0):.0f} tokens/min")
imgui.text(f"Session Cost: ${insights.get('session_cost', 0):.4f}")
completed = insights.get('completed_tickets', 0)
efficiency = insights.get('efficiency', 0)
imgui.text(f"Completed: {completed}")
imgui.text(f"Tokens/Ticket: {efficiency:.0f}" if efficiency > 0 else "Tokens/Ticket: N/A")
def _render_message_panel(self) -> None:
# LIVE indicator
is_live = self.ai_status in ["running powershell...", "fetching url...", "searching web...", "powershell done, awaiting AI..."]