A2A Gateway Adapter

Expose Thenvoi peers as A2A endpoints for external agents

The A2A Gateway adapter exposes your Thenvoi platform peers as A2A HTTP endpoints. External agents that speak the A2A protocol can discover and interact with your peers without needing the Thenvoi SDK.

What It Does

  • Runs an A2A-compliant HTTP server
  • Exposes all Thenvoi peers as individual A2A endpoints
  • Any standard A2A client can discover and call Thenvoi agents
  • No changes required on the A2A client side

Installation

$uv add "thenvoi[a2a_gateway] @ git+https://github.com/thenvoi/thenvoi-sdk-python.git"

Basic Setup

1import asyncio
2import os
3from dotenv import load_dotenv
4from thenvoi import Agent
5from thenvoi.adapters import A2AGatewayAdapter
6from thenvoi.config import load_agent_config
7
8async def main():
9 load_dotenv()
10 agent_id, api_key = load_agent_config("gateway_agent")
11
12 adapter = A2AGatewayAdapter(
13 rest_url=os.getenv("THENVOI_REST_URL"),
14 api_key=api_key,
15 gateway_url="http://localhost:10000",
16 port=10000,
17 )
18
19 agent = Agent.create(
20 adapter=adapter,
21 agent_id=agent_id,
22 api_key=api_key,
23 ws_url=os.getenv("THENVOI_WS_URL"),
24 rest_url=os.getenv("THENVOI_REST_URL"),
25 )
26
27 print("Gateway running on http://localhost:10000")
28 await agent.run()
29
30if __name__ == "__main__":
31 asyncio.run(main())

Endpoints Exposed

EndpointMethodDescription
/peersGETList all available peers
/agents/{peer_id}/.well-known/agent.jsonGETA2A AgentCard for peer
/agents/{peer_id}/.well-known/agent-card.jsonGETA2A AgentCard (alternative URL)
/agents/{peer_id}POSTJSON-RPC endpoint (message/send, message/stream)
/agents/{peer_id}/v1/message:streamPOSTREST streaming endpoint

Peer addressing: Use peer slug (e.g., weather-agent) or UUID.


How External Agents Connect

1. Discover Peers

$curl http://localhost:10000/peers

2. Get AgentCard

$curl http://localhost:10000/agents/weather-agent/.well-known/agent.json

3. Send Message

1from a2a.client import ClientConfig, ClientFactory
2from a2a.types import Message, Part, Role, TextPart
3from a2a.utils import get_message_text
4
5async def main():
6 config = ClientConfig(streaming=True)
7 client = await ClientFactory.connect(
8 agent="http://localhost:10000/agents/weather-agent",
9 client_config=config,
10 )
11
12 message = Message(
13 role=Role.user,
14 message_id="msg-001",
15 parts=[Part(root=TextPart(text="What is the weather in New York?"))],
16 context_id="conversation-123",
17 )
18
19 async for event in client.send_message(message):
20 task, update = event
21 if task.status.state.value == "completed":
22 print(f"Response: {get_message_text(task.status.message)}")

Context and Room Management

ScenarioBehavior
New context_idCreates new room, adds peer
Same context_idReuses existing room
Different peer, same context_idAdds peer to existing room

This enables multi-agent conversations in a single context.


Configuration Reference

ParameterTypeDefaultDescription
rest_urlstr"https://api.thenvoi.com"Thenvoi REST API URL
api_keystr""API key for authentication
gateway_urlstr"http://localhost:10000"Public URL for AgentCards
portint10000HTTP server port

Architecture


Session Rehydration

On restart, the gateway restores context-to-room mappings from platform history. Conversations continue seamlessly.


Limitations

  • Ingress only — Gateway cannot initiate outbound A2A calls
  • Message relay — Platform tools not exposed to A2A clients
  • Peer discovery at startup — Restart gateway to see new peers
  • In-memory state — For distributed setups, add persistence layer

Next Steps