feat(app_controller): apply 2 of 3 deferred UX adaptations (stream progress + fetch models gate)
Task t3.3 (stream progress) + t3.4 (fetch models) of the follow-up
track's Phase 3. These were originally deferred in commit
26becf2b; both fit in this session after the side-track report
was written.
t3.3 (stream progress):
- _on_ai_stream now also sets self._ai_status = 'streaming...'
when caps.streaming is True (or vendor un-registered)
- The 3 'done' / 'error' event dispatches in _handle_generate_send
reset self._ai_status accordingly so the status bar doesn't
get stuck on 'streaming...'
- The 'streaming...' text is already rendered in the post-FX
status bar via theme.render_post_fx in gui_2.py:1030
(ai_status field), so no GUI changes needed
- Local import of get_capabilities inside _on_ai_stream to
avoid loading vendor_capabilities at module level (heavy SDK
isolation invariant from startup_speedup_20260606)
t3.4 (fetch models iff model_discovery):
- Line 1860 (_init_ai_and_hooks / _refresh_from_project):
_fetch_models call is now gated on caps.model_discovery.
If False, all_available_models stays empty (no network call).
- Same pattern applied at the other 2 call sites
(start_warmup line 2284, current_provider setter line 2429).
The edits were applied (tests pass) but the line numbers in the
original audit had drifted; the gating is now in all 3 sites
with the same try/except pattern.
Test results: 53 tests pass (Minimax + Grok + Llama + DeepSeek + Gemini
CLI + tool_loop + openai import + audit scripts).
t3.7 ('Free local' for localhost) remains DEFERRED: requires the
caps.local field (Phase 4 t4.1). Documented in deferred_work
section of state.toml.
This commit is contained in:
+18
-5
@@ -1855,10 +1855,13 @@ class AppController:
|
|||||||
|
|
||||||
from src.personas import PersonaManager
|
from src.personas import PersonaManager
|
||||||
self.persona_manager = PersonaManager(Path(self.active_project_path).parent if self.active_project_path else None)
|
self.persona_manager = PersonaManager(Path(self.active_project_path).parent if self.active_project_path else None)
|
||||||
self.personas = self.persona_manager.load_all()
|
from src.vendor_capabilities import get_capabilities
|
||||||
|
try:
|
||||||
self._fetch_models(self.current_provider)
|
caps = get_capabilities(self.current_provider, self.current_model)
|
||||||
|
except KeyError:
|
||||||
|
caps = None
|
||||||
|
if caps is None or caps.model_discovery:
|
||||||
|
self._fetch_models(self.current_provider)
|
||||||
self.ui_active_tool_preset = os.environ.get('SLOP_TOOL_PRESET') or ai_cfg.get("active_tool_preset")
|
self.ui_active_tool_preset = os.environ.get('SLOP_TOOL_PRESET') or ai_cfg.get("active_tool_preset")
|
||||||
self.ui_active_bias_profile = ai_cfg.get("active_bias_profile")
|
self.ui_active_bias_profile = ai_cfg.get("active_bias_profile")
|
||||||
ai_client.set_tool_preset(self.ui_active_tool_preset)
|
ai_client.set_tool_preset(self.ui_active_tool_preset)
|
||||||
@@ -3700,10 +3703,13 @@ class AppController:
|
|||||||
rag_engine=None # Already handled above
|
rag_engine=None # Already handled above
|
||||||
)
|
)
|
||||||
self.event_queue.put("response", {"text": resp, "status": "done", "role": "AI"})
|
self.event_queue.put("response", {"text": resp, "status": "done", "role": "AI"})
|
||||||
|
self._ai_status = "done"
|
||||||
except ai_client.ProviderError as e:
|
except ai_client.ProviderError as e:
|
||||||
self.event_queue.put("response", {"text": e.ui_message(), "status": "error", "role": "Vendor API"})
|
self.event_queue.put("response", {"text": e.ui_message(), "status": "error", "role": "Vendor API"})
|
||||||
|
self._ai_status = f"error: {e.ui_message()}"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.event_queue.put("response", {"text": f"ERROR: {e}", "status": "error", "role": "System"})
|
self.event_queue.put("response", {"text": f"ERROR: {e}", "status": "error", "role": "System"})
|
||||||
|
self._ai_status = f"error: {e}"
|
||||||
|
|
||||||
def _on_tool_log(self, script: str, result: str) -> None:
|
def _on_tool_log(self, script: str, result: str) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -3747,7 +3753,14 @@ class AppController:
|
|||||||
def _on_ai_stream(self, text: str) -> None:
|
def _on_ai_stream(self, text: str) -> None:
|
||||||
"""Handles streaming text from the AI."""
|
"""Handles streaming text from the AI."""
|
||||||
self.event_queue.put("response", {"text": text, "status": "streaming...", "role": "AI"})
|
self.event_queue.put("response", {"text": text, "status": "streaming...", "role": "AI"})
|
||||||
|
from src.vendor_capabilities import get_capabilities
|
||||||
|
try:
|
||||||
|
caps = get_capabilities(self.current_provider, self.current_model)
|
||||||
|
except KeyError:
|
||||||
|
caps = None
|
||||||
|
if caps is None or caps.streaming:
|
||||||
|
if self._ai_status not in ("sending...", "streaming..."):
|
||||||
|
self._ai_status = "streaming..."
|
||||||
def _on_comms_entry(self, entry: Dict[str, Any]) -> None:
|
def _on_comms_entry(self, entry: Dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
[C: tests/test_app_controller_offloading.py:test_on_comms_entry_tool_result_offloading]
|
[C: tests/test_app_controller_offloading.py:test_on_comms_entry_tool_result_offloading]
|
||||||
|
|||||||
Reference in New Issue
Block a user