diff --git a/backend/src/agent/_llm_health.py b/backend/src/agent/_llm_health.py index 4b285c3a..fd5dc94a 100644 --- a/backend/src/agent/_llm_health.py +++ b/backend/src/agent/_llm_health.py @@ -17,11 +17,7 @@ import time from typing import Any import httpx -from langchain_core.messages import HumanMessage -from langchain_openai import ChatOpenAI -from openai import APIConnectionError, APITimeoutError, AuthenticationError, RateLimitError -from src.agent._llm_params import chat_openai_kwargs from src.core.logger import logger # ── LLM provider health cache ───────────────────────────────────────── @@ -41,12 +37,35 @@ _LLM_LAST_ERROR_TS_KEY = "last_llm_error_ts" # @POST Returns status string: 'ok' | 'unavailable' | 'timeout' | 'auth_error'. # @SIDE_EFFECT Makes a probe request to the LLM provider; caches result in module memory. # @RATIONALE Prevents sending every user request into a dead LLM backend. +# @REJECTED Module-level imports of langchain_core/openai were rejected — these +# packages are only installed in the agent container, not the backend container. +# The /api/agent/llm-status endpoint runs in the backend container and must not +# fail with ModuleNotFoundError. All langchain/openai imports are lazy (inside +# the function body) with ImportError handled gracefully. async def _check_llm_provider_health() -> str: """Check LLM provider connectivity. Cached for _LLM_CHECK_CACHE_TTL seconds.""" now = time.time() if now - _llm_status["last_check_ts"] < _LLM_CHECK_CACHE_TTL: return _llm_status["status"] + # Lazy imports: langchain_core, langchain_openai, and openai are only + # installed in the agent container, not the backend container. + try: + from langchain_core.messages import HumanMessage + from langchain_openai import ChatOpenAI + from openai import ( + APIConnectionError, + APITimeoutError, + AuthenticationError, + RateLimitError, + ) + from src.agent._llm_params import chat_openai_kwargs + except ImportError as exc: + _llm_status["status"] = "unavailable" + _llm_status["last_error"] = f"LLM dependencies not installed: {exc}" + _llm_status["last_check_ts"] = time.time() + return "unavailable" + try: from src.agent.langgraph_setup import _fetch_llm_config as _get_config