fix(workspace): rename supported_protocols → supported_interfaces (a2a-sdk 1.0)

CRITICAL: every workspace boot since the a2a-sdk 1.0 migration (#1974)
has been crashing at AgentCard construction with:
  ValueError: Protocol message AgentCard has no "supported_protocols" field

The protobuf field is `supported_interfaces` (plural, interfaces — see
a2a-sdk types/a2a_pb2.pyi:189). The 0.3→1.0 migration left the kwarg
as `supported_protocols`, which doesn't exist in the 1.0 schema, so
the constructor raises before any subsequent line of main runs.

Why this hid for so long:
  - publish-runtime.yml's smoke step only IMPORTED molecule_runtime.main;
    importing the module is fine, only CONSTRUCTING the AgentCard fails
  - The user-visible symptom is "Workspace failed: " with empty
    last_sample_error, indistinguishable from generic boot timeouts
  - The state_transition_history=True bug (fixed in #2179) was a
    sibling of this — same migration, same class, just caught first

Fix is symmetric with #2179:
  1. workspace/main.py: rename the kwarg + comment explaining why
  2. .github/workflows/publish-runtime.yml: extend the smoke block to
     instantiate AgentCard with the exact production call shape, so
     the next field-rename of this class fails at publish time
     instead of breaking every workspace startup

Verification:
  - Constructed AgentCard against fresh a2a-sdk 1.0.2 in a clean
    venv with the corrected kwarg → succeeds
  - Constructed it with the original `supported_protocols` kwarg →
    fails immediately with the exact error production sees
  - Smoke test pinned to mirror main.py's exact call shape; main.py
    + smoke must stay in lockstep going forward

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hongming Wang 2026-04-27 07:54:23 -07:00
parent 2f5ea7a537
commit 851fd21fb1
2 changed files with 56 additions and 2 deletions

View File

@ -158,6 +158,50 @@ jobs:
assert callable(get_adapter), 'adapters.get_adapter must be callable'
assert hasattr(BaseAdapter, 'name'), 'BaseAdapter interface broken'
assert hasattr(AdapterConfig, '__init__'), 'AdapterConfig dataclass missing'
# Call-shape smoke for AgentCard. Pure imports don't catch
# field-shape regressions in upstream SDKs that only surface
# at construction time. Two bugs of this exact class shipped
# since the a2a-sdk 1.0 migration:
# - state_transition_history=True (fixed in #2179)
# - supported_protocols=[...] (the protobuf field is
# supported_interfaces — caused every workspace boot
# to crash with `ValueError: Protocol message AgentCard
# has no "supported_protocols" field`; fixed alongside
# this smoke)
#
# This block instantiates the EXACT classes main.py uses,
# with the EXACT keyword arguments. If a future a2a-sdk
# upgrade renames any of supported_interfaces / streaming /
# push_notifications / etc., the publish fails here instead
# of breaking every workspace startup. main.py and this
# smoke MUST stay in lockstep — adding a kwarg to one
# without mirroring it here is the regression vector.
from a2a.types import AgentCard, AgentCapabilities, AgentSkill, AgentInterface
AgentCard(
name='smoke-agent',
description='publish-runtime smoke test',
version='0.0.0-smoke',
supported_interfaces=[
AgentInterface(protocol_binding='https://a2a.g/v1', url='http://localhost:8080'),
],
capabilities=AgentCapabilities(
streaming=True,
push_notifications=False,
),
skills=[
AgentSkill(
id='smoke-skill',
name='Smoke',
description='no-op',
tags=['smoke'],
examples=['noop'],
),
],
default_input_modes=['text/plain', 'application/json'],
default_output_modes=['text/plain', 'application/json'],
)
print('✓ AgentCard call-shape smoke passed')
print('✓ smoke import passed')
"

View File

@ -175,14 +175,24 @@ async def main(): # pragma: no cover
machine_ip = os.environ.get("HOSTNAME", get_machine_ip())
workspace_url = f"http://{machine_ip}:{port}"
# v1: AgentCard.url removed; put url+protocol in supported_protocols instead.
# v1: AgentCard.url removed; put url+protocol in supported_interfaces instead.
# v1: AgentCapabilities.inputModes/outputModes removed; move to AgentCard.default_*.
# v1: pushNotifications → push_notifications (Pydantic field name)
#
# AgentCard's protocol message uses `supported_interfaces` (plural,
# interfaces — see a2a-sdk types/a2a_pb2.pyi:189). The 0.3.x→1.0
# migration in #1974 originally used `supported_protocols`, which
# the protobuf doesn't expose at all — every workspace boot since
# then crashed with `ValueError: Protocol message AgentCard has no
# "supported_protocols" field`. The crash didn't surface in the
# publish-runtime smoke because the smoke only IMPORTS
# molecule_runtime.main, never CALLS the AgentCard constructor.
# Don't rename back.
agent_card = AgentCard(
name=config.name,
description=config.description or config.name,
version=config.version,
supported_protocols=[
supported_interfaces=[
AgentInterface(protocol_binding="https://a2a.g/v1", url=workspace_url)
],
capabilities=AgentCapabilities(