From c4dcfbb0898b3186a7b2dd92d41026a8341f9b9d Mon Sep 17 00:00:00 2001 From: Molecule AI Infra-Runtime-BE Date: Mon, 11 May 2026 15:17:53 +0000 Subject: [PATCH] fix(workspace): default PLATFORM_URL to host.docker.internal in all modules (#475) Co-authored-by: Molecule AI Infra-Runtime-BE Co-committed-by: Molecule AI Infra-Runtime-BE --- workspace/a2a_cli.py | 8 ++++---- workspace/a2a_client.py | 8 ++++---- workspace/builtin_tools/temporal_workflow.py | 20 ++++++++++++++++---- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/workspace/a2a_cli.py b/workspace/a2a_cli.py index 5ba7381c..ef045bdf 100644 --- a/workspace/a2a_cli.py +++ b/workspace/a2a_cli.py @@ -25,10 +25,10 @@ _WORKSPACE_ID_raw = os.environ.get("WORKSPACE_ID") if not _WORKSPACE_ID_raw: raise RuntimeError("WORKSPACE_ID environment variable is required but not set") WORKSPACE_ID = _WORKSPACE_ID_raw -if os.path.exists("/.dockerenv") or os.environ.get("DOCKER_VERSION"): - PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080") -else: - PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://localhost:8080") +# Platform URL: always host.docker.internal inside containers. The platform API +# is only reachable via the Docker network mesh from inside a workspace +# container regardless of the runtime environment (Docker/host). +PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080") async def discover(target_id: str) -> dict | None: diff --git a/workspace/a2a_client.py b/workspace/a2a_client.py index 8e499f40..a17572bb 100644 --- a/workspace/a2a_client.py +++ b/workspace/a2a_client.py @@ -26,10 +26,10 @@ _WORKSPACE_ID_raw = os.environ.get("WORKSPACE_ID") if not _WORKSPACE_ID_raw: raise RuntimeError("WORKSPACE_ID environment variable is required but not set") WORKSPACE_ID = _WORKSPACE_ID_raw -if os.path.exists("/.dockerenv") or os.environ.get("DOCKER_VERSION"): - PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080") -else: - PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://localhost:8080") +# Platform URL: always host.docker.internal inside containers. The platform API +# is only reachable via the Docker network mesh from inside a workspace +# container regardless of the runtime environment (Docker/host). +PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080") # Cache workspace ID → name mappings (populated by list_peers calls) _peer_names: dict[str, str] = {} diff --git a/workspace/builtin_tools/temporal_workflow.py b/workspace/builtin_tools/temporal_workflow.py index 8f8e6f41..4552b578 100644 --- a/workspace/builtin_tools/temporal_workflow.py +++ b/workspace/builtin_tools/temporal_workflow.py @@ -54,6 +54,18 @@ import httpx logger = logging.getLogger(__name__) + +def _platform_url() -> str: + """Return the platform URL, defaulting to host.docker.internal. + + The workspace runtime always runs inside a Docker container, so + ``localhost`` refers to the container itself, not the platform host. + The platform API is only reachable via ``host.docker.internal`` from + within a workspace container, regardless of how the container was started. + """ + return os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080") + + # ───────────────────────────────────────────────────────────────────────────── # Constants # ───────────────────────────────────────────────────────────────────────────── @@ -79,12 +91,12 @@ async def _fetch_latest_checkpoint(workspace_id: str) -> Optional[dict]: workspace_id: The workspace to query. Reads: - PLATFORM_URL Platform base URL (default ``http://localhost:8080``). + PLATFORM_URL Platform base URL (default ``http://host.docker.internal:8080``). """ try: from platform_auth import auth_headers as _auth_headers # type: ignore[import] - platform_url = os.environ.get("PLATFORM_URL", "http://localhost:8080") + platform_url = _platform_url() url = f"{platform_url}/workspaces/{workspace_id}/checkpoints/latest" async with httpx.AsyncClient(timeout=5.0) as client: resp = await client.get(url, headers=_auth_headers()) @@ -125,12 +137,12 @@ async def _save_checkpoint( payload: Optional JSON-serialisable dict stored as JSONB. Reads: - PLATFORM_URL Platform base URL (default ``http://localhost:8080``). + PLATFORM_URL Platform base URL (default ``http://host.docker.internal:8080``). """ try: from platform_auth import auth_headers as _auth_headers # type: ignore[import] - platform_url = os.environ.get("PLATFORM_URL", "http://localhost:8080") + platform_url = _platform_url() url = f"{platform_url}/workspaces/{workspace_id}/checkpoints" body: dict = { "workflow_id": workflow_id,