Skip to content

fix(workspace-runtime): route delegate_task through platform A2A proxy - #2418

Merged
HongmingWang-Rabbit merged 1 commit into
stagingfrom
fix/external-delegate-via-platform-proxy
May 1, 2026
Merged

HongmingWang-Rabbit merged 1 commit into
stagingfrom
fix/external-delegate-via-platform-proxy

Conversation

@HongmingWang-Rabbit

Copy link
Copy Markdown
Contributor

Summary

tool_delegate_task was POSTing directly to peer[\"url\"], which for in-container peers is a Docker-internal hostname (http://ws-X-Y:8000). External callers — the standalone molecule-mcp wrapper — fail every delegation with [Errno 8] nodename nor servname provided because that hostname only resolves inside the platform's container DNS.

The platform's /workspaces/:peer-id/a2a proxy endpoint already handles internal forwarding for in-container peers AND is the only path external runtimes can use. This PR unifies on it.

Diff is 4 lines of substance

- target_url = peer.get(\"url\", \"\")
- if not target_url:
-     return f\"Error: workspace {workspace_id} has no URL (may be offline)\"
+ if (peer.get(\"status\") or \"\").lower() == \"offline\":
+     return f\"Error: workspace {workspace_id} is offline\"
+ target_url = f\"{PLATFORM_URL}/workspaces/{workspace_id}/a2a\"

discover_peer is still called for access-control + online-status — only the routing target changes.

Live verification

Against staging tenant hongmingwang.moleculesai.app:

Path Caller Target Result
Direct (old) mac (8dad3e29, external) http://ws-97ac32e9-b7a:8000 ❌ ConnectError: nodename not known
Proxy (new) mac (8dad3e29, external) ${PLATFORM_URL}/workspaces/97ac32e9.../a2a ✅ "acknowledged from claude code agent"

In-container delegation continues to work — the proxy forwards over the same Docker bridge that direct routing already used; the cost is one HTTP hop on a private network (microseconds).

Test plan

  • pytest tests/test_a2a_tools_impl.py — replaced test_peer_has_no_url_returns_error (obsolete) with test_offline_peer_returns_error + new test_routes_through_platform_proxy_not_peer_url that asserts the URL shape
  • 203 tests pass across a2a_tools / a2a_client / inbox / mcp / platform_tools
  • Live test against external runtime → in-container peer (above)
  • Wait for CI green + auto-merge to staging
  • Verify wheel auto-publishes (publish-runtime.yml triggers on workspace/** — touched)
  • Confirm 0.1.50 (or next) wheel with the fix lands on PyPI

Why this matters

This closes the last gap in the universal-MCP claim. With #2412 (token-on-restart), #2413 (standalone register+heartbeat), #2415 (inbox polling), and now this fix, an external operator can run `molecule-mcp` on a laptop and get full bidirectional A2A — including delegating to in-container peers — with no tunnel + no Python-SDK dependency.

🤖 Generated with Claude Code

tool_delegate_task was POSTing directly to peer["url"], which is
the Docker-internal hostname (e.g. http://ws-X-Y:8000) for in-
container peers. External callers — the standalone molecule-mcp
wrapper running on an operator's laptop — get [Errno 8] nodename
nor servname every single delegation, breaking the universal-MCP
path's last "ride the same code as in-container" claim.

The platform's /workspaces/:peer-id/a2a proxy endpoint already
handles internal forwarding for in-container peers AND is the only
path external runtimes can use. Unify on it: in-container callers
pay one extra HTTP hop on the same Docker bridge (microseconds);
external callers get a working delegation path for the first time.

discover_peer is still called for access-control + online-status
detection — only the routing target changes. Verified live on
2026-04-30 against workspace 8dad3e29 (external mac runtime) →
97ac32e9 (Claude Code Agent in-container): direct POST returned
ConnectError, proxy POST returned "acknowledged from claude code
agent" as requested.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@HongmingWang-Rabbit
HongmingWang-Rabbit added this pull request to the merge queue May 1, 2026
Merged via the queue into staging with commit 665582b May 1, 2026
19 checks passed
@HongmingWang-Rabbit
HongmingWang-Rabbit deleted the fix/external-delegate-via-platform-proxy branch May 1, 2026 00:20
HongmingWang-Rabbit pushed a commit that referenced this pull request May 1, 2026
…s UUID

Two cleanups stacked on PR #2418:

1. Refactor `send_a2a_message(target_url, msg)` →
   `send_a2a_message(peer_id, msg)`. After #2418 every caller passes
   `${PLATFORM_URL}/workspaces/{peer_id}/a2a` — the function's
   parameter pretended to accept arbitrary URLs but in practice only
   one shape is meaningful. Owning URL construction inside the
   function makes the contract honest and centralises the peer-id
   validation introduced below.

2. Add `_validate_peer_id` UUID-shape check at the trust boundary.
   `discover_peer` and `send_a2a_message` are the entry points where
   agent-controlled strings flow into URL paths; rejecting non-UUID
   input at this layer eliminates the URL-interpolation class of
   bug (`workspace_id="../admin"` etc.) regardless of how the rest
   of the codebase interpolates ids elsewhere. Auth was already
   gating malicious access — this is consistency + clear failure
   over silent platform 4xx.

In-container tests cover positive UUIDs, malformed input
(``"ws-abc"``, ``"../admin"``, empty), and the contract that
``tool_delegate_task`` hands the peer_id to ``send_a2a_message``
without building URLs itself.

Live-verified: external delegation 8dad3e29 → 97ac32e9 returned
"refactor verified" from Claude Code Agent through the refactored
code; ``_validate_peer_id`` rejects ``"ws-abc"`` and ``"../admin"``
and accepts canonical UUIDs.

Stacked on PR #2418 (proxy-routing fix). Will rebase onto staging
once #2418 merges.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
HongmingWang-Rabbit pushed a commit that referenced this pull request Jun 12, 2026
…sed (#2418 CR)

Removes the gate-weakening #1974 change that made body-section presence
informational only. The SOP checklist gate must remain fail-closed:
missing body sections → failure even when peer acks are present.

Fixes #2418
HongmingWang-Rabbit pushed a commit that referenced this pull request Jun 12, 2026
…D in promote-tenant-image (#676)' (#2418) from fix/676-promote-tenant-image-region-exit64 into main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant