foundation-models 0.6.0

Safe Rust bindings for Apple's FoundationModels framework - on-device LLM on macOS 26+
Documentation

foundation-models

Safe, idiomatic Rust bindings for Apple's FoundationModels framework — the on-device large language model that ships with Apple Intelligence on macOS 26+.

Features

  • Sessions and multi-turn chat — create, restore, inspect, and persist LanguageModelSessions
  • Streaming — text deltas and structured-generation snapshots
  • Tool calling — register Rust callbacks as FoundationModels Tools
  • Structured generation — JSON-schema validation, dynamic schemas, and Rust Generable traits
  • System model configuration — availability, use cases, guardrails, locales, and adapter handles
  • Transcript support — typed transcript inspection plus raw JSON round-tripping
  • Feedback attachments — full LanguageModelFeedback issue/sentiment support

Requirements

  • macOS 26.0 or newer (build host and runtime)
  • Xcode 26 SDK
  • Apple Intelligence enabled in System Settings
  • Apple Silicon

Installation

[dependencies]
foundation-models = { version = "0.6.0", features = ["macos_26_0"] }

Quick start

use foundation_models::prelude::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    if !SystemLanguageModel::is_available() {
        eprintln!("Unavailable: {:?}", SystemLanguageModel::availability());
        return Ok(());
    }

    let session = LanguageModelSession::with_instructions(
        "Answer in a single concise sentence.",
    );
    let reply = session.respond("Why is the sky blue?")?;
    println!("{reply}");
    Ok(())
}

Tool calling

use foundation_models::prelude::*;
use serde::Deserialize;

#[derive(Deserialize)]
struct EchoArgs {
    message: String,
}

# fn main() -> Result<(), Box<dyn std::error::Error>> {
let schema = GenerationSchema::from_dynamic(
    DynamicGenerationSchema::object("EchoArgs").with_property(
        "message",
        DynamicGenerationProperty::new(DynamicGenerationSchema::string()),
    ),
    [],
)?;

let tool = Tool::json("echo", "Echo the provided message.", schema, |args: EchoArgs| {
    Ok(args.message)
});

let session = LanguageModelSession::builder()
    .instructions("Use tools when explicitly asked.")?
    .tool(tool)
    .build()?;

let reply = session.respond_prompt(
    "Use the echo tool exactly once with the message 'hello from Rust'.",
)?;
println!("{reply}");
# Ok(())
# }

Structured generation

use foundation_models::prelude::*;

# fn main() -> Result<(), Box<dyn std::error::Error>> {
let schema = GenerationSchema::from_dynamic(
    DynamicGenerationSchema::object("Movie")
        .with_property(
            "title",
            DynamicGenerationProperty::new(DynamicGenerationSchema::string()),
        )
        .with_property(
            "year",
            DynamicGenerationProperty::new(DynamicGenerationSchema::integer()),
        ),
    [],
)?;

let session = LanguageModelSession::new();
let response = session.respond_generated(
    "Return JSON for one classic science-fiction movie.",
    &schema,
    true,
)?;
println!("{}", response.json_string()?);
# Ok(())
# }

Smoke example

cargo run --example 06_smoke --features macos_26_0

Notes

  • Swift-only compile-time macros such as @Generable and @Guide are exposed as Rust runtime traits/builders (Generable, GenerationGuide, DynamicGenerationSchema).
  • SystemLanguageModel.Adapter::isCompatible(_ assetPack:) is not wrapped because it depends on BackgroundAssets.AssetPack, which this crate does not expose.
  • GenerationID remains opaque in the Apple SDK; generated-content IDs are surfaced as best-effort string metadata.

License

Licensed under either of Apache-2.0 or MIT at your option.