@@ -89,6 +89,8 @@ class LLMBot:
8989 data_collector: Collector for structured run data and statistics.
9090 consecutive_failed_calls: Counter for consecutive failed/error calls.
9191 max_consecutive_failed_calls: Threshold for stopping the run (3 consecutive failed calls).
92+ consecutive_timeout_count: Counter for consecutive LLM timeout errors.
93+ max_consecutive_timeouts: Threshold for stopping due to timeouts (3 consecutive timeouts).
9294 """
9395
9496 def __init__ (self , config : Config , base_url : str , api_key : str , port : int = 12346 ):
@@ -122,6 +124,10 @@ def __init__(self, config: Config, base_url: str, api_key: str, port: int = 1234
122124 self .error_or_failed_calls : int = 0
123125 self .max_error_or_failed_calls : int = 3
124126
127+ # Counter for consecutive timeout errors. Separate from other errors.
128+ self .consecutive_timeout_count : int = 0
129+ self .max_consecutive_timeouts : int = 3
130+
125131 def __enter__ (self ):
126132 self .balatro_client .connect ()
127133 return self
@@ -226,6 +232,9 @@ async def _make_llm_request_with_retries(
226232 request_id = str (time .time_ns () // 1_000_000 )
227233 response = await self .llm_client .chat .completions .create (** request_data )
228234 self .responses .append (response )
235+
236+ # Reset timeout counter on successful request
237+ self .consecutive_timeout_count = 0
229238 if self .config .take_screenshots :
230239 if self .config .use_default_paths :
231240 self .balatro_client .screenshot (None )
@@ -245,7 +254,10 @@ async def _make_llm_request_with_retries(
245254 return response
246255
247256 except APITimeoutError as e :
248- logger .error (e )
257+ self .consecutive_timeout_count += 1
258+ logger .error (
259+ f"LLM request timeout ({ self .consecutive_timeout_count } /{ self .max_consecutive_timeouts } ): { e } "
260+ )
249261 self .data_collector .write_response (
250262 id = str (time .time_ns () // 1_000_000 ),
251263 custom_id = custom_id ,
@@ -255,6 +267,20 @@ async def _make_llm_request_with_retries(
255267 ),
256268 )
257269
270+ # Send get_game_state to keep TCP connection alive
271+ try :
272+ self .balatro_client .send_message ("get_game_state" , {})
273+ logger .info ("Sent get_game_state to keep TCP connection alive" )
274+ except Exception as keepalive_error :
275+ logger .warning (
276+ f"Failed to send keepalive get_game_state: { keepalive_error } "
277+ )
278+
279+ # Check if we've hit the max consecutive timeouts
280+ if self .consecutive_timeout_count >= self .max_consecutive_timeouts :
281+ logger .error ("3 consecutive LLM timeouts - ending run" )
282+ raise LLMBotError ("3 consecutive LLM request timeouts" )
283+
258284 except APIConnectionError as e :
259285 logger .error (e )
260286 self .data_collector .write_response (
0 commit comments