Transport capability matrix
Every tywrap transport exposes a static, transport-level capability descriptor via Transport.capabilities(). The same descriptor is surfaced by RpcClient.capabilities() (it delegates to the held transport). It tells callers what the wire channel can carry and how it frames messages without a network round-trip.
This descriptor is deliberately separate from the bridge meta report (BridgeInfo, fetched via RpcClient.getBridgeInfo()):
- The transport descriptor is authoritative for transport-level flags: what bytes the channel moves and how it frames them. It does not depend on lifecycle state, so it is safe to read before
init()and afterdispose(). - The
BridgeInfometa report is authoritative for the Python environment, including which optional libraries (arrowAvailable,scipyAvailable,torchAvailable,sklearnAvailable) happen to be importable in the running interpreter.
To ask whether a transport can carry Arrow and whether Python has pyarrow, consult both: the transport descriptor for the channel, BridgeInfo for library availability.
TransportCapabilities
interface TransportCapabilities {
backend: 'subprocess' | 'http' | 'pyodide';
supportsArrow: boolean;
supportsBinary: boolean;
supportsChunking: boolean;
supportsStreaming: boolean;
maxFrameBytes: number;
}Matrix
| Backend (transport) | backend | supportsArrow | supportsBinary | supportsChunking | supportsStreaming | maxFrameBytes |
|---|---|---|---|---|---|---|
SubprocessTransport (Node) | subprocess | true | true | true (always-on framing) | false | Per-frame ceiling (default 100 MB) |
HttpTransport | http | true | true | false | false | Number.POSITIVE_INFINITY |
PyodideTransport (WASM) | pyodide | false | true | false | false | Number.POSITIVE_INFINITY |
SubprocessTransport.supportsChunking is always true. The npm package includes the JS and Python framing peers together, so no runtime negotiation is needed. Chunking is subprocess-only. HTTP and Pyodide have no JSONL line ceiling. See Transport framing.
PooledTransport (the multi-process Node path) reports the capabilities of the worker transport it distributes across, which is SubprocessTransport in practice. Its capabilities() is a static descriptor read from an un-initialized probe worker built by the same factory. Each leased worker always uses tywrap-frame/1, and chunked traffic through a lease reassembles correctly.
Notes per flag
supportsArrow
Whether the transport can carry Arrow-encoded payloads (binary IPC frames) on the wire.
- subprocess / http:
true. The channel can move Arrow bytes. Whether Arrow is actually used for a given response still depends on the Python side (BridgeInfo.arrowAvailable) and theTYWRAP_CODEC_FALLBACKsetting. Those are runtime/codec concerns, not transport-level ones. - pyodide:
false. pyarrow is unavailable in WASM, so the Pyodide bootstrap forces JSON markers (force_json_markers=True) and reportsarrowAvailable: false. The channel is JSON-only.
supportsBinary
Whether the transport can carry arbitrary binary data (e.g. Python bytes). It is true on all current backends. Binary rides through base64 bytes envelopes.
supportsChunking and supportsStreaming
supportsChunking is implemented for the subprocess backend as of 0.8.0: it splits one logical message across multiple tywrap-frame/1 frames so a payload can exceed the JSONL line ceiling. The capability is statically true for subprocess. HTTP and Pyodide stay false. See Transport framing for the wire format.
supportsStreaming (incremental results for a single request) is false on every backend. It is not implemented as of 0.10.0.
maxFrameBytes
Maximum size, in bytes, of a single wire frame the transport itself will accept. Number.POSITIVE_INFINITY means the transport imposes no frame ceiling of its own. A higher layer, such as the codec's default 10 MB payload limit, may still cap the size).
- subprocess: the JSONL line-length limit (
maxLineLength, default100 * 1024 * 1024= 100 MB). A response line larger than this raises a protocol error. - http:
Number.POSITIVE_INFINITY. The whole response body is read in one shot. The transport imposes no frame limit. - pyodide:
Number.POSITIVE_INFINITY. Calls are in-memory string passing with no framing.
Example
import { RpcClient } from 'tywrap/runtime';
// rpc holds a transport (e.g. via NodeBridge / PyodideBridge / HttpBridge).
const caps = rpc.capabilities();
if (caps.supportsArrow) {
// The channel can carry Arrow; pair with getBridgeInfo() to confirm pyarrow
// is actually importable on the Python side before relying on Arrow encoding.
const info = await rpc.getBridgeInfo();
const useArrow = info.arrowAvailable;
}