UniEnv remote protocol (version 2)¶
The wire contract of unienv_interface.remote, for writing clients or servers in
other languages. The Python implementation is in wire.py (frames and values),
protocol.py (message layout and the method allowlist) and server.py.
Frames¶
A transport carries ordered, reliable frames. TCP and Unix sockets send frames back to back; WebSocket sends one frame per binary message.
u32 buffer count N | u32 JSON length L | N x u64 buffer length | L bytes UTF-8 JSON | N buffers
All integers are little-endian. The JSON is strict (no NaN / Infinity
literals). Receivers reject frames over their size limit (256 MiB by default),
with more than 65536 buffers, with lengths that do not add up, or whose buffers
are not each referenced exactly once.
Values¶
null, booleans, integers, strings, lists and objects with string keys are plain
JSON. Other values are objects with the reserved key "__t":
__t |
Fields | Value |
|---|---|---|
tuple |
v: list |
tuple |
dict |
v: list of [key, value] |
dict with non-string keys, or with a "__t" key |
float |
v: "nan", "inf", "-inf" |
non-finite float |
bytes |
b: buffer index |
bytes |
nd |
d: dtype, s: shape, b: buffer index |
array, C order |
nd |
d, s, c: codec, o: codec options, b: list of buffer indices |
compressed array (see below) |
space |
v: space_to_json document |
UniEnv space |
graph |
v: n_nodes, n_edges, nodes_features, edges_features, edges |
GraphInstance |
Dtypes are NumPy type strings with an optional byte-order prefix: b1, i1-i8,
u1-u8, f2, f4, f8, c8, c16 (e.g. <f4, |u1). A shape is a list of
at most 32 non-negative integers; product(shape) * itemsize must equal the buffer
length. Scalars of a dtype are 0-d arrays. Nesting is limited to 64 levels. Other
values (objects, strings arrays, structured dtypes, ...) cannot be sent.
Messages¶
| Message | Layout |
|---|---|
| Request | [id, target, method, args, kwargs] |
| Success | [id, 0, value] or [id, 0, value, updates] |
| Error | [id, 1, [exception type name, message, formatted traceback]] |
| Event | [resource name, 2, [kind, sequence, value]] |
id is a client-chosen integer; responses may arrive in any order. target is a
resource name, or "" for the protocol methods below. args is a list, kwargs
an object. Only the methods in protocol.METHODS can be called:
| Kind | Methods |
|---|---|
env |
reset, reload (if defined), step, render |
world |
step, reset, reload, after_reset, after_reload |
node |
reset, reload, after_reset, after_reload, pre_environment_step, post_environment_step, set_next_action, get_context, get_observation, get_reward, get_termination, get_truncation, get_info, render |
Calls on one registered root (and on every hosted object that shares its world)
execute one at a time, in arrival order. A descriptor's world, node and
children links name only objects that are hosted.
Protocol methods¶
hello(version=2, compress=null)must be the first request. It returns{"version": 2, "resources": {name: descriptor}}. A descriptor haskind(env,world,node),methods,attributes(name,batch_size, timings,render_mode,render_fps,supported_render_modes,has_*signals,metadata; only those present),spaces([version, {observation_space, action_space, context_space}]), nodepriorities, and links:worldandnode(resource names) and nodechildren({child name: resource name}).subscribe([env name])/unsubscribe([env name]): start or stop events for that env. After everyreset,reloadandstep, whoever called it, the server sends[name, 2, [method, sequence, result]]. Unsent events are replaced by newer ones (latest wins).
updates ({name: [version, spaces]}) carries spaces that changed since the
client last saw them; the server checks after reset, reload, after_reset and
after_reload calls. Clients ignore updates with a version not newer than theirs.
Compression¶
hello(compress={"image": "jpeg:90"}) asks the server to JPEG-encode (quality 90)
the uint8 array leaves of results whose space has metadata["kind"] == "image", an
HWC or CHW metadata["layout"] (default HWC) and 1 or 3 channels. Such a leaf
is sent as {"__t": "nd", "d": "|u1", "s": shape, "c": "jpeg", "o": {"quality": 90, "layout": ...,
"format": ...}, "b": [one buffer per image]} (leading dimensions are batch
dimensions). Clients never compress what they send.