import { LLMMessage, LLMSendOptions, LLMResponse, LLMStreamOptions, LLMStreamCallback, LLMStreamHandle, BuiltInModel, DownloadableModel, SetModelOptions, JSONSchema, GenerateObjectOptions, GenerateObjectResult, GenerateTextOptions, GenerateTextResult, EmbedResult } from './types'; export * from './types'; export * from './models'; export * from './rag'; /** * Check if on-device AI is available on the current device. * Returns false on unsupported platforms (web, etc.). */ export declare function isAvailable(): Promise; /** * Send messages to the on-device LLM and get a response. * * @param messages - Array of messages representing the conversation * @param options - Optional settings (systemPrompt fallback) * @returns Promise with the generated response * * @example * ```ts * const response = await sendMessage([ * { role: 'user', content: 'What is 2 + 2?' } * ]); * console.log(response.text); // "4" * ``` * * @example * ```ts * // With system prompt * const response = await sendMessage( * [{ role: 'user', content: 'Hello!' }], * { systemPrompt: 'You are a pirate. Respond in pirate speak.' } * ); * ``` * * @example * ```ts * // Multi-turn conversation * const response = await sendMessage([ * { role: 'system', content: 'You are a helpful assistant.' }, * { role: 'user', content: 'My name is Alice.' }, * { role: 'assistant', content: 'Nice to meet you, Alice!' }, * { role: 'user', content: 'What is my name?' } * ]); * ``` */ export declare function sendMessage(messages: LLMMessage[], options?: LLMSendOptions): Promise; /** * Stream messages to the on-device LLM and receive progressive token updates. * * @param messages - Array of messages representing the conversation * @param onToken - Callback function called for each token/chunk received * @param options - Optional settings (systemPrompt fallback) * @returns Object with stop() function to cancel streaming and promise that resolves when complete * * @example * ```ts * // Basic streaming * const { promise } = streamMessage( * [{ role: 'user', content: 'Tell me a story' }], * (event) => { * console.log(event.token); // Each token as it arrives * console.log(event.accumulatedText); // Full text so far * } * ); * await promise; * ``` * * @example * ```ts * // With cancellation * const { promise, stop } = streamMessage( * [{ role: 'user', content: 'Write a long essay' }], * (event) => setText(event.accumulatedText) * ); * * // Cancel after 5 seconds * setTimeout(() => stop(), 5000); * ``` */ export declare function streamMessage(messages: LLMMessage[], onToken: LLMStreamCallback, options?: LLMStreamOptions): LLMStreamHandle; /** * Generate a typed object instead of free text. * * You describe the shape you want with a JSON Schema. expo-ai-kit appends a * strict instruction to the system prompt, runs the on-device model, extracts * the JSON from its output (tolerating prose and ```json fences), validates it * against the schema, and — on a parse error or schema mismatch — feeds the * error back and re-prompts up to `maxRepairAttempts` times. * * Works on every backend (Apple Foundation Models, ML Kit, Gemma) because it is * orchestrated over {@link sendMessage}: it honors the same single-flight guard, * `AbortSignal`, and `systemPrompt` semantics. Keep schemas small and shallow — * on-device models follow flat shapes far more reliably than deeply nested ones. * * @param messages - The conversation, same shape as {@link sendMessage}. * @param schema - A JSON Schema describing the desired result. * @param options - Optional settings (systemPrompt, signal, maxRepairAttempts). * @returns `{ object, text }` — the validated value and the raw output. * @throws {ModelError} INFERENCE_FAILED if no schema-valid JSON is produced * after the repair attempts. Also propagates INFERENCE_BUSY / INFERENCE_CANCELLED * from the underlying generation. * * @example * ```ts * type Recipe = { title: string; minutes: number; ingredients: string[] }; * * const { object } = await generateObject( * [{ role: 'user', content: 'A quick weeknight pasta.' }], * { * type: 'object', * properties: { * title: { type: 'string' }, * minutes: { type: 'integer' }, * ingredients: { type: 'array', items: { type: 'string' } }, * }, * required: ['title', 'minutes', 'ingredients'], * }, * ); * object.title; // typed Recipe * ``` */ export declare function generateObject(messages: LLMMessage[], schema: JSONSchema, options?: GenerateObjectOptions): Promise>; /** * Generate text, optionally letting the model call tools (functions) you provide. * * Unlike {@link generateObject} (where the JSON *is* the answer), tool calling is * a loop: the model proposes a call, expo-ai-kit validates the arguments against * the tool's `parameters`, runs your `execute`, feeds the result back, and lets * the model continue — until it produces a plain-text answer or the `maxSteps` * budget is reached. With no `tools`, this is a single text generation. * * Orchestrated in JS over {@link sendMessage}, so it works on every backend * (Apple Foundation Models, ML Kit, Gemma) and inherits the single-flight guard, * `AbortSignal`, and `systemPrompt` semantics. On-device models are imperfect at * tool selection, so the loop is defensive: malformed calls, unknown tool names, * and schema-invalid arguments are re-prompted up to `maxRepairAttempts` times, * and a tool with no `execute` stops the loop and returns the proposed call for * you to gate. Keep tool sets small and `parameters` flat for best reliability. * * @param messages - The conversation, same shape as {@link sendMessage}. * @param options - Tools, `maxSteps`, `systemPrompt`, `signal`, `maxRepairAttempts`. * @returns `{ text, steps, toolCalls, toolResults, finishReason }`. * @throws {ModelError} INFERENCE_FAILED if the model keeps proposing an unknown * tool or schema-invalid arguments after the repair attempts. Also propagates * INFERENCE_BUSY / INFERENCE_CANCELLED from the underlying generation. * * @example * ```ts * const { text } = await generateText( * [{ role: 'user', content: 'What should I wear in Paris today?' }], * { * tools: { * getWeather: { * description: 'Get the current weather for a city.', * parameters: { * type: 'object', * properties: { city: { type: 'string' } }, * required: ['city'], * }, * execute: async ({ city }: { city: string }) => fetchWeather(city), * }, * }, * }, * ); * ``` * * @example * ```ts * // Human-in-the-loop: omit `execute` to gate the call yourself. * const res = await generateText(messages, { * tools: { deleteAccount: { description: '…', parameters: { type: 'object' } } }, * }); * if (res.finishReason === 'tool-calls') { * const call = res.toolCalls[0]; // confirm with the user before running * } * ``` */ export declare function generateText(messages: LLMMessage[], options?: GenerateTextOptions): Promise; /** * Turn text into embedding vectors for semantic search / on-device RAG. * * Returns one vector per input string (in order), which you can compare with * {@link cosineSimilarity} or store in a {@link createVectorStore} to retrieve * the most relevant chunks before a {@link sendMessage} / {@link generateText} * call. Pair with {@link chunkText} to split documents first. * * **iOS-only for now**, backed by Apple's `NLContextualEmbedding` — a zero- * download, OS-maintained model (no app-size cost, works even where Apple * Intelligence isn't enabled, iOS 17+). On Android/web it throws * `DEVICE_NOT_SUPPORTED`; the RAG toolkit (`chunkText`, `cosineSimilarity`, * `createVectorStore`) still works there with any vector source you bring. * * Embeddings don't use the generation KV-cache, so `embed()` is **not** subject * to the single-flight `INFERENCE_BUSY` guard — it can run alongside other work. * * @param texts - Non-empty array of strings to embed. * @returns `{ embeddings, dimensions }` — `embeddings[i]` is the vector for `texts[i]`. * @throws {ModelError} DEVICE_NOT_SUPPORTED off iOS, or if no embedding model is * available on the device. * * @example * ```ts * import { embed, chunkText, createVectorStore } from 'expo-ai-kit'; * * const chunks = chunkText(document); * const { embeddings } = await embed(chunks); * * const store = createVectorStore<{ text: string }>(); * store.addMany(chunks.map((text, i) => ({ id: `c${i}`, vector: embeddings[i], metadata: { text } }))); * * const { embeddings: [q] } = await embed([question]); * const context = store.search(q, { topK: 4 }).map((h) => h.metadata!.text).join('\n\n'); * const { text } = await sendMessage([ * { role: 'system', content: `Answer using only this context:\n${context}` }, * { role: 'user', content: question }, * ]); * ``` */ export declare function embed(texts: string[]): Promise; /** * Get all built-in models available on the current platform. * * Built-in models are provided by the OS and require no download. * On iOS this returns Apple Foundation Models; on Android, ML Kit. * * @returns Array of built-in models with availability status */ export declare function getBuiltInModels(): Promise; /** * Get all downloadable models from the registry, enriched with on-device status. * * Reads from the hardcoded MODEL_REGISTRY and queries the native layer * for the current download/load status of each model. * * @returns Array of downloadable models with their current status */ export declare function getDownloadableModels(): Promise; /** * Get all downloaded models available on the current device. * * @returns Array of downloadable models whose status is `downloaded`, `loading`, or `ready`. */ export declare function getDownloadedModels(): Promise; /** * Pick the best downloadable model the current device can run. * * Returns the most capable model (largest, by RAM requirement) whose * `meetsRequirements` is true — e.g. Gemma 4 E4B on high-spec phones, falling * back to E2B on more constrained ones — or `null` if the device can't run any. * * This is a convenience over {@link getDownloadableModels}; the caller still * downloads + activates explicitly. Pass `platform` is implicit (current OS). * * @example * ```ts * const best = await getRecommendedModel(); * if (best) { * await downloadModel(best.id, { onProgress }); * await setModel(best.id); * } * ``` */ export declare function getRecommendedModel(): Promise; /** * Download a model to the device. * * Looks up the model in the registry, validates platform support and * device requirements, then initiates the download with integrity verification. * * @param modelId - ID of the model to download (e.g. 'gemma-e2b') * @param options - Optional download configuration * @param options.onProgress - Callback with download progress (0-1) * @throws {ModelError} MODEL_NOT_FOUND if modelId is not in the registry * @throws {ModelError} DEVICE_NOT_SUPPORTED if platform is not supported * @throws {ModelError} DOWNLOAD_FAILED on network error * @throws {ModelError} DOWNLOAD_STORAGE_FULL if insufficient disk space * @throws {ModelError} DOWNLOAD_CORRUPT if SHA256 hash doesn't match */ export declare function downloadModel(modelId: string, options?: { onProgress?: (progress: number) => void; }): Promise; /** * Cancel an in-flight download for a model. * * The in-progress {@link downloadModel} promise rejects with a * DOWNLOAD_CANCELLED {@link ModelError}. No-op if the model isn't downloading. * * @param modelId - ID of the model whose download should be cancelled */ export declare function cancelDownload(modelId: string): Promise; /** * Delete a downloaded model from the device. * * If the model is currently loaded, it will be unloaded first. * * @param modelId - ID of the model to delete * @throws {ModelError} MODEL_NOT_FOUND if modelId is not in the registry */ export declare function deleteModel(modelId: string): Promise; /** * Set the active model for inference. * * This is the sole gatekeeper for model validity. If setModel succeeds, * the model is loaded and ready -- sendMessage never needs its own check. * * For downloadable models, this loads the model into memory (status * transitions: loading -> ready). Only one downloadable model can be * loaded at a time; the previous one is auto-unloaded. * * For built-in models, this simply switches the active backend. * * If setModel was never called, sendMessage uses the platform built-in * model (today's behavior, no error). * * @param modelId - ID of the model to activate (e.g. 'gemma-e2b', 'apple-fm', 'mlkit') * @param options - Optional configuration for model loading * @param options.backend - Hardware backend: 'auto' (default, GPU with CPU fallback), 'gpu', or 'cpu' * @throws {ModelError} MODEL_NOT_FOUND if modelId is invalid * @throws {ModelError} MODEL_NOT_DOWNLOADED if the downloadable model file is not on disk * @throws {ModelError} MODEL_LOAD_FAILED if loading into memory fails * @throws {ModelError} INFERENCE_OOM if device can't fit model in memory */ export declare function setModel(modelId: string, options?: SetModelOptions): Promise; /** * Get the ID of the currently active model. * * @returns The active model ID (e.g. 'apple-fm', 'mlkit', 'gemma-e2b') */ export declare function getActiveModel(): string; /** * Explicitly unload the current downloadable model from memory. * * Frees memory and reverts to the platform built-in model. * No-op if no downloadable model is currently loaded. */ export declare function unloadModel(): Promise; //# sourceMappingURL=index.d.ts.map