Compare commits
7 Commits
a52f3a2ef8
...
e3b483d983
| Author | SHA1 | Date | |
|---|---|---|---|
| e3b483d983 | |||
| 2d22bd7b9c | |||
| 76582c821e | |||
| e47ee14c7b | |||
| e747a783a5 | |||
| 84f05079e3 | |||
| c35170786b |
+1
-1
@@ -9,6 +9,6 @@ This file tracks all major tracks for the project. Each track has its own detail
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
- [~] **Track: Review vendor api usage in regards to conservative context handling**
|
- [x] **Track: Review vendor api usage in regards to conservative context handling**
|
||||||
*Link: [./tracks/api_metrics_20260223/](./tracks/api_metrics_20260223/)*
|
*Link: [./tracks/api_metrics_20260223/](./tracks/api_metrics_20260223/)*
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,11 @@
|
|||||||
- [x] Sub-task: Implement Feature
|
- [x] Sub-task: Implement Feature
|
||||||
- [x] Task: Conductor - User Manual Verification 'Phase 1: Metric Extraction and Logic Review' (Protocol in workflow.md)
|
- [x] Task: Conductor - User Manual Verification 'Phase 1: Metric Extraction and Logic Review' (Protocol in workflow.md)
|
||||||
|
|
||||||
## Phase 2: GUI Telemetry and Plotting
|
## Phase 2: GUI Telemetry and Plotting [checkpoint: 76582c8]
|
||||||
- [ ] Task: Implement token budget visualizer (e.g., Progress bars for limits) in Dear PyGui
|
- [x] Task: Implement token budget visualizer (e.g., Progress bars for limits) in Dear PyGui
|
||||||
- [ ] Sub-task: Write Tests
|
- [x] Sub-task: Write Tests
|
||||||
- [ ] Sub-task: Implement Feature
|
- [x] Sub-task: Implement Feature
|
||||||
- [ ] Task: Implement active caches data display in Provider/Comms panel
|
- [x] Task: Implement active caches data display in Provider/Comms panel
|
||||||
- [ ] Sub-task: Write Tests
|
- [x] Sub-task: Write Tests
|
||||||
- [ ] Sub-task: Implement Feature
|
- [x] Sub-task: Implement Feature
|
||||||
- [ ] Task: Conductor - User Manual Verification 'Phase 2: GUI Telemetry and Plotting' (Protocol in workflow.md)
|
- [x] Task: Conductor - User Manual Verification 'Phase 2: GUI Telemetry and Plotting' (Protocol in workflow.md)
|
||||||
@@ -769,6 +769,35 @@ class App:
|
|||||||
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):
|
||||||
|
"""Updates the token budget visualizer in the Provider panel."""
|
||||||
|
# Update history bleed stats for all providers
|
||||||
|
stats = ai_client.get_history_bleed_stats()
|
||||||
|
if dpg.does_item_exist("token_budget_bar"):
|
||||||
|
percentage = stats.get("percentage", 0.0)
|
||||||
|
dpg.set_value("token_budget_bar", percentage / 100.0 if percentage else 0.0)
|
||||||
|
if dpg.does_item_exist("token_budget_label"):
|
||||||
|
current = stats.get("current", 0)
|
||||||
|
limit = stats.get("limit", 0)
|
||||||
|
dpg.set_value("token_budget_label", f"{current:,} / {limit:,}")
|
||||||
|
|
||||||
|
# Update Gemini-specific cache stats
|
||||||
|
if dpg.does_item_exist("gemini_cache_label"):
|
||||||
|
if self.current_provider == "gemini":
|
||||||
|
try:
|
||||||
|
cache_stats = ai_client.get_gemini_cache_stats()
|
||||||
|
count = cache_stats.get("cache_count", 0)
|
||||||
|
size_bytes = cache_stats.get("total_size_bytes", 0)
|
||||||
|
size_kb = size_bytes / 1024.0
|
||||||
|
text = f"Gemini Caches: {count} ({size_kb:.1f} KB)"
|
||||||
|
dpg.set_value("gemini_cache_label", text)
|
||||||
|
dpg.configure_item("gemini_cache_label", show=True)
|
||||||
|
except Exception as e:
|
||||||
|
# If the API call fails, just hide the label
|
||||||
|
dpg.configure_item("gemini_cache_label", show=False)
|
||||||
|
else:
|
||||||
|
dpg.configure_item("gemini_cache_label", show=False)
|
||||||
|
|
||||||
def _append_comms_entry(self, entry: dict, idx: int):
|
def _append_comms_entry(self, entry: dict, idx: int):
|
||||||
if not dpg.does_item_exist("comms_scroll"):
|
if not dpg.does_item_exist("comms_scroll"):
|
||||||
return
|
return
|
||||||
@@ -1870,6 +1899,12 @@ class App:
|
|||||||
callback=self.cb_model_changed,
|
callback=self.cb_model_changed,
|
||||||
)
|
)
|
||||||
dpg.add_separator()
|
dpg.add_separator()
|
||||||
|
dpg.add_text("Telemetry")
|
||||||
|
dpg.add_text("History Token Budget:", color=_LABEL_COLOR)
|
||||||
|
dpg.add_progress_bar(tag="token_budget_bar", default_value=0.0, width=-1)
|
||||||
|
dpg.add_text("0 / 0", tag="token_budget_label")
|
||||||
|
dpg.add_text("", tag="gemini_cache_label", show=False)
|
||||||
|
dpg.add_separator()
|
||||||
dpg.add_text("Parameters")
|
dpg.add_text("Parameters")
|
||||||
dpg.add_input_float(tag="ai_temperature", label="Temperature", default_value=self.temperature, min_value=0.0, max_value=2.0)
|
dpg.add_input_float(tag="ai_temperature", label="Temperature", default_value=self.temperature, min_value=0.0, max_value=2.0)
|
||||||
dpg.add_input_int(tag="ai_max_tokens", label="Max Tokens (Output)", default_value=self.max_tokens, step=1024)
|
dpg.add_input_int(tag="ai_max_tokens", label="Max Tokens (Output)", default_value=self.max_tokens, step=1024)
|
||||||
@@ -2207,6 +2242,7 @@ class App:
|
|||||||
|
|
||||||
# Flush any comms entries queued from background threads
|
# Flush any comms entries queued from background threads
|
||||||
self._flush_pending_comms()
|
self._flush_pending_comms()
|
||||||
|
self._update_telemetry_panel()
|
||||||
|
|
||||||
dpg.render_dearpygui_frame()
|
dpg.render_dearpygui_frame()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
import pytest
|
||||||
|
from unittest.mock import patch, MagicMock
|
||||||
|
import importlib.util
|
||||||
|
import sys
|
||||||
|
import dearpygui.dearpygui as dpg
|
||||||
|
|
||||||
|
# Load gui.py as a module for testing
|
||||||
|
spec = importlib.util.spec_from_file_location("gui", "gui.py")
|
||||||
|
gui = importlib.util.module_from_spec(spec)
|
||||||
|
sys.modules["gui"] = gui
|
||||||
|
spec.loader.exec_module(gui)
|
||||||
|
from gui import App
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def app_instance():
|
||||||
|
"""
|
||||||
|
Fixture to create an instance of the App class for testing.
|
||||||
|
It creates a real DPG context but mocks functions that would
|
||||||
|
render a window or block execution.
|
||||||
|
"""
|
||||||
|
dpg.create_context()
|
||||||
|
|
||||||
|
# Patch only the functions that would show a window or block,
|
||||||
|
# and the App methods that rebuild UI on init.
|
||||||
|
with patch('dearpygui.dearpygui.create_viewport'), \
|
||||||
|
patch('dearpygui.dearpygui.setup_dearpygui'), \
|
||||||
|
patch('dearpygui.dearpygui.show_viewport'), \
|
||||||
|
patch('dearpygui.dearpygui.start_dearpygui'), \
|
||||||
|
patch('gui.load_config', return_value={}), \
|
||||||
|
patch.object(App, '_rebuild_files_list'), \
|
||||||
|
patch.object(App, '_rebuild_shots_list'), \
|
||||||
|
patch.object(App, '_rebuild_disc_list'), \
|
||||||
|
patch.object(App, '_rebuild_disc_roles_list'), \
|
||||||
|
patch.object(App, '_rebuild_discussion_selector'), \
|
||||||
|
patch.object(App, '_refresh_project_widgets'):
|
||||||
|
|
||||||
|
app = App()
|
||||||
|
yield app
|
||||||
|
|
||||||
|
dpg.destroy_context()
|
||||||
|
|
||||||
|
def test_telemetry_panel_updates_correctly(app_instance):
|
||||||
|
"""
|
||||||
|
Tests that the _update_telemetry_panel method correctly updates
|
||||||
|
DPG widgets based on the stats from ai_client.
|
||||||
|
"""
|
||||||
|
# 1. Set the provider to anthropic
|
||||||
|
app_instance.current_provider = "anthropic"
|
||||||
|
|
||||||
|
# 2. Define the mock stats
|
||||||
|
mock_stats = {
|
||||||
|
"provider": "anthropic",
|
||||||
|
"limit": 180000,
|
||||||
|
"current": 135000,
|
||||||
|
"percentage": 75.0,
|
||||||
|
}
|
||||||
|
|
||||||
|
# 3. Patch the dependencies
|
||||||
|
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.configure_item') as mock_configure_item, \
|
||||||
|
patch('dearpygui.dearpygui.does_item_exist', return_value=True) as mock_does_item_exist:
|
||||||
|
|
||||||
|
# 4. Call the method under test
|
||||||
|
app_instance._update_telemetry_panel()
|
||||||
|
|
||||||
|
# 5. Assert the results
|
||||||
|
mock_get_stats.assert_called_once()
|
||||||
|
|
||||||
|
# Assert history bleed widgets were updated
|
||||||
|
mock_set_value.assert_any_call("token_budget_bar", 0.75)
|
||||||
|
mock_set_value.assert_any_call("token_budget_label", "135,000 / 180,000")
|
||||||
|
|
||||||
|
# Assert Gemini-specific widget was hidden
|
||||||
|
mock_configure_item.assert_any_call("gemini_cache_label", show=False)
|
||||||
|
|
||||||
|
def test_cache_data_display_updates_correctly(app_instance):
|
||||||
|
"""
|
||||||
|
Tests that the _update_telemetry_panel method correctly updates the
|
||||||
|
GUI with Gemini cache statistics when the provider is set to Gemini.
|
||||||
|
"""
|
||||||
|
# 1. Set the provider to Gemini
|
||||||
|
app_instance.current_provider = "gemini"
|
||||||
|
|
||||||
|
# 2. Define mock cache stats
|
||||||
|
mock_cache_stats = {
|
||||||
|
'cache_count': 5,
|
||||||
|
'total_size_bytes': 12345
|
||||||
|
}
|
||||||
|
# Expected formatted string
|
||||||
|
expected_text = "Gemini Caches: 5 (12.1 KB)"
|
||||||
|
|
||||||
|
# 3. Patch dependencies
|
||||||
|
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.configure_item') as mock_configure_item, \
|
||||||
|
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
|
||||||
|
with patch('ai_client.get_history_bleed_stats', return_value={}):
|
||||||
|
|
||||||
|
# 4. Call the method under test
|
||||||
|
app_instance._update_telemetry_panel()
|
||||||
|
|
||||||
|
# 5. Assert the results
|
||||||
|
mock_get_cache_stats.assert_called_once()
|
||||||
|
|
||||||
|
# Check that the UI item was shown and its value was set
|
||||||
|
mock_configure_item.assert_any_call("gemini_cache_label", show=True)
|
||||||
|
mock_set_value.assert_any_call("gemini_cache_label", expected_text)
|
||||||
|
|
||||||
Reference in New Issue
Block a user