This commit is contained in:
2026-03-06 19:54:52 -05:00
parent 36a1bd4257
commit 0e9f84f026
7 changed files with 565 additions and 307 deletions

View File

@@ -148,10 +148,10 @@ class AppController:
"last_latency": 0.0
}
self.mma_tier_usage: Dict[str, Dict[str, Any]] = {
"Tier 1": {"input": 0, "output": 0, "model": "gemini-3.1-pro-preview"},
"Tier 2": {"input": 0, "output": 0, "model": "gemini-3-flash-preview"},
"Tier 3": {"input": 0, "output": 0, "model": "gemini-2.5-flash-lite"},
"Tier 4": {"input": 0, "output": 0, "model": "gemini-2.5-flash-lite"},
"Tier 1": {"input": 0, "output": 0, "provider": "gemini", "model": "gemini-3.1-pro-preview"},
"Tier 2": {"input": 0, "output": 0, "provider": "gemini", "model": "gemini-3-flash-preview"},
"Tier 3": {"input": 0, "output": 0, "provider": "gemini", "model": "gemini-2.5-flash-lite"},
"Tier 4": {"input": 0, "output": 0, "provider": "gemini", "model": "gemini-2.5-flash-lite"},
}
self.perf_monitor: performance_monitor.PerformanceMonitor = performance_monitor.PerformanceMonitor()
self._pending_gui_tasks: List[Dict[str, Any]] = []
@@ -195,6 +195,8 @@ class AppController:
self.ui_global_system_prompt: str = ""
self.ui_agent_tools: Dict[str, bool] = {}
self.available_models: List[str] = []
self.all_available_models: Dict[str, List[str]] = {} # provider -> list of models
self._autofocus_response_tab = False
self.proposed_tracks: List[Dict[str, Any]] = []
self._show_track_proposal_modal: bool = False
self.ai_status: str = 'idle'
@@ -401,6 +403,8 @@ class AppController:
self._trigger_blink = True
if not stream_id:
self._token_stats_dirty = True
if not is_streaming:
self._autofocus_response_tab = True
# ONLY add to history when turn is complete
if self.ui_auto_add_history and not stream_id and not is_streaming:
role = payload.get("role", "AI")
@@ -408,7 +412,7 @@ class AppController:
self._pending_history_adds.append({
"role": role,
"content": self.ai_response,
"collapsed": False,
"collapsed": True,
"ts": project_manager.now_ts()
})
elif action in ("mma_stream", "mma_stream_append"):
@@ -429,7 +433,19 @@ class AppController:
payload = task # Fallback to task if payload missing or wrong type
self.mma_status = payload.get("status", "idle")
self.active_tier = payload.get("active_tier")
self.mma_tier_usage = payload.get("tier_usage", self.mma_tier_usage)
# Preserve existing model/provider config if not explicitly in payload
new_usage = payload.get("tier_usage", {})
for tier, data in new_usage.items():
if tier in self.mma_tier_usage:
# Update usage counts but keep selected model/provider if not in update
self.mma_tier_usage[tier]["input"] = data.get("input", self.mma_tier_usage[tier]["input"])
self.mma_tier_usage[tier]["output"] = data.get("output", self.mma_tier_usage[tier]["output"])
if "model" in data: self.mma_tier_usage[tier]["model"] = data["model"]
if "provider" in data: self.mma_tier_usage[tier]["provider"] = data["provider"]
else:
self.mma_tier_usage[tier] = data
self.active_tickets = payload.get("tickets", [])
track_data = payload.get("track")
if track_data:
@@ -622,6 +638,8 @@ class AppController:
"Tier 4: QA": True,
"Discussion Hub": True,
"Operations Hub": True,
"Message": False,
"Response": False,
"Theme": True,
"Log Management": False,
"Diagnostics": False,
@@ -725,7 +743,14 @@ class AppController:
def do_fetch() -> None:
try:
models_list = ai_client.list_models(provider)
for p in self.PROVIDERS:
try:
self.all_available_models[p] = ai_client.list_models(p)
except Exception as e:
sys.stderr.write(f"[DEBUG] Error fetching models for {p}: {e}\n")
self.all_available_models[p] = []
models_list = self.all_available_models.get(provider, [])
self.available_models = models_list
if self.current_model not in models_list and models_list:
self.current_model = models_list[0]
@@ -851,7 +876,7 @@ class AppController:
self._pending_history_adds.append({
"role": "User",
"content": event.prompt,
"collapsed": False,
"collapsed": True,
"ts": project_manager.now_ts()
})
# Clear response area for new turn
@@ -896,6 +921,13 @@ class AppController:
entry["local_ts"] = time.time()
kind = entry.get("kind")
payload = entry.get("payload", {})
if kind == "response" and "usage" in payload:
u = payload["usage"]
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
if kind in ("tool_result", "tool_call"):
role = "Tool" if kind == "tool_result" else "Vendor API"
content = ""
@@ -1173,7 +1205,7 @@ class AppController:
self._pending_history_adds.append({
"role": "User",
"content": user_msg,
"collapsed": False,
"collapsed": True,
"ts": project_manager.now_ts()
})
try:
@@ -1183,7 +1215,7 @@ class AppController:
self._pending_history_adds.append({
"role": "AI",
"content": resp,
"collapsed": False,
"collapsed": True,
"ts": project_manager.now_ts()
})
self._recalculate_session_usage()
@@ -1669,6 +1701,7 @@ class AppController:
# Save MMA State
mma_sec = proj.setdefault("mma", {})
mma_sec["epic"] = self.ui_epic_input
mma_sec["tier_models"] = {t: {"model": d["model"], "provider": d.get("provider", "gemini")} for t, d in self.mma_tier_usage.items()}
if self.active_track:
mma_sec["active_track"] = asdict(self.active_track)
else:
@@ -1684,7 +1717,11 @@ class AppController:
}
self.config["ai"]["system_prompt"] = self.ui_global_system_prompt
self.config["projects"] = {"paths": self.project_paths, "active": self.active_project_path}
self.config["gui"] = {"show_windows": self.show_windows}
self.config["gui"] = {
"show_windows": self.show_windows,
"separate_message_panel": getattr(self, "ui_separate_message_panel", False),
"separate_response_panel": getattr(self, "ui_separate_response_panel", False),
}
theme.save_to_config(self.config)
def _do_generate(self) -> tuple[str, Path, list[dict[str, Any]], str, str]: