feat(mma): Phase 3 — Focus Agent UI + filter logic

- gui_2.__init__: add ui_focus_agent: str | None = None
- _gui_func: Focus Agent combo (All/Tier2/3/4) + clear button above OperationsTabs
- _render_comms_history_panel: filter by ui_focus_agent; show [source_tier] label per entry
- _render_tool_calls_panel: pre-filter with tool_log_filtered; fix missing i=i_minus_one+1; remove stale tuple destructure
- tests: 6 new Phase 3 tests, 18/18 total
This commit is contained in:
2026-03-02 16:26:41 -05:00
parent 4f77d8fdd9
commit b30e563fc1
2 changed files with 137 additions and 4 deletions

View File

@@ -260,6 +260,7 @@ class App:
self.active_track: Track | None = None
self.active_tickets: list[dict[str, Any]] = []
self.active_tier: str | None = None
self.ui_focus_agent: str | None = None
self.mma_status = "idle"
self._pending_mma_approval: dict[str, Any] | None = None
self._mma_approval_open = False
@@ -1746,6 +1747,21 @@ class App:
if self.show_windows.get("Operations Hub", False):
exp, self.show_windows["Operations Hub"] = imgui.begin("Operations Hub", self.show_windows["Operations Hub"])
if exp:
imgui.text("Focus Agent:")
imgui.same_line()
focus_label = self.ui_focus_agent or "All"
if imgui.begin_combo("##focus_agent", focus_label, imgui.ComboFlags_.width_fit_preview):
if imgui.selectable("All", self.ui_focus_agent is None)[0]:
self.ui_focus_agent = None
for tier in ["Tier 2", "Tier 3", "Tier 4"]:
if imgui.selectable(tier, self.ui_focus_agent == tier)[0]:
self.ui_focus_agent = tier
imgui.end_combo()
imgui.same_line()
if self.ui_focus_agent:
if imgui.button("x##clear_focus"):
self.ui_focus_agent = None
imgui.separator()
if imgui.begin_tab_bar("OperationsTabs"):
if imgui.begin_tab_item("Tool Calls")[0]:
self._render_tool_calls_panel()
@@ -2968,14 +2984,17 @@ class App:
imgui.separator()
imgui.begin_child("scroll_area")
clipper = imgui.ListClipper()
clipper.begin(len(self._tool_log))
tool_log_filtered = self._tool_log if not self.ui_focus_agent else [
e for e in self._tool_log if e.get("source_tier") == self.ui_focus_agent
]
clipper = imgui.ListClipper()
clipper.begin(len(tool_log_filtered))
while clipper.step():
for i_minus_one in range(clipper.display_start, clipper.display_end):
entry = self._tool_log[i_minus_one]
i = i_minus_one + 1
entry = tool_log_filtered[i_minus_one]
script = entry["script"]
result = entry["result"]
script, result, _ = self._tool_log[i_minus_one]
first_line = script.strip().splitlines()[0][:80] if script.strip() else "(empty)"
imgui.text_colored(C_KEY, f"Call #{i}: {first_line}")
# Script Display
imgui.text_colored(C_LBL, "Script:")
@@ -3411,6 +3430,8 @@ class App:
imgui.push_style_color(imgui.Col_.child_bg, vec4(40, 30, 20))
imgui.begin_child("comms_scroll", imgui.ImVec2(0, 0), False, imgui.WindowFlags_.horizontal_scrollbar)
log_to_render = self.prior_session_entries if self.is_viewing_prior_session else list(self._comms_log)
if self.ui_focus_agent and not self.is_viewing_prior_session:
log_to_render = [e for e in log_to_render if e.get("source_tier") == self.ui_focus_agent]
for idx_minus_one, entry in enumerate(log_to_render):
idx = idx_minus_one + 1
local_ts = entry.get("local_ts", 0)
@@ -3442,6 +3463,9 @@ class App:
imgui.text_colored(KIND_COLORS.get(k, C_VAL), k)
imgui.same_line()
imgui.text_colored(C_LBL, f"{entry.get('provider', '?')}/{entry.get('model', '?')}")
imgui.same_line()
tier_label = entry.get("source_tier") or "main"
imgui.text_colored(C_SUB, f"[{tier_label}]")
payload = entry.get("payload", {})
if k == "request":
self._render_heavy_text("message", payload.get("message", ""))

View File

@@ -0,0 +1,109 @@
"""
Tests for mma_agent_focus_ux_20260302 — Phase 3: Focus Agent UI + Filter Logic.
"""
from typing import Generator
import pytest
from unittest.mock import patch
from gui_2 import App
@pytest.fixture
def app_instance() -> Generator[App, None, None]:
with (
patch('gui_2.load_config', return_value={'gui': {'show_windows': {}}}),
patch('gui_2.save_config'),
patch('gui_2.project_manager'),
patch('gui_2.session_logger'),
patch('gui_2.immapp.run'),
patch.object(App, '_load_active_project'),
patch.object(App, '_fetch_models'),
patch.object(App, '_load_fonts'),
patch.object(App, '_post_init')
):
yield App()
def test_ui_focus_agent_state_var_exists(app_instance):
"""App.__init__ must expose ui_focus_agent: str | None = None."""
assert hasattr(app_instance, 'ui_focus_agent'), "ui_focus_agent missing from App"
assert app_instance.ui_focus_agent is None
def test_tool_log_filter_all(app_instance):
"""When ui_focus_agent is None, all tool log entries are visible."""
app = app_instance
app._tool_log = [
{"script": "a", "result": "r1", "ts": 1.0, "source_tier": "Tier 2"},
{"script": "b", "result": "r2", "ts": 2.0, "source_tier": "Tier 3"},
{"script": "c", "result": "r3", "ts": 3.0, "source_tier": None},
]
app.ui_focus_agent = None
filtered = app._tool_log if not app.ui_focus_agent else [
e for e in app._tool_log if e.get("source_tier") == app.ui_focus_agent
]
assert len(filtered) == 3
def test_tool_log_filter_tier3_only(app_instance):
"""When ui_focus_agent='Tier 3', only Tier 3 entries are shown."""
app = app_instance
app._tool_log = [
{"script": "a", "result": "r1", "ts": 1.0, "source_tier": "Tier 2"},
{"script": "b", "result": "r2", "ts": 2.0, "source_tier": "Tier 3"},
{"script": "c", "result": "r3", "ts": 3.0, "source_tier": "Tier 3"},
{"script": "d", "result": "r4", "ts": 4.0, "source_tier": None},
]
app.ui_focus_agent = "Tier 3"
filtered = [e for e in app._tool_log if e.get("source_tier") == app.ui_focus_agent]
assert len(filtered) == 2
assert all(e["source_tier"] == "Tier 3" for e in filtered)
def test_tool_log_filter_excludes_none_tier(app_instance):
"""Filtering to Tier 2 excludes entries with source_tier=None."""
app = app_instance
app._tool_log = [
{"script": "a", "result": "r1", "ts": 1.0, "source_tier": "Tier 2"},
{"script": "b", "result": "r2", "ts": 2.0, "source_tier": None},
]
app.ui_focus_agent = "Tier 2"
filtered = [e for e in app._tool_log if e.get("source_tier") == app.ui_focus_agent]
assert len(filtered) == 1
assert filtered[0]["script"] == "a"
def test_comms_log_filter_tier3_only(app_instance):
"""When ui_focus_agent='Tier 3', comms filter excludes other tiers."""
app = app_instance
import time
app._comms_log = [
{"ts": "10:00", "direction": "OUT", "kind": "request", "provider": "gemini",
"model": "m", "payload": {}, "source_tier": "Tier 2", "local_ts": time.time()},
{"ts": "10:01", "direction": "IN", "kind": "response", "provider": "gemini",
"model": "m", "payload": {}, "source_tier": "Tier 3", "local_ts": time.time()},
{"ts": "10:02", "direction": "OUT", "kind": "request", "provider": "gemini",
"model": "m", "payload": {}, "source_tier": None, "local_ts": time.time()},
]
app.ui_focus_agent = "Tier 3"
app.is_viewing_prior_session = False
log_to_render = list(app._comms_log)
if app.ui_focus_agent and not app.is_viewing_prior_session:
log_to_render = [e for e in log_to_render if e.get("source_tier") == app.ui_focus_agent]
assert len(log_to_render) == 1
assert log_to_render[0]["source_tier"] == "Tier 3"
def test_comms_log_filter_not_applied_for_prior_session(app_instance):
"""Focus filter must NOT apply when viewing prior session log."""
app = app_instance
app.ui_focus_agent = "Tier 3"
app.is_viewing_prior_session = True
prior = [
{"ts": "10:00", "source_tier": "Tier 2"},
{"ts": "10:01", "source_tier": "Tier 3"},
]
app.prior_session_entries = prior
log_to_render = app.prior_session_entries if app.is_viewing_prior_session else list(app._comms_log)
if app.ui_focus_agent and not app.is_viewing_prior_session:
log_to_render = [e for e in log_to_render if e.get("source_tier") == app.ui_focus_agent]
assert len(log_to_render) == 2