conductor(checkpoint): Checkpoint end of Phase 3: Diagnostics UI and Optimization

This commit is contained in:
2026-02-23 14:52:26 -05:00
parent 0625fe10c8
commit 555cf29890
4 changed files with 44 additions and 12 deletions

View File

@@ -25,7 +25,7 @@
- [x] Task: Build the Diagnostics Panel in Dear PyGui 30d838c - [x] Task: Build the Diagnostics Panel in Dear PyGui 30d838c
- [x] Sub-task: Write Tests (verify panel components render) - [x] Sub-task: Write Tests (verify panel components render)
- [x] Sub-task: Implement Feature (plots, stat readouts in `gui.py`) - [x] Sub-task: Implement Feature (plots, stat readouts in `gui.py`)
- [ ] Task: Identify and fix main thread performance bottlenecks - [~] Task: Identify and fix main thread performance bottlenecks
- [ ] Sub-task: Write Tests (reproducible "heavy" load test) - [ ] Sub-task: Write Tests (reproducible "heavy" load test)
- [ ] Sub-task: Implement Feature (refactor heavy logic to workers) - [ ] Sub-task: Implement Feature (refactor heavy logic to workers)
- [ ] Task: Conductor - User Manual Verification 'Phase 3: Diagnostics UI and Optimization' (Protocol in workflow.md) - [ ] Task: Conductor - User Manual Verification 'Phase 3: Diagnostics UI and Optimization' (Protocol in workflow.md)

32
gui.py
View File

@@ -504,6 +504,13 @@ class App:
"input_lag": [0.0] * 100 "input_lag": [0.0] * 100
} }
self.session_usage = {
"input_tokens": 0,
"output_tokens": 0,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 0
}
session_logger.open_session() session_logger.open_session()
ai_client.set_provider(self.current_provider, self.current_model) ai_client.set_provider(self.current_provider, self.current_model)
ai_client.confirm_and_run_callback = self._confirm_and_run ai_client.confirm_and_run_callback = self._confirm_and_run
@@ -511,6 +518,8 @@ class App:
ai_client.tool_log_callback = self._on_tool_log ai_client.tool_log_callback = self._on_tool_log
mcp_client.perf_monitor_callback = self.perf_monitor.get_metrics mcp_client.perf_monitor_callback = self.perf_monitor.get_metrics
self.perf_monitor.alert_callback = self._on_performance_alert self.perf_monitor.alert_callback = self._on_performance_alert
self._last_bleed_update_time = 0
self._recalculate_session_usage()
# ---------------------------------------------------------------- project loading # ---------------------------------------------------------------- project loading
@@ -775,6 +784,21 @@ class App:
"ts": project_manager.now_ts() "ts": project_manager.now_ts()
}) })
def _recalculate_session_usage(self):
"""Aggregates usage across the session from comms log."""
usage = {
"input_tokens": 0,
"output_tokens": 0,
"cache_read_input_tokens": 0,
"cache_creation_input_tokens": 0
}
for entry in ai_client.get_comms_log():
if entry.get("kind") == "response" and "usage" in entry.get("payload", {}):
u = entry["payload"]["usage"]
for k in usage.keys():
usage[k] += u.get(k, 0) or 0
self.session_usage = usage
def _flush_pending_comms(self): def _flush_pending_comms(self):
"""Called every frame from the main render loop.""" """Called every frame from the main render loop."""
with self._pending_comms_lock: with self._pending_comms_lock:
@@ -784,18 +808,22 @@ class App:
self._comms_entry_count += 1 self._comms_entry_count += 1
self._append_comms_entry(entry, self._comms_entry_count) self._append_comms_entry(entry, self._comms_entry_count)
if entries: if entries:
self._recalculate_session_usage()
self._update_token_usage() self._update_token_usage()
def _update_token_usage(self): def _update_token_usage(self):
if not dpg.does_item_exist("ai_token_usage"): if not dpg.does_item_exist("ai_token_usage"):
return return
usage = get_total_token_usage() usage = self.session_usage
total = usage["input_tokens"] + usage["output_tokens"] total = usage["input_tokens"] + usage["output_tokens"]
dpg.set_value("ai_token_usage", f"Tokens: {total} (In: {usage['input_tokens']} Out: {usage['output_tokens']})") dpg.set_value("ai_token_usage", f"Tokens: {total} (In: {usage['input_tokens']} Out: {usage['output_tokens']})")
def _update_telemetry_panel(self): def _update_telemetry_panel(self):
"""Updates the token budget visualizer in the Provider panel.""" """Updates the token budget visualizer in the Provider panel."""
# Update history bleed stats for all providers # Update history bleed stats for all providers (throttled)
now = time.time()
if now - self._last_bleed_update_time > 2.0:
self._last_bleed_update_time = now
stats = ai_client.get_history_bleed_stats() stats = ai_client.get_history_bleed_stats()
if dpg.does_item_exist("token_budget_bar"): if dpg.does_item_exist("token_budget_bar"):
percentage = stats.get("percentage", 0.0) percentage = stats.get("percentage", 0.0)

View File

@@ -35,5 +35,5 @@ active = "main"
[discussion.discussions.main] [discussion.discussions.main]
git_commit = "" git_commit = ""
last_updated = "2026-02-23T14:48:16" last_updated = "2026-02-23T14:52:20"
history = [] history = []

View File

@@ -56,9 +56,11 @@ def test_telemetry_panel_updates_correctly(app_instance):
} }
# 3. Patch the dependencies # 3. Patch the dependencies
app_instance._last_bleed_update_time = 0 # Force update
with patch('ai_client.get_history_bleed_stats', return_value=mock_stats) as mock_get_stats, \ with patch('ai_client.get_history_bleed_stats', return_value=mock_stats) as mock_get_stats, \
patch('dearpygui.dearpygui.set_value') as mock_set_value, \ patch('dearpygui.dearpygui.set_value') as mock_set_value, \
patch('dearpygui.dearpygui.configure_item') as mock_configure_item, \ patch('dearpygui.dearpygui.configure_item') as mock_configure_item, \
patch('dearpygui.dearpygui.is_item_shown', return_value=False), \
patch('dearpygui.dearpygui.does_item_exist', return_value=True) as mock_does_item_exist: patch('dearpygui.dearpygui.does_item_exist', return_value=True) as mock_does_item_exist:
# 4. Call the method under test # 4. Call the method under test
@@ -91,9 +93,11 @@ def test_cache_data_display_updates_correctly(app_instance):
expected_text = "Gemini Caches: 5 (12.1 KB)" expected_text = "Gemini Caches: 5 (12.1 KB)"
# 3. Patch dependencies # 3. Patch dependencies
app_instance._last_bleed_update_time = 0 # Force update
with patch('ai_client.get_gemini_cache_stats', return_value=mock_cache_stats) as mock_get_cache_stats, \ with patch('ai_client.get_gemini_cache_stats', return_value=mock_cache_stats) as mock_get_cache_stats, \
patch('dearpygui.dearpygui.set_value') as mock_set_value, \ patch('dearpygui.dearpygui.set_value') as mock_set_value, \
patch('dearpygui.dearpygui.configure_item') as mock_configure_item, \ patch('dearpygui.dearpygui.configure_item') as mock_configure_item, \
patch('dearpygui.dearpygui.is_item_shown', return_value=False), \
patch('dearpygui.dearpygui.does_item_exist', return_value=True) as mock_does_item_exist: patch('dearpygui.dearpygui.does_item_exist', return_value=True) as mock_does_item_exist:
# We also need to mock get_history_bleed_stats as it's called in the same function # We also need to mock get_history_bleed_stats as it's called in the same function