This document describes the v2 wire protocol for communication between the Sentinel proxy dataplane and external processing agents.
Protocol Constants
| Constant | Value | Description |
|---|---|---|
PROTOCOL_VERSION | 2 | Current protocol version |
MAX_MESSAGE_SIZE_GRPC | 10,485,760 (10 MB) | Maximum message size for gRPC |
MAX_MESSAGE_SIZE_UDS | 16,777,216 (16 MB) | Maximum message size for UDS binary |
Transport Options
Protocol v2 supports three transport mechanisms:
| Transport | Use Case | Latency | Features |
|---|---|---|---|
| gRPC over HTTP/2 | Remote agents, cross-network | ~1.2ms | TLS, flow control, streaming |
| Binary over UDS | Co-located agents | ~0.4ms | Lowest latency, simple format |
| Reverse Connections | NAT traversal, dynamic scaling | Varies | Agent-initiated connections |
gRPC Transport
Service Definition
syntax = "proto3";
package sentinel.agent.v2;
service AgentProcessorV2 {
// Bidirectional streaming for request/response lifecycle
rpc ProcessStream(stream AgentMessage) returns (stream AgentMessage);
// Health check
rpc HealthCheck(HealthRequest) returns (HealthResponse);
// Capability query
rpc GetCapabilities(CapabilityRequest) returns (CapabilityResponse);
}
message AgentMessage {
uint64 request_id = 1;
oneof payload {
RequestHeaders request_headers = 2;
RequestBodyChunk request_body_chunk = 3;
ResponseHeaders response_headers = 4;
ResponseBodyChunk response_body_chunk = 5;
AgentDecision decision = 6;
CancelRequest cancel = 7;
}
}
Streaming Semantics
Unlike v1’s request-response model, v2 uses bidirectional streaming:
Proxy Agent
│ │
│ ──── RequestHeaders (id=1) ──────────► │
│ ──── RequestBodyChunk (id=1) ────────► │
│ │
│ ◄──── Decision (id=1) ──────────────── │
│ │
│ ──── RequestHeaders (id=2) ──────────► │ (pipelined)
│ ──── CancelRequest (id=1) ───────────► │ (cancellation)
│ │
Message Ordering
- Messages for a single
request_idare ordered - Messages for different
request_ids may be interleaved CancelRequestterminates processing for arequest_id
Binary UDS Transport
Wire Format
┌──────────────────┬──────────────────┬─────────────────────────────────┐
│ Length (4 bytes) │ Type (1 byte) │ JSON Payload (variable length) │
│ Big-endian u32 │ Message type ID │ UTF-8 encoded │
└──────────────────┴──────────────────┴─────────────────────────────────┘
- Length prefix: 4-byte unsigned integer in big-endian byte order (includes type byte)
- Type byte: Message type identifier (see table below)
- Payload: JSON-encoded message body
- Maximum size: 16 MB total
Message Types
| Type ID | Name | Direction | Description |
|---|---|---|---|
0x01 | HandshakeRequest | Proxy → Agent | Initial capability negotiation |
0x02 | HandshakeResponse | Agent → Proxy | Capability confirmation |
0x10 | RequestHeaders | Proxy → Agent | HTTP request headers |
0x11 | RequestBodyChunk | Proxy → Agent | Request body chunk |
0x12 | ResponseHeaders | Proxy → Agent | HTTP response headers |
0x13 | ResponseBodyChunk | Proxy → Agent | Response body chunk |
0x20 | Decision | Agent → Proxy | Processing decision |
0x21 | BodyMutation | Agent → Proxy | Body chunk mutation |
0x30 | CancelRequest | Proxy → Agent | Cancel in-flight request |
0x31 | CancelAll | Proxy → Agent | Cancel all requests |
0xF0 | Ping | Either | Keep-alive ping |
0xF1 | Pong | Either | Keep-alive response |
Example Frame
00 00 00 4A 10 {"request_id":1,"method":"GET","uri":"/api/users"...}
└────┬─────┘ └┘ └──────────────────────┬────────────────────────┘
74 bytes │ JSON payload (RequestHeaders)
│
Type: RequestHeaders (0x10)
Handshake Protocol
Connection establishment requires a handshake:
Reverse Connections
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
- Load-based connection management
Registration Protocol
When an agent connects via reverse connection:
Agent Proxy
│ │
│ ──── Connect to listener socket ─────► │
│ │
│ ──── RegistrationRequest ────────────► │
│ │
│ ◄──── RegistrationResponse ─────────── │
│ │
│ (normal v2 protocol) │
│ │
Registration Messages
Message Types (Detailed)
RequestHeaders
Sent when HTTP request headers are received.
RequestBodyChunk
Sent for each chunk of the request body.
Decision
Agent’s processing decision for a request.
CancelRequest
Cancels processing for a specific request.
Request Lifecycle
Normal Flow
┌─────────┐ RequestHeaders ┌─────────┐
│ Proxy │ ───────────────────► │ Agent │
│ │ │ │
│ │ RequestBodyChunk │ │
│ │ ───────────────────► │ │
│ │ (repeat) │ │
│ │ │ │
│ │ Decision │ │
│ │ ◄─────────────────── │ │
└─────────┘ └─────────┘
Cancellation Flow
┌─────────┐ RequestHeaders ┌─────────┐
│ Proxy │ ───────────────────► │ Agent │
│ │ │ │
│ │ CancelRequest │ │
│ │ ───────────────────► │ │
│ │ │ │
│ │ (agent cleans up) │ │
└─────────┘ └─────────┘
Protocol Guarantees
Ordering
- Messages for a single
request_idare delivered in order - Messages for different requests may be interleaved
CancelRequestis processed immediately, discarding pending messages
Reliability
- Each message must be acknowledged (Decision for requests)
- Timeouts are enforced per-message and per-request
- Connection failures trigger reconnection with backoff
Concurrency
- Multiple requests can be in-flight simultaneously
max_concurrent_requestsin capabilities limits concurrency- Backpressure via flow control (gRPC) or queue bounds (UDS)
Compatibility
v1 to v2 Migration
| v1 Feature | v2 Equivalent |
|---|---|
| Length-prefixed JSON | Binary UDS (type byte added) |
| Unary gRPC calls | Bidirectional streaming |
| Per-request connections | Multiplexed connections |
| N/A | Request cancellation |
| N/A | Reverse connections |
Version Negotiation
- gRPC: Service name includes version (
AgentProcessorV2) - UDS:
protocol_versionfield in handshake - Reverse:
protocol_versionfield in registration
Agents should reject connections with incompatible versions.