Skip to content

C# Client API

The production client path is role-first and Rust-backed:

  1. Connect an NnrpClient to an application-facing NNRP endpoint.
  2. Open an NnrpClientSession.
  3. Submit operations or send typed Preview4 control/object frames.
  4. Consume results and runtime events.
  5. Close the session and client.

NnrpClient.ConnectAsync

csharp
public static ValueTask<NnrpClient> ConnectAsync(
    NnrpClientOptions options,
    CancellationToken cancellationToken = default);

The method validates the application endpoint, resolves registered providers, connects the selected provider, completes the NNRP handshake, and owns the resulting native connection. It fails instead of falling back to a managed protocol implementation.

NnrpClientOptions

PropertyTypeRequiredDescription
EndpointNnrpEndpointYesnnrp:// or nnrps:// application endpoint.
ProviderRoutesIReadOnlyDictionary<TransportId, NnrpClientProviderRoute>?NoPer-carrier locator and peer-verification configuration.
TransportPolicyTransportPolicyNoDefaults to Auto.
SessionDefaultsNnrpClientSessionOptions?NoDefaults merged into each opened session.

TCP and QUIC may derive their host and port from Endpoint. IPC and WebSocket routes require a matching unix://, npipe://, ws://, or wss:// locator. Auto/Prefer retains unresolved routes in candidate diagnostics and probes every viable route; Force fails without fallback.

NnrpClient.OpenSessionAsync

csharp
public ValueTask<NnrpClientSession> OpenSessionAsync(
    NnrpClientSessionOptions? options = null,
    CancellationToken cancellationToken = default);

NnrpClientSessionOptions contains only transport-neutral protocol intent. Native handles and generations are internal and never appear in this type.

PropertyTypeDefaultDescription
RequestedSessionIduint0Preferred wire session id; zero lets the server assign it.
ProfileIdushortStandard token profileRequested profile id.
SchemaIduintStandard token delta schemaRequested schema id.
SchemaVersionuintStandard token delta versionRequested schema version.
PriorityClassSessionPriorityClassBalancedSession scheduling class.
DefaultDeadlineMillisecondsuint500Default operation deadline.
MaxInFlightOperationsushort4Requested session concurrency ceiling.
LeaseTtlHintMillisecondsuint30000Requested cache lease lifetime.
AllowResumeboolfalseEnables resumable-session negotiation.
ResumeTokenBytesuint0Local recovery-token capacity; zero selects the runtime default.
CacheHintsIReadOnlyList<CacheObjectKind>EmptyCache kinds folded into the automatic connection hello.

The runtime derives wire flags, extension lengths, and the client session tag. ResumeTokenBytes does not create or carry a token on a fresh open, and CacheHints contributes to the connection hello before the first session opens.

Session Recovery

csharp
public ValueTask<NnrpClientSession> ResumeSessionAsync(
    NnrpSessionRecoveryTicket ticket,
    NnrpClientSessionOptions? options = null,
    CancellationToken cancellationToken = default);

NnrpClientSession.GetRecoveryTicket() returns the current runtime-issued NnrpSessionRecoveryTicket?. Applications may persist it with ToBytes() and restore it with NnrpSessionRecoveryTicket.FromBytes(ReadOnlySpan<byte>), but may not construct, inspect, truncate, or replace its opaque resume token.

PropertyTypeDescription
SessionIduintNon-zero runtime session id.
ResumeTokenReadOnlyMemory<byte>Non-empty opaque runtime proof.
ResumeFromOperationIdulong?Optional last confirmed operation id.
ResumeWindowMillisecondsuintNegotiated ticket validity window.

The persisted value is the canonical little-endian NRTK version 1 envelope. Decoding rejects wrong magic or version, reserved flags, zero ids, empty tokens, truncation, and trailing bytes.

Submission And Results

MethodReturnsSemantics
SubmitAsync(NnrpSubmitRequest, CancellationToken)ValueTask<NnrpResult>Submits and waits for the matching terminal result.
SubmitNoWaitAsync(NnrpSubmitRequest, CancellationToken)ValueTask<ulong>Submits and returns the non-zero operation ID.
NextResultAsync(CancellationToken)ValueTask<NnrpResult>Skips non-result events and returns the next terminal result.
NextEventAsync(CancellationToken)ValueTask<NnrpClientEvent>Returns the next runtime or lifecycle event in order for this session.

NnrpSubmitRequest carries a non-zero OperationId, independent FrameId, payload/tensor values, profile, schema and cache metadata, and submit mode. The role API owns packing and performs one coarse native submit call; callers never construct an FFI buffer.

NnrpClientEvent.Kind is Runtime or Lifecycle. Its Match<TResult>(Func<NnrpRuntimeEvent, TResult>, Func<NnrpOperationLifecycleEvent, TResult>) method requires both callbacks and exposes exactly one active value; lifecycle events never receive a fabricated wire header.

NnrpResult

PropertyTypeDescription
OperationIdulongNon-zero submitted operation identity.
TerminalStateNnrpResultTerminalStateSuccess, Cancelled, Dropped, or Error.
EventNnrpTerminalEventSealed Runtime or Lifecycle terminal-evidence value.

Successful results preserve ResultPush; non-success results preserve the exact wire or local lifecycle event that established the terminal state. NnrpTerminalEvent contains exactly one variant; the managed API never exposes nullable parallel event fields or fabricates headers.

NnrpTerminalEvent.Kind is Runtime or Lifecycle. Its Match<TResult>(Func<NnrpRuntimeEvent, TResult>, Func<NnrpOperationLifecycleEvent, TResult>) method requires both callbacks and exposes only the active value. A runtime terminal maps ResultPush to Success, ResultDrop and ResultDropReason to Dropped; ResultPushMetadata.StatusCode never selects the protocol terminal state. A lifecycle terminal maps Completed to Success, Cancelled to Cancelled, Superseded to Dropped, and Failed to Error.

NnrpOperationLifecycleEvent

PropertyTypeDescription
OperationIdulongNon-zero operation identity.
StateNnrpOperationStateExact local lifecycle state.

This is a local role notification. It never contains a fabricated RuntimeFrameHeader; native lifecycle records without a header remain separate from wire NnrpRuntimeEvent values.

Client Control Methods

Every method validates metadata/tail lengths and emits the named runtime frame through the active native session.

MethodMessageTail
CancelAsync(ControlRequestMetadata, ReadOnlyMemory<byte>, CancellationToken)CancelDiagnostic bytes
AbortAsync(ControlRequestMetadata, ReadOnlyMemory<byte>, CancellationToken)AbortDiagnostic bytes
UpdatePriorityAsync(SchedulingMetadata, CancellationToken)PriorityUpdateNone
UpdateDeadlineAsync(SchedulingMetadata, CancellationToken)DeadlineNone
ExpireAtAsync(SchedulingMetadata, CancellationToken)ExpireAtNone
SupersedeAsync(SupersedeMetadata, ReadOnlyMemory<byte>, CancellationToken)SupersedeDiagnostic bytes
UpdateBudgetAsync(BudgetMetadata, CancellationToken)BudgetUpdateNone
NegotiateCapabilitiesAsync(CapabilityMetadata, ReadOnlyMemory<byte>, CancellationToken)CapabilityNegotiationCapability entries
DegradeProfileAsync(CapabilityMetadata, ReadOnlyMemory<byte>, CancellationToken)DegradeProfileCapability entries
SendRouteHintAsync(RouteHintMetadata, ReadOnlyMemory<byte>, CancellationToken)RouteHintTyped hint body
SendExecutionHintAsync(RouteHintMetadata, ReadOnlyMemory<byte>, CancellationToken)ExecutionHintTyped hint body
SendTraceContextAsync(TraceContextMetadata, ReadOnlyMemory<byte>, ulong?, CancellationToken)TraceContextTrace attributes; null operation is session scope
SendControlAsync(MessageType, IRuntimeControlMetadata, ReadOnlyMemory<byte>, CancellationToken)Any client-sendable runtime controlDeclared tail

SendControlAsync is a typed escape hatch. It rejects metadata whose concrete type does not match MessageType.

Client Object And Cache Methods

MethodMessageTail
DeclareObjectAsync(ObjectDescriptorMetadata, ReadOnlyMemory<byte>, CancellationToken)ObjectDeclareObject metadata
ReferenceObjectAsync(ObjectReferenceMetadata, ReadOnlyMemory<byte>, CancellationToken)ObjectRefReference metadata
ReleaseObjectAsync(ObjectReleaseMetadata, ReadOnlyMemory<byte>, CancellationToken)ObjectReleaseDiagnostic bytes
PatchObjectAsync(ObjectDeltaMetadata, ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, CancellationToken)ObjectPatchMetadata body, then delta
SendObjectDeltaAsync(ObjectDeltaMetadata, ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, CancellationToken)ObjectDeltaMetadata body, then delta
ReferenceCacheAsync(CacheReferenceMetadata, ReadOnlyMemory<byte>, CancellationToken)CacheReferenceCache metadata
ReportCacheMissAsync(CacheMissMetadata, ReadOnlyMemory<byte>, CancellationToken)CacheMissDiagnostic bytes
InvalidateCacheAsync(CacheInvalidateMetadata, CancellationToken)CacheInvalidateNone

Object and cache methods never perform implicit cache lookup or JSON serialization.

Cancellation And Late Results

After cancel or abort reaches terminal state, normal result iteration suppresses late RESULT_PUSH and PARTIAL_RESULT frames for that operation. RESULT_DROP_REASON remains observable so callers can diagnose the discarded result.

Shutdown

NnrpClientSession and NnrpClient implement IAsyncDisposable. Session disposal closes its native session and releases in-flight state. Client disposal closes owned sessions, the role connection, and the selected provider runtime.

Managed packet/session helpers over INnrpMessageTransport belong to diagnostics and custom carrier integrations; they are not aliases for this production API.

NNRP Documentation