From 1b0fab674b3d806b7a1f7600ad04f92bcf8b44ea Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Mon, 27 Apr 2026 17:34:12 -0700 Subject: [PATCH] ci(publish-runtime): smoke well-known mount alignment + message helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing wheel-smoke catches AgentCard kwarg-shape regressions (state_transition_history, supported_protocols) but doesn't catch the SDK-contract drift class that #2193 just fixed in production: the a2a-sdk 1.x rename of /.well-known/agent.json → /.well-known/agent-card.json, plus AGENT_CARD_WELL_KNOWN_PATH moving to a2a.utils.constants. main.py's readiness probe hardcoded the old literal and 404'd every attempt, silently dropping every workspace's initial_prompt for ~weeks before a user reported it. Two additions to the smoke block: 1. Mount alignment: build an AgentCard, call create_agent_card_routes(), and assert AGENT_CARD_WELL_KNOWN_PATH is among the mounted paths. Catches a future SDK release that decouples the constant value from the route factory's mount path. The source-tree test (workspace/tests/test_agent_card_well_known_path.py) catches the main.py side; this catches the SDK side BEFORE PyPI upload. 2. Message helper smoke: import a2a.helpers.new_text_message and instantiate one. The v0→v1 cheat sheet (memory: reference_a2a_sdk_v0_to_v1_migration.md) flagged this as a real migration find — main.py and a2a_executor.py call it in hot paths, so an import break errors every reply before the message even leaves the workspace. Verified by running the equivalent Python inside ghcr.io/molecule-ai/workspace-template-langgraph:latest: ✓ well-known mount alignment OK (/.well-known/agent-card.json) ✓ message helper import + call OK Closes the structural-fix half of the #2193 finding from the code- review-and-quality pass: "the wheel publish smoke didn't catch this. This is the 7th a2a-sdk migration find of this kind. Task #131 is the right root-cause fix." Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/publish-runtime.yml | 50 +++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/.github/workflows/publish-runtime.yml b/.github/workflows/publish-runtime.yml index e1fd659d..226c0279 100644 --- a/.github/workflows/publish-runtime.yml +++ b/.github/workflows/publish-runtime.yml @@ -212,6 +212,56 @@ jobs: default_output_modes=['text/plain', 'application/json'], ) print('✓ AgentCard call-shape smoke passed') + + # Well-known agent-card path probe alignment. main.py's + # _send_initial_prompt() polls AGENT_CARD_WELL_KNOWN_PATH + # to know when the local A2A server is ready. If the SDK + # ever splits the constant value from the path that + # create_agent_card_routes() actually mounts at, every + # workspace silently drops its initial_prompt: + # - Probe gets 404 every attempt. + # - Falls through to 'server not ready after 30s, + # skipping' even though the server is fine. + # - The user hits a fresh chat with no kickoff context. + # This was the #2193 incident class — the v0.x → v1.x + # rename of /.well-known/agent.json → /.well-known/agent-card.json + # plus the constant itself moving to a2a.utils.constants. + # source-tree pytest (test_agent_card_well_known_path.py) + # catches main.py-side regressions; this catches the + # SDK-side ones BEFORE PyPI upload. + from a2a.utils.constants import AGENT_CARD_WELL_KNOWN_PATH + from a2a.server.routes import create_agent_card_routes + mounted_paths = [ + getattr(r, 'path', None) + for r in create_agent_card_routes( + AgentCard( + name='wk-smoke', + description='well-known mount alignment', + version='0.0.0-smoke', + ) + ) + ] + assert AGENT_CARD_WELL_KNOWN_PATH in mounted_paths, ( + f'AGENT_CARD_WELL_KNOWN_PATH ({AGENT_CARD_WELL_KNOWN_PATH!r}) ' + f'is NOT among paths mounted by create_agent_card_routes ' + f'({mounted_paths!r}). The SDK constant and its own route ' + f'factory have drifted — workspace probes will 404 forever, ' + f'silently dropping every workspace initial_prompt.' + ) + print(f'✓ well-known mount alignment OK ({AGENT_CARD_WELL_KNOWN_PATH})') + + # Message helper smoke. a2a-sdk renamed + # new_agent_text_message → new_text_message in the v1.x + # protobuf-flat migration (per the v0→v1 cheat sheet). main.py + # and a2a_executor.py call new_text_message in hot paths; if + # the import breaks, every reply errors with ImportError before + # the message even leaves the workspace. Importing here + # catches a future v2.x rename at publish time. + from a2a.helpers import new_text_message + msg = new_text_message('smoke') + assert msg is not None, 'new_text_message returned None' + print('✓ message helper import + call OK') + print('✓ smoke import passed') "