iOS 27 opens the Foundation Models framework to third-party LLM providers via a public LanguageModel protocol, allowing developers to plug in any local or server-based model โ including community packages for Claude and Gemini โ while sharing the same session API.
โข Drop-in model swapping: any LanguageModel-conforming type works with existing LanguageModelSession code, so apps can switch between on-device, PCC, Core AI, MLX, or third-party models with one line change
โข Community ecosystem: Anthropic and Google are shipping Swift packages that conform to the protocol, meaning state-of-the-art frontier models integrate without custom networking code
โข Framework benefits for free: structured generation, tool calling, streaming, dynamic profiles, and automatic executor lifecycle management all work regardless of which model backs the session
Demonstrates implementing the LanguageModel and LanguageModelExecutor protocols to create a simple echo-based custom model, then using it through the standard LanguageModelSession API.
import FoundationModels
// MARK: - Custom Model Configuration (the cache key)
struct EchoModelConfiguration: LanguageModelExecutorConfiguration, Hashable {
let maxTokens: Int
}
// MARK: - The Executor: where inference actually runs
final class EchoModelExecutor: LanguageModelExecutor {
typealias Configuration = EchoModelConfiguration
private let configuration: EchoModelConfiguration
required init(configuration: EchoModelConfiguration) {
self.configuration = configuration
}
func prewarm() async {
// Load weights, open connections, etc.
// No-op for this echo model.
}
func respond(
to request: LanguageModelRequest,
model: EchoLanguageModel,
channel: LanguageModelResponseChannel
) async throws {
// 1. Send metadata first so callers can log/track the request.
await channel.send(.metadataUpdate(.init(
modelID: "echo-model-v1",
requestID: UUID().uuidString
)))
// 2. Count prompt tokens from the transcript.
let promptTokenCount = request.transcript.entries.reduce(0) { count, entry in
if case .prompt(let content) = entry { return count + content.text.split(separator: " ").count }
return count
}
await channel.send(.usageUpdate(.init(promptTokenCount: promptTokenCount)))
// 3. Stream the response token-by-token.
let lastPrompt: String = request.transcript.entries.compactMap { entry -> String? in
if case .prompt(let content) = entry { return content.text }
return nil
}.last ?? "(nothing)"
let reply = "Echo: \(lastPrompt)"
for word in reply.split(separator: " ") {
await channel.send(.textDelta(String(word) + " "))
}
}
}
// MARK: - The LanguageModel: describes capabilities & provides configuration
struct EchoLanguageModel: LanguageModel {
typealias Executor = EchoModelExecutor
var capabilities: LanguageModelCapabilities {
LanguageModelCapabilities(supportsToolCalling: false, supportsVision: false)
}
func makeConfiguration() -> EchoModelConfiguration {
EchoModelConfiguration(maxTokens: 256)
}
}
// MARK: - Usage: identical to the built-in system model
@main
struct EchoProviderDemo {
static func main() async throws {
let model = EchoLanguageModel()
let session = LanguageModelSession(model: model)
let response = try await session.respond(to: "Hello, custom model!")
print(response.content) // Echo: Hello, custom model!
}
}Foundation Models framework is open source but the protocol is new in iOS 27 โ no back-deployment. Third-party packages from Anthropic/Google were announced but may not ship on day one of iOS 27. The Configuration type must be Hashable because the framework uses it as an executor cache key; identical configurations share one executor instance. prewarm() is not guaranteed to be called before respond().
On-device models (Core AI, MLX) require Apple Silicon; server-backed models (PCC, Claude, Gemini) have no hardware constraint but require network access and authentication
More iOS 27 APIs land every week.
Get notified when new capabilities are published โ no noise, just signal.