Skip to content

Cap-go/capacitor-llm

@capgo/capacitor-llm

Capgo - Instant updates for Capacitor

Adds support for LLM locally run for Capacitor

It uses Apple Intelligence for the iOS system model, MediaPipe for existing .task models, and ExecuTorch .pte models on both iOS and Android.

Mac Catalyst: Native iOS functionality is disabled for Mac Catalyst builds. MediaPipe pods are skipped and native calls will return an unsupported response; use an iOS/iPadOS target for native features.

Documentation

The most complete doc is available here: https://capgo.app/docs/plugins/llm/

Compatibility

Plugin version Capacitor compatibility Maintained
v8.*.* v8.*.*
v7.*.* v7.*.* On demand
v6.*.* v6.*.*
v5.*.* v5.*.*

Note: The major version of this plugin follows the major version of Capacitor. Use the version that matches your Capacitor installation (e.g., plugin v8 for Capacitor 8). Only the latest major version is actively maintained.

Installation

bun add @capgo/capacitor-llm
bunx cap sync

iOS Additional Setup for Custom Models

Apple Intelligence works without bundled model files on supported iOS versions. For custom models, the plugin supports MediaPipe through CocoaPods and ExecuTorch when the host app links ExecuTorch with Swift Package Manager. The plugin package remains iOS 15 compatible; iOS ExecuTorch requires an iOS 17 or newer app target because ExecuTorch requires iOS 17.

Using CocoaPods: The MediaPipe dependencies are already configured in the podspec. Make sure to run pod install after adding the plugin.

ExecuTorch is not provided by the CocoaPods integration. CocoaPods installs MediaPipe only. CocoaPods builds reject engine: 'executorch' with a clear runtime error unless the app also links ExecuTorch separately.

Note about Static Framework Warning: When running pod install, you may see a warning about transitive dependencies with statically linked binaries. To fix this, update your Podfile:

# Change this:
use_frameworks!

# To this:
use_frameworks! :linkage => :static

# And add this to your post_install hook:
post_install do |installer|
  assertDeploymentTarget(installer)

  # Fix for static framework dependencies
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
    end

    # Specifically for MediaPipe pods
    if target.name.include?('MediaPipeTasksGenAI')
      target.build_configurations.each do |config|
        config.build_settings['ENABLE_BITCODE'] = 'NO'
      end
    end
  end
end

Using Swift Package Manager: The plugin's Package.swift does not link ExecuTorch directly because that would force every Swift Package Manager user onto iOS 17 or newer, even when they only use Apple Intelligence or MediaPipe.

To use ExecuTorch on iOS, add it to your app target:

  1. Set the app target deployment version to iOS 17 or newer.
  2. In Xcode, open the app project, select Package Dependencies, and add https://github.com/pytorch/executorch.git.
  3. Use the swiftpm-1.2.0 branch, or the ExecuTorch branch that matches the runtime version you want.
  4. Add these products to the app target: executorch_llm, backend_xnnpack, kernels_llm, kernels_optimized, kernels_quantized, and kernels_torchao.
  5. Add the .pte model and tokenizer file to the app target's Copy Bundle Resources, or download them at runtime.

If those ExecuTorch products are not linked into the app target, setModel({ engine: 'executorch' }) rejects with a clear runtime error. MediaPipe GenAI still does not officially support SPM, so use CocoaPods for MediaPipe .task models.

Adding a Model to Your App

The simplest cross-platform custom model path is ExecuTorch. It uses the same kind of .pte model file on iOS and Android, plus a tokenizer file.

ExecuTorch Models (iOS and Android)

iOS uses ExecuTorch only when the host app links the ExecuTorch Swift Package products. It is not included by CocoaPods or by the plugin's Package.swift, so an app without those products can use Apple Intelligence or MediaPipe but will refuse engine: 'executorch'. Android uses the ExecuTorch Maven package.

Bundle the model files:

  • iOS: add the .pte model and tokenizer file to your app target's Copy Bundle Resources.
  • Android: place the .pte model and tokenizer file under android/app/src/main/assets/, then reference them with /android_asset/....
import { Capacitor } from '@capacitor/core';
import { CapgoLLM } from '@capgo/capacitor-llm';

const isAndroid = Capacitor.getPlatform() === 'android';

await CapgoLLM.setModel({
  engine: 'executorch',
  path: isAndroid ? '/android_asset/model.pte' : 'model.pte',
  tokenizerPath: isAndroid ? '/android_asset/tokenizer.model' : 'tokenizer.model',
  maxTokens: 2048,
  sequenceLength: 2048,
  temperature: 0.8,
});

const { id: chatId } = await CapgoLLM.createChat();

engine: 'auto' also selects ExecuTorch when the model path ends in .pte or when tokenizerPath is provided. Passing engine: 'executorch' is recommended when loading ExecuTorch models so failures are explicit.

MediaPipe Models

MediaPipe remains available for existing .task models. Android models usually need both .task and .litertlm files. iOS MediaPipe support is available through CocoaPods and remains experimental for some .task files.

await CapgoLLM.setModel({
  path: '/android_asset/gemma-3-270m-it-int8.task',
  modelType: 'task',
  maxTokens: 2048,
  topk: 40,
  temperature: 0.8,
});

Apple Intelligence

On supported iOS devices, Apple Intelligence can be used without bundling a model.

await CapgoLLM.setModel({
  path: 'Apple Intelligence',
  engine: 'apple',
});

Downloading Models at Runtime

Use downloadModel to keep large model files out of the app bundle. For ExecuTorch, companionUrl can point at the tokenizer file.

const result = await CapgoLLM.downloadModel({
  url: 'https://your-server.com/models/model.pte',
  companionUrl: 'https://your-server.com/models/tokenizer.model',
  filename: 'model.pte',
});

await CapgoLLM.setModel({
  engine: 'executorch',
  path: result.path,
  tokenizerPath: result.companionPath,
  sequenceLength: 2048,
});

Usage Example

import { CapgoLLM } from '@capgo/capacitor-llm';

const { readiness } = await CapgoLLM.getReadiness();
console.log('LLM readiness:', readiness);

const { id: chatId } = await CapgoLLM.createChat();

CapgoLLM.addListener('textFromAi', (event) => {
  console.log('AI:', event.text);
});

CapgoLLM.addListener('aiFinished', (event) => {
  console.log('AI finished responding to chat:', event.chatId);
});

await CapgoLLM.sendMessage({
  chatId,
  message: 'Hello! How are you today?',
});

API

LLM Plugin interface for interacting with on-device language models

createChat()

createChat() => Promise<{ id: string; instructions?: string; }>

Creates a new chat session

Returns: Promise<{ id: string; instructions?: string; }>


sendMessage(...)

sendMessage(options: { chatId: string; message: string; }) => Promise<void>

Sends a message to the AI in a specific chat session

Param Type Description
options { chatId: string; message: string; } - The chat id and message to send

getReadiness()

getReadiness() => Promise<{ readiness: string; }>

Gets the readiness status of the LLM

Returns: Promise<{ readiness: string; }>


setModel(...)

setModel(options: ModelOptions) => Promise<void>

Sets the model configuration

  • iOS: Use "Apple Intelligence" as path for system model, provide a MediaPipe model, or set engine to "executorch"
  • Android: Path to a MediaPipe or ExecuTorch model file (in assets or files directory)
Param Type Description
options ModelOptions - The model configuration

downloadModel(...)

downloadModel(options: DownloadModelOptions) => Promise<DownloadModelResult>

Downloads a model from a URL and saves it to the appropriate location

  • iOS: Downloads to the app's documents directory
  • Android: Downloads to the app's files directory
Param Type Description
options DownloadModelOptions - The download configuration

Returns: Promise<DownloadModelResult>


addListener('textFromAi', ...)

addListener(eventName: 'textFromAi', listenerFunc: (event: TextFromAiEvent) => void) => Promise<{ remove: () => Promise<void>; }>

Adds a listener for text received from AI

Param Type Description
eventName 'textFromAi' - Event name 'textFromAi'
listenerFunc (event: TextFromAiEvent) => void - Callback function for text events

Returns: Promise<{ remove: () => Promise<void>; }>


addListener('aiFinished', ...)

addListener(eventName: 'aiFinished', listenerFunc: (event: AiFinishedEvent) => void) => Promise<{ remove: () => Promise<void>; }>

Adds a listener for AI completion events

Param Type Description
eventName 'aiFinished' - Event name 'aiFinished'
listenerFunc (event: AiFinishedEvent) => void - Callback function for finish events

Returns: Promise<{ remove: () => Promise<void>; }>


addListener('downloadProgress', ...)

addListener(eventName: 'downloadProgress', listenerFunc: (event: DownloadProgressEvent) => void) => Promise<{ remove: () => Promise<void>; }>

Adds a listener for model download progress events

Param Type Description
eventName 'downloadProgress' - Event name 'downloadProgress'
listenerFunc (event: DownloadProgressEvent) => void - Callback function for progress events

Returns: Promise<{ remove: () => Promise<void>; }>


addListener('readinessChange', ...)

addListener(eventName: 'readinessChange', listenerFunc: (event: ReadinessChangeEvent) => void) => Promise<{ remove: () => Promise<void>; }>

Adds a listener for readiness status changes

Param Type Description
eventName 'readinessChange' - Event name 'readinessChange'
listenerFunc (event: ReadinessChangeEvent) => void - Callback function for readiness events

Returns: Promise<{ remove: () => Promise<void>; }>


getPluginVersion()

getPluginVersion() => Promise<{ version: string; }>

Get the native Capacitor plugin version.

Returns: Promise<{ version: string; }>

Since: 1.0.0


Interfaces

ModelOptions

Model configuration options

Prop Type Description
path string Model path or "Apple Intelligence" for iOS system model
engine 'auto' | 'apple' | 'mediapipe' | 'executorch' Runtime engine to use. - "auto": uses Apple Intelligence on iOS when path is "Apple Intelligence", ExecuTorch for .pte or tokenizerPath, otherwise MediaPipe - "apple": iOS Foundation Models / Apple Intelligence - "mediapipe": MediaPipe GenAI .task models - "executorch": ExecuTorch .pte models with a tokenizer file
modelType string Model file type/extension (e.g., "task", "bin", "litertlm"). If not provided, will be extracted from path.
tokenizerPath string Tokenizer path for ExecuTorch models. Required when engine is "executorch".
specialTokens string[] Optional special tokens passed to iOS ExecuTorch tokenizers.
maxTokens number Maximum number of tokens the model handles
sequenceLength number Sequence length for ExecuTorch generation. Defaults to maxTokens when omitted.
topk number Number of tokens the model considers at each step
temperature number Amount of randomness in generation (0.0-1.0)
randomSeed number Random seed for generation

DownloadModelResult

Result of model download

Prop Type Description
path string Path where the model was saved
companionPath string Path where the companion file was saved (if applicable)

DownloadModelOptions

Options for downloading a model

Prop Type Description
url string URL of the model file to download
companionUrl string Optional: URL of companion file (e.g., .litertlm for Android)
filename string Optional: Custom filename (defaults to filename from URL)

TextFromAiEvent

Event data for text received from AI

Prop Type Description
text string The text content from AI - this is an incremental chunk, not the full text
chatId string The chat session ID
isChunk boolean Whether this is a complete chunk (true) or partial streaming data (false)

AiFinishedEvent

Event data for AI completion

Prop Type Description
chatId string The chat session ID that finished

DownloadProgressEvent

Event data for download progress

Prop Type Description
progress number Percentage of download completed (0-100)
totalBytes number Total bytes to download
downloadedBytes number Bytes downloaded so far

ReadinessChangeEvent

Event data for readiness status changes

Prop Type Description
readiness string The readiness status

Example App Model Setup

The example app can use either the older MediaPipe assets or the new ExecuTorch assets.

Recommended Custom Path: ExecuTorch

  1. Export or download an ExecuTorch .pte model and matching tokenizer file.
  2. Add both files to the iOS app bundle, or place both files in example-app/android/app/src/main/assets/ for Android.
  3. Call setModel with engine: 'executorch', path, and tokenizerPath.

Legacy MediaPipe Path

Android still supports Gemma 3 LiteRT assets from Kaggle. Download both files and place them in example-app/android/app/src/main/assets/:

  • gemma-3-270m-it-int8.task
  • gemma-3-270m-it-int8.litertlm

iOS MediaPipe remains experimental because some .task models can fail during prefill. Apple Intelligence or ExecuTorch is preferred on iOS.

Known Issues

  • ExecuTorch is native-only and is not available on web.
  • iOS ExecuTorch requires linking the ExecuTorch SwiftPM products in the app target, and that app target must support iOS 17 or newer.
  • Apple Intelligence requires iOS 26.0 or later and a supported device.
  • Android requires minSdkVersion 24 or higher.
  • Model files are large, so production apps should usually download them after install.

About

Capacitor plugin to run LLM models locally in IOS and Android, support AppleInteligence

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

 

Packages

 
 
 

Contributors