From 93f066e3acd5decb858a165c224c2462d8e357fe Mon Sep 17 00:00:00 2001 From: rasdani <73563550+rasdani@users.noreply.github.com> Date: Sun, 19 Apr 2026 21:34:39 +0000 Subject: [PATCH 1/2] =?UTF-8?q?fix(get=5Fpath):=20bump=20default=20max=5Fa?= =?UTF-8?q?ttempts=2010=20=E2=86=92=20120=20+=20env-var=20override?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GetPath.__call__ polls the async path-handle with exponential backoff (50ms → 1s cap). The old 10-attempt default gave ~6.5s wall-clock budget, which is not enough on a fresh world: the first distant `move_to` has to wait for Factorio's chunk-generation before A* can even start, and chunk-gen routinely exceeds 6.5s. Empirically: - 24-task gpt-5.4 throughput eval at the 10-attempt default: 12/129 tool messages (~9.3%) raised "Path request timed out after 10 attempts", always on the first distant move_to of each rollout. - 6-task Sonnet-4.5 eval at a 30-attempt client-side patch: 2/229 (~0.9%). - 1-task gpt-4o eval at 60-attempt: 1/40 (~2.5%). Bumping the default to 120 (~115s wall-clock budget). Override with `FLE_GETPATH_MAX_ATTEMPTS=N` when running on slower hardware, or lower it explicitly if failing fast on unreachable targets matters more than tolerating cold chunks. --- fle/env/tools/admin/get_path/client.py | 32 ++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/fle/env/tools/admin/get_path/client.py b/fle/env/tools/admin/get_path/client.py index ecdab149..d983075d 100644 --- a/fle/env/tools/admin/get_path/client.py +++ b/fle/env/tools/admin/get_path/client.py @@ -1,9 +1,17 @@ +import os from time import sleep from typing import List from fle.env.entities import Position from fle.env.tools import Tool +# Default budget: 120 backoff polls (~115s wall-clock) instead of 10 (~6.5s). +# Long-distance move_to on fresh worlds has to wait for Factorio's +# chunk-generation before A* can start; 10 polls is not enough, and +# empirically 30 and 60 still miss occasionally. Override at runtime with +# `FLE_GETPATH_MAX_ATTEMPTS`. +_DEFAULT_MAX_ATTEMPTS = int(os.environ.get("FLE_GETPATH_MAX_ATTEMPTS", "120")) + class GetPath(Tool): def __init__(self, connection, game_state): @@ -11,9 +19,21 @@ def __init__(self, connection, game_state): # self.connection = connection # self.game_state = game_state - def __call__(self, path_handle: int, max_attempts: int = 10) -> List[Position]: - """ - Retrieve a path requested from the game, using backoff polling. + def __call__( + self, + path_handle: int, + max_attempts: int = _DEFAULT_MAX_ATTEMPTS, + ) -> List[Position]: + """Retrieve a path requested from the game, using backoff polling. + + The path is computed asynchronously on the Factorio side; this + method polls `get_path(path_handle)` with exponential backoff + (50ms → 1s cap) for up to ``max_attempts`` rounds before + giving up with a timeout exception. + + The default can also be overridden via the + ``FLE_GETPATH_MAX_ATTEMPTS`` environment variable, which is read + at module import time. """ try: @@ -55,7 +75,11 @@ def __call__(self, path_handle: int, max_attempts: int = 10) -> List[Position]: sleep(wait_time) wait_time = min(wait_time * 2, 1.0) - raise Exception(f"Path request timed out after {max_attempts} attempts") + raise Exception( + f"Path request timed out after {max_attempts} attempts " + "(set FLE_GETPATH_MAX_ATTEMPTS higher if your world is slow " + "to chunk-generate)" + ) except Exception as e: # raise ConnectionError( From ebe81805f50f5be7d55fe9c9b1c5bb2d3bd371f0 Mon Sep 17 00:00:00 2001 From: Kian Kyars Date: Thu, 11 Jun 2026 15:51:49 -0700 Subject: [PATCH 2/2] fix(get_path): validate max attempts env var --- fle/env/tools/admin/get_path/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fle/env/tools/admin/get_path/client.py b/fle/env/tools/admin/get_path/client.py index d983075d..12fe01bb 100644 --- a/fle/env/tools/admin/get_path/client.py +++ b/fle/env/tools/admin/get_path/client.py @@ -10,7 +10,7 @@ # chunk-generation before A* can start; 10 polls is not enough, and # empirically 30 and 60 still miss occasionally. Override at runtime with # `FLE_GETPATH_MAX_ATTEMPTS`. -_DEFAULT_MAX_ATTEMPTS = int(os.environ.get("FLE_GETPATH_MAX_ATTEMPTS", "120")) +_DEFAULT_MAX_ATTEMPTS = int(v) if (v := os.environ.get("FLE_GETPATH_MAX_ATTEMPTS", "120")).isdigit() and int(v) > 0 else 120 class GetPath(Tool):