Private
Public Access
refactor(ai_client): obliterate 5 legacy model-list wrappers (Phase 4)
Phase 4 (5 of 9 cruft sites obliterated): OBLITERATED wrappers: 1. _reread_file_items (4 callers in _send_gemini + _send_gemini_cli + 2 others) 2. _list_anthropic_models (1 caller in list_models) 3. _list_gemini_models (1 caller in list_models) 4. _extract_gemini_thoughts (1 caller in _send_gemini) 5. _list_minimax_models (2 callers in _set_minimax_provider_result + set_provider) Migration: each caller now uses the _result sibling directly with .ok check + .data extraction. The Result[T] error context (structured ErrorInfo) is now propagated instead of dropped. _send_gemini gets .data with explicit .ok check. Updated tests to assert OBLITERATED state (5 sub-track 5 tests inverted from '_legacy_preserved' to '_legacy_obliterated'): - tests/test_baseline_result.py: test_phase9_redo_modules_import_cleanly - tests/tier2/phase10_invariant_test.py: _list_gemini_models removed from list - tests/tier2/phase10_site1_test.py: _legacy_unchanged -> _legacy_obliterated - tests/tier2/phase11_invariant_test.py: _extract/_list_minimax moved to obliterated - tests/tier2/phase11_sites78_test.py: _legacy_preserved -> _legacy_obliterated - tests/tier2/phase12_invariant_test.py: _list_anthropic moved to obliterated - tests/tier2/phase12_site4_test.py: _legacy_preserved -> _legacy_obliterated - tests/test_gemini_thinking_format.py: helper uses _result directly - tests/test_cruft_removal.py: 5 new obliterated-wrappers invariant tests Test result: 122/122 pass (31 baseline + 16 heuristic + 9 cruft + 5 thinking + 61 tier2). Audit gate: src/ai_client.py --strict exits 0 (no new violations introduced). Wrapper count: 9 -> 3 (Phase 5-6 remaining: rag_engine 1, gui_2 2).
This commit is contained in:
@@ -9,10 +9,18 @@ ThinkingSegment.
|
||||
from unittest.mock import MagicMock, patch
|
||||
from google.genai.types import Part, Content, Candidate, GenerateContentResponse
|
||||
|
||||
from src.ai_client import _extract_gemini_thoughts
|
||||
from src.ai_client import _extract_gemini_thoughts_result
|
||||
from src.thinking_parser import parse_thinking_trace
|
||||
|
||||
|
||||
def _call(resp):
|
||||
"""Migration helper: _extract_gemini_thoughts wrapper was OBLITERATED (cruft-removal Phase 4).
|
||||
Call _extract_gemini_thoughts_result(...).data directly; on failure return empty string.
|
||||
"""
|
||||
result = _extract_gemini_thoughts_result(resp)
|
||||
return result.data if result.ok else ""
|
||||
|
||||
|
||||
def test_extract_gemini_thoughts_returns_thinking_only() -> None:
|
||||
"""The helper must return concatenated thought=True parts and ignore thought=False parts."""
|
||||
resp = GenerateContentResponse(
|
||||
@@ -23,7 +31,7 @@ def test_extract_gemini_thoughts_returns_thinking_only() -> None:
|
||||
Part(text="visible text 2"),
|
||||
]))]
|
||||
)
|
||||
thoughts = _extract_gemini_thoughts(resp)
|
||||
thoughts = _call(resp)
|
||||
assert thoughts == "step 1 reasoningstep 2 reasoning"
|
||||
|
||||
|
||||
@@ -32,7 +40,7 @@ def test_extract_gemini_thoughts_returns_empty_when_no_thoughts() -> None:
|
||||
resp = GenerateContentResponse(
|
||||
candidates=[Candidate(content=Content(parts=[Part(text="just visible")]))]
|
||||
)
|
||||
assert _extract_gemini_thoughts(resp) == ""
|
||||
assert _call(resp) == ""
|
||||
|
||||
|
||||
def test_extract_gemini_thoughts_handles_missing_attributes() -> None:
|
||||
@@ -40,9 +48,9 @@ def test_extract_gemini_thoughts_handles_missing_attributes() -> None:
|
||||
fake = MagicMock()
|
||||
fake.candidates = [MagicMock()]
|
||||
fake.candidates[0].content.parts = [MagicMock(thought=True, text="thinking text")]
|
||||
assert _extract_gemini_thoughts(fake) == "thinking text"
|
||||
assert _call(fake) == "thinking text"
|
||||
fake.candidates = []
|
||||
assert _extract_gemini_thoughts(fake) == ""
|
||||
assert _call(fake) == ""
|
||||
|
||||
|
||||
def test_gemini_thinking_segment_extractable_after_wrap() -> None:
|
||||
@@ -53,7 +61,7 @@ def test_gemini_thinking_segment_extractable_after_wrap() -> None:
|
||||
Part(text="final answer"),
|
||||
]))]
|
||||
)
|
||||
thoughts = _extract_gemini_thoughts(resp)
|
||||
thoughts = _call(resp)
|
||||
wrapped = f"<thinking>\n{thoughts}\n</thinking>\n\nfinal answer"
|
||||
segments, response = parse_thinking_trace(wrapped)
|
||||
assert len(segments) == 1
|
||||
@@ -64,7 +72,7 @@ def test_gemini_thinking_segment_extractable_after_wrap() -> None:
|
||||
|
||||
def test_extract_gemini_thoughts_handles_none_resp() -> None:
|
||||
"""Defensive: must not crash on None response."""
|
||||
assert _extract_gemini_thoughts(None) == ""
|
||||
assert _call(None) == ""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user