Datums and blobs
Text, file and image values, inline blobs, and attachments that move large bytes over a stream.
Datums
Three kinds of datum cross the wire as values inside params, result or stream items:
{ "kind": "text", "text": "…", "format": "markdown" }
{ "kind": "file", "filename": "report.pdf", "description": "Q3 export",
"media_type": "application/pdf", "blob": <blob> }
{ "kind": "image", "name": "screen.png", "description": "current display",
"media_type": "image/png", "blob": <blob> }Blobs
A blob is either inline or an attachment.
Inline
Allowed only up to 512 KiB: a msgpack bin, or a base64 string under negotiated JSON — one
reason msgpack is the default.
The ceiling comes from the far end rather than the wire. A deployment that measures a result as JSON pays base64's four-for-three, so 512 KiB arrives as 699,052 bytes; Attacca's result limit defaults to 1,000,000 bytes.
Attachment
Metadata in place of the bytes:
{ "attachment": { "stream": 42, "size": 48293812, "sha256": "…", "offset": 0 } }The bytes follow as STREAM_DATA chunks on the referenced stream, and s_end.trailer.sha256 gives
end-to-end integrity. An interrupted transfer resumes by re-issuing the call with offset.
When attachments are used
Attachments are negotiated: both peers must advertise the attachments feature in the
handshake. Against a peer that did not, blobs stay inline whatever their size.
Where they are negotiated, the conversion is automatic and by size. A responder detaches every blob over 4 MiB as it writes the response:
- It allocates a stream from its own id parity — the byte sender allocates, so no
req.stream.idis involved. - It writes the attachment reference in place of the bytes and sends the
res. - It pushes the bytes as STREAM_DATA chunks of at most
max_chunk, paced by the receiver's credit. s_endcarries the digest, which the reference also names, so the receiver can check length and content without having trusted either end alone.
The receiver opens the stream when it decodes the payload, not when its caller gets around to reading it — chunks are already in flight by then. An announced attachment nobody claims within two minutes is cancelled, because an unclaimed stream otherwise holds its sender at the credit ceiling for the life of the connection.
Implementation status
Implemented: inline blobs, chunked uni_streams (which cover bulk file transfer through
file_io.read_stream and write_at), and attachments in responses. Attachments in request
parameters — a large datum travelling towards the callee, as file_io.write would want — are the
same mechanism mirrored and are not implemented yet.