Managed streaming
SDK 0.4.0 supports managed providers in all four I/O modes. Streaming uses a fresh authenticated media connection per invocation, independent of health.
| Mode | Caller input | Provider output |
|---|---|---|
| Unary | One JSON request | One result |
| Server streaming | Initial JSON request | Chunks, then terminal |
| Client streaming | Initial request, input chunks, input terminal | One final output terminal |
| Bidirectional | Initial request, input chunks, input terminal | Chunks, then output terminal |
Implement the child handler
When the primary IPC loop receives StreamInvoke, start an owned task calling
execute_stream(startup, message, handler). Continue answering Health; cancel
and await your owned task on shutdown or primary-channel loss.
from collections.abc import AsyncGenerator, AsyncIterator
from skulk_capability_sdk.contracts import StreamInvoke
from skulk_capability_sdk.streams import StreamFrame
async def echo_stream(
call: StreamInvoke,
inputs: AsyncIterator[StreamFrame],
) -> AsyncGenerator[StreamFrame]:
sequence = 1
async for frame in inputs:
if frame.kind == "chunk":
yield StreamFrame(
call_id=call.call_id,
direction="provider_to_caller",
sequence=sequence,
kind="chunk",
payload=frame.payload,
media=frame.media,
)
sequence += 1
if frame.is_terminal:
break
yield StreamFrame(
call_id=call.call_id,
direction="provider_to_caller",
sequence=sequence,
kind="completed",
)
This bidirectional example requires matching input/output chunk schemas. Skulk™
owns output started at sequence zero. Your handler starts at one, emits exactly
one terminal, and returns. Cleanup finishes before the helper publishes the
terminal and private acknowledgment. Extra frames after a terminal are rejected.
Half-close, cancellation and bounds
Caller input completed carries no payload or media and half-closes input while output remains open. Caller
cancellation or disconnect cancels the invocation. Use try/finally for provider
resources and keep blocking work off the event loop. Provider output completion
stops input forwarding before cleanup closes the media connection.
- One active invocation per child, shared by all modes.
- One stream deadline, capped at 300 seconds by
Bounds.stream_seconds. - Each packet has a four-byte network-order header length, at most 64 KiB of finite JSON, then at most 1 MiB of raw inline media. Bytes never appear in JSON.
- Eight-frame ingress queues and awaited socket writes apply backpressure.
- The helper uses only the owner-provisioned
Startup.stream_socket, process token, installed identity, manifest digest and fresh local call identity. - Wrong identity, sequence, schema or framing fails the call. Failed processes follow normal supervision and restart budgets; work is never replayed.
- Media stays out of replicated State and event logs. Blob attachments remain immutable references; the bridge does not open caller-supplied files.
Deploy the compatible Skulk™ reader before enabling protocol-4 streaming bundles. Rebuild immutable runtimes with the compatible SDK and qualify signed installation separately from source tests. Protocol 3 unary children remain compatible for one release cycle; protocol 2 requires rebuilding.
The managed host callback channel is a fixed unary management interface. General Fabric clients use the public caller contract. This SDK's streaming interface serves those calls from managed children.