refactor(sdk-py): wrap relaycast-sdk in hosted communicate transport
Summary
Refactors the Python SDK's hosted communicate transport (agent_relay.communicate.transport.RelayTransport) to wrap the published relaycast-sdk (PyPI relaycast-sdk, module relay_sdk) instead of hand-rolling aiohttp HTTP/WS. relay_sdk now owns the wire protocol (envelope unwrap, 5xx retry, auth errors, the WebSocket lifecycle).
Mapping
| Operation | relay_sdk call |
|---|---|
| register_agent | AsyncRelay(...).agents.register(name, type="agent") (reads .id/.token) |
| unregister | relay._client.delete("/v1/agents/{name}") escape hatch (no agents.delete() exists) |
| post to channel | AsyncAgentClient.send(channel, text) |
| reply | AsyncAgentClient.reply(id, text) |
| dm | AsyncAgentClient.dm(to, text) |
| check_inbox | raw agent.client.get("/v1/inbox") (typed InboxResponse drops messages) |
| list_agents | AsyncRelay(...).agents.list() |
| WebSocket | relay_sdk.WsClient with on(event, handler) |
What mapped cleanly vs needed workarounds
Clean: register, list, post, reply, dm, error translation (RelayError → RelayAuthError/RelayConnectionError), 5xx retry, 401 handling, base-URL pass-through.
Workarounds:
- unregister —
relay_sdkhas noagents.delete(); used the http-client escape hatch. The cleanup path also swallows the empty-body decode errorrelay_sdkraises on204 No Content. - check_inbox —
AgentClient.inbox()returns the typedInboxResponse(unread metadata only) and discards the deliverablemessagesarray; read the raw/v1/inboxpayload through the agent http client (still envelope-unwrapped/retried/auth-checked) to preserve behavior. - WebSocket pong —
WsClienthas no pong-on-server-ping primitive; kept a minimal local workaround (on("ping", ...)→_send_json({"type":"pong"})). - WebSocket open gating —
WsClient.connect()blocks for the socket lifetime, so it runs in a background task;connect()waits on the"open"event so the socket is live on return.
Constraints honored
- Default base URL
https://api.relaycast.devpreserved and passed explicitly into therelay_sdkclients. RelayConfig/ public types andAgentRelayClientbroker behavior untouched.RelayTransportpublic method signatures andagent_id/tokenattributes kept stable.relaycast-sdkadded to thecommunicate(anddev) extras;aiohttpretained for the A2A modules.
Tests
relaycast-sdk was installed and inspected to verify the surface. The in-process mock relay server was updated to return SDK-contract-compliant payloads, and the retry/reconnect transport tests were adapted to relay_sdk's behavior (retry = initial + 3; reconnect owned by WsClient).
python -m pytest tests/communicate → 211 passed, 2 skipped.
🤖 Generated with Claude Code