From 84de5433786453520407e4e94373bbc2dec1ff7b Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Thu, 16 Apr 2026 00:53:18 -0700 Subject: [PATCH] fix(a2a): add missing Authorization header to delegation and message calls (#401) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(a2a): add missing Authorization header to delegation and message calls Three A2A client functions were missing the Bearer token on their HTTP calls after the Phase 30.1 workspace-auth enforcement rollout: 1. send_a2a_message (a2a_client.py): POST to target workspace's /message/send used WorkspaceAuth middleware that fails-closed on missing auth header. Fix: headers=auth_headers() — auth_headers() already imported. 2. tool_delegate_task_async (a2a_tools.py): POST to platform /delegate endpoint requires the caller's workspace bearer token since Phase 30.1. Fix: headers=_auth_headers_for_heartbeat() 3. tool_check_task_status (a2a_tools.py): GET /delegations endpoint, same issue. Fix: headers=_auth_headers_for_heartbeat() tool_list_peers already uses _auth_headers_for_heartbeat() correctly — that's why list_peers works while delegation returns 401/[A2A_ERROR]. Root cause of the multi-session A2A outage. PR #386 (TTL fix) addressed the workspace-restart cascade; this fixes the underlying 401 on each call. Closes #391 Co-Authored-By: Claude Sonnet 4.6 * fix(a2a): add missing auth headers to /activity and /notify endpoints Two more Phase 30.1 regressions in a2a_tools.py found during send_message_to_user debugging (it was returning 401): - tool_report_activity: POST /workspaces/:id/activity missing headers - tool_send_message_to_user: POST /workspaces/:id/notify missing headers Both now use headers=_auth_headers_for_heartbeat() matching the pattern used by commit_memory, recall_memory, and the heartbeat POST in the same file. Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: PM (Molecule AI) Co-authored-by: Claude Sonnet 4.6 --- workspace-template/a2a_client.py | 1 + workspace-template/a2a_tools.py | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/workspace-template/a2a_client.py b/workspace-template/a2a_client.py index 15038bce..0ae6dd28 100644 --- a/workspace-template/a2a_client.py +++ b/workspace-template/a2a_client.py @@ -52,6 +52,7 @@ async def send_a2a_message(target_url: str, message: str) -> str: try: resp = await client.post( target_url, + headers=auth_headers(), json={ "jsonrpc": "2.0", "id": str(uuid.uuid4()), diff --git a/workspace-template/a2a_tools.py b/workspace-template/a2a_tools.py index 5612b61c..6ba37a08 100644 --- a/workspace-template/a2a_tools.py +++ b/workspace-template/a2a_tools.py @@ -52,6 +52,7 @@ async def report_activity( await client.post( f"{PLATFORM_URL}/workspaces/{WORKSPACE_ID}/activity", json=payload, + headers=_auth_headers_for_heartbeat(), ) # Also push current_task via heartbeat for canvas card display if summary: @@ -127,6 +128,7 @@ async def tool_delegate_task_async(workspace_id: str, task: str) -> str: resp = await client.post( f"{PLATFORM_URL}/workspaces/{WORKSPACE_ID}/delegate", json={"target_id": workspace_id, "task": task}, + headers=_auth_headers_for_heartbeat(), ) if resp.status_code == 202: data = resp.json() @@ -151,7 +153,10 @@ async def tool_check_task_status(workspace_id: str, task_id: str) -> str: """ try: async with httpx.AsyncClient(timeout=10.0) as client: - resp = await client.get(f"{PLATFORM_URL}/workspaces/{WORKSPACE_ID}/delegations") + resp = await client.get( + f"{PLATFORM_URL}/workspaces/{WORKSPACE_ID}/delegations", + headers=_auth_headers_for_heartbeat(), + ) if resp.status_code != 200: return f"Error: failed to check delegations ({resp.status_code})" delegations = resp.json() @@ -185,6 +190,7 @@ async def tool_send_message_to_user(message: str) -> str: resp = await client.post( f"{PLATFORM_URL}/workspaces/{WORKSPACE_ID}/notify", json={"message": message}, + headers=_auth_headers_for_heartbeat(), ) if resp.status_code == 200: return "Message sent to user"