diff --git a/tests/test_google_thinking_level.py b/tests/test_google_thinking_level.py index e711c2aab..1bcd51e27 100644 --- a/tests/test_google_thinking_level.py +++ b/tests/test_google_thinking_level.py @@ -60,3 +60,11 @@ def test_no_thinking_level_is_omitted(): kw = _captured_kwargs("gemini-3.5-flash") assert "thinking_level" not in kw assert "thinking_budget" not in kw + + +@pytest.mark.unit +def test_a_gemini_call_times_out_like_the_other_providers(): + """The OpenAI and Anthropic SDKs give up after 600s; Gemini's waits forever + unless told otherwise, so a stalled call would hang the run (#1417).""" + assert _captured_kwargs("gemini-3.5-flash")["timeout"] == 600 + assert _captured_kwargs("gemini-3.5-flash", timeout=30)["timeout"] == 30 diff --git a/tradingagents/llm_clients/google_client.py b/tradingagents/llm_clients/google_client.py index 134baf556..78bd27baa 100644 --- a/tradingagents/llm_clients/google_client.py +++ b/tradingagents/llm_clients/google_client.py @@ -31,6 +31,10 @@ class NormalizedChatGoogleGenerativeAI(ChatGoogleGenerativeAI): return normalize_content(super().invoke(input, config, **kwargs)) +# The read timeout the OpenAI and Anthropic SDKs use by default. +REQUEST_TIMEOUT_SECONDS = 600 + + class GoogleClient(BaseLLMClient): """Client for Google Gemini models.""" @@ -49,6 +53,9 @@ class GoogleClient(BaseLLMClient): "callbacks", "http_client", "http_async_client"): if key in self.kwargs: llm_kwargs[key] = self.kwargs[key] + # Without a timeout a stalled Gemini call waits forever; the OpenAI and + # Anthropic SDKs give up after the same 600 seconds (#1417). + llm_kwargs.setdefault("timeout", REQUEST_TIMEOUT_SECONDS) # Unified api_key maps to provider-specific google_api_key google_api_key = self.kwargs.get("api_key") or self.kwargs.get("google_api_key")