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 returnsResult<O, E>whereOisSerialize + JsonSchemaandEconverts intoToolError. - 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 generatesmain.
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.