Private
Public Access
0
0

fix(ai_client): move openai_compatible imports to local scope; fix startup_speedup invariant

The follow-up track's tool-loop refactor moved
'from src.openai_compatible import send_openai_compatible,
 OpenAICompatibleRequest, NormalizedResponse' to MODULE level
in src/ai_client.py. This violates the startup_speedup_20260606
invariant: heavy SDKs must not be loaded at module level because
ai_client.py is on the main thread's import chain.

src/openai_compatible.py line 5 does 'from openai import
OpenAIError, ...', so any import from it triggers the openai SDK
to load. test_ai_client_does_not_import_openai_at_module_level
guards this invariant and was failing.

Fix: move the imports back to local scope inside the function
bodies that need them:
- _default_send closure inside run_with_tool_loop
  (imports send_openai_compatible)
- _send_grok (imports OpenAICompatibleRequest)
- _send_minimax (imports OpenAICompatibleRequest)
- _send_llama (imports OpenAICompatibleRequest)
- _send_gemini_cli (imports OpenAICompatibleRequest + NormalizedResponse)

Test patches: tests that previously patched
'src.ai_client.send_openai_compatible' now patch
'src.openai_compatible.send_openai_compatible' (the actual
import source). _execute_tool_calls_concurrently patches
unchanged (it's defined in src/ai_client.py itself).

Green confirmed: 62 vendor + tool + import-isolation tests
pass. 0 regressions.
This commit is contained in:
2026-06-11 16:15:49 -04:00
parent 4748d13490
commit 9ddfa98133
3 changed files with 22 additions and 16 deletions
+16 -10
View File
@@ -42,7 +42,6 @@ from src import mcp_client
from src import mma_prompts
from src import performance_monitor
from src import project_manager
from src.openai_compatible import send_openai_compatible, OpenAICompatibleRequest, NormalizedResponse
from src.vendor_capabilities import VendorCapabilities, get_capabilities
# TODO(Ed): Eliminate these?
@@ -822,8 +821,9 @@ def run_with_tool_loop(
on_pre_dispatch: Optional[Callable[[int, list[dict[str, Any]]], list[dict[str, Any]]]] = None,
) -> str:
def _default_send(_round_idx: int) -> NormalizedResponse:
from src.openai_compatible import send_openai_compatible as _send_oc
assert capabilities is not None, "capabilities required when send_func is not provided"
return send_openai_compatible(client, request_builder(_round_idx), capabilities=capabilities)
return _send_oc(client, request_builder(_round_idx), capabilities=capabilities)
request_builder: Callable[[int], OpenAICompatibleRequest] = (request if callable(request) else (lambda _i: request))
dispatch_send: Callable[[int], NormalizedResponse] = send_func or _default_send
response_text: str = ""
@@ -1760,8 +1760,10 @@ def _send_gemini_cli(md_content: str, user_message: str, base_dir: str,
qa_callback: Optional[Callable[[str], str]] = None,
stream_callback: Optional[Callable[[str], None]] = None,
patch_callback: Optional[Callable[[str, str], Optional[str]]] = None) -> str:
from src.openai_compatible import OpenAICompatibleRequest, NormalizedResponse
"""
[C: src/ai_server.py:_handle_send]
[C: src/ai_server.py:_handle_send]
"""
global _gemini_cli_adapter
try:
@@ -2248,6 +2250,8 @@ def _send_grok(md_content: str, user_message: str, base_dir: str,
qa_callback: Optional[Callable[[str], str]] = None,
stream_callback: Optional[Callable[[str], None]] = None,
patch_callback: Optional[Callable[[str, str], Optional[str]]] = None) -> str:
from src.openai_compatible import OpenAICompatibleRequest
client = _ensure_grok_client()
client = _ensure_grok_client()
tools: list[dict[str, Any]] | None = _get_deepseek_tools() or None
with _grok_history_lock:
@@ -2260,6 +2264,7 @@ def _send_grok(md_content: str, user_message: str, base_dir: str,
_grok_history.append({"role": "user", "content": f"[DISCUSSION HISTORY]\n\n{discussion_history}\n\n---\n\n{user_message}"})
else:
_grok_history.append({"role": "user", "content": user_content})
_grok_history.append({"role": "user", "content": user_content})
def _build_grok_request(_round_idx: int) -> OpenAICompatibleRequest:
with _grok_history_lock:
messages: list[dict[str, Any]] = [{"role": "system", "content": f"{_get_combined_system_prompt()}\n\n<context>\n{md_content}\n</context>"}]
@@ -2287,16 +2292,14 @@ def _send_minimax(md_content: str, user_message: str, base_dir: str,
stream: bool = False,
pre_tool_callback: Optional[Callable[[str, str, Optional[Callable[[str], str]]], Optional[str]]] = None,
qa_callback: Optional[Callable[[str], str]] = None,
stream_callback: Optional[Callable[[str], None]] = None,
patch_callback: Optional[Callable[[str, str], Optional[str]]] = None) -> str:
from src.openai_compatible import OpenAICompatibleRequest
_ensure_minimax_client()
tools: list[dict[str, Any]] | None = _get_deepseek_tools() or None
with _minimax_history_lock:
_repair_minimax_history(_minimax_history)
if discussion_history and not _minimax_history:
_minimax_history.append({"role": "user", "content": f"[DISCUSSION HISTORY]\n\n{discussion_history}\n\n---\n\n{user_message}"})
else:
_minimax_history.append({"role": "user", "content": user_message})
_repair_minimax_history(_minimax_history)
if discussion_history and not _minimax_history:
_minimax_history.append({"role": "user", "content": f"[DISCUSSION HISTORY]\n\n{discussion_history}\n\n---\n\n{user_message}"})
else:
_minimax_history.append({"role": "user", "content": user_message})
def _build_minimax_request(_round_idx: int) -> OpenAICompatibleRequest:
with _minimax_history_lock:
messages: list[dict[str, Any]] = [{"role": "system", "content": f"{_get_combined_system_prompt()}\n\n<context>\n{md_content}\n</context>"}]
@@ -2454,6 +2457,7 @@ def _send_llama(md_content: str, user_message: str, base_dir: str,
qa_callback: Optional[Callable[[str], str]] = None,
stream_callback: Optional[Callable[[str], None]] = None,
patch_callback: Optional[Callable[[str, str], Optional[str]]] = None) -> str:
from src.openai_compatible import OpenAICompatibleRequest
client = _ensure_llama_client()
tools: list[dict[str, Any]] | None = _get_deepseek_tools() or None
with _llama_history_lock:
@@ -2466,6 +2470,8 @@ def _send_llama(md_content: str, user_message: str, base_dir: str,
_llama_history.append({"role": "user", "content": f"[DISCUSSION HISTORY]\n\n{discussion_history}\n\n---\n\n{user_message}"})
else:
_llama_history.append({"role": "user", "content": user_content})
def _build_llama_request(_round_idx: int) -> OpenAICompatibleRequest:
_llama_history.append({"role": "user", "content": user_content})
def _build_llama_request(_round_idx: int) -> OpenAICompatibleRequest:
with _llama_history_lock:
messages: list[dict[str, Any]] = [{"role": "system", "content": f"{_get_combined_system_prompt()}\n\n<context>\n{md_content}\n</context>"}]