A unified Swift framework for interacting with multiple language model providers through a single, protocol-based API.
Write against the LanguageModel protocol and use Ollama, Claude, OpenAI Responses API, and on-device MLX — side by side in the same application.
- Unified
LanguageModelprotocol — one interface for all providers - Structured output via
@Generablemacro — get typed Swift structs from LLM responses - Tool calling with automatic execution loop
- Streaming responses with partial content parsing
- Swift 6 concurrency — fully
Sendable,async/awaitnative - Trait-gated compilation — keep package size small by compiling only the backends you need
- Swift 6.2+
- macOS 15+ / iOS 18+ / visionOS 2+
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/1amageek/AnyFoundationModels.git", branch: "main"),
]Enable the backends you need via traits. Each backend compiles only when its trait is active, keeping your binary small:
targets: [
.executableTarget(
name: "MyApp",
dependencies: [
.product(name: "OpenFoundationModels", package: "AnyFoundationModels"),
.product(name: "ClaudeFoundationModels", package: "AnyFoundationModels",
condition: .when(traits: ["Claude"])),
.product(name: "ResponseFoundationModels", package: "AnyFoundationModels",
condition: .when(traits: ["Response"])),
.product(name: "OllamaFoundationModels", package: "AnyFoundationModels",
condition: .when(traits: ["Ollama"])),
.product(name: "MLXFoundationModels", package: "AnyFoundationModels",
condition: .when(traits: ["MLX"])),
]
)
]Build with the traits you need:
swift build --traits Claude,Response,Ollamaimport OpenFoundationModels
import ClaudeFoundationModels
let model = ClaudeLanguageModel(
configuration: ClaudeConfiguration(apiKey: "sk-..."),
modelName: "claude-sonnet-4-5-20250929"
)
let session = LanguageModelSession(model: model)
let response = try await session.respond(to: "Explain quantum computing in one sentence.")
print(response.content)Use the @Generable macro to get typed Swift structs directly from LLM responses:
import OpenFoundationModels
import OpenFoundationModelsMacros
@Generable
struct Recipe {
@Guide(description: "Name of the recipe")
var name: String
@Guide(description: "List of ingredients")
var ingredients: [String]
@Guide(description: "Step-by-step instructions")
var steps: [String]
@Guide(description: "Estimated cooking time in minutes")
var cookingTimeMinutes: Int
}
let response = try await session.respond(
to: "Give me a recipe for pancakes",
generating: Recipe.self
)
print(response.content.name) // "Classic Pancakes"
print(response.content.ingredients) // ["flour", "eggs", ...]Define tools that the model can invoke automatically:
import OpenFoundationModels
import OpenFoundationModelsMacros
@Generable
struct WeatherArguments {
@Guide(description: "City name")
var city: String
}
struct WeatherTool: Tool {
var description: String { "Get current weather for a city" }
func call(arguments: WeatherArguments) async throws -> String {
return "Sunny, 24°C in \(arguments.city)"
}
}
let session = LanguageModelSession(
model: model,
tools: [WeatherTool()],
instructions: "You are a helpful assistant."
)
let response = try await session.respond(to: "What's the weather in Tokyo?")
// The session automatically executes the tool and returns the final answerlet stream = session.streamResponse(to: "Write a short story about a cat.")
for try await snapshot in stream {
print(snapshot.content, terminator: "")
}Streaming also works with structured output:
let stream = session.streamResponse(
to: "Give me a recipe for miso soup",
generating: Recipe.self
)
for try await snapshot in stream {
// snapshot.content is Recipe.PartiallyGenerated
print(snapshot.content)
}
let final = try await stream.collect()
print(final.content.name) // fully parsed Recipeimport ClaudeFoundationModels
let config = ClaudeConfiguration(apiKey: "sk-...")
// Or from environment: ClaudeConfiguration.fromEnvironment()
let model = ClaudeLanguageModel(
configuration: config,
modelName: "claude-sonnet-4-5-20250929",
thinkingBudgetTokens: 10000 // optional: enable extended thinking
)import ResponseFoundationModels
let config = ResponseConfiguration(apiKey: "sk-...")
let model = ResponseLanguageModel(configuration: config, model: "gpt-4.1")import OllamaFoundationModels
let config = OllamaConfiguration() // defaults to http://127.0.0.1:11434, temperature: 0
let model = OllamaLanguageModel(configuration: config, modelName: "llama3.2")import MLXFoundationModels
let factory = MLXLanguageModelFactory()
let model = try await factory.makeLanguageModel(
descriptor: .nanbeige41_3B_8bit
)Custom Hugging Face models:
let descriptor = MLXModelDescriptor(
id: "mlx-community/your-model-4bit",
promptStyle: .llama3
)
let model = try await factory.makeLanguageModel(descriptor: descriptor)All backends conform to LanguageModel, so you can use them side by side in the same application:
import ClaudeFoundationModels
import OllamaFoundationModels
let claude = ClaudeLanguageModel(
configuration: ClaudeConfiguration(apiKey: "sk-..."),
modelName: "claude-sonnet-4-5-20250929"
)
let ollama = OllamaLanguageModel(
configuration: OllamaConfiguration(),
modelName: "llama3.2"
)
// Use different models for different tasks
let session1 = LanguageModelSession(model: claude, instructions: "You are a translator.")
let session2 = LanguageModelSession(model: ollama, instructions: "You are a code reviewer.")
async let translation = session1.respond(to: "Translate to Japanese: Hello")
async let review = session2.respond(to: "Review this function: ...")┌─────────────────────────────────────────────────────┐
│ Your Application │
├─────────────────────────────────────────────────────┤
│ LanguageModelSession │
│ (tool loop, transcript, streaming) │
├─────────────────────────────────────────────────────┤
│ LanguageModel Protocol │
│ generate() / stream() / isAvailable │
├──────────┬──────────┬──────────┬────────────────────┤
│ Claude │ Response │ Ollama │ MLX │
│ (API) │ (API) │ (Local) │ (On-Device) │
└──────────┴──────────┴──────────┴────────────────────┘
| Module | Description |
|---|---|
OpenFoundationModelsCore |
Core protocols: Generable, GeneratedContent, GenerationSchema |
OpenFoundationModels |
LanguageModel, LanguageModelSession, Transcript, Tool |
OpenFoundationModelsMacros |
@Generable and @Guide macros |
OpenFoundationModelsExtra |
Internal accessors for backend implementations |
ClaudeFoundationModels |
Anthropic Claude API backend |
ResponseFoundationModels |
OpenAI Responses API backend |
OllamaFoundationModels |
Ollama local server backend |
MLXFoundationModels |
Apple MLX on-device inference backend |
MIT