Skip to content

Python — Server API

The server API starts at session acceptance: accept a transport connection, receive frame submits, send results or drops, then close. Message and packet pages remain the low-level reference.

Imports

python
from nnrp.server import (
    ServerProfile,
    ServerSession,
    ServerSessionAcceptResolution,
    ReceivedSubmit,
    accept_server_connection,
    accept_server_session,
)

Server Workflow

  1. Create a ServerProfile.
  2. Open a listener with a transport adapter, such as serve_tcp or serve_quic.
  3. Call accept_server_session for each listener, or accept_server_connection when a runtime already accepted the connection or prefetched the first control packet.
  4. Loop on ServerSession.receive_submit.
  5. Send one response per frame with send_result or send_result_drop.
  6. Close the session when the peer disconnects or the application rejects further work.

NativeRuntimeServerSession Preview4 Frames

Native server hosts use the same role-neutral runtime-frame ABI as clients. The server session exposes these application-facing methods:

MethodMessage
send_progress(metadata, body=b"")PROGRESS
send_partial_result(metadata, body=b"")PARTIAL_RESULT
send_backpressure(metadata), send_credit_update(metadata)pressure messages
send_result_drop_reason(metadata, diagnostic=b"")RESULT_DROP_REASON
send_trace_context(metadata, body=b"")TRACE_CONTEXT
send_recoverable_error(metadata, diagnostic=b""), send_retry_after(...)recovery messages
declare_object, reference_object, release_objectobject lifecycle messages
patch_object, send_object_deltaobject update messages
reference_cache, report_cache_miss, invalidate_cachecache messages

poll_runtime_frames() and iter_runtime_frames() return the decoded NativeRuntimeFrameEvent. No application-facing server method accepts a raw control_code.

accept_server_session

Accepts a connection, validates CLIENT_HELLO, sends SERVER_HELLO_ACK, and returns an active ServerSession.

ParameterTypeRequiredValues / RangeDescription
listenerServerListenerYesOpen listenerQUIC/TCP listener.
session_idint | NoneNoDefaults to the requested idServer-assigned or overridden session id.
active_model_namestrNoDefaults to ""Retained on ServerSession.active_model_name; not written into the SERVER_HELLO_ACK body.
server_profileServerProfileNoDefaults to ServerProfile()Server capabilities and limits.
timeoutfloatNoSeconds, default 10.0Accept and handshake receive timeout.
session_resolverCallable[[ClientHelloContext], ServerSessionAcceptResolution | Awaitable[...]] | NoneNoDefaults to NoneResolves the final session_id and active_model_name after parsing CLIENT_HELLO.
ReturnsRaises
ServerSessionTransport errors, auth rejection, malformed handshake, or capability rejection.
python
session = await accept_server_session(
    listener,
    server_profile=ServerProfile(max_concurrent_frames=4),
    active_model_name="render-v1",
)

accept_server_connection

Runs the server-side handshake on an already accepted transport connection. Use this entrypoint when a runtime owns the accept loop, handles TRANSPORT_PROBE first, or has already prefetched the first control packet.

ParameterTypeRequiredValues / RangeDescription
connectionServerConnectionYesAccepted connectionQUIC/TCP connection.
first_packetNnrpPacket | NoneNoDefaults to NonePrefetched CLIENT_HELLO; when omitted the SDK reads it.
session_idint | NoneNoDefaults to the requested idUsed when session_resolver is not provided.
active_model_namestrNoDefaults to ""Application-visible model name retained on ServerSession.
server_profileServerProfileNoDefaults to ServerProfile()Server capabilities and limits.
timeoutfloatNoSeconds, default 10.0Handshake receive timeout.
session_resolverCallable[[ClientHelloContext], ServerSessionAcceptResolution | Awaitable[...]] | NoneNoDefaults to NoneResolves the server session from the parsed CLIENT_HELLO.

Both accept_server_connection and accept_server_session construct SERVER_HELLO_ACK inside the SDK. The Preview3 SDK writes a control_extension_block into the ACK body, including at least the transport policy ack extension that declares active_transport_id. control_extension_bytes must match the ACK body length; application model names, runtime session ids, or other business state must not be encoded into the ACK body.

python
def resolve_session(hello):
    requested_model = hello.auth_block.decode("utf-8") if hello.auth_block else ""
    opened = open_runtime_session(requested_model)
    return ServerSessionAcceptResolution(
        session_id=opened.wire_session_id,
        active_model_name=opened.active_model_name,
    )

session = await accept_server_connection(
    connection,
    first_packet=client_hello_packet,
    server_profile=ServerProfile(max_concurrent_frames=4),
    session_resolver=resolve_session,
)

ServerSession

An established server-side session.

ServerSession.receive_submit

Receives the next FRAME_SUBMIT and parses it into a structured request.

ParameterTypeRequiredValues / RangeDescription
timeoutfloat | NoneNoSeconds; None disables timeoutMaximum wait for a submit frame.
ReturnsRaises
ReceivedSubmitasyncio.TimeoutError, malformed packet, session mismatch, unsupported wire format.
python
received = await session.receive_submit(timeout=30.0)

ServerSession.send_result

Pushes an inference result for a received frame.

ParameterTypeRequiredValues / RangeDescription
frame_idintYesFrame id from ReceivedSubmitCorrelates the result with the client request.
tile_idstuple[int, ...]NoDefaults to emptyResult tile ids.
sectionstuple[TensorSectionData, ...]NoDefaults to emptyTensor result sections.
typed_payloadstuple[TypedPayload, ...]NoDefaults to emptyNon-tensor result payloads.
result_classResultClassNoDefaults to COMPLETECompleteness classification.
applied_budget_policyBudgetPolicyNoDefaults to NONEActual degradation policy applied by the server.
inference_msintNoMillisecondsModel execution time.
queue_msintNoMillisecondsQueue wait time.
server_total_msintNoMillisecondsTotal server-side time.
status_codeintNoApplication-definedResult status detail.
trace_idintNo0..2^64-1Trace id echoed in the packet header.
ReturnsRaises
int total bytes sentSerialization or transport errors.
python
await session.send_result(
    frame_id=received.metadata.frame_id,
    sections=run_inference(received.request),
    result_class=ResultClass.COMPLETE,
)

ServerSession.send_result_drop

Notifies the client that a submitted frame will not produce a result.

ParameterTypeRequiredValues / RangeDescription
frame_idintYesSubmitted frame idFrame to drop.
reasonintNoApplication-definedDrop reason code when supported by the current message shape.
ReturnsRaises
int total bytes sentSerialization or transport errors.
python
if queue_is_full:
    await session.send_result_drop(frame_id=received.metadata.frame_id)

ServerSession.send_flow_update

Sends backpressure or credit information to the client.

ParameterTypeRequiredValues / RangeDescription
metadataFlowUpdateMetadataYesSee message typesFlow-control metadata to serialize.
ReturnsRaises
int total bytes sentSerialization or transport errors.
python
await session.send_flow_update(flow_update_metadata)

ServerSession.close

Closes the server session and transport.

ParameterTypeRequiredValues / RangeDescription
None---No parameters.
ReturnsRaises
NoneTransport close errors.
python
await session.close()

Core Types

ServerProfile

Server-side capabilities and limits.

FieldTypeDefaultDescription
max_concurrent_framesint1Advertised in-flight frame limit.
enable_cacheboolTrueEnables cache negotiation.
max_sectionsint16Maximum tensor sections per frame.
max_body_bytesint33554432Maximum request body size.

ReceivedSubmit

Parsed frame submission.

FieldTypeDescription
packetNnrpPacketRaw FRAME_SUBMIT packet.
metadataFrameSubmitMetadataParsed frame metadata.
requestSubmitRequestStructured submit request.
tensor_bodyTensorBodyView | NoneParsed tensor body view when present.

ClientHelloContext

Handshake context retained on the server session.

FieldTypeDescription
packetNnrpPacketRaw CLIENT_HELLO packet.
metadataClientHelloMetadataParsed handshake metadata.
auth_blockbytesApplication-defined auth payload.
control_extensionstuple[ControlExtensionEntry, ...]Handshake extensions.

ServerSessionAcceptResolution

Return value for session_resolver.

FieldTypeDescription
session_idintFinal wire session id accepted by the server.
active_model_namestrApplication-visible active model name; it is not encoded into the ACK body.

Example

python
async def handle_session(session: ServerSession) -> None:
    try:
        while True:
            received = await session.receive_submit(timeout=30.0)
            sections = await run_inference_async(received.request)
            await session.send_result(
                frame_id=received.metadata.frame_id,
                sections=sections,
                result_class=ResultClass.COMPLETE,
            )
    finally:
        await session.close()

Common Pitfalls

WARNING

  1. Do not run blocking inference inside the receive coroutine; use an executor or worker pool.
  2. Every accepted frame needs a result or a drop. Silent drops leave clients waiting.
  3. ServerProfile.max_concurrent_frames is a protocol limit, not a full application scheduler.
  4. Runtime integrations should not construct SERVER_HELLO_ACK manually; use accept_server_connection(first_packet=...) when the first packet has already been read.

NNRP Documentation