This document covers the three transport mechanisms available in Agent Protocol v2: gRPC, Unix Domain Sockets (UDS), and Reverse Connections.
Transport Comparison
| Feature | gRPC | UDS Binary | Reverse Connection |
|---|---|---|---|
| Latency | ~1.2ms | ~0.4ms | ~0.5ms |
| Throughput | 28K req/s | 45K req/s | 40K req/s |
| TLS Support | Yes | N/A (local) | Yes |
| Cross-network | Yes | No | Yes |
| NAT Traversal | No | No | Yes |
| Max Message | 10 MB | 16 MB | 16 MB |
| Flow Control | HTTP/2 | Manual | Manual |
gRPC Transport
Overview
gRPC over HTTP/2 is the best choice for:
- Remote agents across networks
- Agents requiring TLS encryption
- Language-agnostic implementations
- Complex streaming scenarios
Client Setup
use AgentClientV2;
use Duration;
// Basic connection
let client = connect.await?;
// With TLS
use TlsConfig;
let tls_config = TlsConfig ;
let client = connect_with_tls.await?;
Streaming Semantics
gRPC v2 uses bidirectional streaming for efficient request handling:
Proxy Agent
│ │
│ ──── RequestHeaders (id=1) ──────────► │
│ ──── RequestBodyChunk (id=1) ────────► │
│ │
│ ◄──── Decision (id=1) ──────────────── │
│ │
│ ──── RequestHeaders (id=2) ──────────► │ (pipelined)
│ ──── CancelRequest (id=1) ───────────► │ (cancellation)
│ │
Unix Domain Socket (UDS) Transport
Overview
UDS binary transport is the best choice for:
- Co-located agents on the same host
- Lowest possible latency requirements
- High-throughput local processing
- Simple deployment without TLS
Wire Format
┌──────────────────┬──────────────────┬─────────────────────────────────┐
│ Length (4 bytes) │ Type (1 byte) │ JSON Payload (variable length) │
│ Big-endian u32 │ Message type ID │ UTF-8 encoded │
└──────────────────┴──────────────────┴─────────────────────────────────┘
Client Setup
use AgentClientV2Uds;
use Duration;
let client = connect.await?;
// Query capabilities after handshake
let caps = client.capabilities;
println!;
println!;
Handshake Protocol
UDS connections begin with a handshake:
Proxy Agent
│ │
│ ──── Connect ────────────────────────────────► │
│ │
│ ──── HandshakeRequest ─────────────────────────► │
│ { │
│ protocol_version: 2, │
│ client_name: "sentinel-proxy", │
│ supported_features: ["streaming", ...] │
│ } │
│ │
│ ◄──────────────────────── HandshakeResponse ─── │
│ { │
│ protocol_version: 2, │
│ agent_name: "auth-agent", │
│ capabilities: { ... } │
│ } │
│ │
│ (normal message flow) │
│ │
Message Types
| Type ID | Name | Direction |
|---|---|---|
0x01 | HandshakeRequest | Proxy → Agent |
0x02 | HandshakeResponse | Agent → Proxy |
0x10 | RequestHeaders | Proxy → Agent |
0x11 | RequestBodyChunk | Proxy → Agent |
0x12 | ResponseHeaders | Proxy → Agent |
0x13 | ResponseBodyChunk | Proxy → Agent |
0x20 | Decision | Agent → Proxy |
0x30 | CancelRequest | Proxy → Agent |
0x31 | CancelAll | Proxy → Agent |
0xF0 | Ping | Either |
0xF1 | Pong | Either |
Binary Encoding (MessagePack)
UDS supports MessagePack encoding for improved performance over JSON. Encoding is negotiated during the handshake.
Enable in Cargo.toml:
= { = "0.3", = ["binary-uds"] }
Handshake with encoding negotiation:
Proxy Agent
│ │
│ ──── HandshakeRequest ─────────────────────────► │
│ { supported_encodings: ["msgpack", "json"] }│
│ │
│ ◄──────────────────────── HandshakeResponse ─── │
│ { encoding: "msgpack" } │
│ │
│ (subsequent messages use msgpack) │
Available encodings:
| Encoding | Pros | Cons |
|---|---|---|
json | Human readable, always available | Larger payloads, slower |
msgpack | Compact, fast serialization | Requires binary-uds feature |
Zero-Copy Body Streaming
For large request/response bodies, use binary body chunk methods to avoid base64 encoding overhead:
use ;
// Create binary body chunk (no base64)
let chunk = new;
// Send via UDS client
// - With MessagePack: raw bytes (most efficient)
// - With JSON: falls back to base64
client.send_request_body_chunk_binary.await?;
Performance comparison (1KB body chunk):
| Method | Encoding | Serialized Size |
|---|---|---|
send_request_body_chunk | JSON + base64 | ~1,450 bytes |
send_request_body_chunk_binary | MessagePack | ~1,050 bytes |
Reverse Connections
Overview
Reverse connections allow agents to connect to the proxy instead of the proxy connecting to agents. This enables:
- Agents behind NAT/firewalls
- Dynamic agent scaling
- Cloud-native deployments
- Zero-config agent discovery
Architecture
Agent Proxy
│ │
│ ──── TCP/UDS Connect ───────►│
│ │
│ ──── RegistrationRequest ──►│
│ - agent_id │
│ - capabilities │
│ - auth_token │
│ │
│ ◄── RegistrationResponse ───│
│ - accepted │
│ - config │
│ │
│ (bidirectional protocol) │
│ │
Listener Setup
use ;
let config = ReverseConnectionConfig ;
// UDS listener for local agents
let listener = bind_uds.await?;
// TCP listener for remote agents
let listener = bind_tcp.await?;
See Reverse Connections for detailed setup instructions.
V2Transport Abstraction
The V2Transport enum provides a unified interface across all transport types:
use V2Transport;
// All transports support the same operations
Choosing a Transport
| Scenario | Recommended Transport |
|---|---|
| Same host, lowest latency | UDS Binary |
| Remote agent, needs TLS | gRPC |
| Agent behind NAT/firewall | Reverse Connection |
| Cloud-native, dynamic scaling | Reverse Connection |
| Cross-language agent | gRPC |
| Simple local deployment | UDS Binary |
| Mixed environment | AgentPool (auto-detect) |
Auto-Detection in AgentPool
let pool = new;
// Transport is auto-detected from endpoint format
pool.add_agent.await?; // → UDS
pool.add_agent.await?; // → gRPC
pool.add_agent.await?; // → gRPC+TLS