A2A agent mesh: agent card (discovery) + A2A client bridge#82
Merged
Conversation
agents-api's WP_Agent_Message::toolCall() builds envelopes with role='assistant' and content='Calling <tool_name>'. That makes sense for inspector/debug surfaces, but for a chat channel the content is internal-infrastructure leakage. A Mantia user hit this on 2026-05-26 — a real WhatsApp bubble read literally "Calling mantia__register-prediction" because the LLM turn finished on a tool_call without a subsequent text reply. last_assistant_text() walked the transcript backwards, found the tool_call envelope (role=assistant), and surfaced its content as the bot's answer. Fix: filter by envelope \`type\`. tool_call / tool_result / delta / error / approval_required / input_required / multimodal_part all skip; only text envelopes (or untyped, defaulting to text) return. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds three interaction surfaces that downstream consumers (Mantia) now
need from the WhatsApp webhook + outbound payload builder:
Inbound:
- type=reaction → emit a virtual command
whatsapp_reaction:<emoji>:<original_msg_id> so the consumer can
route by emoji + map to message-specific actions.
- type=interactive nfm_reply → emit
whatsapp_flow:<flow_name>:<json_payload> so the consumer can
parse the form data and route by flow name.
Outbound:
- New type='flow' branch in build_interactive_payload — packages a
flow_id + flow_token + flow_action_payload into the messaging
envelope per Meta's spec.
- apply_interactive_header() centralizes header-shape resolution
across button/list/flow payloads. Now supports:
'header' => 'string' → text header (capped 60)
'header' => ['text' => '…'] → text header
'header' => ['image' => 'url'] → image header (link)
'header' => ['image_id' => '…'] → image header (media id)
No public API removals; consumers passing the old string-only
'header' shape stay unaffected.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Phase 1 + 2 of the "A2A version of Studio" proposal (docs/a2a-studio-proposal.md). Phase 1 — Discovery: - OpenclaWP_Agent_Card serves an A2A Agent Card at /openclawp/v1/agenttic/<slug>/.well-known/agent-card.json, derived from a registered agent (skills from tools + subagents, streaming capability, JSON-RPC endpoint). Gated to manage_options by default — the card exposes the system prompt + tool inventory — with openclawp_agent_card_permission to opt into public discovery. Phase 2 — A2A client + caller chain: - OpenclaWP_A2a_Client_Transport: outbound message/send + fetch_card, emitting the canonical agents-api X-Agents-Api-* caller-chain headers (#81). - OpenclaWP_A2a_Client_Bridge: registers each openclawp_a2a_peers entry as an a2a/<slug> tool any local agent can call (mirrors the MCP client bridge). - Agenttic bridge receive side tags inbound peer calls as client_context source=peer-agent (peer_agent_call=true), failing closed on malformed caller headers (#180). Covered by tests/unit/ (AgentCard, A2aClientBridge, A2aClientTransport) and a tests/smoke.php section that asserts the card is gated, serves when opened via filter, 404s for unknown agents, and registers a peer ability. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 1 + 2 of the "A2A version of Studio" proposal — turning openclaWP from an A2A server into a peer that can both advertise itself and call other agents.
What's in here
Phase 1 — Discovery (agent card)
OpenclaWP_Agent_Cardserves an A2A Agent Card atGET /openclawp/v1/agenttic/<slug>/.well-known/agent-card.json, derived from a registered agent: name, description, JSON-RPC endpoint,streamingcapability, and skills derived from the agent's tools + subagents.Phase 2 — A2A client + caller chain
OpenclaWP_A2a_Client_Transport— outboundmessage/send+fetch_card, emitting the canonical agents-apiX-Agents-Api-*caller-chain headers (agents-api#81).OpenclaWP_A2a_Client_Bridge— registers eachopenclawp_a2a_peersentry as ana2a/<slug>tool any local agent can call (mirrorsOpenclaWP_Mcp_Client_Bridge).client_context.source = peer-agent/peer_agent_call = true, failing closed on malformed caller headers (agents-api#180).This lets two local native-PHP sites delegate to each other over A2A with a proper caller chain — zero external infra.
Security
manage_optionsby default (the card exposes the system prompt + tool inventory); opt into public discovery viaopenclawp_agent_card_permission. The card is never more permissive than the bridge endpoint it describes.openclawp_a2a_peersfilter (admin/code-controlled); tool args control only the message body, never the URL.esc_url_rawapplied.manage_optionsgate. Malformed headers fail closed.manage_options(filterable).Tests
tests/unit/—AgentCardTest,A2aClientBridgeTest,A2aClientTransportTest(card shape + skill derivation, peer plan/validation, caller-header chain + Task parsing, including a round-trip through the realWP_Agent_Caller_Context).tests/smoke.php— fetches a live card (gated → 401 unauth; 200 when opened via filter; 404 unknown agent) and registers a peer ability.🤖 Generated with Claude Code