Files
codex/codex-rs/exec-server/src/proto/codex.exec_server.relay.v1.rs
Anton Panasenko ac466c0dbd feat(exec-server): use protobuf relay frames (#22343)
## Why

Remote exec-server now needs one executor websocket to serve multiple
harness JSON-RPC sessions. Rendezvous routes by `stream_id`, and the
exec-server side needs to use the same stable relay frame contract
instead of a hand-rolled JSON shape.

The relay protocol also needs to make ownership boundaries clear:
harness and executor endpoints own sequencing, acks, retries, duplicate
suppression, segmentation, and reassembly; rendezvous only routes
frames.

## What Changed

- Add the checked-in `codex.exec_server.relay.v1.RelayMessageFrame`
proto plus generated prost bindings for `codex-exec-server`.
- Encode remote harness/executor relay traffic as binary protobuf
websocket frames while keeping local websocket JSON-RPC unchanged.
- Demux executor-side relay streams into independent
`ConnectionProcessor` sessions keyed by `stream_id`.
- Add a programmatic `RemoteExecutorConfig::with_bearer_token(...)`
constructor for non-CLI callers and integration tests.
- Add an integration test that starts the remote executor against a fake
registry/rendezvous websocket and verifies two virtual streams share one
executor websocket without cross-talk, including per-stream reset
behavior.
- Document the remote relay envelope, sequence ranges, `ack`/`ack_bits`,
and endpoint responsibilities in `exec-server/README.md`.

## Verification

- `cargo test -p codex-exec-server --test relay
multiplexed_remote_executor_routes_independent_virtual_streams --
--exact`
- `cargo test -p codex-exec-server --test relay`
- `cargo test -p codex-exec-server` passed outside the sandbox. The
sandboxed run hit macOS `sandbox-exec: sandbox_apply: Operation not
permitted` in filesystem sandbox tests.
2026-05-12 16:50:45 -07:00

55 lines
1.7 KiB
Rust

// This file is @generated by prost-build.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RelayMessageFrame {
#[prost(uint32, tag = "1")]
pub version: u32,
#[prost(string, tag = "2")]
pub stream_id: ::prost::alloc::string::String,
#[prost(uint32, tag = "3")]
pub ack: u32,
#[prost(uint32, tag = "4")]
pub ack_bits: u32,
#[prost(oneof = "relay_message_frame::Body", tags = "5, 6, 7, 8, 9")]
pub body: ::core::option::Option<relay_message_frame::Body>,
}
pub mod relay_message_frame {
#[derive(Clone, PartialEq, ::prost::Oneof)]
pub enum Body {
#[prost(message, tag = "5")]
Data(super::RelayData),
#[prost(message, tag = "6")]
AckFrame(super::RelayAck),
#[prost(message, tag = "7")]
Resume(super::RelayResume),
#[prost(message, tag = "8")]
Reset(super::RelayReset),
#[prost(message, tag = "9")]
Heartbeat(super::RelayHeartbeat),
}
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RelayData {
#[prost(uint32, tag = "1")]
pub seq: u32,
#[prost(uint32, tag = "2")]
pub segment_index: u32,
#[prost(uint32, tag = "3")]
pub segment_count: u32,
#[prost(bytes = "vec", tag = "4")]
pub payload: ::prost::alloc::vec::Vec<u8>,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RelayAck {}
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RelayResume {
#[prost(uint32, tag = "1")]
pub next_seq: u32,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RelayReset {
#[prost(string, tag = "1")]
pub reason: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct RelayHeartbeat {}