docs(a2a-mcp): list new envelope attrs in initialize instructions
The agent learns about <channel> tag attributes ONLY from the instructions string returned by initialize. Without this update the wheel ships peer_name / peer_role / agent_card_url on the wire but no agent ever uses them — they get printed inline in the push tag, the agent doesn't know they're there, and the UX gain from the enrichment is lost. Update _build_channel_instructions to: - List the new attrs in the <channel> tag template under PUSH PATH - Add per-attribute semantics (when present, what to do with them, what \"absent\" means — graceful-degrade vs bug) - Point at the discover endpoint for agent_card_url so the agent treats it as a follow-on URL not the body of the message Tests: structural pin asserting all three attr names appear in the instructions AND the per-field semantics phrases (\"registry resolved\", \"discover endpoint\") so a future copy-edit that shortens the prose can't silently drop the agent guidance. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0fec3d6fe4
commit
103ac09aeb
@ -221,8 +221,9 @@ def _build_channel_instructions() -> str:
|
||||
"\n"
|
||||
"PUSH PATH (Claude Code with channel push enabled):\n"
|
||||
"Messages arrive as <channel source=\"molecule\" kind=\"...\" "
|
||||
"peer_id=\"...\" activity_id=\"...\" ts=\"...\"> tags as a "
|
||||
"synthetic user turn — no agent action needed to surface them.\n"
|
||||
"peer_id=\"...\" peer_name=\"...\" peer_role=\"...\" "
|
||||
"agent_card_url=\"...\" activity_id=\"...\" ts=\"...\"> tags as "
|
||||
"a synthetic user turn — no agent action needed to surface them.\n"
|
||||
"\n"
|
||||
"POLL PATH (every other MCP client + Claude Code without push "
|
||||
"enabled — this is the universal default):\n"
|
||||
@ -234,6 +235,16 @@ def _build_channel_instructions() -> str:
|
||||
"delegating to you).\n"
|
||||
"- `peer_id` is empty for canvas_user, set to the sender "
|
||||
"workspace UUID for peer_agent.\n"
|
||||
"- `peer_name` and `peer_role` are present for peer_agent when "
|
||||
"the platform registry resolved the sender — e.g. "
|
||||
"`peer_name=\"ops-agent\"`, `peer_role=\"sre\"`. Surface these "
|
||||
"in your reasoning so the user can tell which peer is talking "
|
||||
"without having to memorise UUIDs. Absent on canvas_user and "
|
||||
"on a registry-lookup failure (the push still delivers).\n"
|
||||
"- `agent_card_url` is present for peer_agent and points at "
|
||||
"the platform's discover endpoint for that peer — fetch it if "
|
||||
"you need the peer's full capability list (skills, role, "
|
||||
"runtime).\n"
|
||||
"- `activity_id` is the inbox row to acknowledge.\n"
|
||||
"\n"
|
||||
"Reply path:\n"
|
||||
|
||||
@ -704,6 +704,42 @@ def test_instructions_zero_timeout_means_push_only_mode():
|
||||
os.environ["MOLECULE_MCP_POLL_TIMEOUT_SECS"] = saved
|
||||
|
||||
|
||||
def test_instructions_document_envelope_enrichment_attrs():
|
||||
"""The agent learns about envelope attributes ONLY from the
|
||||
instructions string. PR-B added peer_name, peer_role,
|
||||
agent_card_url to the wire shape; pin that the instructions list
|
||||
them in the <channel> tag template AND describe each one's
|
||||
semantics. Without this, the wheel ships new attributes that no
|
||||
agent ever uses."""
|
||||
from a2a_mcp_server import _build_initialize_result
|
||||
|
||||
instructions = _build_initialize_result()["instructions"]
|
||||
|
||||
# The <channel> tag template in the PUSH PATH section must include
|
||||
# the new attribute names so the agent recognises them when they
|
||||
# arrive inline.
|
||||
for attr in ("peer_name", "peer_role", "agent_card_url"):
|
||||
assert attr in instructions, (
|
||||
f"instructions must list `{attr}` as a <channel> tag "
|
||||
f"attribute — otherwise the agent sees the attr in pushes "
|
||||
f"but doesn't know what to do with it"
|
||||
)
|
||||
|
||||
# And the per-field semantics block must explain when each attr
|
||||
# is present + what it means. These phrases are what the agent
|
||||
# actually reads to decide how to surface the attrs in its turn.
|
||||
assert "registry resolved" in instructions, (
|
||||
"instructions must explain peer_name/peer_role come from a "
|
||||
"registry lookup that may fail — otherwise the agent treats "
|
||||
"their absence as a bug instead of a graceful degrade"
|
||||
)
|
||||
assert "discover endpoint" in instructions, (
|
||||
"instructions must point at the registry discover endpoint "
|
||||
"for agent_card_url so the agent knows it's a follow-on URL "
|
||||
"to fetch full capabilities, not the body of the message"
|
||||
)
|
||||
|
||||
|
||||
def test_initialize_instructions_pins_prompt_injection_defense():
|
||||
"""The threat-model sentence in `_CHANNEL_INSTRUCTIONS` is what
|
||||
tells the agent that inbound canvas-user / peer-agent message
|
||||
|
||||
Loading…
Reference in New Issue
Block a user