npm install cactus-react-native react-native-nitro-modulesGet started with Cactus in just a few lines of code:
import { CactusLM, type Message } from 'cactus-react-native';
// Create a new instance
const cactusLM = new CactusLM();
// Download the model
await cactusLM.download({
onProgress: (progress) => console.log(`Download: ${Math.round(progress * 100)}%`)
});
// Generate a completion
const messages: Message[] = [
{ role: 'user', content: 'What is the capital of France?' }
];
const result = await cactusLM.complete({ messages });
console.log(result.response); // "The capital of France is Paris."
// Clean up resources
await cactusLM.destroy();Using the React Hook:
import { useCactusLM } from 'cactus-react-native';
const App = () => {
const cactusLM = useCactusLM();
useEffect(() => {
// Download the model if not already available
if (!cactusLM.isDownloaded) {
cactusLM.download();
}
}, []);
const handleGenerate = () => {
// Generate a completion
cactusLM.complete({
messages: [{ role: 'user', content: 'Hello!' }],
});
};
if (cactusLM.isDownloading) {
return (
<Text>
Downloading model: {Math.round(cactusLM.downloadProgress * 100)}%
</Text>
);
}
return (
<>
<Button onPress={handleGenerate} title="Generate" />
<Text>{cactusLM.completion}</Text>
</>
);
};Generate text responses from the model by providing a conversation history.
import { CactusLM, type Message } from 'cactus-react-native';
const cactusLM = new CactusLM();
const messages: Message[] = [{ role: 'user', content: 'Hello, World!' }];
const onToken = (token: string) => { console.log('Token:', token) };
const result = await cactusLM.complete({ messages, onToken });
console.log('Completion result:', result);import { useCactusLM, type Message } from 'cactus-react-native';
const App = () => {
const cactusLM = useCactusLM();
const handleComplete = async () => {
const messages: Message[] = [{ role: 'user', content: 'Hello, World!' }];
const result = await cactusLM.complete({ messages });
console.log('Completion result:', result);
};
return (
<>
<Button title="Complete" onPress={handleComplete} />
<Text>{cactusLM.completion}</Text>
</>
);
};Vision allows you to pass images along with text prompts, enabling the model to analyze and understand visual content.
import { CactusLM, type Message } from 'cactus-react-native';
// Vision-capable model
const cactusLM = new CactusLM({ model: 'lfm2-vl-450m' });
const messages: Message[] = [
{
role: 'user',
content: "What's in the image?",
images: ['path/to/your/image'],
},
];
const result = await cactusLM.complete({ messages });
console.log('Response:', result.response);import { useCactusLM, type Message } from 'cactus-react-native';
const App = () => {
// Vision-capable model
const cactusLM = useCactusLM({ model: 'lfm2-vl-450m' });
const handleAnalyze = async () => {
const messages: Message[] = [
{
role: 'user',
content: "What's in the image?",
images: ['path/to/your/image'],
},
];
await cactusLM.complete({ messages });
};
return (
<>
<Button title="Analyze Image" onPress={handleAnalyze} />
<Text>{cactusLM.completion}</Text>
</>
);
};Enable the model to generate function calls by defining available tools and their parameters.
import { CactusLM, type Message, type Tool } from 'cactus-react-native';
const tools: Tool[] = [
{
name: 'get_weather',
description: 'Get current weather for a location',
parameters: {
type: 'object',
properties: {
location: {
type: 'string',
description: 'City name',
},
},
required: ['location'],
},
},
];
const cactusLM = new CactusLM();
const messages: Message[] = [
{ role: 'user', content: "What's the weather in San Francisco?" },
];
const result = await cactusLM.complete({ messages, tools });
console.log('Response:', result.response);
console.log('Function calls:', result.functionCalls);import { useCactusLM, type Message, type Tool } from 'cactus-react-native';
const tools: Tool[] = [
{
name: 'get_weather',
description: 'Get current weather for a location',
parameters: {
type: 'object',
properties: {
location: {
type: 'string',
description: 'City name',
},
},
required: ['location'],
},
},
];
const App = () => {
const cactusLM = useCactusLM();
const handleComplete = async () => {
const messages: Message[] = [
{ role: 'user', content: "What's the weather in San Francisco?" },
];
const result = await cactusLM.complete({ messages, tools });
console.log('Response:', result.response);
console.log('Function calls:', result.functionCalls);
};
return <Button title="Complete" onPress={handleComplete} />;
};RAG allows you to provide a corpus of documents that the model can reference during generation, enabling it to answer questions based on your data.
import { CactusLM, type Message } from 'cactus-react-native';
const cactusLM = new CactusLM({
corpusDir: 'path/to/your/corpus', // Directory containing .txt files
});
const messages: Message[] = [
{ role: 'user', content: 'What information is in the documents?' },
];
const result = await cactusLM.complete({ messages });
console.log(result.response);import { useCactusLM, type Message } from 'cactus-react-native';
const App = () => {
const cactusLM = useCactusLM({
corpusDir: 'path/to/your/corpus', // Directory containing .txt files
});
const handleAsk = async () => {
const messages: Message[] = [
{ role: 'user', content: 'What information is in the documents?' },
];
await cactusLM.complete({ messages });
};
return (
<>
<Button title="Ask Question" onPress={handleAsk} />
<Text>{cactusLM.completion}</Text>
</>
);
};Convert text and images into numerical vector representations that capture semantic meaning, useful for similarity search and semantic understanding.
import { CactusLM } from 'cactus-react-native';
const cactusLM = new CactusLM();
const result = await cactusLM.embed({ text: 'Hello, World!' });
console.log('Embedding vector:', result.embedding);
console.log('Embedding vector length:', result.embedding.length);import { useCactusLM } from 'cactus-react-native';
const App = () => {
const cactusLM = useCactusLM();
const handleEmbed = async () => {
const result = await cactusLM.embed({ text: 'Hello, World!' });
console.log('Embedding vector:', result.embedding);
console.log('Embedding vector length:', result.embedding.length);
};
return <Button title="Embed" onPress={handleEmbed} />;
};import { CactusLM } from 'cactus-react-native';
const cactusLM = new CactusLM({ model: 'lfm2-vl-450m' });
const result = await cactusLM.imageEmbed({ imagePath: 'path/to/your/image.jpg' });
console.log('Image embedding vector:', result.embedding);
console.log('Embedding vector length:', result.embedding.length);import { useCactusLM } from 'cactus-react-native';
const App = () => {
const cactusLM = useCactusLM({ model: 'lfm2-vl-450m' });
const handleImageEmbed = async () => {
const result = await cactusLM.imageEmbed({ imagePath: 'path/to/your/image.jpg' });
console.log('Image embedding vector:', result.embedding);
console.log('Embedding vector length:', result.embedding.length);
};
return <Button title="Embed Image" onPress={handleImageEmbed} />;
};The CactusLM supports a hybrid completion mode that falls back to a cloud-based LLM provider OpenRouter if local inference fails.
import { CactusLM, type Message } from 'cactus-react-native';
const cactusLM = new CactusLM();
const messages: Message[] = [
{ role: 'user', content: 'Hello, World!' }
];
// Falls back to remote if local fails
const result = await cactusLM.complete({
messages,
mode: 'hybrid'
});import { useCactusLM, type Message } from 'cactus-react-native';
const App = () => {
const cactusLM = useCactusLM();
const handleComplete = async () => {
const messages: Message[] = [
{ role: 'user', content: 'Hello, World!' }
];
// Falls back to remote if local fails
await cactusLM.complete({
messages,
mode: 'hybrid'
});
};
return (
<>
<Button title="Complete" onPress={handleComplete} />
<Text>{cactusLM.completion}</Text>
</>
);
};The CactusSTT class provides audio transcription and audio embedding capabilities using Whisper models.
Transcribe audio files to text with streaming support.
import { CactusSTT } from 'cactus-react-native';
const cactusSTT = new CactusSTT({ model: 'whisper-small' });
await cactusSTT.init();
const result = await cactusSTT.transcribe({
audioFilePath: 'path/to/audio.wav',
onToken: (token) => console.log('Token:', token)
});
console.log('Transcription:', result.response);import { useCactusSTT } from 'cactus-react-native';
const App = () => {
const cactusSTT = useCactusSTT({ model: 'whisper-small' });
const handleTranscribe = async () => {
const result = await cactusSTT.transcribe({
audioFilePath: 'path/to/audio.wav',
});
console.log('Transcription:', result.response);
};
return (
<>
<Button onPress={handleTranscribe} title="Transcribe" />
<Text>{cactusSTT.transcription}</Text>
</>
);
};Generate embeddings from audio files for audio understanding.
import { CactusSTT } from 'cactus-react-native';
const cactusSTT = new CactusSTT();
await cactusSTT.init();
const result = await cactusSTT.audioEmbed({
audioPath: 'path/to/audio.wav'
});
console.log('Audio embedding vector:', result.embedding);
console.log('Embedding vector length:', result.embedding.length);import { useCactusSTT } from 'cactus-react-native';
const App = () => {
const cactusSTT = useCactusSTT();
const handleAudioEmbed = async () => {
const result = await cactusSTT.audioEmbed({
audioPath: 'path/to/audio.wav'
});
console.log('Audio embedding vector:', result.embedding);
console.log('Embedding vector length:', result.embedding.length);
};
return <Button title="Embed Audio" onPress={handleAudioEmbed} />;
};new CactusLM(params?: CactusLMParams)
Parameters:
model- Model slug (default:'qwen3-0.6').contextSize- Context window size (default:2048).corpusDir- Directory containing text files for RAG (default:undefined).
download(params?: CactusLMDownloadParams): Promise<void>
Downloads the model. If the model is already downloaded, returns immediately with progress 1. Throws an error if a download is already in progress.
Parameters:
onProgress- Callback for download progress (0-1).
init(): Promise<void>
Initializes the model and prepares it for inference. Safe to call multiple times (idempotent). Throws an error if the model is not downloaded yet.
complete(params: CactusLMCompleteParams): Promise<CactusLMCompleteResult>
Performs text completion with optional streaming and tool support. Automatically calls init() if not already initialized. Throws an error if a generation (completion or embedding) is already in progress.
Parameters:
messages- Array ofMessageobjects.options- Generation options:temperature- Sampling temperature (default: model-optimized).topP- Nucleus sampling threshold (default: model-optimized).topK- Top-K sampling limit (default: model-optimized).maxTokens- Maximum number of tokens to generate (default:512).stopSequences- Array of strings to stop generation (default:undefined).
tools- Array ofToolobjects for function calling (default:undefined).onToken- Callback for streaming tokens.mode- Completion mode:'local'|'hybrid'(default:'local')
embed(params: CactusLMEmbedParams): Promise<CactusLMEmbedResult>
Generates embeddings for the given text. Automatically calls init() if not already initialized. Throws an error if a generation (completion or embedding) is already in progress.
Parameters:
text- Text to embed.
imageEmbed(params: CactusLMImageEmbedParams): Promise<CactusLMImageEmbedResult>
Generates embeddings for the given image. Requires a vision-capable model. Automatically calls init() if not already initialized. Throws an error if a generation (completion or embedding) is already in progress.
Parameters:
imagePath- Path to the image file.
stop(): Promise<void>
Stops ongoing generation.
reset(): Promise<void>
Resets the model's internal state, clearing any cached context. Automatically calls stop() first.
destroy(): Promise<void>
Releases all resources associated with the model. Automatically calls stop() first. Safe to call even if the model is not initialized.
getModels(): Promise<CactusModel[]>
Fetches available models from the database and checks their download status. Results are cached in memory after the first call and subsequent calls return the cached results.
The useCactusLM hook manages a CactusLM instance with reactive state. When model parameters (model, contextSize, or corpusDir) change, the hook creates a new instance and resets all state. The hook automatically cleans up resources when the component unmounts.
completion: string- Current generated text. Automatically accumulated during streaming. Cleared before each new completion and when callingreset()ordestroy().isGenerating: boolean- Whether the model is currently generating (completion or embedding). Both operations share this flag.isInitializing: boolean- Whether the model is initializing.isDownloaded: boolean- Whether the model is downloaded locally. Automatically checked when the hook mounts or model changes.isDownloading: boolean- Whether the model is being downloaded.downloadProgress: number- Download progress (0-1). Reset to0after download completes.error: string | null- Last error message from any operation, ornullif there is no error. Cleared before starting new operations.
download(params?: CactusLMDownloadParams): Promise<void>- Downloads the model. UpdatesisDownloadinganddownloadProgressstate during download. SetsisDownloadedtotrueon success.init(): Promise<void>- Initializes the model for inference. SetsisInitializingtotrueduring initialization.complete(params: CactusLMCompleteParams): Promise<CactusLMCompleteResult>- Generates text completions. Automatically accumulates tokens in thecompletionstate during streaming. SetsisGeneratingtotruewhile generating. Clearscompletionbefore starting.embed(params: CactusLMEmbedParams): Promise<CactusLMEmbedResult>- Generates embeddings for the given text. SetsisGeneratingtotrueduring operation.imageEmbed(params: CactusLMImageEmbedParams): Promise<CactusLMImageEmbedResult>- Generates embeddings for the given image. SetsisGeneratingtotruewhile generating.stop(): Promise<void>- Stops ongoing generation. Clears any errors.reset(): Promise<void>- Resets the model's internal state, clearing cached context. Also clears thecompletionstate.destroy(): Promise<void>- Releases all resources associated with the model. Clears thecompletionstate. Automatically called when the component unmounts.getModels(): Promise<CactusModel[]>- Fetches available models from the database and checks their download status. Results are cached in memory and reused on subsequent calls.
new CactusSTT(params?: CactusSTTParams)
Parameters:
model- Model slug (default:'whisper-small').contextSize- Context window size (default:2048).
download(params?: CactusSTTDownloadParams): Promise<void>
Downloads the model. If the model is already downloaded, returns immediately with progress 1. Throws an error if a download is already in progress.
Parameters:
onProgress- Callback for download progress (0-1).
init(): Promise<void>
Initializes the model and prepares it for inference. Safe to call multiple times (idempotent). Throws an error if the model is not downloaded yet.
transcribe(params: CactusSTTTranscribeParams): Promise<CactusSTTTranscribeResult>
Transcribes audio to text with optional streaming support. Automatically calls init() if not already initialized. Throws an error if a generation is already in progress.
Parameters:
audioFilePath- Path to the audio file.prompt- Optional prompt to guide transcription (default:'<|startoftranscript|><|en|><|transcribe|><|notimestamps|>').options- Transcription options:temperature- Sampling temperature (default: model-optimized).topP- Nucleus sampling threshold (default: model-optimized).topK- Top-K sampling limit (default: model-optimized).maxTokens- Maximum number of tokens to generate (default:512).stopSequences- Array of strings to stop generation (default:undefined).
onToken- Callback for streaming tokens.
audioEmbed(params: CactusSTTAudioEmbedParams): Promise<CactusSTTAudioEmbedResult>
Generates embeddings for the given audio file. Automatically calls init() if not already initialized. Throws an error if a generation is already in progress.
Parameters:
audioPath- Path to the audio file.
stop(): Promise<void>
Stops ongoing transcription or embedding generation.
reset(): Promise<void>
Resets the model's internal state. Automatically calls stop() first.
destroy(): Promise<void>
Releases all resources associated with the model. Automatically calls stop() first. Safe to call even if the model is not initialized.
getModels(): Promise<CactusModel[]>
Fetches available models from the database and checks their download status. Results are cached in memory after the first call and subsequent calls return the cached results.
The useCactusSTT hook manages a CactusSTT instance with reactive state. When model parameters (model, contextSize) change, the hook creates a new instance and resets all state. The hook automatically cleans up resources when the component unmounts.
transcription: string- Current transcription text. Automatically accumulated during streaming. Cleared before each new transcription and when callingreset()ordestroy().isGenerating: boolean- Whether the model is currently generating (transcription or embedding). Both operations share this flag.isInitializing: boolean- Whether the model is initializing.isDownloaded: boolean- Whether the model is downloaded locally. Automatically checked when the hook mounts or model changes.isDownloading: boolean- Whether the model is being downloaded.downloadProgress: number- Download progress (0-1). Reset to0after download completes.error: string | null- Last error message from any operation, ornullif there is no error. Cleared before starting new operations.
download(params?: CactusSTTDownloadParams): Promise<void>- Downloads the model. UpdatesisDownloadinganddownloadProgressstate during download. SetsisDownloadedtotrueon success.init(): Promise<void>- Initializes the model for inference. SetsisInitializingtotrueduring initialization.transcribe(params: CactusSTTTranscribeParams): Promise<CactusSTTTranscribeResult>- Transcribes audio to text. Automatically accumulates tokens in thetranscriptionstate during streaming. SetsisGeneratingtotruewhile generating. Clearstranscriptionbefore starting.audioEmbed(params: CactusSTTAudioEmbedParams): Promise<CactusSTTAudioEmbedResult>- Generates embeddings for the given audio. SetsisGeneratingtotrueduring operation.stop(): Promise<void>- Stops ongoing generation. Clears any errors.reset(): Promise<void>- Resets the model's internal state. Also clears thetranscriptionstate.destroy(): Promise<void>- Releases all resources associated with the model. Clears thetranscriptionstate. Automatically called when the component unmounts.getModels(): Promise<CactusModel[]>- Fetches available models from the database and checks their download status. Results are cached in memory and reused on subsequent calls.
interface CactusLMParams {
model?: string;
contextSize?: number;
corpusDir?: string;
}interface CactusLMDownloadParams {
onProgress?: (progress: number) => void;
}interface Message {
role: 'user' | 'assistant' | 'system';
content?: string;
images?: string[];
}interface CompleteOptions {
temperature?: number;
topP?: number;
topK?: number;
maxTokens?: number;
stopSequences?: string[];
}interface Tool {
name: string;
description: string;
parameters: {
type: 'object';
properties: {
[key: string]: {
type: string;
description: string;
};
};
required: string[];
};
}interface CactusLMCompleteParams {
messages: Message[];
options?: CompleteOptions;
tools?: Tool[];
onToken?: (token: string) => void;
mode?: 'local' | 'hybrid';
}interface CactusLMCompleteResult {
success: boolean;
response: string;
functionCalls?: {
name: string;
arguments: { [key: string]: any };
}[];
timeToFirstTokenMs: number;
totalTimeMs: number;
tokensPerSecond: number;
prefillTokens: number;
decodeTokens: number;
totalTokens: number;
}interface CactusLMEmbedParams {
text: string;
}interface CactusLMEmbedResult {
embedding: number[];
}interface CactusLMImageEmbedParams {
imagePath: string;
}interface CactusLMImageEmbedResult {
embedding: number[];
}interface CactusModel {
name: string;
slug: string;
quantization: number;
sizeMb: number;
downloadUrl: string;
supportsToolCalling: boolean;
supportsVision: boolean;
createdAt: Date;
isDownloaded: boolean;
}interface CactusSTTParams {
model?: string;
contextSize?: number;
}interface CactusSTTDownloadParams {
onProgress?: (progress: number) => void;
}interface TranscribeOptions {
temperature?: number;
topP?: number;
topK?: number;
maxTokens?: number;
stopSequences?: string[];
}interface CactusSTTTranscribeParams {
audioFilePath: string;
prompt?: string;
options?: TranscribeOptions;
onToken?: (token: string) => void;
}interface CactusSTTTranscribeResult {
success: boolean;
response: string;
timeToFirstTokenMs: number;
totalTimeMs: number;
tokensPerSecond: number;
prefillTokens: number;
decodeTokens: number;
totalTokens: number;
}interface CactusSTTAudioEmbedParams {
audioPath: string;
}interface CactusSTTAudioEmbedResult {
embedding: number[];
}Cactus offers powerful telemetry for all your projects. Create a token on the Cactus dashboard.
import { CactusConfig } from 'cactus-react-native';
// Enable Telemetry for your project
CactusConfig.telemetryToken = 'your-telemetry-token-here';
// Disable telemetry
CactusConfig.isTelemetryEnabled = false;Enable cloud fallback.
import { CactusConfig } from 'cactus-react-native';
// Set your Cactus token for hybrid mode
CactusConfig.cactusToken = 'your-cactus-token-here';- Model Selection - Choose smaller models for faster inference on mobile devices.
- Context Size - Reduce the context size to lower memory usage.
- Memory Management - Always call
destroy()when you're done with models to free up resources.
Check out our example app for a complete React Native implementation.
