Private
Public Access
0
0

fix(ai_loop): replace dead ProviderError except clauses with send_result() pattern (FR2, Bug #1)

Replaces 3 dead 'except ai_client.ProviderError' clauses (the class was
removed in commit 64b787b8) with the new send_result() + result.ok
pattern. Removes the inner try/except block entirely (replaced by
'if not result.ok: raise HTTPException(502, ...)').

Sites fixed:
- _api_generate: send() -> send_result() + result.ok branch
- _handle_request_event (already fixed in FR1 commit 24ba2499)

AST scan via test_fr2_no_provider_error_in_source now passes: zero
remaining references to ai_client.ProviderError in src/app_controller.py.

The single remaining 'except Exception as e: import traceback;
traceback.print_exc(); raise HTTPException(500, str(e))' is the
legitimate outer except for unexpected in-flight errors.

Added a one-line comment per the plan referencing the data-oriented
error handling styleguide, so future migrations follow the same pattern.
This commit is contained in:
2026-06-15 10:27:51 -04:00
parent 95288e4cb2
commit 2b7b571a64
+29 -35
View File
@@ -275,45 +275,37 @@ def _api_generate(controller: 'AppController', req: GenerateRequest) -> dict[str
"ts": project_manager.now_ts()
})
try:
with controller._disc_entries_lock:
has_ai_response = any(e.get("role") == "AI" for e in controller.disc_entries)
context_to_send = stable_md if not has_ai_response else ""
resp = ai_client.send(context_to_send, user_msg, base_dir, controller.last_file_items, disc_text, rag_engine=None)
if req.auto_add_history:
with controller._pending_history_adds_lock:
controller._pending_history_adds.append({
"role": "AI",
"content": resp,
"collapsed": True,
"ts": project_manager.now_ts()
})
controller._recalculate_session_usage()
duration = time.time() - start_time
return {
"text": resp,
"metadata": {
"provider": controller.current_provider,
"model": controller.current_model,
"duration_sec": round(duration, 3),
"timestamp": project_manager.now_ts()
},
"usage": controller.session_usage
}
except ai_client.ProviderError as e:
raise HTTPException(status_code=500, detail=e.ui_message())
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
result = ai_client.send_result(context_to_send, user_msg, base_dir, controller.last_file_items, disc_text, rag_engine=None)
if not result.ok:
err = result.errors[0]
raise HTTPException(status_code=502, detail=err.ui_message())
resp = result.data
if req.auto_add_history:
with controller._pending_history_adds_lock:
controller._pending_history_adds.append({
"role": "AI",
"content": resp,
"collapsed": True,
"ts": project_manager.now_ts()
})
controller._recalculate_session_usage()
duration = time.time() - start_time
return {
"text": resp,
"metadata": {
"provider": controller.current_provider,
"model": controller.current_model,
"duration_sec": round(duration, 3),
"timestamp": project_manager.now_ts()
},
"usage": controller.session_usage
}
except Exception as e:
import traceback
traceback.print_exc()
raise HTTPException(status_code=500, detail=str(e))
except ai_client.ProviderError as e:
raise HTTPException(status_code=502, detail=f"AI Provider Error: {e.ui_message()}")
except Exception as e:
raise HTTPException(status_code=500, detail=f"In-flight AI request failure: {e}")
async def _api_stream(controller: 'AppController', req: GenerateRequest) -> Any:
"""
@@ -3673,6 +3665,8 @@ class AppController:
ai_client.set_model_params(self.temperature, self.max_tokens, self.history_trunc_limit, self.top_p)
ai_client.set_agent_tools(self.ui_agent_tools) # Force update adapter path right before send to bypass potential duplication issues
self._update_gcli_adapter(self.ui_gemini_cli_path)
# FR2 / Bug #1: per conductor/code_styleguides/error_handling.md section 3.1 (AND over OR),
# we check result.ok instead of catching a ProviderError exception.
result = ai_client.send_result(
event.stable_md,
user_msg,