Rust SDK

sovereign-router — async Rust client for the Sovereign Frontier AIEM registry and SovereignRouter inference gateway. Built on reqwest + tokio; every chat response carries a cryptographically-attested provenance envelope.

Rust ≥ 1.75 crates.io: sovereign-router Apache-2.0 GitHub source ↗

Installation

Cargo.toml
[dependencies] sovereign-router = "0.1" tokio = { version = "1", features = ["macros", "rt-multi-thread"] } anyhow = "1"

Uses rustls-tls by default (no OpenSSL dependency). Requires Rust 1.75+ for the async fn in traits stabilisation.

Runtime: the SDK is async-only. Wrap calls in #[tokio::main] or your existing Tokio runtime.

Quickstart

rust
use sovereign_router::Client; #[tokio::main] async fn main() -> anyhow::Result<()> { let sr = Client::builder("https://router.example.com") .api_key("sk-router-...") .policy("default") .build()?; let reply = sr.chat() .model("qwen/qwen3-235b-a22b") .system("You are a helpful assistant.") .user("Explain Merkle trees.") .send().await?; println!("{}", reply.choices[0].message.content); println!("rekor_index: {}", reply.attestation.rekor_index); println!("tier: {}", reply.attestation.tier_observed); Ok(()) }

Client::builder

The Client is cheaply cloneable (Arc-wrapped internally) and safe to share across tasks.

Client::builder(base_url: impl Into<String>) → ClientBuilder
builder.api_key(k) → ClientBuilder
Tenant key sent as X-Router-Key header on all non-admin requests.
builder.policy(p) → ClientBuilder
Default routing policy. Can be overridden per ChatBuilder call.
builder.admin_token(t) → ClientBuilder
Bearer token for admin-gated endpoints (tenant/provider management).
builder.build() → Result<Client>
Construct the client. Fails only if the underlying reqwest::Client cannot be built (extremely rare).

chat() — ChatBuilder

sr.chat() returns a ChatBuilder. Chain setter methods then call .send().await for a single response, or .stream().await for an SSE stream.

sr.chat() → ChatBuilder
builder.model(m: impl Into<String>) → ChatBuilder
Required. Model identifier as registered in the AIEM registry.
builder.user(content) · .system(content) · .assistant(content) → ChatBuilder
Append a message with the given role. Call multiple times to build a conversation.
builder.max_tokens(n: u32) → ChatBuilder
builder.temperature(t: f32) → ChatBuilder
builder.policy(p) → ChatBuilder
Override the client-level default policy for this request.
builder.provider(p) → ChatBuilder
Pin to a specific provider ID, bypassing the router's selection logic.
builder.send().awaitResult<ChatResponse>
Execute the non-streaming request. Returns a ChatResponse including attestation.
example — multi-turn
let resp = sr.chat() .model("qwen/qwen3-235b-a22b") .system("Reply concisely.") .user("What is 2+2?") .assistant("4.") .user("Multiply that by 3.") .max_tokens(64) .send().await?; println!("{}", resp.choices[0].message.content);

stream() — SSE streaming

builder.stream().awaitResult<impl Stream<Item = Result<StreamEvent>>>
Returns an async Stream of StreamEvent items. Consume with futures_util::StreamExt::next() or while let. The final events are always FinishAttestationDone.
rust — streaming example
use futures_util::StreamExt; use sovereign_router::StreamEvent; let mut stream = sr.chat() .model("qwen/qwen3-235b-a22b") .user("Count to 10.") .stream().await?; while let Some(event) = stream.next().await { match event? { StreamEvent::Delta(text) => print!("{text}"), StreamEvent::Attestation(att) => { println!("\nrekor_index: {}", att.rekor_index); } StreamEvent::Done => break, _ => {} } }

Provider management

sr.list_providers().awaitResult<Vec<Provider>>
sr.register_provider(p: Provider).awaitResult<Provider> admin
Register a new inference provider. Requires admin_token.
sr.provider_health().awaitResult<HealthSnapshot>

Policy management

sr.list_policies().awaitResult<Vec<Policy>>
sr.get_policy(id: &str).awaitResult<Policy>

Tenant management

sr.create_tenant(req: CreateTenantRequest).awaitResult<Tenant> admin
Mint a new tenant and return the generated sk-router-... API key.
sr.list_tenants().awaitResult<Vec<Tenant>>
sr.get_tenant(id: &str).awaitResult<Tenant>
example — create tenant
use sovereign_router::CreateTenantRequest; let tenant = sr.create_tenant(CreateTenantRequest { id: "acme-corp".into(), display_name: "ACME Corp".into(), usd_cap: Some(500.0), requests_per_minute: 120, allowed_policies: vec!["default".into(), "clinical-strict".into()], }).await?; println!("api_key: {}", tenant.api_key);

Audit feed

sr.recent_calls(limit: usize).awaitResult<CallsResponse>
Recent inference call log with tenant, model, policy, and attestation metadata.

Supply-chain endpoints

sr.get_bom(category: &str, artifact_id: &str).awaitResult<Value>
SBOM + risk score for one artifact.
sr.list_suppliers().awaitResult<Value>
Ranked supplier roster with revocation and risk metadata.
sr.supply_chain_risk_summary().awaitResult<Value>
Fleet rollup by tier, risk band, and sanctioned-entity flags.
sr.firmware_receipt(category: &str, artifact_id: &str, build: Option<&str>).awaitResult<Value>
Offline-verifiable firmware receipt bundle. Pass build to pin to a specific build ID.

Types — chat

struct ChatResponse
pub struct ChatResponse { pub id: String, pub model: String, pub choices: Vec<Choice>, pub usage: Usage, pub attestation: Attestation, } pub struct Choice { pub index: u32, pub message: Message, pub finish_reason: String, } pub struct Message { pub role: String, pub content: String } pub struct Usage { pub prompt_tokens: u32, pub completion_tokens: u32, pub total_tokens: u32 }
struct Attestation
pub struct Attestation { pub model_content_hash: String, // SHA-256 of the model weights served pub provider_id: String, // provider that served the request pub policy_id: String, // routing policy applied pub route_decision_id: String, // unique ID for this routing decision pub rekor_index: i64, // Rekor transparency-log entry index pub mirror_id: String, // attested mirror that holds the weights pub tier_observed: String, // sealed | hardened | quarantine | interdicted }

Types — StreamEvent

pub enum StreamEvent { Role(String), // role announcement ("assistant") Delta(String), // incremental content chunk Finish(String), // finish_reason: "stop", "length", … Attestation(Attestation), // provenance envelope Done, // [DONE] sentinel — stream is exhausted }

Types — Provider

pub struct Provider { pub id: String, pub kind: String, // "openai-compatible" | "vllm" | … pub display_name: String, pub endpoint: String, pub serves_models: Vec<String>, pub region: Option<String>, pub cost_per_million_tokens_usd: Option<f64>, pub typical_latency_ms: Option<u64>, pub api_key_id: Option<String>, }

Types — Policy

pub struct Policy { pub id: String, pub display_name: String, pub require_tier: Option<String>, pub allowed_origins: Vec<String>, pub require_drift_clean: bool, pub max_latency_ms: Option<u64>, pub max_cost_per_request_usd: Option<f64>, pub preferred_providers: Vec<String>, }

Types — Tenant · CreateTenantRequest

pub struct Tenant { pub id: String, pub display_name: String, pub api_key: String, // sk-router-... key for this tenant pub usd_spent: f64, pub usd_cap: Option<f64>, pub allowed_policies: Vec<String>, pub requests_per_minute: u32, } pub struct CreateTenantRequest { pub id: String, pub display_name: String, pub usd_cap: Option<f64>, pub requests_per_minute: u32, pub allowed_policies: Vec<String>, }

Types — HealthSnapshot · ProviderHealth

pub struct HealthSnapshot { pub providers: Vec<ProviderHealth> } pub struct ProviderHealth { pub provider_id: String, pub successes: u64, pub failures: u64, pub latency_p50_ms: Option<u64>, pub latency_p95_ms: Option<u64>, pub last_error: Option<String>, pub score: f32, // 0.0 – 1.0 }

Error handling

All async methods return anyhow::Result<T>. HTTP errors are surfaced as anyhow::Error with the status code and response body in the message. Use anyhow::Context to add context.

example

Feature flags

default features: rustls-tls
TLS via rustls. No OpenSSL dependency — safe for static/musl builds.

To use native OpenSSL instead, disable default features and enable native-tls:

Cargo.toml
sovereign-router = { version = "0.1", default-features = false, features = ["native-tls"] }