foundation-models 0.7.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, string-choice schemas, array guides, 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
  • Response / tool definitionsResponseFormat::generating, inferred Tool::generable, and transcript ToolDefinition helpers
  • 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.7.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(())
# }

Coverage-oriented helpers

use foundation_models::prelude::*;

# fn main() -> Result<(), Box<dyn std::error::Error>> {
let schema = GenerationSchema::from_dynamic(
    DynamicGenerationSchema::array_of(DynamicGenerationSchema::string()).with_guides([
        GenerationGuide::minimum_count(1),
        GenerationGuide::maximum_count(3),
        GenerationGuide::element(GenerationGuide::string_pattern("^[a-z]+$")),
    ]),
    [],
)?;

let response_format = ResponseFormat::generating::<GeneratedContent>()?;
let tool = Tool::generable("echo", "Echo structured content", |args: GeneratedContent| {
    Ok(args.json_string()?)
})?;

println!("{}", schema.json_schema());
println!("{}", response_format.name());
println!("{}", tool.definition().name);
# Ok(())
# }

Smoke example

cargo run --example 06_smoke --features macos_26_0
cargo run --example 07_schema_surface --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.
  • Xcode 26.2's FoundationModels.swiftinterface does not expose standalone PromptTag, Conversation, ToolCallingMode, SystemPrompt, Examples, LanguageModelInputContent, LanguageModelOutputContent, or Streaming symbols; see COVERAGE.md for the audited matrix.

License

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