Skip to navigation

Rust Worker

View as Markdown

The examples/rust-grpc-worker-plugin project is the compiled counterpart to the Python worker. It depends on nemo-relay-worker 0.11.0, implements WorkerPlugin, registers all 16 surfaces, and lets the SDK create the authenticated grpc-v1 server from the activation environment Relay provides.

Internal Diagnostic Observations

Use runtime.diagnostics().await to obtain diagnostics for the activation. The SDK negotiates delivery once and reuses the host’s selected context. It does not create a worker-local store or enable diagnostic collection.

This example matches the Rust native and Python worker example. Register its component once from asynchronous code, then retain it for later lookups. WorkerPlugin::register is synchronous. Capture the runtime and shared state in an asynchronous callback, then initialize the helper once with a Tokio OnceCell. Cache initialization failure as well to avoid repeated registration attempts. It declares separate failure and success codes, records positive occurrence counts, and attaches a request ID. Call the failure helper only after observing an unavailable backend. Call the success helper only after a completed lookup.

Lookup diagnostics
use nemo_relay_worker::PluginRuntime;
use nemo_relay_worker::diagnostics::{
DiagnosticComponent, DiagnosticDeliveryError, DiagnosticExtensionDefinition,
DiagnosticObservation, DiagnosticObservationOutcome as Outcome,
DiagnosticObservationSeverity as Severity, WorkerDiagnostics, extension_code,
};
/// Register the lookup vocabulary once for this activation.
pub async fn register_lookup_diagnostics(
runtime: &PluginRuntime,
) -> Result<(WorkerDiagnostics, DiagnosticComponent), DiagnosticDeliveryError> {
let diagnostics = runtime.diagnostics().await.clone();
let component = diagnostics
.component(
"example.lookup",
vec![
extension_code(DiagnosticExtensionDefinition {
name: "lookup_failed".into(),
description: "The lookup backend was unavailable".into(),
outcome: Outcome::Failure as i32,
allowed_failure_classes: vec!["unavailable".into()],
}),
extension_code(DiagnosticExtensionDefinition {
name: "lookup_completed".into(),
description: "A lookup completed".into(),
outcome: Outcome::Success as i32,
allowed_failure_classes: vec![],
}),
],
)
.await?;
Ok((diagnostics, component))
}
/// Record a lookup whose backend is known to be unavailable.
pub fn record_lookup_failure(
component: &DiagnosticComponent,
request_id: &str,
) -> Result<(), DiagnosticDeliveryError> {
component.try_record_lazy(|| DiagnosticObservation {
code: 1,
count: 1,
outcome: Outcome::Failure as i32,
severity: Severity::Error as i32,
failure_class: Some("unavailable".into()),
detail: Some("The lookup backend was unavailable".into()),
request_id: Some(request_id.into()),
..Default::default()
})
}
/// Record an independently observed successful lookup.
pub fn record_lookup_success(
component: &DiagnosticComponent,
request_id: &str,
) -> Result<(), DiagnosticDeliveryError> {
component.try_record_lazy(|| DiagnosticObservation {
code: 2,
count: 1,
outcome: Outcome::Success as i32,
severity: Severity::Info as i32,
detail: Some("A lookup completed".into()),
request_id: Some(request_id.into()),
..Default::default()
})
}

Handle registration and recording failures separately from execution failures. Rust returns DiagnosticDeliveryError variants. The helpers expose those errors so the caller can apply its delivery policy. Do not propagate an optional diagnostic failure as the lookup’s result.

try_record_lazy returns Ok(()) after local queue admission. It does not return a host acceptance receipt. An inactive component returns without recording. Disabled or unsupported collection skips the observation factory. A full queue also skips the factory. diagnostics.availability() reports negotiated availability.

Check diagnostics.delivery_stats() for dropped, rejected, and uncertain work. Use diagnostics.flush(Duration).await to wait for earlier queue work. The timeout is a std::time::Duration. Flush does not return per-record receipts or acknowledge disk storage. Never replay uncertain observations into a new session.

Use component.close().await when the component’s work ends. SDK shutdown limits diagnostic drain time and closes delivery tasks. Explicit delivery shutdown uses diagnostics.close(Duration).await. Canonical snapshot and memory reads are not available to workers, even when a native plugin has a read grant.

Refer to Plugin Diagnostics for the shared pattern, built-in code declarations, and native/worker API differences. The delivery protocol defines host limits, retries, and session authority.

Configure the Snapshot Location

Relay copies the worker runtime closure into an isolated activation snapshot before starting the worker. Set NEMO_RELAY_PLUGIN_SNAPSHOT_DIR in the environment that starts Relay to use a directory of your choice; Relay creates it when it does not exist. Choose a location outside every directory copied into a snapshot, including active plugin packages and external library directories:

$env:NEMO_RELAY_PLUGIN_SNAPSHOT_DIR = "C:\\nrs"
export NEMO_RELAY_PLUGIN_SNAPSHOT_DIR=/var/tmp/nrs

Build and Calculate Integrity

Build the executable and materialize its platform-specific manifest as follows:

  1. Run the example from its own directory.

    cargo nextest run
    cargo build
  2. Copy relay-plugin.toml to relay-plugin.local.toml and replace <platform-worker-file> with nemo-relay-rust-grpc-worker-plugin-example on macOS or Linux, or the same name with .exe on Windows.

  3. Calculate the promised digest before registration. On macOS run:

    shasum -a 256 target/debug/<platform-worker-file>

    On Linux run sha256sum target/debug/<platform-worker-file>. In PowerShell run Get-FileHash -Algorithm SHA256 target/debug/<platform-worker-file>. Put the lowercase hexadecimal value after sha256: in [integrity].sha256.

Success at this stage means tests pass, the manifest entrypoint resolves to the built executable, and integrity describes the exact executable that starts.

The local manifest retains the checked package identity and replaces only the executable name and digest placeholders:

manifest_version = 1
[plugin]
id = "examples.rust_grpc_worker"
kind = "worker"
[compat]
relay = ">=0.10.0,<1.0"
worker_protocol = "grpc-v1"
[defaults]
enabled = false
[capabilities]
items = ["plugin_worker", "config_schema"]
[config_schema]
path = "config.schema.json"
[source]
artifact = "target/debug/<platform-worker-file>"
[integrity]
sha256 = "sha256:<artifact-sha256>"
[load]
runtime = "rust"
entrypoint = "target/debug/<platform-worker-file>"

The manifest requires Relay 0.10 because this worker uses the context-aware tool execution contract and the LlmExecutionContext callback shape. The protocol identifier remains grpc-v1. ToolNext::call returns ToolExecutionResult, preserving an application payload and optional opaque annotation separately from Relay-owned pending marks. Rebuild the worker when adopting this SDK release.

The artifact and entrypoint paths must identify the same executable. Relay verifies the artifact digest before it starts the command, and the worker handshake must return the same plugin identity and grpc-v1 protocol.

Register and Start the Worker

Use the following procedure to register the manifest and inspect worker activation:

  1. From the repository root, validate, add, and enable the local manifest.

    nemo-relay plugins validate ./examples/rust-grpc-worker-plugin/relay-plugin.local.toml
    nemo-relay plugins add --user ./examples/rust-grpc-worker-plugin/relay-plugin.local.toml
    nemo-relay plugins enable examples.rust_grpc_worker
  2. Start Relay from the repository root. Inspect the activation report and confirm the handshake reports plugin identity, SDK and runtime metadata, grpc-v1, multiple-component behavior, and all 16 surfaces.

    nemo-relay --bind 127.0.0.1:4040

Build the Worker Implementation

The example uses the current public worker crate and creates both a library for focused tests and the executable named in the manifest.

[package]
name = "nemo-relay-rust-grpc-worker-plugin-example"
version = "0.1.0"
edition = "2024"
publish = false
[dependencies]
futures-util = "0.3"
nemo-relay-worker = { version = "0.11.0", path = "../../crates/worker" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
[lib]
name = "nemo_relay_rust_grpc_worker_plugin_example"
[[bin]]
name = "nemo-relay-rust-grpc-worker-plugin-example"
path = "src/main.rs"

WorkerPlugin::register is a synchronous description step. It parses the validated JSON and fills the PluginContext with callbacks; the callbacks themselves return futures.

pub struct DocumentationWorker;
impl WorkerPlugin for DocumentationWorker {
fn plugin_id(&self) -> &str {
"examples.rust_grpc_worker"
}
fn allows_multiple_components(&self) -> bool {
false
}
fn validate(&self, config: &Json) -> Vec<ConfigDiagnostic> {
config::validate(config)
}
fn register(&self, context: &mut PluginContext, config: &Json) -> Result<()> {
let settings = ExampleConfig::parse(config)
.map_err(WorkerSdkError::InvalidInput)?;
if settings.observe.enabled {
register_observation(context, &settings);
}
if settings.requests.enabled {
register_requests(context, &settings);
}
register_execution(context, &settings);
Ok(())
}
}

The binary contains no transport configuration. serve_plugin reads the activation environment, starts the authenticated SDK service, and stays alive until Relay sends the shutdown stage.

use nemo_relay_rust_grpc_worker_plugin_example::DocumentationWorker;
use nemo_relay_worker::{Result, serve_plugin};
#[tokio::main]
async fn main() -> Result<()> {
serve_plugin(DocumentationWorker).await
}

Exercise and Remove the Worker

Use the following procedure to verify the registered callbacks and stop the worker cleanly:

  1. Exercise allowed and blocked calls, unary and streaming continuations, codec decode and encode proxies, pending marks, optimization contributions, nested and isolated scopes, and cancellation.

  2. Disable and remove the component only after in-flight invocations have settled.

    nemo-relay plugins disable examples.rust_grpc_worker
    nemo-relay plugins remove examples.rust_grpc_worker

Success means shutdown rejects new invocations, cancels or drains active work, closes the authenticated endpoint, stops the process, and leaves no owned runtime registrations.