Last Updated: 3/9/2026
Rust Client
A Rust client for interacting with the Pie server.
Installation
Add to your Cargo.toml:
[dependencies][dependencies]pie-client = "0.1"pie-client = "0.1"tokio = { version = "1", features = ["full"] }tokio = { version = "1", features = ["full"] }anyhow = "1"anyhow = "1"Quick Start
use pie_client::{Client, InstanceEvent}; use pie_client::{Client, InstanceEvent}; use anyhow::Result; use anyhow:: Result; #[tokio::main] #[tokio::main] async fn main() -> Result<()> { async fn main() -> Result<()> { // Connect to server
// Connect to server let client = Client::connect("ws://127.0.0.1:8080").await?; let client = Client:: connect("ws://127.0.0.1:8080"). await?; // Authenticate
// Authenticate client.authenticate("username", &None).await?; client. authenticate("username", & None). await?; // Launch an inferlet from registry
// Launch an inferlet from registry let mut instance = client.launch_instance_from_registry( let mut instance = client. launch_instance_from_registry( "text-completion".to_string(), "text-completion". to_string(), vec!["--prompt".to_string(), "Hello, world!".to_string()], vec!["--prompt". to_string(), "Hello, world!". to_string()], false, // not detached false,
// not detached ).await?; ). await?; // Receive output
// Receive output loop { loop { match instance.recv().await? { match instance. recv(). await? { InstanceEvent::Stdout(text) => print!("{}", text), InstanceEvent:: Stdout(text) => print!("{}", text), InstanceEvent::Completed(_) => break, InstanceEvent:: Completed(_) => break, InstanceEvent::Exception(msg) => { InstanceEvent:: Exception(msg) => { eprintln!("Error: {}", msg); eprintln!("Error: {}", msg); break; break; } } _ => {} _ => {} } } } } client.close()?; client. close()?; Ok(()) Ok(()) } }Client
The main client struct for connecting to a Pie server.
Construction
let client = Client::connect("ws://127.0.0.1:8080").await?; let client = Client:: connect("ws://127.0.0.1:8080"). await?;Methods
| Method | Returns | Description |
|---|---|---|
connect(ws_host) | Result<Client> | Connect to server |
close(self) | Result<()> | Close connection |
authenticate(username, key) | Result<()> | Authenticate with server |
internal_authenticate(token) | Result<()> | Internal token auth |
upload_program(bytes) | Result<()> | Upload WASM program |
program_exists(hash) | Result<bool> | Check if program exists |
launch_instance(hash, args, detached) | Result<Instance> | Launch by hash |
launch_instance_from_registry(name, args, detached) | Result<Instance> | Launch from registry |
attach_instance(id) | Result<Instance> | Attach to existing |
list_instances() | Result<Vec<InstanceInfo>> | List instances |
terminate_instance(id) | Result<()> | Terminate instance |
ping() | Result<()> | Check connectivity |
Authentication
use pie_client::crypto::ParsedPrivateKey; use pie_client:: crypto:: ParsedPrivateKey; // With SSH key
// With SSH key let key = ParsedPrivateKey::from_file("~/.ssh/id_ed25519")?; let key = ParsedPrivateKey:: from_file("~/.ssh/id_ed25519")?; client.authenticate("username", &Some(key)).await?; client. authenticate("username", & Some(key)). await?; // Without key (when server auth is disabled)
// Without key (when server auth is disabled) client.authenticate("username", &None).await?; client. authenticate("username", & None). await?;Instance
Represents a running program instance.
Methods
| Method | Returns | Description |
|---|---|---|
id() | InstanceId | Get instance ID |
send(message) | Result<()> | Send string message |
upload_blob(bytes) | Result<()> | Upload binary data |
recv() | Result<InstanceEvent> | Receive next event |
Example
let mut instance = client.launch_instance_from_registry(let mut instance = client. launch_instance_from_registry( "chat".to_string(), "chat". to_string(), vec![], vec![], false, false, ).await?; ). await?; // Send a message
// Send a message instance.send("What is 2 + 2?")?; instance. send("What is 2 + 2?")?; // Receive response
// Receive response match instance.recv().await? { match instance. recv(). await? { InstanceEvent::Message(text) => println!("{}", text), InstanceEvent:: Message(text) => println!("{}", text), InstanceEvent::Stdout(text) => print!("{}", text), InstanceEvent:: Stdout(text) => print!("{}", text), _ => {} _ => {} } }InstanceEvent
Events received from instances:
pub enum InstanceEvent {pub enum InstanceEvent { /// Text message from instance
/// Text message from instance Message(String), Message(String), /// Instance completed successfully
/// Instance completed successfully Completed(String), Completed(String), /// Instance was aborted
/// Instance was aborted Aborted(String), Aborted(String), /// Instance raised an exception
/// Instance raised an exception Exception(String), Exception(String), /// Server-side error
/// Server-side error ServerError(String), ServerError(String), /// Resource limit reached
/// Resource limit reached OutOfResources(String), OutOfResources(String), /// Binary data
/// Binary data Blob(Vec<u8>), Blob(Vec< u8>), /// Streaming stdout
/// Streaming stdout Stdout(String), Stdout(String), /// Streaming stderr
/// Streaming stderr Stderr(String), Stderr(String), } }Pattern Matching
loop {loop { match instance.recv().await? { match instance. recv(). await? { InstanceEvent::Stdout(text) => { InstanceEvent:: Stdout(text) => { print!("{}", text); print!("{}", text); std::io::stdout().flush()?; std:: io:: stdout(). flush()?; } } InstanceEvent::Stderr(text) => { InstanceEvent:: Stderr(text) => { eprint!("{}", text); eprint!("{}", text); } } InstanceEvent::Completed(msg) => { InstanceEvent:: Completed(msg) => { println!("\nCompleted: {}", msg); println!("\nCompleted: {}", msg); break; break; } } InstanceEvent::Exception(err) => { InstanceEvent:: Exception(err) => { return Err(anyhow!("Inferlet error: {}", err)); return Err(anyhow!("Inferlet error: {}", err)); } } InstanceEvent::ServerError(err) => { InstanceEvent:: ServerError(err) => { return Err(anyhow!("Server error: {}", err)); return Err(anyhow!("Server error: {}", err)); } } _ => {} _ => {} } } } }Upload Custom Inferlet
use pie_client::hash_blob; use pie_client:: hash_blob; // Read and upload
// Read and upload let wasm_bytes = std::fs::read("my_inferlet.wasm")?; let wasm_bytes = std:: fs:: read("my_inferlet.wasm")?; client.upload_program(&wasm_bytes).await?; client. upload_program(& wasm_bytes). await?; // Get hash for launching
// Get hash for launching let program_hash = hash_blob(&wasm_bytes); let program_hash = hash_blob(& wasm_bytes); // Launch
// Launch let mut instance = client.launch_instance( let mut instance = client. launch_instance( program_hash, program_hash, vec!["--arg".to_string(), "value".to_string()], vec!["--arg". to_string(), "value". to_string()], false, false, ).await?; ). await?;Detached Instances
// Launch detached
// Launch detached let instance = client.launch_instance_from_registry( let instance = client. launch_instance_from_registry( "long-task".to_string(), "long-task". to_string(), vec![], vec![], true, // detached true,
// detached ).await?; ). await?; let instance_id = instance.id(); let instance_id = instance. id(); // Later, reattach
// Later, reattach let mut attached = client.attach_instance(&instance_id.to_string()).await?; let mut attached = client. attach_instance(& instance_id. to_string()). await?; let event = attached.recv().await?; let event = attached. recv(). await?;Error Handling
use anyhow::{Result, Context}; use anyhow::{Result, Context}; async fn run() -> Result<()> { async fn run() -> Result<()> { let client = Client::connect("ws://127.0.0.1:8080") let client = Client:: connect("ws://127.0.0.1:8080") .await . await .context("Failed to connect to Pie server")?; . context("Failed to connect to Pie server")?; client.authenticate("username", &None) client. authenticate("username", & None) .await . await .context("Authentication failed")?; . context("Authentication failed")?; // ...
// ... Ok(()) Ok(()) } }Thread Safety
The Client is thread-safe and can be shared across tasks:
use std::sync::Arc; use std:: sync:: Arc; let client = Arc::new(Client::connect("ws://127.0.0.1:8080").await?); let client = Arc:: new(Client:: connect("ws://127.0.0.1:8080"). await?); let c1 = client.clone(); let c1 = client. clone(); let h1 = tokio::spawn(async move { let h1 = tokio:: spawn(async move { // Use c1
// Use c1 }); }); let c2 = client.clone(); let c2 = client. clone(); let h2 = tokio::spawn(async move { let h2 = tokio:: spawn(async move { // Use c2
// Use c2 }); }); h1.await?; h1. await?; h2.await?; h2. await?;