capacitor-foundation-models
A Capacitor plugin that provides access to Apple's Foundation Models framework introduced on WWDC 2025, enabling on-device AI interactions with privacy and performance in mind.
Maintainer | GitHub | Social | |
---|---|---|---|
Luan Freitas (ludufre) | ludufre | @ludufre | Luan Freitas |
- 🤖 Apple Foundation Models: Direct integration with Apple's on-device AI models
- 🔒 Privacy-First: All processing happens on-device, no data sent to external servers
- 📱 iOS 26+ Support: Leverages the latest Apple Intelligence capabilities
- 🎯 Schema Validation: Define structured output schemas for consistent AI responses
- ⚡ Session Management: Maintain conversation context across multiple interactions
- 🌡️ Temperature Control: Fine-tune response creativity and randomness
- 📊 Availability Checking: Detect device compatibility and model availability
- 📱 Example App: A complete example app demonstrating all features
- iOS 26.0+ (Foundation Models framework requirement)
- Apple Intelligence enabled on the device
- Compatible device (iPhone 15 Pro/Pro Max or newer, iPad with M1 or newer, Mac with Apple Silicon)
npm install capacitor-foundation-models
npx cap sync
First, check if Foundation Models are available on the device:
import { FoundationModels } from 'capacitor-foundation-models';
const { available, reason, capabilities } = await FoundationModels.checkAvailability();
if (available) {
console.log('Foundation Models available with capabilities:', capabilities);
} else {
console.log('Not available:', reason);
}
Initialize a language model session with optional instructions:
await FoundationModels.startSession({
instructions: 'You are a helpful assistant that provides concise answers.'
});
Generate responses without structured output:
const result = await FoundationModels.promptWithoutSchema({
prompt: 'Explain quantum computing in simple terms',
temperature: 0.7
});
console.log(result.response);
Define a schema for structured responses:
// First, create a schema
await FoundationModels.createSchema({
name: 'ProductReview',
schema: {
rating: 'number',
summary: 'string',
pros: 'string',
cons: 'string',
recommended: 'boolean'
}
});
// Use the schema for structured output
const result = await FoundationModels.promptWithSchema({
prompt: 'Review this product: iPhone 15 Pro',
schema: 'ProductReview',
temperature: 0.5
});
// result.response will be a structured object matching the schema
console.log(result.response);
// {
// rating: 4.5,
// summary: "Excellent flagship phone with advanced features",
// pros: "Great camera system, powerful A17 Pro chip, premium build quality",
// cons: "Expensive, battery life could be better",
// recommended: true
// }
The schema system allows you to define structured output formats for AI responses, ensuring consistent data structures that integrate seamlessly with your application logic.
-
'string'
- Text values -
'number'
- Numeric values (integers or floats) -
'boolean'
- True/false values
await FoundationModels.createSchema({
name: 'UserProfile',
schema: {
name: 'string',
age: 'number',
isActive: 'boolean'
}
});
Arrays are defined using single-element arrays containing the element type:
-
['string']
- Array of strings -
['number']
- Array of numbers -
['boolean']
- Array of booleans
await FoundationModels.createSchema({
name: 'ShoppingList',
schema: {
listName: 'string',
items: ['string'], // Array of strings
prices: ['number'], // Array of numbers
purchased: ['boolean'] // Array of booleans
}
});
// Example output:
// {
// listName: "Grocery Shopping",
// items: ["Milk", "Bread", "Eggs"],
// prices: [3.99, 2.50, 4.20],
// purchased: [false, true, false]
// }
Objects are defined using nested structure:
await FoundationModels.createSchema({
name: 'Recipe',
schema: {
name: 'string',
servings: 'number',
ingredients: ['string'],
nutrition: { // Nested object
calories: 'number',
protein: 'number',
carbs: 'number'
}
}
});
Define arrays containing complex objects:
await FoundationModels.createSchema({
name: 'Quiz',
schema: {
title: 'string',
questions: [{ // Array of objects
question: 'string',
options: ['string'], // Array within object
correctAnswer: 'number',
explanation: 'string'
}]
}
});
// Example output:
// {
// title: "JavaScript Basics Quiz",
// questions: [
// {
// question: "What is a closure?",
// options: ["A function", "A variable", "A method", "A loop"],
// correctAnswer: 0,
// explanation: "A closure is a function that has access to outer scope"
// }
// ]
// }
await FoundationModels.createSchema({
name: 'ProductCatalog',
schema: {
categoryName: 'string',
products: [{
name: 'string',
price: 'number',
inStock: 'boolean',
tags: ['string'],
specifications: {
weight: 'number',
dimensions: 'string',
warranty: 'string'
},
reviews: [{
rating: 'number',
comment: 'string',
verified: 'boolean'
}]
}]
}
});
await FoundationModels.createSchema({
name: 'TravelPlan',
schema: {
destination: 'string',
duration: 'string',
totalBudget: 'number',
days: [{
day: 'number',
activities: ['string'],
meals: [{
type: 'string', // breakfast, lunch, dinner
restaurant: 'string',
cost: 'number'
}],
transportation: ['string']
}],
tips: ['string']
}
});
// Create a schema
await FoundationModels.createSchema({
name: 'MySchema',
schema: { /* definition */ }
});
// Get all created schemas
const { schemas } = await FoundationModels.getSchemas();
console.log('Available schemas:', schemas);
// Use a schema for structured output
const result = await FoundationModels.promptWithSchema({
prompt: 'Generate content using the schema',
schema: 'MySchema',
temperature: 0.7
});
-
Descriptive Names: Use clear, descriptive schema names
// Good name: 'BookReview' // Bad name: 'Schema1'
-
Appropriate Types: Choose the right data types for your needs
schema: { price: 'number', // For calculations description: 'string', // For text content isAvailable: 'boolean' // For flags }
-
Arrays for Lists: Use arrays when you expect multiple items
schema: { authors: ['string'], // Multiple authors chapters: [{ // Multiple chapters with details title: 'string', pages: 'number' }] }
-
Nested Objects for Related Data: Group related properties
schema: { contact: { // Group contact information email: 'string', phone: 'string', address: 'string' } }
Common schema-related errors and solutions:
try {
await FoundationModels.createSchema({
name: 'TestSchema',
schema: { /* definition */ }
});
} catch (error) {
// Handle schema creation errors
if (error.message.includes('already exists')) {
console.log('Schema already exists, skipping creation');
} else if (error.message.includes('unsupported type')) {
console.log('Invalid schema type used');
}
}
checkAvailability() => Promise<AvailabilityResult>
Checks if Foundation Models are available on the current device.
Returns: Promise resolving to availability status, reason if unavailable, and supported capabilities.
startSession(options?: StartSessionOptions) => Promise<void>
Starts a new language model session with optional instructions.
Param | Type | Description |
---|---|---|
options | StartSessionOptions |
Session configuration (optional) |
createSchema(options: SchemaOptions) => Promise<void>
Creates a new schema for structured output generation.
Param | Type | Description |
---|---|---|
options | SchemaOptions |
Schema definition with name and structure |
getSchemas() => Promise<{ schemas: SchemaOptions[] }>
Retrieves all available schemas that have been created in the current session.
Returns: Promise resolving to an object containing an array of all created schemas.
promptWithoutSchema(options: PromptWithoutSchemaOptions) => Promise<PromptResult>
Generates a text response without structured output constraints.
Param | Type | Description |
---|---|---|
options | PromptWithoutSchemaOptions |
Prompt text and generation options |
promptWithSchema(options: PromptWithSchemaOptions) => Promise<PromptResult>
Generates a structured response based on a predefined schema.
Param | Type | Description |
---|---|---|
options | PromptWithSchemaOptions |
Prompt text, schema name, and generation options |
Property | Type | Description |
---|---|---|
available | boolean |
Whether Foundation Models are available |
reason | string |
Reason if not available (optional) |
capabilities | string[] |
Available language capabilities (optional) |
Property | Type | Description |
---|---|---|
instructions | string |
System instructions for the model (optional) |
Property | Type | Description |
---|---|---|
prompt | string |
The input prompt text |
temperature | number |
Controls randomness (0.0-2.0, default: 1.0) |
Property | Type | Description |
---|---|---|
prompt | string |
The input prompt text |
schema | string |
Name of the schema to use |
temperature | number |
Controls randomness (0.0-2.0, default: 1.0) |
Property | Type | Description |
---|---|---|
name | string |
Unique name for the schema |
schema | Record<string, SchemaValue> |
Schema definition object |
Supported schema types:
-
Primitive Types:
'string'
,'number'
,'boolean'
-
Array Types:
['string']
,['number']
,['boolean']
,[object]
-
Nested Objects:
{ [key: string]: SchemaValue }
The SchemaValue
type is recursive, allowing for complex nested structures combining all supported types.
The plugin provides detailed error messages for various scenarios:
try {
await FoundationModels.promptWithoutSchema({
prompt: 'Hello',
temperature: 0.5
});
} catch (error) {
console.error('Error:', error.message);
// Possible errors:
// - "Language model session has not been started. Call startSession() first."
// - "Invalid temperature value: 3.0. Must be between 0.0 and 2.0"
// - "Prompt cannot be empty"
// - "Language model is unavailable: [reason]"
}
Platform | Support | Notes |
---|---|---|
iOS | ✅ iOS 26.0+ | Requires Apple Intelligence enabled |
Android | ❌ | Foundation Models is Apple-exclusive |
Web | ❌ | Foundation Models requires native iOS |
Check out the example app for a complete implementation example showing:
- Availability checking
- Session management
- Schema creation and usage
- Error handling
- Temperature control
- Ensure you're running iOS 26.0 or later
- Verify Apple Intelligence is enabled in Settings
- Check that your device supports Apple Intelligence
- Confirm you're testing on a physical device, not simulator
- Always call
startSession()
before making prompt requests - Handle session initialization errors appropriately
- Ensure schema names are unique and not empty
- Verify schema structure matches supported types
- Create schemas before using them in prompts
Contributions are welcome! Please feel free to submit pull requests or open issues.
This project is licensed under the MIT License.
Luan Freitas - @ludufre
- Built with Capacitor
- Powered by Apple's Foundation Models framework
- Designed for privacy-first AI interactions