Private
Public Access
refactor(ai_client): extract _send_cli_round_result helper (Phase 10 site 6)
Site L1990: inner _send(r_idx) in _send_gemini_cli had:
try: resp_data = adapter.send(...)
except Exception as e: events.emit('response_received', {'error': str(e)}); raise
This is Re-Raise Pattern 2 (catch + emit event + raise). Per TIER1_REVIEW,
the migration is to Result[T] because the audit does not yet recognize
events.emit as a structured error carrier.
New helper _send_cli_round_result(r_idx, adapter, payload, ...) -> Result[dict]:
- Emits request_start + [CLI] comms before SDK call
- Returns Result(data=resp_data) on SDK success
- On failure: emits response_received error event + returns Result(errors=[ErrorInfo(original=e)])
Inner _send refactored:
send_result = _send_cli_round_result(r_idx, adapter, payload, ...)
if not send_result.ok:
raise cast(Exception, send_result.errors[0].original)
resp_data = send_result.data
This preserves the original re-raise behavior so the outer
_send_gemini_cli try/except still catches and converts to Result.
Audit: ai_client BC 4 -> 3.
This commit is contained in:
+26
-9
@@ -1704,6 +1704,28 @@ def _create_gemini_cache_result(sys_instr: str, tools_decl: Any, file_items: lis
|
|||||||
errors=[ErrorInfo(kind=ErrorKind.INTERNAL, message=f"failed to create gemini cache: {type(e).__name__}: {e}", source="ai_client._create_gemini_cache_result", original=e)],
|
errors=[ErrorInfo(kind=ErrorKind.INTERNAL, message=f"failed to create gemini cache: {type(e).__name__}: {e}", source="ai_client._create_gemini_cache_result", original=e)],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _send_cli_round_result(r_idx: int, adapter: Any, payload: Any, safety_settings: list[Any], sys_instr: str, stream_callback: Optional[Callable[[str], None]]) -> Result[dict[str, Any]]:
|
||||||
|
"""Call the Gemini CLI adapter for one round. Returns Result[resp_data].
|
||||||
|
|
||||||
|
On SDK failure, emits a response_received event with the error info
|
||||||
|
(preserving the original side-effect semantics) and returns
|
||||||
|
Result(errors=[ErrorInfo]). The caller (_send in _send_gemini_cli)
|
||||||
|
re-raises the original exception to preserve the outer catch flow.
|
||||||
|
"""
|
||||||
|
events.emit("request_start", payload={"provider": "gemini_cli", "model": _model, "round": r_idx})
|
||||||
|
if r_idx > 0:
|
||||||
|
_append_comms("OUT", "request", {"message": f"[CLI] [round {r_idx}] [msg {len(payload)}]"})
|
||||||
|
send_payload: Any = json.dumps(payload) if isinstance(payload, list) else payload
|
||||||
|
try:
|
||||||
|
resp_data = adapter.send(cast(str, send_payload), safety_settings=safety_settings, system_instruction=sys_instr, model=_model, stream_callback=stream_callback)
|
||||||
|
return Result(data=resp_data)
|
||||||
|
except Exception as e:
|
||||||
|
events.emit("response_received", payload={"provider": "gemini_cli", "model": _model, "usage": {}, "latency": 0, "round": r_idx, "error": str(e)})
|
||||||
|
return Result(
|
||||||
|
data=None,
|
||||||
|
errors=[ErrorInfo(kind=ErrorKind.INTERNAL, message=str(e), source="ai_client._send_cli_round_result", original=e)],
|
||||||
|
)
|
||||||
|
|
||||||
def _extract_gemini_thoughts(resp: Any) -> str:
|
def _extract_gemini_thoughts(resp: Any) -> str:
|
||||||
"""
|
"""
|
||||||
Extracts concatenated thinking text from a Gemini response object's parts.
|
Extracts concatenated thinking text from a Gemini response object's parts.
|
||||||
@@ -1981,15 +2003,10 @@ def _send_gemini_cli(md_content: str, user_message: str, base_dir: str,
|
|||||||
def _send(r_idx: int) -> NormalizedResponse:
|
def _send(r_idx: int) -> NormalizedResponse:
|
||||||
if adapter is None:
|
if adapter is None:
|
||||||
return NormalizedResponse(text="(adapter unavailable)", tool_calls=[], usage_input_tokens=0, usage_output_tokens=0, usage_cache_read_tokens=0, usage_cache_creation_tokens=0, raw_response=None)
|
return NormalizedResponse(text="(adapter unavailable)", tool_calls=[], usage_input_tokens=0, usage_output_tokens=0, usage_cache_read_tokens=0, usage_cache_creation_tokens=0, raw_response=None)
|
||||||
events.emit("request_start", payload={"provider": "gemini_cli", "model": _model, "round": r_idx})
|
send_result = _send_cli_round_result(r_idx, adapter, payload, safety_settings, sys_instr, stream_callback)
|
||||||
if r_idx > 0:
|
if not send_result.ok:
|
||||||
_append_comms("OUT", "request", {"message": f"[CLI] [round {r_idx}] [msg {len(payload)}]"})
|
raise cast(Exception, send_result.errors[0].original)
|
||||||
send_payload: Any = json.dumps(payload) if isinstance(payload, list) else payload
|
resp_data = send_result.data
|
||||||
try:
|
|
||||||
resp_data = adapter.send(cast(str, send_payload), safety_settings=safety_settings, system_instruction=sys_instr, model=_model, stream_callback=stream_callback)
|
|
||||||
except Exception as e:
|
|
||||||
events.emit("response_received", payload={"provider": "gemini_cli", "model": _model, "usage": {}, "latency": 0, "round": r_idx, "error": str(e)})
|
|
||||||
raise
|
|
||||||
cli_stderr = resp_data.get("stderr", "")
|
cli_stderr = resp_data.get("stderr", "")
|
||||||
if cli_stderr:
|
if cli_stderr:
|
||||||
sys.stderr.write(f"\n--- Gemini CLI stderr ---\n{cli_stderr}\n-------------------------\n")
|
sys.stderr.write(f"\n--- Gemini CLI stderr ---\n{cli_stderr}\n-------------------------\n")
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
"""Phase 10 site 6: _send_cli_round_result helper.
|
||||||
|
|
||||||
|
Site L1990 (in _send_gemini_cli):
|
||||||
|
try: resp_data = adapter.send(...)
|
||||||
|
except Exception as e: events.emit('response_received', {'error': str(e)}); raise
|
||||||
|
|
||||||
|
Re-Raise Pattern 2 (catch + emit + raise). Migration: extract Result helper.
|
||||||
|
The inner _send calls the helper; on error, re-raise original exception
|
||||||
|
(preserving outer _send_gemini_cli catch behavior).
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
sys.path.insert(0, ".")
|
||||||
|
|
||||||
|
|
||||||
|
def test_phase10_site6_send_cli_round_result_exists():
|
||||||
|
import src.ai_client
|
||||||
|
assert hasattr(src.ai_client, "_send_cli_round_result"), \
|
||||||
|
"_send_cli_round_result helper missing"
|
||||||
|
|
||||||
|
|
||||||
|
def test_phase10_site6_send_cli_round_result_returns_result():
|
||||||
|
import src.ai_client
|
||||||
|
import inspect
|
||||||
|
fn = src.ai_client._send_cli_round_result
|
||||||
|
sig = inspect.signature(fn)
|
||||||
|
assert "Result" in str(sig.return_annotation), \
|
||||||
|
f"_send_cli_round_result return must be Result, got {sig.return_annotation}"
|
||||||
Reference in New Issue
Block a user