Destiner's Notes

Swift FoundationModels Cheatsheet

29 June 2025

Tip: use the #Playground macro to preview your prompt outputs inside Xcode.

Quickstart

import Playgrounds
import FoundationModels

func generate() async throws {
    let session = LanguageModelSession()
    let response = try await session.respond(to: "Capital of England, in one word.")
    // → "London"
}

Chat

Multi-turn conversation, where the model preserves the context of previous messages.

func generate() async throws {
    let session = LanguageModelSession()
    let responseA = try await session.respond(to: "Capital of England, in one word.")
    // → "London"
    let responseB = try await session.respond(to: "What about France?")
    // → "Paris"
}

System Prompt

High-level instructions that have higher priority over user-provided messages.

func generate() async throws {
    let session = LanguageModelSession(instructions: "Respond in one word")
    let response = try await session.respond(to: "Capital of England?")
    // → "London"
}

You can also use a builder pattern for more complex and dynamic prompts:

func generate() async throws {
    let concise = true
    let session = LanguageModelSession {
        """
        You're given a country name. Output with the name of a capital for that country.
        """
        
        """
        \(concise ? "Respond in one word" : "Respond with a full sentence")
        """
    }
    let response = try await session.respond(to: "England")
    // → "London"
}

Structured Outputs

@Generable
struct Country {
    let name: String
    let capital: String
}

func generate() async throws {
    let session = LanguageModelSession()
    let response = try await session.respond(
        generating: Country.self,
        includeSchemaInPrompt: false
    ) {
        "Get a country based on its name"

        "England"
    }
    // → { "name": "England", "capital": "London" }
}

Guides

You can use the @Guide macro to guardrail the output.

@Generable
struct Country {
    @Guide(description: "Official country name")
    let name: String
    @Guide(description: "The capital city name")
    let capital: String
    @Guide(.count(3))
    let cities: String[]
}

The full list of available guides:

// Int/Float/Double/Decimal
.minimum(1)
.maximum(10)
.range(1..10)

// Array
.minimumCount(1)
.maximumCount(10)
.count(3)
.element(.minimum(1))

// String
.constant("capital")
.anyOf(["state", "republic", "province"])
.patterns(/[A-Z]{3}/) // IATA airport code

Tool Calling

final class WeatherTool: Tool {
    let name = "getWeather"
    let description = "Fetches the latest weather for a given city"

    @Generable
    struct Arguments {
        @Guide(description: "A name of a city to fetch the weather for")
        let city: String
    }
    
    func call(arguments: Arguments) async throws -> ToolOutput {
        let temperature = getTemperature(for: arguments.city)
        guard let temperature else {
            return ToolOutput("Couldn't find weather for \(arguments.city)")
        }
        return ToolOutput("The weather in \(arguments.city) is \(temperature)°C")
    }
    
    private func getTemperature(for city: String) -> Double? {
        switch (city) {
        case "London":
            return 15
        case "Paris":
            return 17
        default:
            return nil
        }
    }
}

func generate() async throws {
    let weatherTool = WeatherTool()
    let session = LanguageModelSession(
        tools: [weatherTool]
    )
    let response = try await session.respond() {
        "Weather in London"
    }
    // → "The current temperature in London is 15.0°C."
}

Output Streaming

func generate() async throws {
    let session = LanguageModelSession()
    let stream = session.streamResponse() {
        "Describe a country"

        "England"
    }
    for try await partialResponse in stream {
        print(partialResponse)
    }
    // → "England is a country"
    // → "England is a country that is part of the United Kingdom"
    // → "England is a country that is part of the United Kingdom, located off the northwestern coast of continental Europe."
    // …
}

With structured outputs:

@Generable
struct Country {
    let name: String
    let capital: String
    let description: String
}

func generate() async throws {
    @State var country: Country.PartiallyGenerated?
    
    let session = LanguageModelSession()
    let stream = session.streamResponse(
        generating: Country.self,
        includeSchemaInPrompt: false
    ) {
        "Get a country based on its name"

        "England"
    }
    for try await partialResponse in stream {
        print(partialResponse)
    }
    // → { "name": "England", "capital": nil, "description": nil }
    // → { "name": "England", "capital": "London", "description": nil }
    // → { "name": "England", "capital": "London", "description": "England is a country" }
    // …
}

Check Availability

struct ContentView: View {
    private let model = SystemLanguageModel.default
    
    var body: some View {
        switch model.availability {
        case .available:
            CountryView()
        case .unavailable(.appleIntelligenceNotEnabled):
            Text("Apple Intelligence has not been turned on.")
        case .unavailable(.modelNotReady):
            Text("Not yet ready. Try again later.")
        case .unavailable(.deviceNotEligible):
            FallbackView()
    }
}

Tip: simulate the model unavailability by setting a custom value for “Simulated Foundation Models Availability” in the target scheme editor.