This demo proves that UAM (Universal Agent Messaging) works across:
- Different languages -- Python agent + TypeScript agent
- Different relays -- Relay Alpha (alpha.demo) + Relay Beta (beta.demo)
- Different frameworks -- PyNaCl (Python) + libsodium-wrappers (TypeScript)
- Zero custom integration -- both agents use only the public SDK API
Two agents on completely different stacks exchange encrypted, signed messages through federated relays with no special configuration.
- Docker (with Docker Compose) -- for running the two relay instances
- Python 3.10+ -- for the Python agent
- Node.js 18+ -- for the TypeScript agent
- UAM Python SDK installed:
pip install -e .(from project root) - UAM TypeScript SDK built:
cd ts-sdk && npm install && npm run build
cd examples/interop-demo
chmod +x run-demo.sh
./run-demo.shThat's it. The script handles everything: building the Docker image, starting two federated relays, running both agents, and showing the results.
The orchestrator starts two independent relay instances:
Relay Alpha (alpha.demo) -- port 9001
Relay Beta (beta.demo) -- port 9002
Both relays have federation enabled and can discover each other via Docker
network DNS aliases (simulating .well-known discovery in production).
The Python agent:
- Creates a fresh identity (Ed25519 keypair)
- Registers on Relay Alpha as
py-demo::alpha.demo - Sends an encrypted message to
ts-demo::beta.demo - Waits for and reads replies from the TypeScript agent
- Sends a follow-up message
The TypeScript agent:
- Creates a fresh identity (Ed25519 keypair via libsodium)
- Registers on Relay Beta as
ts-demo::beta.demo - Checks inbox for the Python agent's message
- Sends an encrypted reply back to
py-demo::alpha.demo - Checks for and responds to follow-up messages
Federation
Python Agent -----> Relay Alpha ---------> Relay Beta -----> TypeScript Agent
(py-demo) (alpha.demo) (beta.demo) (ts-demo)
|
TypeScript Agent <-- Relay Beta <--------- Relay Alpha <------+
(ts-demo) (beta.demo) (alpha.demo) (reply)
[1/8] Creating agent 'py-demo' on http://localhost:9001 (alpha.demo)...
Address: py-demo::alpha.demo
Public key: abc123...
[3/8] Sending message to ts-demo::beta.demo...
Sent message to ts-demo::beta.demo: msg-uuid-here
[5/8] Checking inbox...
From: ts-demo::beta.demo
Body: Hello from TypeScript! Received your message loud and clear.
+------------------+ +------------------+
| Python Agent | | TypeScript Agent |
| (demo.py) | | (ts-agent.mjs) |
| | | |
| from uam.sdk | | import { Agent }|
| import Agent | | from 'uam' |
+--------+---------+ +--------+---------+
| |
| HTTP transport | HTTP transport
| |
+--------v---------+ +--------v---------+
| Relay Alpha | | Relay Beta |
| alpha.demo | <------> | beta.demo |
| port 9001 | federation| port 9002 |
+------------------+ +------------------+
| |
+--------- Docker Network -----+
(uam-demo)
Key points:
- Each agent connects ONLY to its home relay
- Agents do NOT know about federation -- it's transparent
- Messages are encrypted end-to-end (NaCl Box)
- Messages are signed with Ed25519 -- tamper-proof
- Relays forward encrypted payloads -- they cannot read message content
For debugging, you can run each component separately:
# Build the relay image
docker build -f ../../docker/Dockerfile -t uam-relay ../..
# Start both relays
docker compose -f docker-compose.demo.yml up -d
# Verify health
curl http://localhost:9001/health
curl http://localhost:9002/healthpython3 demo.py \
--relay http://localhost:9001 \
--domain alpha.demo \
--name py-demo \
--peer ts-demo::beta.demonode ts-agent.mjs \
--relay http://localhost:9002 \
--domain beta.demo \
--name ts-demo \
--peer py-demo::alpha.demodocker compose -f docker-compose.demo.yml downLook for these indicators in the output:
- Both agents register successfully -- each prints its UAM address
- Messages are sent with unique IDs -- UUIDs in the "Sent message" lines
- Messages are received and decrypted -- inbox shows plaintext content
- Cross-relay delivery works -- Python on alpha.demo receives from beta.demo
- Summaries show send/receive counts -- both agents report messages exchanged
ERROR: Cannot connect to the Docker daemon
Start Docker Desktop or the Docker service, then retry.
ERROR: Bind for 0.0.0.0:9001 failed: port is already allocated
Stop any existing relay containers:
docker compose -f docker-compose.demo.yml downOr use different ports by editing docker-compose.demo.yml.
Error: Cannot find module '../../ts-sdk/dist/index.js'
Build the TypeScript SDK first:
cd ../../ts-sdk
npm install
npm run build
cd ../examples/interop-demoModuleNotFoundError: No module named 'uam'
Install the Python SDK in development mode:
cd ../..
pip install -e ".[relay]"
cd examples/interop-demoIf the health check times out after 60 seconds:
# Check relay logs
docker compose -f docker-compose.demo.yml logs relay-alpha
docker compose -f docker-compose.demo.yml logs relay-betaCommon causes: Docker build failure, missing dependencies, port conflicts.
If Docker is unavailable, you can start relays manually and use the --no-docker flag:
# Start relays some other way (e.g., directly with uvicorn)
# Then run the demo without Docker:
./run-demo.sh --no-dockerThis skips Docker image building and container startup, but expects relays to already be running on ports 9001 and 9002.