microsandbox-agent-client
AgentClient is Client<AgentProtocol> from microsandbox-protocol-client. The agent package supplies relay setup and generation metadata; the shared engine supplies one reader, writer, allocator, and ownership registry. SDK services such as execution collection and filesystem handles remain in microsandbox.
TypedMessage / EncodedMessage / raw envelope / exact packet
|
Client<AgentProtocol>
|
current or legacy relay handshake
|
agent relay
Native, encoded, and raw messages
use ;
use ;
async
Message.t is the actual wire string. Unknown names and unknown envelope fields remain inspectable: Message::raw() borrows the original frame and into_raw() returns it. Ordinary requests surface peer error messages as messages. Optional Request<AgentProtocol> implementations add checked unary decoding without narrowing the generic API.
Owned streams and explicit IDs
use ;
use ;
async
Both split parts retain the connection and ID lease; sender handles may be cloned and there is one consuming receiver. Terminal receipt disables sends and delivers the terminal frame once. Closing or dropping the receiver disables sends and retains bounded drain state until terminal completion. It sends no process signal or filesystem EOF. Transport loss before a terminal frame is an error, distinct from clean exhaustion.
request_raw(flags, body), stream_raw(flags, body), and send_raw(id, flags, body) exchange opaque envelopes without CBOR decoding. write_unchecked(packet_bytes) serializes exact caller bytes without allocating an ID or subscribing for replies. TransportPacket remains an optional standalone framing helper; packet.into_bytes() feeds the exact write API. Standalone packet readers require exclusive transport ownership.
Setup and metadata
Enable uds for native Unix sockets or named-pipe for Windows pipes. connect_stream accepts an owned AsyncRead + AsyncWrite + Unpin + Send transport, including UdsTransport and NamedPipeTransport. The stream feature name remains accepted for existing manifests; generic owned transports are available without additional dependencies.
use AgentClient;
use Duration;
async
Setup has one deadline across dial and handshake. The current [id_min,id_max] relay prologue and the supported pre-0.5 [id_offset] prologue retain their existing parsing, ID ranges, and ready payload behavior. Known operations use the smaller host/peer generation as their availability gate. Current connections continue emitting the host's existing envelope generation; legacy connections emit generation one. Source-level API changes do not retire the legacy wire path.
Migration from the previous active client
| Previous API | Shared-client API |
|---|---|
connect(path) / connect_stream(stream) |
Same entry points; owned streams no longer require the stream feature |
request(type, &payload) |
request(TypedMessage::new(type, &payload)) |
stream(type, &payload) -> (id, receiver) |
stream(TypedMessage::new(type, &payload)), then id() / into_parts() |
send(id, type, &payload) |
send(id, TypedMessage::new(type, &payload)) |
request_raw(flags, body) |
Same call; retains drain state after a nonterminal first reply |
stream_raw(flags, body) -> (id, receiver) |
Owned raw stream, then id() / into_parts() |
send_raw(id, flags, body) |
Same call, requiring a live owned ID |
connect_with_timeout(path, duration) |
`connect_with(path, |
connect_stream_with_timeout(stream, duration) |
`connect_stream_with(stream, |
connect_with_deadline(path, deadline) |
`connect_with(path, |
connect_stream_with_deadline(stream, deadline) |
`connect_stream_with(stream, |
ready() |
ready().agent |
ready_bytes() |
ready().ready_bytes() |
negotiated_version() / supports(type) |
ready().negotiated_version / ready().supports(type) |
protocol() / is_legacy_protocol() |
ready().wire_format / ready().is_legacy_protocol() |
agent_version() |
ready().agent_version() |
ensure_version_compat(type) |
AgentProtocol::ensure_version_compat_for(type, client.ready().negotiated_version) |
AgentClient::ensure_version_compat_for(type, generation) |
AgentProtocol::ensure_version_compat_for(type, generation) |
Unwired AgentStream<T> / packet-only AgentTransport |
Active AgentStream / owned byte transports accepted directly by connect_stream |
| Connection close by ownership transfer | Shared close(&self); last client/stream owner also closes the transport |
ClientError.delivery distinguishes NotSent from Unknown after writer admission. Requests are never automatically replayed. Raw stream access, known-ID sends, custom transports, ready bytes, dynamic names, and encoded payloads remain available without adopting SDK domain objects.
Deadline conversions use tokio::time::Instant, matching the original absolute-deadline API. Keep the conversion inside the options closure so it uses the remaining duration when setup begins. Known native and encoded sends perform the same availability check automatically; the public AgentProtocol helper supports callers retaining only the generation. Unsupported operations now use the shared ClientError category rather than the previous agent-specific error fields.
Validation: cargo test -p microsandbox-agent-client --all-features --locked. Unix-socket tests require permission to bind temporary local sockets. The migrated historical handshake cases are source-level regression tests; they do not replace live historical runtime/SDK validation.
The SDK retains an internal optimized client for generation-eight bulk transfers and Unix shared arenas. Its existing bulk APIs remain available; the generic client is the public transport-independent framed API.