Skip to content
Subako Docs
English
Esc
↑↓navigate↵open⌘Jpreview
On this page

Rust

The Rust SDK.

subako-function-sdk turns ordinary Rust functions into tools. A function’s name is the tool’s name, its doc comment is the description the model reads, and its input and output types, which derive JsonSchema, become the tool’s schemas.

Start a package

The Rust template sets up the crate, the toolchain, and the script that builds the bundle:

rustup target add wasm32-wasip1
cargo install cargo-generate
cargo generate subako-ai/subako-function-template-rust --name orders

Or add the SDK to a crate of your own:

[dependencies]
schemars = "1"
serde = { version = "1", features = ["derive"] }
subako-function-sdk = "0.2"

[profile.release]
opt-level = "s"
lto = true

Tools

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use subako_function_sdk::{ToolError, function, package};

#[derive(Deserialize, JsonSchema)]
struct LookupInput {
    /// The order's number, such as 1042.
    order: u32,
}

#[derive(Serialize, JsonSchema)]
struct Order {
    status: String,
    total_cents: u64,
}

/// Look an order up by its number.
#[function]
fn lookup(input: LookupInput) -> Result<Order, ToolError> {
    if input.order == 0 {
        return Err(ToolError::new("order numbers start at 1"));
    }
    Ok(Order { status: "shipped".into(), total_cents: 12_900 })
}

/// Cancel an order that has not shipped.
#[function]
fn cancel(input: LookupInput) -> Result<Order, ToolError> {
    Err(ToolError::new(format!("order {} has already shipped", input.order)))
}

package! {
    name: "orders",
    description: "Looks orders up, and cancels them.",
    functions: [lookup, cancel],
}
  • Every #[function] needs a doc comment: it is the description the model reads, and the build fails without one.
  • A function takes one argument that is Deserialize + JsonSchema, and returns Result<O, E> where O is Serialize + JsonSchema and E converts into ToolError.
  • Field doc comments become the descriptions of the schema’s properties. Write them for the model: they are how it learns what to pass.
  • package! names the package, lists its functions, and generates main.

Errors

ToolError::new makes an error the model reads. It converts from String, &str, std::io::Error, and the SDK’s HttpError, so ? hands the model the reason. Input that does not match the schema is answered as an error before your function runs.

Return errors rather than panicking: a panic is a crash, and the model learns only that the function stopped.

Files

Use std::fs on the volume and assets:

let csv = std::fs::read_to_string("/volume/tmp/export.csv")?;
std::fs::create_dir_all("/volume/data/reports")?;
std::fs::write("/volume/data/reports/q3.md", summary)?;
let template = std::fs::read_to_string("/package/templates/report.md")?;

HTTP

http::request sends a request through Subako, under the grant’s network and credentials:

use subako_function_sdk::http::{self, Request, RequestBody, ResponseBody, ResponseOutput};

/// Fetch a page's text.
#[function]
fn fetch(input: FetchInput) -> Result<Page, ToolError> {
    let response = http::request(&Request::get(input.url))?;
    match response.body {
        ResponseBody::Inline { text } => Ok(Page { status: response.status, text }),
        ResponseBody::File { .. } => Err(ToolError::new("the body was saved to a file")),
    }
}

The body comes back inline as text, up to http::INLINE_MAX_BYTES. Set the request’s output to ResponseOutput::File { path } to stream a larger or binary body into the volume instead, and send a volume file as the body with RequestBody::File { path }.

Images

Return an Answer to show the model an image from the volume as well as the value:

use subako_function_sdk::{Answer, ToolError, function};

/// Plot a chart and show it.
#[function]
fn plot(input: PlotInput) -> Result<Answer<Plot>, ToolError> {
    let path = "/volume/tmp/chart.png".to_string();
    // ... write the chart to `path` ...
    Ok(Answer::new(Plot { path: path.clone() }).with_image_file(path))
}

Build and test

cargo test                                         # tools run as plain Rust
cargo build --release --target wasm32-wasip1       # target/wasm32-wasip1/release/orders.wasm
cargo run -- --subako-manifest > subako-package.json

Built for your own machine, the crate prints its subako-package.json when run with --subako-manifest, so the manifest always matches the code. The template’s package.sh does all three and packs dist/<name>.tar.gz, ready to upload.

The API reference is on docs.rs.

Was this page helpful?