iRoute.Sdk 0.1.0-alpha.3

This is a prerelease version of iRoute.Sdk.
dotnet add package iRoute.Sdk --version 0.1.0-alpha.3
                    
NuGet\Install-Package iRoute.Sdk -Version 0.1.0-alpha.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="iRoute.Sdk" Version="0.1.0-alpha.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="iRoute.Sdk" Version="0.1.0-alpha.3" />
                    
Directory.Packages.props
<PackageReference Include="iRoute.Sdk" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add iRoute.Sdk --version 0.1.0-alpha.3
                    
#r "nuget: iRoute.Sdk, 0.1.0-alpha.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package iRoute.Sdk@0.1.0-alpha.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=iRoute.Sdk&version=0.1.0-alpha.3&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=iRoute.Sdk&version=0.1.0-alpha.3&prerelease
                    
Install as a Cake Tool

iRoute .NET SDK

iRoute.Sdk is the typed .NET client for the iRoute v1 HTTP and SSE API. It uses the public contracts from iRoute.Contracts and supports asynchronous execution, polling, event streaming, cancellation, approvals, artifacts, gateway health, and observability.

Routing, provider selection, memory, validation, workflow retries, and fallback remain server-side.

Status and requirements

  • SDK version: 0.1.0-alpha.1
  • Verified baseline: .NET 10 / C# 14
  • Package ID: iRoute.Sdk
  • License: Apache-2.0

Once published, the public alpha is installed from NuGet as a prerelease package. The source installation below remains available.

Start iRoute

From the repository root, start the complete local API and worker:

docker compose --file deploy/compose.sqlite.yaml up --build --wait

The default URL is http://localhost:8080. See the shared SDK usage guide for source-run and authentication options.

Install from NuGet

dotnet add package iRoute.Sdk --version 0.1.0-alpha.1

Install from source

Reference the SDK project from your application:

dotnet add MyApp.csproj reference ../iRoute/src/iRoute.Sdk.DotNet/iRoute.Sdk.DotNet.csproj

Or build and consume a local package:

dotnet pack ../iRoute/src/iRoute.Sdk.DotNet \
  --configuration Release \
  --output ../packages
dotnet add MyApp.csproj package iRoute.Sdk \
  --version 0.1.0-alpha.1 \
  --source ../packages

Adjust paths for your checkout.

Create a client

using iRoute.Sdk.DotNet;

using var http = new HttpClient
{
    BaseAddress = new Uri(
        Environment.GetEnvironmentVariable("IROUTE_URL")
        ?? "http://localhost:8080"),
    Timeout = TimeSpan.FromSeconds(30)
};

var client = new IRouteClient(http, new IRouteClientOptions(
    TenantId: Environment.GetEnvironmentVariable("IROUTE_TENANT") ?? "demo",
    ActorId: Environment.GetEnvironmentVariable("IROUTE_ACTOR") ?? "dotnet-app",
    PermissionScopes: [],
    BearerToken: Environment.GetEnvironmentVariable("IROUTE_TOKEN")));

In Development, tenant, actor, and permission options become headers. In JWT mode the server derives identity and scopes from token claims and will not allow headers to elevate them.

Submit an execution

using System.Text.Json;
using iRoute.Contracts;

using var input = JsonDocument.Parse("""
    {"purpose":"Confirm the .NET SDK integration."}
    """);

var request = new TaskRequest(
    TaskType: "email.draft",
    Input: input.RootElement.Clone(),
    IdempotencyKey: "dotnet-email-001",
    Constraints: new TaskConstraints(
        MaxOutputTokens: 500,
        DeadlineMilliseconds: 30_000,
        MinimumQuality: 0.8m));

var snapshot = await client.ExecuteAsync(request);

Console.WriteLine($"{snapshot.ExecutionId}: {snapshot.Status}");

Keep the same idempotency key when retrying the same logical request. A queued submission normally returns immediately with HTTP 202.

Poll until terminal

The SDK intentionally leaves polling policy to the application:

static bool IsTerminal(ExecutionStatus status) => status is
    ExecutionStatus.Succeeded or
    ExecutionStatus.Failed or
    ExecutionStatus.Cancelled or
    ExecutionStatus.TimedOut;

using var deadline = new CancellationTokenSource(TimeSpan.FromMinutes(2));

while (!IsTerminal(snapshot.Status))
{
    await Task.Delay(TimeSpan.FromMilliseconds(500), deadline.Token);
    snapshot = await client.GetAsync(snapshot.ExecutionId, deadline.Token)
        ?? throw new InvalidOperationException("Execution is not visible to this tenant.");
}

if (snapshot.Status == ExecutionStatus.Succeeded)
{
    Console.WriteLine(snapshot.Outcome!.Output);
}
else
{
    Console.Error.WriteLine($"{snapshot.Error?.Code}: {snapshot.Error?.Detail}");
}

WaitingForApproval is non-terminal and requires a decision before processing can resume.

Stream and reconnect to events

StreamEventsAsync reads SSE incrementally. Persist the last processed sequence and pass it back when reconnecting:

long lastSequence = 0;

await foreach (var executionEvent in client.StreamEventsAsync(
    snapshot.ExecutionId,
    afterSequence: lastSequence,
    cancellationToken: deadline.Token))
{
    Console.WriteLine($"{executionEvent.Sequence} {executionEvent.Type}");
    lastSequence = executionEvent.Sequence;
}

Unknown event types and fields must be ignored. A terminal execution closes its replay stream after all newer events are sent.

Cancel an execution

var accepted = await client.CancelAsync(snapshot.ExecutionId);
if (!accepted)
{
    Console.WriteLine("Execution was not found.");
}

Cancellation is durable but cooperative. A running worker observes it through its heartbeat; a later snapshot confirms the terminal state.

Approve or deny an action

Read the durable actionId from an approval.required event, then submit a decision:

var result = await client.SubmitApprovalAsync(
    snapshot.ExecutionId,
    new ApprovalDecision(
        ActionId: actionId,
        Approved: true,
        Reason: "Reviewed by the operator"));

snapshot = result.Execution;

The deciding identity needs approval:grant and the action's required scope. Never invent or reuse an action ID from another execution.

Retrieve an artifact

var artifactReference = snapshot.Outcome?.Artifacts.FirstOrDefault();
if (artifactReference is not null)
{
    var artifact = await client.GetArtifactAsync(artifactReference.ArtifactId);
    Console.WriteLine(artifact?.Content);
}

Not found returns null, including for cross-tenant access.

Health and observability

var gateway = await client.GetModelGatewayHealthAsync();
Console.WriteLine($"{gateway.GatewayId}: {gateway.Status}");

var summary = await client.GetObservabilitySummaryAsync(
    new ObservabilityQueryOptions(
        From: DateTimeOffset.UtcNow.AddHours(-24),
        To: DateTimeOffset.UtcNow,
        TaskType: "email.draft"));
Console.WriteLine($"observed={summary.Totals.Executions}");

var timeline = await client.GetExecutionTimelineAsync(snapshot.ExecutionId);
Console.WriteLine(timeline?.TraceId);

Gateway health returns a typed body for both HTTP 200 and 503. Observability is tenant scoped. Reported cost has no currency in the v1 contract.

Errors, timeouts, and cancellation

HTTP problem details are mapped to IRouteApiException:

try
{
    snapshot = await client.ExecuteAsync(request, deadline.Token);
}
catch (IRouteApiException error)
{
    var status = error.StatusCode is { } statusCode ? (int)statusCode : 0;
    Console.Error.WriteLine(
        $"HTTP {status} {error.Code}: {error.Detail}");
    Console.Error.WriteLine(error.ResponseBody);
}
catch (OperationCanceledException) when (deadline.IsCancellationRequested)
{
    Console.Error.WriteLine("Client deadline elapsed.");
}

Configure transport timeout on HttpClient and operation cancellation with a CancellationToken. The SDK does not automatically retry. Retrying a submission requires the same idempotency key.

Method reference

Method Result
ExecuteAsync(TaskRequest) ExecutionSnapshot
GetAsync(Guid) Snapshot or null
CancelAsync(Guid) false when not found
SubmitApprovalAsync(Guid, ApprovalDecision) ApprovalResult
StreamEventsAsync(Guid, long) Incremental IAsyncEnumerable<ExecutionEvent>
GetArtifactAsync(Guid) Artifact or null
GetModelGatewayHealthAsync() ModelGatewayHealth
GetObservabilitySummaryAsync(...) ObservabilitySummary
GetExecutionTimelineAsync(Guid) Timeline or null

Run the example and tests

dotnet run --project examples/sdks/dotnet
dotnet run --project tests/iRoute.UnitTests -- -reporter quiet

Public wire shapes are defined by the repository's OpenAPI document and JSON Schemas.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0-alpha.3 75 8/18/2026
0.1.0-alpha.2 71 8/3/2026

Adds typed model-profile provenance fields to the v1 protocol client.