Skip to main content

Rust SDK Setup

Add the Rust port of @baleybots/core to your Rust project — async, streaming, and type-safe over the same three-tier model as the TypeScript and Swift SDKs.

Private package

The Rust SDK currently lives in a private mirror repo. You need read access to baleybots/baleybots-rust on GitHub. Reach out in the org if you don't have it yet.

Requirements

  • Rust 1.80+ (2021 edition)

  • A Tokio runtime — the SDK is async and built on tokio + reqwest

  • An API key for whichever provider you use, in the environment:

    ProviderCargo featureEnv var
    Anthropic(default)ANTHROPIC_API_KEY
    OpenAIopenaiOPENAI_API_KEY
    Google (Gemini)googleGEMINI_API_KEY
    OllamaollamaOLLAMA_HOST (local needs no key)

Anthropic builds by default; the other three providers are additive Cargo features — turn on only what you use.

Add the package

The crate ships from the baleybots-rust mirror, synced from this monorepo. Depend on it by git URL:

[dependencies]
# Anthropic only (default):
baleybots = { git = "https://github.com/baleybots/baleybots-rust", branch = "main" }

# …or with extra providers:
# baleybots = { git = "https://github.com/baleybots/baleybots-rust", branch = "main", features = ["openai", "google", "ollama"] }

tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
futures = "0.3" # only if you consume streams

Pin to a tag once a release is cut (tag = "rust-v0.1.0") instead of tracking branch = "main".

Authenticating Cargo to a private repo

Cargo uses the same credentials as git clone against github.com. Pick whichever you already have set up:

  • HTTPS (credential helper) — tell Cargo to shell out to the system git, so it reuses your credential helper:

    # ~/.cargo/config.toml
    [net]
    git-fetch-with-cli = true

    or per-command: CARGO_NET_GIT_FETCH_WITH_CLI=true cargo build.

  • SSH (recommended for dev) — change the URL to ssh://git@github.com/baleybots/baleybots-rust and Cargo uses your SSH agent, no extra config.

Rule of thumb: if you can git clone the mirror, cargo build will pull it.

Hello, world

#[tokio::main]
async fn main() -> Result<(), baleybots::Error> {
// Tier 1 — one-liner. `None` model = resolve from the environment.
let answer = baleybots::generate("Capital of France?", None, None).await?;
println!("{answer}");
Ok(())
}

export ANTHROPIC_API_KEY=sk-ant-… and cargo run.

What's in the package

Three composable tiers, all built on one Processable primitive:

TierEntry pointWhen to use
Tier 1generate / streamOne-line completions, prototyping
Tier 2ModelClientCustom loops, parallel fan-out, your own retry policy
Tier 3BaleybotGoal-driven agent with tool loop, multi-turn history, typed structured output
use baleybots::{AnthropicModel, Baleybot, Model, ModelClient};

let model = Model::Anthropic(AnthropicModel::ClaudeHaiku45);

// Tier 2 — one round-trip, you own the loop.
let client = ModelClient::new(model.clone())?;
let haiku = client.generate("Write a haiku about ownership.", None).await?;

// Tier 3 — a goal-driven agent with a tool loop.
let bot = Baleybot::builder("researcher", "Answer precisely; use tools.", model).build()?;
let reply = bot.process("Summarize the borrow checker in one line.".to_string()).await?;

Plus building blocks that span all three:

  • Tool + TypedTool — local Rust functions as model tools (one trait; derive a typed one for schema-aware decoding)
  • HttpTool — remote tools (REST endpoints) via the same Tool trait, no separate protocol
  • process_typed::<T> — typed structured output; the answer decodes straight into your Deserialize type
  • Multimodalimage_path / file_path builders; each provider renders only the media kinds (and image subtypes) its API accepts and skips the rest

Streaming + drop-based cancellation

Streaming is Stream<Item = Result<_, Error>>, never callbacks — and the work runs inside the stream, so dropping the consumer cancels the in-flight request. No cancel token to thread:

use baleybots::stream;
use futures::StreamExt;

let mut s = stream("Name three primary colors.", None, None);
while let Some(token) = s.next().await {
print!("{}", token?);
}
// Drop `s` early — break out of the loop — and the HTTP request,
// the SSE parse, and any running tool futures all cancel with it.

This is the piece Rust does uniquely well: cancellation is the language's Drop, not bookkeeping you maintain.

Connecting to a proxy server

Routing through a @baleybots/proxy-server deployment instead of calling the provider directly:

use baleybots::{AnthropicModel, Model, ModelClient, Url};

let client = ModelClient::with_proxy(
Model::Anthropic(AnthropicModel::ClaudeHaiku45),
Url::parse("https://your-proxy.example.com").unwrap(),
)?;
let answer = client.generate("Capital of France?", None).await?;

No API key needed on the device — the proxy injects its own credentials.

What's in v0.1

The Rust port is feature-complete across the matrix:

  • All four providers — Anthropic, OpenAI, Google (Gemini), Ollama — across all three tiers, with model discovery
  • Multimodal input — images and files, capability-gated per provider (and Ollama gates per-model via /api/show)
  • Typed structured output — native JSON modes where available, forced tool-calling on Anthropic, identical surface either way
  • Prompt caching, remote tools (HttpTool), drop-cancellable streaming throughout

APIs may still shift before 0.1. No todo!(), no stubs.

Source + contributing

  • Rust SDK source: github.com/baleybots/baleybots-rust
  • Development happens in the monorepo: PRs go to baleybots/baleybots under rust/. The mirror repo is a derived artifact synced from monorepo main.
  • Project guide: rust/AGENTS.md (named invariants, shape rules)
  • Release procedure: rust/docs/RELEASE.md