Skip to main content

Crate foundation_models

Crate foundation_models 

Source
Expand description

§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
  • Structured content helpers — typed GenerationId, string-backed Decimal, GeneratedContentKind, and generated-content builders with optional IDs
  • 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
  • Typed error metadataFMError accessors for recovery suggestions, refusal helpers, tool-call details, and schema/generation contexts
  • 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.1", 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,
}

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}");

§Structured generation

use foundation_models::prelude::*;

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()?);

§Coverage-oriented helpers

use foundation_models::prelude::*;

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);

§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 now round-trips as GenerationId via GeneratedContent::generation_id_handle(); GeneratedContent::generation_id() remains as a best-effort string helper.
  • Typed generation/schema refusal metadata is available through FMError::{generation_error_context, schema_error_context, recovery_suggestion, failure_reason, refusal, tool_call_error}.
  • 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.


§API Documentation

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

Generate text, hold multi-turn conversations, and stream tokens from the system language model on macOS 26.0+.

§Quick start

use foundation_models::{LanguageModelSession, SystemLanguageModel};

if !SystemLanguageModel::is_available() {
    eprintln!("Model unavailable: {:?}", SystemLanguageModel::availability());
    return Ok(());
}

let session = LanguageModelSession::new();
let reply = session.respond("Name three Norse gods.")?;
println!("{reply}");

§Streaming

use foundation_models::{LanguageModelSession, StreamEvent};
use std::io::Write;

let session = LanguageModelSession::new();
session.stream("Tell me a haiku about Rust.", |event| match event {
    StreamEvent::Chunk(s) => {
        print!("{s}");
        std::io::stdout().flush().ok();
    }
    StreamEvent::Done => println!(),
    StreamEvent::Error(e) => eprintln!("\nstream error: {e}"),
    _ => {}
})?;

Re-exports§

pub use content::Decimal;
pub use content::FromGeneratedContent;
pub use content::GeneratedContent;
pub use content::GeneratedContentKind;
pub use content::GenerationId;
pub use content::ToGeneratedContent;
pub use error::FMError;
pub use error::GenerationErrorContext;
pub use error::Refusal;
pub use error::SchemaErrorContext;
pub use error::ToolCallError;
pub use error::Unavailability;
pub use generation::GenerationOptions;
pub use generation::SamplingMode;
pub use model::Adapter;
pub use model::Availability;
pub use model::ConfiguredSystemLanguageModel;
pub use model::Guardrails;
pub use model::SystemLanguageModel;
pub use model::UseCase;
pub use prompt::Instructions;
pub use prompt::Prompt;
pub use prompt::ResponseFormat;
pub use prompt::Segment;
pub use prompt::StructuredSegment;
pub use prompt::TextSegment;
pub use prompt::ToInstructions;
pub use prompt::ToPrompt;
pub use prompt::ToolDefinition;
pub use schema::DynamicGenerationProperty;
pub use schema::DynamicGenerationSchema;
pub use schema::Generable;
pub use schema::GenerationGuide;
pub use schema::GenerationSchema;
pub use session::FeedbackAttachmentRequest;
pub use session::FeedbackIssue;
pub use session::FeedbackIssueCategory;
pub use session::FeedbackSentiment;
pub use session::LanguageModelSession;
pub use session::SessionBuilder;
pub use session::SessionResponse;
pub use session::StreamEvent;
pub use session::StructuredStreamEvent;
pub use session::StructuredStreamSnapshot;
pub use tool::Tool;
pub use tool::ToolOutput;
pub use tool::ToolSpec;
pub use transcript::Entry as TranscriptEntry;
pub use transcript::ToolCall;
pub use transcript::ToolCalls;
pub use transcript::ToolOutput as TranscriptToolOutput;
pub use transcript::Transcript;
pub use transcript::TranscriptInstructions;
pub use transcript::TranscriptPrompt;
pub use transcript::TranscriptResponse;

Modules§

content
GeneratedContent — structured model output represented as JSON.
error
Errors produced by the FoundationModels bridge.
ffi
Raw FFI declarations matching the Swift @_cdecl exports in swift-bridge/Sources/FoundationModelsBridge.
generation
Knobs that control how the model produces text.
model
SystemLanguageModel — entry point for querying device capability and building configured model handles.
prelude
Common imports for users of this crate.
prompt
Prompt and instructions builders.
schema
JSON-schema and dynamic schema builders for structured generation.
session
LanguageModelSession — a stateful conversation with the on-device model.
tool
Tool calling support.
transcript
Transcript inspection and restoration.