π¦ @noxy-network/rust-sdk
SDK for AI agent runtimes integrating with the Noxy Decision Layer: send encrypted, actionable decision payloads (tool proposals, approvals, next-step hints) to registered agent devices over gRPC.
Before you integrate: Create your app at noxy.network. When the app is created, you receive an app id and an app token (auth token). This Rust SDK authenticates with the relay using the app token (auth_token in NoxyConfig). The app id is used by client SDKs (browser, iOS, Android, Telegram bot), not as the bearer token here.
Overview
Use this SDK to:
- Route decisions to devices bound to a Web3 identity (
0xβ¦address) β structured JSON you define (e.g. proposed tool calls, parameters, user-visible summaries). - Receive delivery outcomes from the relay (
DELIVERED,QUEUED,NO_DEVICES, etc.) plus adecision_idwhen the relay accepts the route. - Wait for human-in-the-loop resolution β the wallet user approves, rejects, or the decision expires. The usual path is
send_decision_and_wait_for_outcome(route + poll in one step). Useget_decision_outcome/wait_for_decision_outcomealone for finer control. - Query quota for your agent application on the relay.
- Resolve identity devices so each device receives its own encrypted copy of the decision.
The wire API uses agent.proto (noxy.agent.AgentService): RouteDecision, GetDecisionOutcome, GetQuota, GetIdentityDevices.
Communication is gRPC over TLS with Bearer authentication. Payloads are encrypted end-to-end (Kyber + AES-256-GCM) per device before leaving your process; the relay sees ciphertext only.
Architecture
The encrypted path covers SDK β relay and relay β device: decision content is ciphertext on both hops; the relay forwards without decrypting.
Ciphertext only (E2E) Ciphertext only (E2E)
ββββββββββββββββββββ gRPC (TLS) βββββββββββββββββββ gRPC (TLS) ββββββββββββββββββββ
β AI agent / β βββββββββββββββββββΊ β Noxy relay β ββββββββββββββββββββΊ β Agent device β
β orchestrator β RouteDecision β (Decision β β (human approves β
β (this SDK) β GetDecisionOutcomeβ Layer) β β or rejects) β
β β GetQuota β forwards only β β decrypts β
β β GetIdentityDevicesβ β β β
ββββββββββββββββββββ βββββββββββββββββββ ββββββββββββββββββββ
Requirements
- Rust >= 1.70
- Tokio async runtime
Installation
[]
= "2.0"
= { = "1", = ["rt-multi-thread", "macros"] }
= "1"
Quick start
Route a decision and wait until the user approves, rejects, or the decision expires (one call):
use ;
async
resolution.outcome is a NoxyHumanDecisionOutcome. Approved β continue; anything else β stop or fallback. Use is_terminal_human_outcome(outcome) for βfinalized vs still pendingβ; for one-off get_decision_outcome polls, also read pending.
Configuration
| Option | Type | Required | Description |
|---|---|---|---|
endpoint |
String |
Yes | Relay gRPC endpoint (e.g. https://relay.noxy.network). https:// is stripped; TLS is used. |
auth_token |
String |
Yes | Bearer token for relay auth (Authorization header). |
decision_ttl_seconds |
u32 |
Yes | TTL for routed decisions (seconds). |
SendDecisionAndWaitOptions
Optional third argument to send_decision_and_wait_for_outcome.
| Option | Type | Required | Description |
|---|---|---|---|
initial_poll_interval_ms |
Option<u64> |
No | Delay after the first poll before the next attempt (ms). Default 400. |
max_poll_interval_ms |
Option<u64> |
No | Maximum delay between polls (ms). Default 30000. |
max_wait_ms |
Option<u64> |
No | Total time budget for polling (ms). Default 900000 (15 minutes). Exceeded β WaitForDecisionOutcomeTimeoutError. |
backoff_multiplier |
Option<f64> |
No | Multiplier applied to the poll interval after each attempt. Default 1.6. |
API
init_noxy_agent_client(config) -> Result<NoxyAgentClient, Error>
Async init (establishes gRPC + Kyber for post-quantum encapsulation).
NoxyAgentClient
send_decision(identity_address, actionable_decision)
Routes an encrypted decision to every device registered for the identity.
- Returns per device: relay
status,request_id, anddecision_idwhen applicable.
get_decision_outcome(decision_id, identity_id)
Single poll for human-in-the-loop state (pending + outcome).
send_decision_and_wait_for_outcome(identity_address, actionable_decision, options?)
Runs send_decision, then wait_for_decision_outcome using the first delivery with a non-empty decision_id. Polling uses identity_address as identity_id.
- Returns
NoxyGetDecisionOutcomeResponse. Errors withSendDecisionAndWaitNoDecisionIdErrorif nodecision_idwas returned (boxedError).
wait_for_decision_outcome(options)
Polls with exponential backoff until terminal outcome, pending == false, or max_wait_ms β WaitForDecisionOutcomeTimeoutError.
get_quota()
Quota usage for the application.
Helpers (re-exported)
is_terminal_human_outcomeWaitForDecisionOutcomeTimeoutError,SendDecisionAndWaitNoDecisionIdError
Types
NoxyDeliveryStatus:Delivered|Queued|NoDevices|Rejected|ErrorNoxyHumanDecisionOutcome:Pending|Approved|Rejected|ExpiredNoxyQuotaStatus:QuotaActive|QuotaSuspended|QuotaDeleted
Encryption (summary)
- Kyber768 encapsulation per device
pq_public_key. - HKDF-SHA256 β AES-256-GCM key; random 12-byte nonce.
- JSON payload encrypted; only
kyber_ct,nonce,ciphertextcross the relay.
License
MIT