expo-ai-kit 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,8 +7,8 @@ On-device AI for Expo & React Native — run LLMs locally. No API keys, no cloud
7
7
 
8
8
  Runs **Apple Foundation Models** (iOS 26+), **ML Kit** (Android), and downloadable
9
9
  **Gemma 4** (E2B / E4B, iOS + Android via [LiteRT-LM](https://ai.google.dev/edge/litert-lm))
10
- — with streaming, structured output, tool calling, cancellation, and runtime model switching,
11
- all on-device.
10
+ — with streaming, structured output, tool calling, **embeddings & on-device RAG**,
11
+ cancellation, and runtime model switching, all on-device.
12
12
 
13
13
  ## Install
14
14
 
@@ -98,6 +98,37 @@ Omit a tool's `execute` to gate it yourself: the loop stops with `finishReason:
98
98
  and hands you the proposed call to confirm before running. Keep tool sets small and parameter
99
99
  schemas flat — on-device models pick tools more reliably that way.
100
100
 
101
+ ## Embeddings & RAG
102
+
103
+ Turn text into vectors for semantic search and retrieval-augmented generation — find the
104
+ chunks of your own documents most relevant to a question, then feed them to the model. All
105
+ on-device: your data never leaves the phone.
106
+
107
+ ```tsx
108
+ import { embed, chunkText, createVectorStore, sendMessage } from 'expo-ai-kit';
109
+
110
+ // 1. Index your document once: split → embed → store
111
+ const chunks = chunkText(document); // overlapping, sentence-aware chunks
112
+ const { embeddings } = await embed(chunks); // one vector per chunk
113
+ const store = createVectorStore<{ text: string }>();
114
+ store.addMany(chunks.map((text, i) => ({ id: `c${i}`, vector: embeddings[i], metadata: { text } })));
115
+
116
+ // 2. At query time: embed the question, retrieve the top matches, answer from them
117
+ const { embeddings: [q] } = await embed([question]);
118
+ const context = store.search(q, { topK: 4 }).map((h) => h.metadata!.text).join('\n\n');
119
+
120
+ const { text } = await sendMessage([
121
+ { role: 'system', content: `Answer using only this context:\n${context}` },
122
+ { role: 'user', content: question },
123
+ ]);
124
+ ```
125
+
126
+ `embed()` is backed by Apple's `NLContextualEmbedding` — a **zero-download, OS-maintained**
127
+ model (iOS 17+, works even without Apple Intelligence). **iOS-only for now**; on Android it
128
+ throws `DEVICE_NOT_SUPPORTED` (MediaPipe support is planned). The toolkit —
129
+ `chunkText`, `cosineSimilarity`, and the `createVectorStore` (add / search top-k / `toJSON`
130
+ for persistence) — is pure JS and works on **both platforms with any vector source**.
131
+
101
132
  ## Downloadable models
102
133
 
103
134
  Beyond the OS built-ins, you can download open models (via LiteRT-LM) and switch to them at
@@ -166,6 +197,7 @@ file persists on disk, so its `'downloaded'` status survives restarts once re-re
166
197
  ## API
167
198
 
168
199
  Inference: `isAvailable`, `sendMessage`, `streamMessage`, `generateObject`, `generateText`.
200
+ Embeddings & RAG: `embed`, `chunkText`, `cosineSimilarity`, `createVectorStore`.
169
201
  Models: `getBuiltInModels`, `getDownloadableModels`, `getRecommendedModel`,
170
202
  `downloadModel`, `cancelDownload`, `deleteModel`, `setModel`, `unloadModel`, `getActiveModel`.
171
203
  Custom models: `registerModel`, `unregisterModel`, `getRegisteredModels`, `fetchModelMetadata`.
@@ -128,6 +128,20 @@ class ExpoAiKitModule : Module() {
128
128
  activeStreamJobs.remove(sessionId)
129
129
  }
130
130
 
131
+ // ==================================================================
132
+ // Embeddings
133
+ // ==================================================================
134
+ // iOS-only for now (Apple NLContextualEmbedding). The JS layer guards the
135
+ // platform and throws before reaching native, so this is a defensive stub
136
+ // that honors the same "CODE::reason" error contract. Android support via
137
+ // MediaPipe Text Embedder is planned.
138
+ AsyncFunction("embed") { _: List<String> ->
139
+ throw RuntimeException(
140
+ "DEVICE_NOT_SUPPORTED::On-device embeddings are iOS-only for now " +
141
+ "(Apple NLContextualEmbedding); Android support via MediaPipe is planned"
142
+ )
143
+ }
144
+
131
145
  // ==================================================================
132
146
  // Model discovery
133
147
  // ==================================================================
@@ -18,6 +18,10 @@ export interface ExpoAiKitNativeModule {
18
18
  sendMessage(messages: LLMMessage[], systemPrompt: string, sessionId: string): Promise<LLMResponse>;
19
19
  startStreaming(messages: LLMMessage[], systemPrompt: string, sessionId: string): Promise<void>;
20
20
  stopStreaming(sessionId: string): Promise<void>;
21
+ embed(texts: string[]): Promise<{
22
+ embeddings: number[][];
23
+ dimensions: number;
24
+ }>;
21
25
  getBuiltInModels(): BuiltInModel[];
22
26
  getDownloadableModelStatus(modelId: string): Promise<DownloadableModelStatus>;
23
27
  getDeviceRamBytes(): number;
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoAiKitModule.d.ts","sourceRoot":"","sources":["../src/ExpoAiKitModule.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EACL,YAAY,EACZ,uBAAuB,EACvB,UAAU,EACV,WAAW,EACX,cAAc,EACd,0BAA0B,EAC1B,qBAAqB,EACtB,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,qBAAqB,GAAG;IAClC,aAAa,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC/C,kBAAkB,EAAE,CAAC,KAAK,EAAE,0BAA0B,KAAK,IAAI,CAAC;IAChE,kBAAkB,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAC5D,CAAC;AAEF,8FAA8F;AAC9F,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,WAAW,qBAAqB;IAEpC,WAAW,IAAI,OAAO,CAAC;IAEvB,WAAW,CACT,QAAQ,EAAE,UAAU,EAAE,EACtB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC,CAAC;IACxB,cAAc,CACZ,QAAQ,EAAE,UAAU,EAAE,EACtB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGhD,gBAAgB,IAAI,YAAY,EAAE,CAAC;IAGnC,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC9E,iBAAiB,IAAI,MAAM,CAAC;IAM5B,QAAQ,CACN,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,sBAAsB,GACjC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,cAAc,IAAI,MAAM,CAAC;IAGzB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAG7B,aAAa,CACX,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAG5C,WAAW,CAAC,CAAC,SAAS,MAAM,qBAAqB,EAC/C,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,qBAAqB,CAAC,CAAC,CAAC,GACjC,iBAAiB,CAAC;CACtB;AAED,QAAA,MAAM,eAAe,uBACoC,CAAC;AAE1D,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"ExpoAiKitModule.d.ts","sourceRoot":"","sources":["../src/ExpoAiKitModule.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EACL,YAAY,EACZ,uBAAuB,EACvB,UAAU,EACV,WAAW,EACX,cAAc,EACd,0BAA0B,EAC1B,qBAAqB,EACtB,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,qBAAqB,GAAG;IAClC,aAAa,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC/C,kBAAkB,EAAE,CAAC,KAAK,EAAE,0BAA0B,KAAK,IAAI,CAAC;IAChE,kBAAkB,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAC5D,CAAC;AAEF,8FAA8F;AAC9F,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,WAAW,qBAAqB;IAEpC,WAAW,IAAI,OAAO,CAAC;IAEvB,WAAW,CACT,QAAQ,EAAE,UAAU,EAAE,EACtB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC,CAAC;IACxB,cAAc,CACZ,QAAQ,EAAE,UAAU,EAAE,EACtB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAIhD,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,EAAE,EAAE,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAGhF,gBAAgB,IAAI,YAAY,EAAE,CAAC;IAGnC,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC9E,iBAAiB,IAAI,MAAM,CAAC;IAM5B,QAAQ,CACN,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,sBAAsB,GACjC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,cAAc,IAAI,MAAM,CAAC;IAGzB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAG7B,aAAa,CACX,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAG5C,WAAW,CAAC,CAAC,SAAS,MAAM,qBAAqB,EAC/C,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,qBAAqB,CAAC,CAAC,CAAC,GACjC,iBAAiB,CAAC;CACtB;AAED,QAAA,MAAM,eAAe,uBACoC,CAAC;AAE1D,eAAe,eAAe,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoAiKitModule.js","sourceRoot":"","sources":["../src/ExpoAiKitModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAmFxD,MAAM,eAAe,GACnB,mBAAmB,CAAwB,WAAW,CAAC,CAAC;AAE1D,eAAe,eAAe,CAAC","sourcesContent":["import { requireNativeModule } from 'expo-modules-core';\nimport type { EventSubscription } from 'expo-modules-core';\nimport {\n BuiltInModel,\n DownloadableModelStatus,\n LLMMessage,\n LLMResponse,\n LLMStreamEvent,\n ModelDownloadProgressEvent,\n ModelStateChangeEvent,\n} from './types';\n\nexport type ExpoAiKitModuleEvents = {\n onStreamToken: (event: LLMStreamEvent) => void;\n onDownloadProgress: (event: ModelDownloadProgressEvent) => void;\n onModelStateChange: (event: ModelStateChangeEvent) => void;\n};\n\n/** Generation parameters passed to native. All fields optional; -1 / absent means \"unset\". */\nexport type NativeGenerationConfig = {\n temperature?: number;\n topK?: number;\n topP?: number;\n seed?: number;\n maxTokens?: number;\n};\n\nexport interface ExpoAiKitNativeModule {\n // Existing inference API\n isAvailable(): boolean;\n // sessionId lets stopStreaming() cancel an in-flight (non-streaming) generation too.\n sendMessage(\n messages: LLMMessage[],\n systemPrompt: string,\n sessionId: string\n ): Promise<LLMResponse>;\n startStreaming(\n messages: LLMMessage[],\n systemPrompt: string,\n sessionId: string\n ): Promise<void>;\n // Cancels either a streaming session or a sendMessage session by id.\n stopStreaming(sessionId: string): Promise<void>;\n\n // Model discovery\n getBuiltInModels(): BuiltInModel[];\n // Async: iOS reads actor-isolated state (so it bridges as a Promise); Android\n // returns synchronously. Callers must await — see getDownloadableModels.\n getDownloadableModelStatus(modelId: string): Promise<DownloadableModelStatus>;\n getDeviceRamBytes(): number;\n\n // Model selection & memory management\n // setModel is async: switching to a downloadable model loads it into memory.\n // Auto-unloads the previous downloadable model (only one loaded at a time).\n // `generation` carries best-effort sampling defaults for the session.\n setModel(\n modelId: string,\n minRamBytes: number,\n backend: string,\n generation: NativeGenerationConfig\n ): Promise<void>;\n getActiveModel(): string;\n // Explicitly free memory from the loaded downloadable model.\n // Reverts to the platform built-in model.\n unloadModel(): Promise<void>;\n\n // Model lifecycle (downloadable models only)\n downloadModel(\n modelId: string,\n url: string,\n sha256: string\n ): Promise<void>;\n // Cancels an in-flight download for the given model (no-op if none).\n cancelDownload(modelId: string): Promise<void>;\n deleteModel(modelId: string): Promise<void>;\n\n // Event subscription\n addListener<K extends keyof ExpoAiKitModuleEvents>(\n eventName: K,\n listener: ExpoAiKitModuleEvents[K]\n ): EventSubscription;\n}\n\nconst ExpoAiKitModule =\n requireNativeModule<ExpoAiKitNativeModule>('ExpoAiKit');\n\nexport default ExpoAiKitModule;\n"]}
1
+ {"version":3,"file":"ExpoAiKitModule.js","sourceRoot":"","sources":["../src/ExpoAiKitModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAuFxD,MAAM,eAAe,GACnB,mBAAmB,CAAwB,WAAW,CAAC,CAAC;AAE1D,eAAe,eAAe,CAAC","sourcesContent":["import { requireNativeModule } from 'expo-modules-core';\nimport type { EventSubscription } from 'expo-modules-core';\nimport {\n BuiltInModel,\n DownloadableModelStatus,\n LLMMessage,\n LLMResponse,\n LLMStreamEvent,\n ModelDownloadProgressEvent,\n ModelStateChangeEvent,\n} from './types';\n\nexport type ExpoAiKitModuleEvents = {\n onStreamToken: (event: LLMStreamEvent) => void;\n onDownloadProgress: (event: ModelDownloadProgressEvent) => void;\n onModelStateChange: (event: ModelStateChangeEvent) => void;\n};\n\n/** Generation parameters passed to native. All fields optional; -1 / absent means \"unset\". */\nexport type NativeGenerationConfig = {\n temperature?: number;\n topK?: number;\n topP?: number;\n seed?: number;\n maxTokens?: number;\n};\n\nexport interface ExpoAiKitNativeModule {\n // Existing inference API\n isAvailable(): boolean;\n // sessionId lets stopStreaming() cancel an in-flight (non-streaming) generation too.\n sendMessage(\n messages: LLMMessage[],\n systemPrompt: string,\n sessionId: string\n ): Promise<LLMResponse>;\n startStreaming(\n messages: LLMMessage[],\n systemPrompt: string,\n sessionId: string\n ): Promise<void>;\n // Cancels either a streaming session or a sendMessage session by id.\n stopStreaming(sessionId: string): Promise<void>;\n\n // Embeddings. iOS-only (Apple NLContextualEmbedding); the JS layer guards the\n // platform, so this is never reached on Android/web.\n embed(texts: string[]): Promise<{ embeddings: number[][]; dimensions: number }>;\n\n // Model discovery\n getBuiltInModels(): BuiltInModel[];\n // Async: iOS reads actor-isolated state (so it bridges as a Promise); Android\n // returns synchronously. Callers must await — see getDownloadableModels.\n getDownloadableModelStatus(modelId: string): Promise<DownloadableModelStatus>;\n getDeviceRamBytes(): number;\n\n // Model selection & memory management\n // setModel is async: switching to a downloadable model loads it into memory.\n // Auto-unloads the previous downloadable model (only one loaded at a time).\n // `generation` carries best-effort sampling defaults for the session.\n setModel(\n modelId: string,\n minRamBytes: number,\n backend: string,\n generation: NativeGenerationConfig\n ): Promise<void>;\n getActiveModel(): string;\n // Explicitly free memory from the loaded downloadable model.\n // Reverts to the platform built-in model.\n unloadModel(): Promise<void>;\n\n // Model lifecycle (downloadable models only)\n downloadModel(\n modelId: string,\n url: string,\n sha256: string\n ): Promise<void>;\n // Cancels an in-flight download for the given model (no-op if none).\n cancelDownload(modelId: string): Promise<void>;\n deleteModel(modelId: string): Promise<void>;\n\n // Event subscription\n addListener<K extends keyof ExpoAiKitModuleEvents>(\n eventName: K,\n listener: ExpoAiKitModuleEvents[K]\n ): EventSubscription;\n}\n\nconst ExpoAiKitModule =\n requireNativeModule<ExpoAiKitNativeModule>('ExpoAiKit');\n\nexport default ExpoAiKitModule;\n"]}
package/build/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { LLMMessage, LLMSendOptions, LLMResponse, LLMStreamOptions, LLMStreamCallback, LLMStreamHandle, BuiltInModel, DownloadableModel, SetModelOptions, JSONSchema, GenerateObjectOptions, GenerateObjectResult, GenerateTextOptions, GenerateTextResult } from './types';
1
+ import { LLMMessage, LLMSendOptions, LLMResponse, LLMStreamOptions, LLMStreamCallback, LLMStreamHandle, BuiltInModel, DownloadableModel, SetModelOptions, JSONSchema, GenerateObjectOptions, GenerateObjectResult, GenerateTextOptions, GenerateTextResult, EmbedResult } from './types';
2
2
  export * from './types';
3
3
  export * from './models';
4
+ export * from './rag';
4
5
  /**
5
6
  * Check if on-device AI is available on the current device.
6
7
  * Returns false on unsupported platforms (web, etc.).
@@ -174,6 +175,47 @@ export declare function generateObject<T = unknown>(messages: LLMMessage[], sche
174
175
  * ```
175
176
  */
176
177
  export declare function generateText(messages: LLMMessage[], options?: GenerateTextOptions): Promise<GenerateTextResult>;
178
+ /**
179
+ * Turn text into embedding vectors for semantic search / on-device RAG.
180
+ *
181
+ * Returns one vector per input string (in order), which you can compare with
182
+ * {@link cosineSimilarity} or store in a {@link createVectorStore} to retrieve
183
+ * the most relevant chunks before a {@link sendMessage} / {@link generateText}
184
+ * call. Pair with {@link chunkText} to split documents first.
185
+ *
186
+ * **iOS-only for now**, backed by Apple's `NLContextualEmbedding` — a zero-
187
+ * download, OS-maintained model (no app-size cost, works even where Apple
188
+ * Intelligence isn't enabled, iOS 17+). On Android/web it throws
189
+ * `DEVICE_NOT_SUPPORTED`; the RAG toolkit (`chunkText`, `cosineSimilarity`,
190
+ * `createVectorStore`) still works there with any vector source you bring.
191
+ *
192
+ * Embeddings don't use the generation KV-cache, so `embed()` is **not** subject
193
+ * to the single-flight `INFERENCE_BUSY` guard — it can run alongside other work.
194
+ *
195
+ * @param texts - Non-empty array of strings to embed.
196
+ * @returns `{ embeddings, dimensions }` — `embeddings[i]` is the vector for `texts[i]`.
197
+ * @throws {ModelError} DEVICE_NOT_SUPPORTED off iOS, or if no embedding model is
198
+ * available on the device.
199
+ *
200
+ * @example
201
+ * ```ts
202
+ * import { embed, chunkText, createVectorStore } from 'expo-ai-kit';
203
+ *
204
+ * const chunks = chunkText(document);
205
+ * const { embeddings } = await embed(chunks);
206
+ *
207
+ * const store = createVectorStore<{ text: string }>();
208
+ * store.addMany(chunks.map((text, i) => ({ id: `c${i}`, vector: embeddings[i], metadata: { text } })));
209
+ *
210
+ * const { embeddings: [q] } = await embed([question]);
211
+ * const context = store.search(q, { topK: 4 }).map((h) => h.metadata!.text).join('\n\n');
212
+ * const { text } = await sendMessage([
213
+ * { role: 'system', content: `Answer using only this context:\n${context}` },
214
+ * { role: 'user', content: question },
215
+ * ]);
216
+ * ```
217
+ */
218
+ export declare function embed(texts: string[]): Promise<EmbedResult>;
177
219
  /**
178
220
  * Get all built-in models available on the current platform.
179
221
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,UAAU,EACV,cAAc,EACd,WAAW,EACX,gBAAgB,EAEhB,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,iBAAiB,EAIjB,eAAe,EACf,UAAU,EACV,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAInB,MAAM,SAAS,CAAC;AAiBjB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AA0HzB;;;GAGG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAKpD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,UAAU,EAAE,EACtB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,WAAW,CAAC,CAmEtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,UAAU,EAAE,EACtB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,CAAC,EAAE,gBAAgB,GACzB,eAAe,CAwFjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAsB,cAAc,CAAC,CAAC,GAAG,OAAO,EAC9C,QAAQ,EAAE,UAAU,EAAE,EACtB,MAAM,EAAE,UAAU,EAClB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAoElC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,UAAU,EAAE,EACtB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,CAmJ7B;AAMD;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAKhE;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAkC1E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAM7E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACpD,OAAO,CAAC,IAAI,CAAC,CA+Cf;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKnE;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhE;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAQxF;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAEjD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,UAAU,EACV,cAAc,EACd,WAAW,EACX,gBAAgB,EAEhB,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,iBAAiB,EAIjB,eAAe,EACf,UAAU,EACV,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAIlB,WAAW,EACZ,MAAM,SAAS,CAAC;AAiBjB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC;AA0HtB;;;GAGG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAKpD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,UAAU,EAAE,EACtB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,WAAW,CAAC,CAmEtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,UAAU,EAAE,EACtB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,CAAC,EAAE,gBAAgB,GACzB,eAAe,CAwFjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAsB,cAAc,CAAC,CAAC,GAAG,OAAO,EAC9C,QAAQ,EAAE,UAAU,EAAE,EACtB,MAAM,EAAE,UAAU,EAClB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAoElC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,UAAU,EAAE,EACtB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,CAmJ7B;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAsB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAkBjE;AAMD;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAKhE;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAkC1E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAM7E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACpD,OAAO,CAAC,IAAI,CAAC,CA+Cf;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKnE;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhE;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAQxF;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAEjD"}
package/build/index.js CHANGED
@@ -6,6 +6,7 @@ import { buildToolInstruction, parseToolCall, buildUnknownToolRepair, buildToolA
6
6
  import { getAllModels, getRegistryEntry } from './models';
7
7
  export * from './types';
8
8
  export * from './models';
9
+ export * from './rag';
9
10
  const DEFAULT_SYSTEM_PROMPT = 'You are a helpful, friendly assistant. Answer the user directly and concisely.';
10
11
  const DEFAULT_OBJECT_SYSTEM_PROMPT = 'You output structured data as JSON. Follow the provided JSON Schema exactly.';
11
12
  let streamIdCounter = 0;
@@ -598,6 +599,64 @@ export async function generateText(messages, options) {
598
599
  };
599
600
  }
600
601
  // ============================================================================
602
+ // Embeddings API
603
+ // ============================================================================
604
+ /**
605
+ * Turn text into embedding vectors for semantic search / on-device RAG.
606
+ *
607
+ * Returns one vector per input string (in order), which you can compare with
608
+ * {@link cosineSimilarity} or store in a {@link createVectorStore} to retrieve
609
+ * the most relevant chunks before a {@link sendMessage} / {@link generateText}
610
+ * call. Pair with {@link chunkText} to split documents first.
611
+ *
612
+ * **iOS-only for now**, backed by Apple's `NLContextualEmbedding` — a zero-
613
+ * download, OS-maintained model (no app-size cost, works even where Apple
614
+ * Intelligence isn't enabled, iOS 17+). On Android/web it throws
615
+ * `DEVICE_NOT_SUPPORTED`; the RAG toolkit (`chunkText`, `cosineSimilarity`,
616
+ * `createVectorStore`) still works there with any vector source you bring.
617
+ *
618
+ * Embeddings don't use the generation KV-cache, so `embed()` is **not** subject
619
+ * to the single-flight `INFERENCE_BUSY` guard — it can run alongside other work.
620
+ *
621
+ * @param texts - Non-empty array of strings to embed.
622
+ * @returns `{ embeddings, dimensions }` — `embeddings[i]` is the vector for `texts[i]`.
623
+ * @throws {ModelError} DEVICE_NOT_SUPPORTED off iOS, or if no embedding model is
624
+ * available on the device.
625
+ *
626
+ * @example
627
+ * ```ts
628
+ * import { embed, chunkText, createVectorStore } from 'expo-ai-kit';
629
+ *
630
+ * const chunks = chunkText(document);
631
+ * const { embeddings } = await embed(chunks);
632
+ *
633
+ * const store = createVectorStore<{ text: string }>();
634
+ * store.addMany(chunks.map((text, i) => ({ id: `c${i}`, vector: embeddings[i], metadata: { text } })));
635
+ *
636
+ * const { embeddings: [q] } = await embed([question]);
637
+ * const context = store.search(q, { topK: 4 }).map((h) => h.metadata!.text).join('\n\n');
638
+ * const { text } = await sendMessage([
639
+ * { role: 'system', content: `Answer using only this context:\n${context}` },
640
+ * { role: 'user', content: question },
641
+ * ]);
642
+ * ```
643
+ */
644
+ export async function embed(texts) {
645
+ if (Platform.OS !== 'ios') {
646
+ throw new ModelError('DEVICE_NOT_SUPPORTED', '', Platform.OS === 'android'
647
+ ? 'embed() is iOS-only for now (Apple NLContextualEmbedding); Android support via MediaPipe is planned. ' +
648
+ 'The RAG toolkit (chunkText, cosineSimilarity, createVectorStore) works on Android with any vector source.'
649
+ : 'embed() is only available on iOS');
650
+ }
651
+ if (!Array.isArray(texts) || texts.length === 0) {
652
+ throw new Error('texts array cannot be empty');
653
+ }
654
+ if (!texts.every((t) => typeof t === 'string')) {
655
+ throw new Error('texts must be an array of strings');
656
+ }
657
+ return wrapNative(() => ExpoAiKitModule.embed(texts));
658
+ }
659
+ // ============================================================================
601
660
  // Model Management API
602
661
  // ============================================================================
603
662
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import ExpoAiKitModule, { type NativeGenerationConfig } from './ExpoAiKitModule';\nimport { Platform } from 'react-native';\nimport {\n LLMMessage,\n LLMSendOptions,\n LLMResponse,\n LLMStreamOptions,\n LLMStreamEvent,\n LLMStreamCallback,\n LLMStreamHandle,\n BuiltInModel,\n DownloadableModel,\n GenerationConfig,\n ModelError,\n ModelErrorCode,\n SetModelOptions,\n JSONSchema,\n GenerateObjectOptions,\n GenerateObjectResult,\n GenerateTextOptions,\n GenerateTextResult,\n ToolCall,\n ToolResult,\n StepResult,\n} from './types';\nimport {\n buildSchemaInstruction,\n buildSchemaRepair,\n extractJson,\n validateAgainstSchema,\n REPAIR_INVALID_JSON,\n} from './structured';\nimport {\n buildToolInstruction,\n parseToolCall,\n buildUnknownToolRepair,\n buildToolArgsRepair,\n formatToolResult,\n} from './tools';\nimport { getAllModels, getRegistryEntry } from './models';\n\nexport * from './types';\nexport * from './models';\n\nconst DEFAULT_SYSTEM_PROMPT =\n 'You are a helpful, friendly assistant. Answer the user directly and concisely.';\n\nconst DEFAULT_OBJECT_SYSTEM_PROMPT =\n 'You output structured data as JSON. Follow the provided JSON Schema exactly.';\n\nlet streamIdCounter = 0;\nfunction generateSessionId(): string {\n return `gen_${Date.now()}_${++streamIdCounter}`;\n}\n\n// The set of codes the native layer encodes in error messages as \"CODE:modelId:reason\".\nconst KNOWN_ERROR_CODES = new Set<ModelErrorCode>([\n 'MODEL_NOT_FOUND',\n 'MODEL_NOT_DOWNLOADED',\n 'DOWNLOAD_FAILED',\n 'DOWNLOAD_CORRUPT',\n 'DOWNLOAD_STORAGE_FULL',\n 'DOWNLOAD_CANCELLED',\n 'INFERENCE_OOM',\n 'INFERENCE_FAILED',\n 'INFERENCE_BUSY',\n 'INFERENCE_CANCELLED',\n 'MODEL_LOAD_FAILED',\n 'DEVICE_NOT_SUPPORTED',\n]);\n\n/**\n * Normalize an error from the native layer into a {@link ModelError}.\n *\n * The native modules format failures as \"CODE:modelId:reason\" (see the\n * GemmaError/GemmaInferenceClient contract). Expo surfaces that string as the\n * error's message, so we parse it here and rethrow a typed ModelError with a\n * reliable `.code` and `.modelId`. Anything unrecognized becomes UNKNOWN.\n */\nfunction toModelError(e: unknown): never {\n if (e instanceof ModelError) throw e;\n const message = String((e as any)?.message ?? e ?? '');\n const match = /^([A-Z_]+):([^:]*):([\\s\\S]*)$/.exec(message);\n if (match && KNOWN_ERROR_CODES.has(match[1] as ModelErrorCode)) {\n throw new ModelError(match[1] as ModelErrorCode, match[2], match[3]);\n }\n throw new ModelError('UNKNOWN', '', message);\n}\n\n/** Run a native promise, normalizing any rejection into a ModelError. */\nasync function wrapNative<T>(run: () => Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (e) {\n toModelError(e);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Single-flight inference guard\n// ---------------------------------------------------------------------------\n// On-device models are backed by a single native context + KV cache that is not\n// safe for concurrent decodes (interleaving can corrupt the cache and crash the\n// native side). JS is single-threaded, so a synchronous check-and-set of this\n// flag before any `await` is race-free. The flag is shared by sendMessage and\n// streamMessage and is held until the *native* call settles — not until an\n// early abort — so a detached-but-still-running generation still blocks a new one.\nlet inferenceInFlight = false;\n\nfunction acquireInference(): void {\n if (inferenceInFlight) {\n throw new ModelError(\n 'INFERENCE_BUSY',\n '',\n 'A generation is already in flight. Wait for it to finish, or stop the active stream first.'\n );\n }\n inferenceInFlight = true;\n}\n\n/**\n * Map the public GenerationConfig to the native shape, dropping undefined fields\n * and validating ranges up front so callers get a clear error instead of an\n * opaque native MODEL_LOAD_FAILED from the sampler.\n */\nfunction toNativeGeneration(g?: GenerationConfig): NativeGenerationConfig {\n const out: NativeGenerationConfig = {};\n if (g?.temperature != null) {\n if (g.temperature < 0) {\n throw new Error('generation.temperature must be >= 0');\n }\n out.temperature = g.temperature;\n }\n if (g?.topK != null) {\n if (!Number.isInteger(g.topK) || g.topK <= 0) {\n throw new Error('generation.topK must be a positive integer');\n }\n out.topK = g.topK;\n }\n if (g?.topP != null) {\n if (g.topP < 0 || g.topP > 1) {\n throw new Error('generation.topP must be within [0, 1]');\n }\n out.topP = g.topP;\n }\n if (g?.seed != null) {\n if (!Number.isInteger(g.seed)) {\n throw new Error('generation.seed must be an integer');\n }\n out.seed = g.seed;\n }\n if (g?.maxTokens != null) {\n if (!Number.isInteger(g.maxTokens) || g.maxTokens <= 0) {\n throw new Error('generation.maxTokens must be a positive integer');\n }\n out.maxTokens = g.maxTokens;\n }\n return out;\n}\n\n// ============================================================================\n// Inference API\n// ============================================================================\n\n/**\n * Check if on-device AI is available on the current device.\n * Returns false on unsupported platforms (web, etc.).\n */\nexport async function isAvailable(): Promise<boolean> {\n if (Platform.OS !== 'ios' && Platform.OS !== 'android') {\n return false;\n }\n return ExpoAiKitModule.isAvailable();\n}\n\n/**\n * Send messages to the on-device LLM and get a response.\n *\n * @param messages - Array of messages representing the conversation\n * @param options - Optional settings (systemPrompt fallback)\n * @returns Promise with the generated response\n *\n * @example\n * ```ts\n * const response = await sendMessage([\n * { role: 'user', content: 'What is 2 + 2?' }\n * ]);\n * console.log(response.text); // \"4\"\n * ```\n *\n * @example\n * ```ts\n * // With system prompt\n * const response = await sendMessage(\n * [{ role: 'user', content: 'Hello!' }],\n * { systemPrompt: 'You are a pirate. Respond in pirate speak.' }\n * );\n * ```\n *\n * @example\n * ```ts\n * // Multi-turn conversation\n * const response = await sendMessage([\n * { role: 'system', content: 'You are a helpful assistant.' },\n * { role: 'user', content: 'My name is Alice.' },\n * { role: 'assistant', content: 'Nice to meet you, Alice!' },\n * { role: 'user', content: 'What is my name?' }\n * ]);\n * ```\n */\nexport async function sendMessage(\n messages: LLMMessage[],\n options?: LLMSendOptions\n): Promise<LLMResponse> {\n if (Platform.OS !== 'ios' && Platform.OS !== 'android') {\n return { text: '' };\n }\n\n if (!messages || messages.length === 0) {\n throw new Error('messages array cannot be empty');\n }\n\n if (options?.signal?.aborted) {\n throw new ModelError('INFERENCE_CANCELLED', '', 'Aborted before start');\n }\n\n // Determine system prompt: use from messages array if present, else options, else default\n const hasSystemMessage = messages.some((m) => m.role === 'system');\n const systemPrompt = hasSystemMessage\n ? '' // Native will extract from messages\n : options?.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;\n\n acquireInference(); // throws INFERENCE_BUSY if a generation is already running\n const sessionId = generateSessionId();\n\n // Hold the single-flight flag until the NATIVE call settles — even if the\n // caller aborts early — because the model may keep computing in the background.\n const native = ExpoAiKitModule.sendMessage(messages, systemPrompt, sessionId);\n const release = () => {\n inferenceInFlight = false;\n };\n native.then(release, release);\n\n const signal = options?.signal;\n if (!signal) {\n try {\n return await native;\n } catch (e) {\n toModelError(e);\n }\n }\n\n // Race the native result against the abort signal. On abort we unblock the\n // caller immediately and best-effort ask native to cancel; the flag stays\n // held (via `release` above) until the native call actually finishes.\n return await new Promise<LLMResponse>((resolve, reject) => {\n let done = false;\n const finish = (action: () => void) => {\n if (done) return;\n done = true;\n signal.removeEventListener('abort', onAbort);\n action();\n };\n function onAbort() {\n ExpoAiKitModule.stopStreaming(sessionId).catch(() => {});\n finish(() => reject(new ModelError('INFERENCE_CANCELLED', '', 'Aborted by caller')));\n }\n signal.addEventListener('abort', onAbort);\n native.then(\n (r) => finish(() => resolve(r)),\n (e) =>\n finish(() => {\n try {\n toModelError(e);\n } catch (me) {\n reject(me);\n }\n })\n );\n });\n}\n\n/**\n * Stream messages to the on-device LLM and receive progressive token updates.\n *\n * @param messages - Array of messages representing the conversation\n * @param onToken - Callback function called for each token/chunk received\n * @param options - Optional settings (systemPrompt fallback)\n * @returns Object with stop() function to cancel streaming and promise that resolves when complete\n *\n * @example\n * ```ts\n * // Basic streaming\n * const { promise } = streamMessage(\n * [{ role: 'user', content: 'Tell me a story' }],\n * (event) => {\n * console.log(event.token); // Each token as it arrives\n * console.log(event.accumulatedText); // Full text so far\n * }\n * );\n * await promise;\n * ```\n *\n * @example\n * ```ts\n * // With cancellation\n * const { promise, stop } = streamMessage(\n * [{ role: 'user', content: 'Write a long essay' }],\n * (event) => setText(event.accumulatedText)\n * );\n *\n * // Cancel after 5 seconds\n * setTimeout(() => stop(), 5000);\n * ```\n */\nexport function streamMessage(\n messages: LLMMessage[],\n onToken: LLMStreamCallback,\n options?: LLMStreamOptions\n): LLMStreamHandle {\n // Handle unsupported platforms\n if (Platform.OS !== 'ios' && Platform.OS !== 'android') {\n return {\n promise: Promise.resolve({ text: '' }),\n stop: () => {},\n };\n }\n\n if (!messages || messages.length === 0) {\n return {\n promise: Promise.reject(new Error('messages array cannot be empty')),\n stop: () => {},\n };\n }\n\n if (inferenceInFlight) {\n return {\n promise: Promise.reject(\n new ModelError(\n 'INFERENCE_BUSY',\n '',\n 'A generation is already in flight. Stop the active stream first.'\n )\n ),\n stop: () => {},\n };\n }\n inferenceInFlight = true; // set synchronously — race-free with other JS\n\n const sessionId = generateSessionId();\n\n // Determine system prompt: use from messages array if present, else options, else default\n const hasSystemMessage = messages.some((m) => m.role === 'system');\n const systemPrompt = hasSystemMessage\n ? '' // Native will extract from messages\n : options?.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;\n\n let finalText = '';\n let settled = false;\n let subscription: ReturnType<typeof ExpoAiKitModule.addListener> | undefined;\n let resolveOuter!: (r: LLMResponse) => void;\n let rejectOuter!: (e: unknown) => void;\n\n // Settle exactly once: remove the listener and release the single-flight flag.\n const settle = (action: () => void) => {\n if (settled) return;\n settled = true;\n subscription?.remove();\n inferenceInFlight = false;\n action();\n };\n\n const promise = new Promise<LLMResponse>((resolve, reject) => {\n resolveOuter = resolve;\n rejectOuter = reject;\n });\n\n subscription = ExpoAiKitModule.addListener(\n 'onStreamToken',\n (event: LLMStreamEvent) => {\n if (event.sessionId !== sessionId) return;\n finalText = event.accumulatedText;\n onToken(event);\n if (event.isDone) settle(() => resolveOuter({ text: finalText }));\n }\n );\n\n ExpoAiKitModule.startStreaming(messages, systemPrompt, sessionId).catch(\n (error) => {\n settle(() => {\n try {\n toModelError(error);\n } catch (me) {\n rejectOuter(me);\n }\n });\n }\n );\n\n const stop = () => {\n // Best-effort native cancel (native also emits a terminal isDone on cancel),\n // but resolve immediately with the text so far so `promise` can never hang.\n ExpoAiKitModule.stopStreaming(sessionId).catch(() => {});\n settle(() => resolveOuter({ text: finalText }));\n };\n\n return { promise, stop };\n}\n\n/**\n * Generate a typed object instead of free text.\n *\n * You describe the shape you want with a JSON Schema. expo-ai-kit appends a\n * strict instruction to the system prompt, runs the on-device model, extracts\n * the JSON from its output (tolerating prose and ```json fences), validates it\n * against the schema, and — on a parse error or schema mismatch — feeds the\n * error back and re-prompts up to `maxRepairAttempts` times.\n *\n * Works on every backend (Apple Foundation Models, ML Kit, Gemma) because it is\n * orchestrated over {@link sendMessage}: it honors the same single-flight guard,\n * `AbortSignal`, and `systemPrompt` semantics. Keep schemas small and shallow —\n * on-device models follow flat shapes far more reliably than deeply nested ones.\n *\n * @param messages - The conversation, same shape as {@link sendMessage}.\n * @param schema - A JSON Schema describing the desired result.\n * @param options - Optional settings (systemPrompt, signal, maxRepairAttempts).\n * @returns `{ object, text }` — the validated value and the raw output.\n * @throws {ModelError} INFERENCE_FAILED if no schema-valid JSON is produced\n * after the repair attempts. Also propagates INFERENCE_BUSY / INFERENCE_CANCELLED\n * from the underlying generation.\n *\n * @example\n * ```ts\n * type Recipe = { title: string; minutes: number; ingredients: string[] };\n *\n * const { object } = await generateObject<Recipe>(\n * [{ role: 'user', content: 'A quick weeknight pasta.' }],\n * {\n * type: 'object',\n * properties: {\n * title: { type: 'string' },\n * minutes: { type: 'integer' },\n * ingredients: { type: 'array', items: { type: 'string' } },\n * },\n * required: ['title', 'minutes', 'ingredients'],\n * },\n * );\n * object.title; // typed Recipe\n * ```\n */\nexport async function generateObject<T = unknown>(\n messages: LLMMessage[],\n schema: JSONSchema,\n options?: GenerateObjectOptions\n): Promise<GenerateObjectResult<T>> {\n if (Platform.OS !== 'ios' && Platform.OS !== 'android') {\n throw new ModelError(\n 'DEVICE_NOT_SUPPORTED',\n '',\n 'generateObject is only available on iOS and Android'\n );\n }\n if (!messages || messages.length === 0) {\n throw new Error('messages array cannot be empty');\n }\n if (!schema || typeof schema !== 'object') {\n throw new Error('schema must be a JSON Schema object');\n }\n\n const maxRepairAttempts = Math.max(0, options?.maxRepairAttempts ?? 2);\n const instruction = buildSchemaInstruction(schema);\n\n // Inject the schema instruction. If the caller supplied a system message we\n // append to it (sendMessage reads system from the array); otherwise we carry\n // the instruction via the systemPrompt option, which sendMessage applies when\n // the array has no system message — including on the repair turns we append.\n const sysIdx = messages.findIndex((m) => m.role === 'system');\n let working: LLMMessage[];\n let systemPrompt: string | undefined;\n if (sysIdx >= 0) {\n working = messages.map((m, i) =>\n i === sysIdx ? { role: m.role, content: `${m.content}\\n\\n${instruction}` } : m\n );\n systemPrompt = undefined; // the array carries the system message\n } else {\n working = [...messages];\n systemPrompt = `${options?.systemPrompt ?? DEFAULT_OBJECT_SYSTEM_PROMPT}\\n\\n${instruction}`;\n }\n\n let lastText = '';\n for (let attempt = 0; attempt <= maxRepairAttempts; attempt++) {\n const { text } = await sendMessage(working, { systemPrompt, signal: options?.signal });\n lastText = text;\n\n const parsed = extractJson(text);\n if (parsed.ok) {\n const errors = validateAgainstSchema(parsed.value, schema);\n if (errors.length === 0) {\n return { object: parsed.value as T, text };\n }\n if (attempt < maxRepairAttempts) {\n working = [\n ...working,\n { role: 'assistant', content: text },\n { role: 'user', content: buildSchemaRepair(errors) },\n ];\n }\n } else if (attempt < maxRepairAttempts) {\n working = [\n ...working,\n { role: 'assistant', content: text },\n { role: 'user', content: REPAIR_INVALID_JSON },\n ];\n }\n }\n\n throw new ModelError(\n 'INFERENCE_FAILED',\n getActiveModel(),\n `generateObject: model did not return schema-valid JSON after ${maxRepairAttempts + 1} attempt(s). ` +\n `Last output: ${lastText.slice(0, 200)}`\n );\n}\n\n/**\n * Generate text, optionally letting the model call tools (functions) you provide.\n *\n * Unlike {@link generateObject} (where the JSON *is* the answer), tool calling is\n * a loop: the model proposes a call, expo-ai-kit validates the arguments against\n * the tool's `parameters`, runs your `execute`, feeds the result back, and lets\n * the model continue — until it produces a plain-text answer or the `maxSteps`\n * budget is reached. With no `tools`, this is a single text generation.\n *\n * Orchestrated in JS over {@link sendMessage}, so it works on every backend\n * (Apple Foundation Models, ML Kit, Gemma) and inherits the single-flight guard,\n * `AbortSignal`, and `systemPrompt` semantics. On-device models are imperfect at\n * tool selection, so the loop is defensive: malformed calls, unknown tool names,\n * and schema-invalid arguments are re-prompted up to `maxRepairAttempts` times,\n * and a tool with no `execute` stops the loop and returns the proposed call for\n * you to gate. Keep tool sets small and `parameters` flat for best reliability.\n *\n * @param messages - The conversation, same shape as {@link sendMessage}.\n * @param options - Tools, `maxSteps`, `systemPrompt`, `signal`, `maxRepairAttempts`.\n * @returns `{ text, steps, toolCalls, toolResults, finishReason }`.\n * @throws {ModelError} INFERENCE_FAILED if the model keeps proposing an unknown\n * tool or schema-invalid arguments after the repair attempts. Also propagates\n * INFERENCE_BUSY / INFERENCE_CANCELLED from the underlying generation.\n *\n * @example\n * ```ts\n * const { text } = await generateText(\n * [{ role: 'user', content: 'What should I wear in Paris today?' }],\n * {\n * tools: {\n * getWeather: {\n * description: 'Get the current weather for a city.',\n * parameters: {\n * type: 'object',\n * properties: { city: { type: 'string' } },\n * required: ['city'],\n * },\n * execute: async ({ city }: { city: string }) => fetchWeather(city),\n * },\n * },\n * },\n * );\n * ```\n *\n * @example\n * ```ts\n * // Human-in-the-loop: omit `execute` to gate the call yourself.\n * const res = await generateText(messages, {\n * tools: { deleteAccount: { description: '…', parameters: { type: 'object' } } },\n * });\n * if (res.finishReason === 'tool-calls') {\n * const call = res.toolCalls[0]; // confirm with the user before running\n * }\n * ```\n */\nexport async function generateText(\n messages: LLMMessage[],\n options?: GenerateTextOptions\n): Promise<GenerateTextResult> {\n if (Platform.OS !== 'ios' && Platform.OS !== 'android') {\n throw new ModelError(\n 'DEVICE_NOT_SUPPORTED',\n '',\n 'generateText is only available on iOS and Android'\n );\n }\n if (!messages || messages.length === 0) {\n throw new Error('messages array cannot be empty');\n }\n\n const tools = options?.tools ?? {};\n const toolNames = Object.keys(tools);\n const maxSteps = Math.max(1, options?.maxSteps ?? 5);\n const maxRepairAttempts = Math.max(0, options?.maxRepairAttempts ?? 2);\n\n // Inject the tool instruction the same way generateObject injects its schema\n // instruction: into the array's system message if present, else via the\n // systemPrompt option. With no tools, this is a plain single-shot generation.\n const instruction = toolNames.length > 0 ? buildToolInstruction(tools) : '';\n const sysIdx = messages.findIndex((m) => m.role === 'system');\n let working: LLMMessage[];\n let systemPrompt: string | undefined;\n if (instruction === '') {\n working = [...messages];\n systemPrompt = options?.systemPrompt;\n } else if (sysIdx >= 0) {\n working = messages.map((m, i) =>\n i === sysIdx ? { role: m.role, content: `${m.content}\\n\\n${instruction}` } : m\n );\n systemPrompt = undefined; // the array carries the system message\n } else {\n working = [...messages];\n systemPrompt = `${options?.systemPrompt ?? DEFAULT_SYSTEM_PROMPT}\\n\\n${instruction}`;\n }\n\n const steps: StepResult[] = [];\n const allToolCalls: ToolCall[] = [];\n const allToolResults: ToolResult[] = [];\n\n for (let step = 0; step < maxSteps; step++) {\n // One model round-trip, with an inner repair loop for malformed/invalid calls.\n let call: ToolCall | null = null;\n let text = '';\n\n for (let repair = 0; ; repair++) {\n const r = await sendMessage(working, { systemPrompt, signal: options?.signal });\n text = r.text;\n\n if (toolNames.length === 0) break; // no tools → this is the final answer\n\n const parsed = parseToolCall(text, toolNames);\n if (parsed.kind === 'text') break; // plain answer, no tool call\n\n if (parsed.kind === 'unknown-tool') {\n if (repair >= maxRepairAttempts) {\n throw new ModelError(\n 'INFERENCE_FAILED',\n getActiveModel(),\n `generateText: model called unknown tool \"${parsed.toolName}\" after ${maxRepairAttempts + 1} attempt(s).`\n );\n }\n working = [\n ...working,\n { role: 'assistant', content: text },\n { role: 'user', content: buildUnknownToolRepair(parsed.toolName, toolNames) },\n ];\n continue;\n }\n\n // parsed.kind === 'tool' — validate the proposed args before executing.\n const errors = validateAgainstSchema(parsed.args, tools[parsed.toolName].parameters);\n if (errors.length === 0) {\n call = { toolName: parsed.toolName, args: parsed.args };\n break;\n }\n if (repair >= maxRepairAttempts) {\n throw new ModelError(\n 'INFERENCE_FAILED',\n getActiveModel(),\n `generateText: arguments for \"${parsed.toolName}\" failed schema validation after ` +\n `${maxRepairAttempts + 1} attempt(s): ${errors.slice(0, 4).join('; ')}`\n );\n }\n working = [\n ...working,\n { role: 'assistant', content: text },\n { role: 'user', content: buildToolArgsRepair(parsed.toolName, errors) },\n ];\n }\n\n // No tool call this step → the model produced its final text answer.\n if (!call) {\n steps.push({ text, toolCalls: [], toolResults: [] });\n return {\n text,\n steps,\n toolCalls: allToolCalls,\n toolResults: allToolResults,\n finishReason: 'stop',\n };\n }\n\n allToolCalls.push(call);\n const tool = tools[call.toolName];\n\n // No execute → hand the proposed call back to the caller (human-in-the-loop).\n if (typeof tool.execute !== 'function') {\n steps.push({ text, toolCalls: [call], toolResults: [] });\n return {\n text,\n steps,\n toolCalls: allToolCalls,\n toolResults: allToolResults,\n finishReason: 'tool-calls',\n };\n }\n\n // Run the tool. A thrown error is fed back as the result so the model can recover.\n let result: unknown;\n try {\n result = await tool.execute(call.args);\n } catch (e) {\n result = { error: String((e as any)?.message ?? e) };\n }\n const toolResult: ToolResult = { toolName: call.toolName, args: call.args, result };\n allToolResults.push(toolResult);\n steps.push({ text, toolCalls: [call], toolResults: [toolResult] });\n\n // Feed the call + result back into the conversation for the next step.\n working = [\n ...working,\n { role: 'assistant', content: text },\n { role: 'user', content: formatToolResult(call.toolName, result) },\n ];\n }\n\n // Step budget exhausted while still calling tools — no final answer was\n // produced. Signal it via finishReason so the caller can raise maxSteps.\n return {\n text: '',\n steps,\n toolCalls: allToolCalls,\n toolResults: allToolResults,\n finishReason: 'max-steps',\n };\n}\n\n// ============================================================================\n// Model Management API\n// ============================================================================\n\n/**\n * Get all built-in models available on the current platform.\n *\n * Built-in models are provided by the OS and require no download.\n * On iOS this returns Apple Foundation Models; on Android, ML Kit.\n *\n * @returns Array of built-in models with availability status\n */\nexport async function getBuiltInModels(): Promise<BuiltInModel[]> {\n if (Platform.OS !== 'ios' && Platform.OS !== 'android') {\n return [];\n }\n return ExpoAiKitModule.getBuiltInModels();\n}\n\n/**\n * Get all downloadable models from the registry, enriched with on-device status.\n *\n * Reads from the hardcoded MODEL_REGISTRY and queries the native layer\n * for the current download/load status of each model.\n *\n * @returns Array of downloadable models with their current status\n */\nexport async function getDownloadableModels(): Promise<DownloadableModel[]> {\n if (Platform.OS !== 'ios' && Platform.OS !== 'android') {\n return [];\n }\n\n const platformModels = getAllModels().filter((entry) =>\n entry.supportedPlatforms.includes(Platform.OS as 'ios' | 'android')\n );\n\n let deviceRamBytes = 0;\n try {\n deviceRamBytes = ExpoAiKitModule.getDeviceRamBytes();\n } catch {\n // Native call unavailable -- default to 0 (all models will show meetsRequirements: false)\n }\n\n return Promise.all(\n platformModels.map(async (entry) => {\n // Await: on iOS this bridges as a Promise (reads actor state); on Android\n // it's synchronous and awaiting a plain value is a no-op.\n const status = await ExpoAiKitModule.getDownloadableModelStatus(entry.id);\n return {\n id: entry.id,\n name: entry.name,\n parameterCount: entry.parameterCount,\n license: entry.license,\n sizeBytes: entry.sizeBytes,\n contextWindow: entry.contextWindow,\n minRamBytes: entry.minRamBytes,\n meetsRequirements: deviceRamBytes >= entry.minRamBytes,\n status,\n };\n })\n );\n}\n\n/**\n * Pick the best downloadable model the current device can run.\n *\n * Returns the most capable model (largest, by RAM requirement) whose\n * `meetsRequirements` is true — e.g. Gemma 4 E4B on high-spec phones, falling\n * back to E2B on more constrained ones — or `null` if the device can't run any.\n *\n * This is a convenience over {@link getDownloadableModels}; the caller still\n * downloads + activates explicitly. Pass `platform` is implicit (current OS).\n *\n * @example\n * ```ts\n * const best = await getRecommendedModel();\n * if (best) {\n * await downloadModel(best.id, { onProgress });\n * await setModel(best.id);\n * }\n * ```\n */\nexport async function getRecommendedModel(): Promise<DownloadableModel | null> {\n const models = await getDownloadableModels();\n const runnable = models.filter((m) => m.meetsRequirements);\n if (runnable.length === 0) return null;\n // Higher RAM requirement ⇒ larger/more capable model. Prefer the biggest that fits.\n return runnable.sort((a, b) => b.minRamBytes - a.minRamBytes)[0];\n}\n\n/**\n * Download a model to the device.\n *\n * Looks up the model in the registry, validates platform support and\n * device requirements, then initiates the download with integrity verification.\n *\n * @param modelId - ID of the model to download (e.g. 'gemma-e2b')\n * @param options - Optional download configuration\n * @param options.onProgress - Callback with download progress (0-1)\n * @throws {ModelError} MODEL_NOT_FOUND if modelId is not in the registry\n * @throws {ModelError} DEVICE_NOT_SUPPORTED if platform is not supported\n * @throws {ModelError} DOWNLOAD_FAILED on network error\n * @throws {ModelError} DOWNLOAD_STORAGE_FULL if insufficient disk space\n * @throws {ModelError} DOWNLOAD_CORRUPT if SHA256 hash doesn't match\n */\nexport async function downloadModel(\n modelId: string,\n options?: { onProgress?: (progress: number) => void }\n): Promise<void> {\n const entry = getRegistryEntry(modelId);\n if (!entry) {\n throw new ModelError('MODEL_NOT_FOUND', modelId);\n }\n\n if (!entry.supportedPlatforms.includes(Platform.OS as 'ios' | 'android')) {\n throw new ModelError(\n 'DEVICE_NOT_SUPPORTED',\n modelId,\n `Model ${modelId} is not supported on ${Platform.OS}`\n );\n }\n\n try {\n const deviceRamBytes = ExpoAiKitModule.getDeviceRamBytes();\n if (deviceRamBytes < entry.minRamBytes) {\n throw new ModelError(\n 'DEVICE_NOT_SUPPORTED',\n modelId,\n `Device has ${Math.round(deviceRamBytes / 1e9)}GB RAM, model requires ${Math.round(entry.minRamBytes / 1e9)}GB`\n );\n }\n } catch (e) {\n if (e instanceof ModelError) throw e;\n // If getDeviceRamBytes is unavailable, skip the check\n }\n\n let subscription: ReturnType<typeof ExpoAiKitModule.addListener> | undefined;\n if (options?.onProgress) {\n subscription = ExpoAiKitModule.addListener(\n 'onDownloadProgress',\n (event) => {\n if (event.modelId === modelId) {\n options.onProgress!(event.progress);\n }\n }\n );\n }\n\n try {\n await wrapNative(() =>\n ExpoAiKitModule.downloadModel(modelId, entry.downloadUrl, entry.sha256)\n );\n } finally {\n subscription?.remove();\n }\n}\n\n/**\n * Cancel an in-flight download for a model.\n *\n * The in-progress {@link downloadModel} promise rejects with a\n * DOWNLOAD_CANCELLED {@link ModelError}. No-op if the model isn't downloading.\n *\n * @param modelId - ID of the model whose download should be cancelled\n */\nexport async function cancelDownload(modelId: string): Promise<void> {\n if (Platform.OS !== 'ios' && Platform.OS !== 'android') {\n return;\n }\n await wrapNative(() => ExpoAiKitModule.cancelDownload(modelId));\n}\n\n/**\n * Delete a downloaded model from the device.\n *\n * If the model is currently loaded, it will be unloaded first.\n *\n * @param modelId - ID of the model to delete\n * @throws {ModelError} MODEL_NOT_FOUND if modelId is not in the registry\n */\nexport async function deleteModel(modelId: string): Promise<void> {\n const entry = getRegistryEntry(modelId);\n if (!entry) {\n throw new ModelError('MODEL_NOT_FOUND', modelId);\n }\n\n await wrapNative(() => ExpoAiKitModule.deleteModel(modelId));\n}\n\n/**\n * Set the active model for inference.\n *\n * This is the sole gatekeeper for model validity. If setModel succeeds,\n * the model is loaded and ready -- sendMessage never needs its own check.\n *\n * For downloadable models, this loads the model into memory (status\n * transitions: loading -> ready). Only one downloadable model can be\n * loaded at a time; the previous one is auto-unloaded.\n *\n * For built-in models, this simply switches the active backend.\n *\n * If setModel was never called, sendMessage uses the platform built-in\n * model (today's behavior, no error).\n *\n * @param modelId - ID of the model to activate (e.g. 'gemma-e2b', 'apple-fm', 'mlkit')\n * @param options - Optional configuration for model loading\n * @param options.backend - Hardware backend: 'auto' (default, GPU with CPU fallback), 'gpu', or 'cpu'\n * @throws {ModelError} MODEL_NOT_FOUND if modelId is invalid\n * @throws {ModelError} MODEL_NOT_DOWNLOADED if the downloadable model file is not on disk\n * @throws {ModelError} MODEL_LOAD_FAILED if loading into memory fails\n * @throws {ModelError} INFERENCE_OOM if device can't fit model in memory\n */\nexport async function setModel(modelId: string, options?: SetModelOptions): Promise<void> {\n const entry = getRegistryEntry(modelId);\n const minRamBytes = entry?.minRamBytes ?? 0;\n const backend = options?.backend ?? 'auto';\n const generation = toNativeGeneration(options?.generation);\n await wrapNative(() =>\n ExpoAiKitModule.setModel(modelId, minRamBytes, backend, generation)\n );\n}\n\n/**\n * Get the ID of the currently active model.\n *\n * @returns The active model ID (e.g. 'apple-fm', 'mlkit', 'gemma-e2b')\n */\nexport function getActiveModel(): string {\n return ExpoAiKitModule.getActiveModel();\n}\n\n/**\n * Explicitly unload the current downloadable model from memory.\n *\n * Frees memory and reverts to the platform built-in model.\n * No-op if no downloadable model is currently loaded.\n */\nexport async function unloadModel(): Promise<void> {\n await wrapNative(() => ExpoAiKitModule.unloadModel());\n}\n\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import ExpoAiKitModule, { type NativeGenerationConfig } from './ExpoAiKitModule';\nimport { Platform } from 'react-native';\nimport {\n LLMMessage,\n LLMSendOptions,\n LLMResponse,\n LLMStreamOptions,\n LLMStreamEvent,\n LLMStreamCallback,\n LLMStreamHandle,\n BuiltInModel,\n DownloadableModel,\n GenerationConfig,\n ModelError,\n ModelErrorCode,\n SetModelOptions,\n JSONSchema,\n GenerateObjectOptions,\n GenerateObjectResult,\n GenerateTextOptions,\n GenerateTextResult,\n ToolCall,\n ToolResult,\n StepResult,\n EmbedResult,\n} from './types';\nimport {\n buildSchemaInstruction,\n buildSchemaRepair,\n extractJson,\n validateAgainstSchema,\n REPAIR_INVALID_JSON,\n} from './structured';\nimport {\n buildToolInstruction,\n parseToolCall,\n buildUnknownToolRepair,\n buildToolArgsRepair,\n formatToolResult,\n} from './tools';\nimport { getAllModels, getRegistryEntry } from './models';\n\nexport * from './types';\nexport * from './models';\nexport * from './rag';\n\nconst DEFAULT_SYSTEM_PROMPT =\n 'You are a helpful, friendly assistant. Answer the user directly and concisely.';\n\nconst DEFAULT_OBJECT_SYSTEM_PROMPT =\n 'You output structured data as JSON. Follow the provided JSON Schema exactly.';\n\nlet streamIdCounter = 0;\nfunction generateSessionId(): string {\n return `gen_${Date.now()}_${++streamIdCounter}`;\n}\n\n// The set of codes the native layer encodes in error messages as \"CODE:modelId:reason\".\nconst KNOWN_ERROR_CODES = new Set<ModelErrorCode>([\n 'MODEL_NOT_FOUND',\n 'MODEL_NOT_DOWNLOADED',\n 'DOWNLOAD_FAILED',\n 'DOWNLOAD_CORRUPT',\n 'DOWNLOAD_STORAGE_FULL',\n 'DOWNLOAD_CANCELLED',\n 'INFERENCE_OOM',\n 'INFERENCE_FAILED',\n 'INFERENCE_BUSY',\n 'INFERENCE_CANCELLED',\n 'MODEL_LOAD_FAILED',\n 'DEVICE_NOT_SUPPORTED',\n]);\n\n/**\n * Normalize an error from the native layer into a {@link ModelError}.\n *\n * The native modules format failures as \"CODE:modelId:reason\" (see the\n * GemmaError/GemmaInferenceClient contract). Expo surfaces that string as the\n * error's message, so we parse it here and rethrow a typed ModelError with a\n * reliable `.code` and `.modelId`. Anything unrecognized becomes UNKNOWN.\n */\nfunction toModelError(e: unknown): never {\n if (e instanceof ModelError) throw e;\n const message = String((e as any)?.message ?? e ?? '');\n const match = /^([A-Z_]+):([^:]*):([\\s\\S]*)$/.exec(message);\n if (match && KNOWN_ERROR_CODES.has(match[1] as ModelErrorCode)) {\n throw new ModelError(match[1] as ModelErrorCode, match[2], match[3]);\n }\n throw new ModelError('UNKNOWN', '', message);\n}\n\n/** Run a native promise, normalizing any rejection into a ModelError. */\nasync function wrapNative<T>(run: () => Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (e) {\n toModelError(e);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Single-flight inference guard\n// ---------------------------------------------------------------------------\n// On-device models are backed by a single native context + KV cache that is not\n// safe for concurrent decodes (interleaving can corrupt the cache and crash the\n// native side). JS is single-threaded, so a synchronous check-and-set of this\n// flag before any `await` is race-free. The flag is shared by sendMessage and\n// streamMessage and is held until the *native* call settles — not until an\n// early abort — so a detached-but-still-running generation still blocks a new one.\nlet inferenceInFlight = false;\n\nfunction acquireInference(): void {\n if (inferenceInFlight) {\n throw new ModelError(\n 'INFERENCE_BUSY',\n '',\n 'A generation is already in flight. Wait for it to finish, or stop the active stream first.'\n );\n }\n inferenceInFlight = true;\n}\n\n/**\n * Map the public GenerationConfig to the native shape, dropping undefined fields\n * and validating ranges up front so callers get a clear error instead of an\n * opaque native MODEL_LOAD_FAILED from the sampler.\n */\nfunction toNativeGeneration(g?: GenerationConfig): NativeGenerationConfig {\n const out: NativeGenerationConfig = {};\n if (g?.temperature != null) {\n if (g.temperature < 0) {\n throw new Error('generation.temperature must be >= 0');\n }\n out.temperature = g.temperature;\n }\n if (g?.topK != null) {\n if (!Number.isInteger(g.topK) || g.topK <= 0) {\n throw new Error('generation.topK must be a positive integer');\n }\n out.topK = g.topK;\n }\n if (g?.topP != null) {\n if (g.topP < 0 || g.topP > 1) {\n throw new Error('generation.topP must be within [0, 1]');\n }\n out.topP = g.topP;\n }\n if (g?.seed != null) {\n if (!Number.isInteger(g.seed)) {\n throw new Error('generation.seed must be an integer');\n }\n out.seed = g.seed;\n }\n if (g?.maxTokens != null) {\n if (!Number.isInteger(g.maxTokens) || g.maxTokens <= 0) {\n throw new Error('generation.maxTokens must be a positive integer');\n }\n out.maxTokens = g.maxTokens;\n }\n return out;\n}\n\n// ============================================================================\n// Inference API\n// ============================================================================\n\n/**\n * Check if on-device AI is available on the current device.\n * Returns false on unsupported platforms (web, etc.).\n */\nexport async function isAvailable(): Promise<boolean> {\n if (Platform.OS !== 'ios' && Platform.OS !== 'android') {\n return false;\n }\n return ExpoAiKitModule.isAvailable();\n}\n\n/**\n * Send messages to the on-device LLM and get a response.\n *\n * @param messages - Array of messages representing the conversation\n * @param options - Optional settings (systemPrompt fallback)\n * @returns Promise with the generated response\n *\n * @example\n * ```ts\n * const response = await sendMessage([\n * { role: 'user', content: 'What is 2 + 2?' }\n * ]);\n * console.log(response.text); // \"4\"\n * ```\n *\n * @example\n * ```ts\n * // With system prompt\n * const response = await sendMessage(\n * [{ role: 'user', content: 'Hello!' }],\n * { systemPrompt: 'You are a pirate. Respond in pirate speak.' }\n * );\n * ```\n *\n * @example\n * ```ts\n * // Multi-turn conversation\n * const response = await sendMessage([\n * { role: 'system', content: 'You are a helpful assistant.' },\n * { role: 'user', content: 'My name is Alice.' },\n * { role: 'assistant', content: 'Nice to meet you, Alice!' },\n * { role: 'user', content: 'What is my name?' }\n * ]);\n * ```\n */\nexport async function sendMessage(\n messages: LLMMessage[],\n options?: LLMSendOptions\n): Promise<LLMResponse> {\n if (Platform.OS !== 'ios' && Platform.OS !== 'android') {\n return { text: '' };\n }\n\n if (!messages || messages.length === 0) {\n throw new Error('messages array cannot be empty');\n }\n\n if (options?.signal?.aborted) {\n throw new ModelError('INFERENCE_CANCELLED', '', 'Aborted before start');\n }\n\n // Determine system prompt: use from messages array if present, else options, else default\n const hasSystemMessage = messages.some((m) => m.role === 'system');\n const systemPrompt = hasSystemMessage\n ? '' // Native will extract from messages\n : options?.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;\n\n acquireInference(); // throws INFERENCE_BUSY if a generation is already running\n const sessionId = generateSessionId();\n\n // Hold the single-flight flag until the NATIVE call settles — even if the\n // caller aborts early — because the model may keep computing in the background.\n const native = ExpoAiKitModule.sendMessage(messages, systemPrompt, sessionId);\n const release = () => {\n inferenceInFlight = false;\n };\n native.then(release, release);\n\n const signal = options?.signal;\n if (!signal) {\n try {\n return await native;\n } catch (e) {\n toModelError(e);\n }\n }\n\n // Race the native result against the abort signal. On abort we unblock the\n // caller immediately and best-effort ask native to cancel; the flag stays\n // held (via `release` above) until the native call actually finishes.\n return await new Promise<LLMResponse>((resolve, reject) => {\n let done = false;\n const finish = (action: () => void) => {\n if (done) return;\n done = true;\n signal.removeEventListener('abort', onAbort);\n action();\n };\n function onAbort() {\n ExpoAiKitModule.stopStreaming(sessionId).catch(() => {});\n finish(() => reject(new ModelError('INFERENCE_CANCELLED', '', 'Aborted by caller')));\n }\n signal.addEventListener('abort', onAbort);\n native.then(\n (r) => finish(() => resolve(r)),\n (e) =>\n finish(() => {\n try {\n toModelError(e);\n } catch (me) {\n reject(me);\n }\n })\n );\n });\n}\n\n/**\n * Stream messages to the on-device LLM and receive progressive token updates.\n *\n * @param messages - Array of messages representing the conversation\n * @param onToken - Callback function called for each token/chunk received\n * @param options - Optional settings (systemPrompt fallback)\n * @returns Object with stop() function to cancel streaming and promise that resolves when complete\n *\n * @example\n * ```ts\n * // Basic streaming\n * const { promise } = streamMessage(\n * [{ role: 'user', content: 'Tell me a story' }],\n * (event) => {\n * console.log(event.token); // Each token as it arrives\n * console.log(event.accumulatedText); // Full text so far\n * }\n * );\n * await promise;\n * ```\n *\n * @example\n * ```ts\n * // With cancellation\n * const { promise, stop } = streamMessage(\n * [{ role: 'user', content: 'Write a long essay' }],\n * (event) => setText(event.accumulatedText)\n * );\n *\n * // Cancel after 5 seconds\n * setTimeout(() => stop(), 5000);\n * ```\n */\nexport function streamMessage(\n messages: LLMMessage[],\n onToken: LLMStreamCallback,\n options?: LLMStreamOptions\n): LLMStreamHandle {\n // Handle unsupported platforms\n if (Platform.OS !== 'ios' && Platform.OS !== 'android') {\n return {\n promise: Promise.resolve({ text: '' }),\n stop: () => {},\n };\n }\n\n if (!messages || messages.length === 0) {\n return {\n promise: Promise.reject(new Error('messages array cannot be empty')),\n stop: () => {},\n };\n }\n\n if (inferenceInFlight) {\n return {\n promise: Promise.reject(\n new ModelError(\n 'INFERENCE_BUSY',\n '',\n 'A generation is already in flight. Stop the active stream first.'\n )\n ),\n stop: () => {},\n };\n }\n inferenceInFlight = true; // set synchronously — race-free with other JS\n\n const sessionId = generateSessionId();\n\n // Determine system prompt: use from messages array if present, else options, else default\n const hasSystemMessage = messages.some((m) => m.role === 'system');\n const systemPrompt = hasSystemMessage\n ? '' // Native will extract from messages\n : options?.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;\n\n let finalText = '';\n let settled = false;\n let subscription: ReturnType<typeof ExpoAiKitModule.addListener> | undefined;\n let resolveOuter!: (r: LLMResponse) => void;\n let rejectOuter!: (e: unknown) => void;\n\n // Settle exactly once: remove the listener and release the single-flight flag.\n const settle = (action: () => void) => {\n if (settled) return;\n settled = true;\n subscription?.remove();\n inferenceInFlight = false;\n action();\n };\n\n const promise = new Promise<LLMResponse>((resolve, reject) => {\n resolveOuter = resolve;\n rejectOuter = reject;\n });\n\n subscription = ExpoAiKitModule.addListener(\n 'onStreamToken',\n (event: LLMStreamEvent) => {\n if (event.sessionId !== sessionId) return;\n finalText = event.accumulatedText;\n onToken(event);\n if (event.isDone) settle(() => resolveOuter({ text: finalText }));\n }\n );\n\n ExpoAiKitModule.startStreaming(messages, systemPrompt, sessionId).catch(\n (error) => {\n settle(() => {\n try {\n toModelError(error);\n } catch (me) {\n rejectOuter(me);\n }\n });\n }\n );\n\n const stop = () => {\n // Best-effort native cancel (native also emits a terminal isDone on cancel),\n // but resolve immediately with the text so far so `promise` can never hang.\n ExpoAiKitModule.stopStreaming(sessionId).catch(() => {});\n settle(() => resolveOuter({ text: finalText }));\n };\n\n return { promise, stop };\n}\n\n/**\n * Generate a typed object instead of free text.\n *\n * You describe the shape you want with a JSON Schema. expo-ai-kit appends a\n * strict instruction to the system prompt, runs the on-device model, extracts\n * the JSON from its output (tolerating prose and ```json fences), validates it\n * against the schema, and — on a parse error or schema mismatch — feeds the\n * error back and re-prompts up to `maxRepairAttempts` times.\n *\n * Works on every backend (Apple Foundation Models, ML Kit, Gemma) because it is\n * orchestrated over {@link sendMessage}: it honors the same single-flight guard,\n * `AbortSignal`, and `systemPrompt` semantics. Keep schemas small and shallow —\n * on-device models follow flat shapes far more reliably than deeply nested ones.\n *\n * @param messages - The conversation, same shape as {@link sendMessage}.\n * @param schema - A JSON Schema describing the desired result.\n * @param options - Optional settings (systemPrompt, signal, maxRepairAttempts).\n * @returns `{ object, text }` — the validated value and the raw output.\n * @throws {ModelError} INFERENCE_FAILED if no schema-valid JSON is produced\n * after the repair attempts. Also propagates INFERENCE_BUSY / INFERENCE_CANCELLED\n * from the underlying generation.\n *\n * @example\n * ```ts\n * type Recipe = { title: string; minutes: number; ingredients: string[] };\n *\n * const { object } = await generateObject<Recipe>(\n * [{ role: 'user', content: 'A quick weeknight pasta.' }],\n * {\n * type: 'object',\n * properties: {\n * title: { type: 'string' },\n * minutes: { type: 'integer' },\n * ingredients: { type: 'array', items: { type: 'string' } },\n * },\n * required: ['title', 'minutes', 'ingredients'],\n * },\n * );\n * object.title; // typed Recipe\n * ```\n */\nexport async function generateObject<T = unknown>(\n messages: LLMMessage[],\n schema: JSONSchema,\n options?: GenerateObjectOptions\n): Promise<GenerateObjectResult<T>> {\n if (Platform.OS !== 'ios' && Platform.OS !== 'android') {\n throw new ModelError(\n 'DEVICE_NOT_SUPPORTED',\n '',\n 'generateObject is only available on iOS and Android'\n );\n }\n if (!messages || messages.length === 0) {\n throw new Error('messages array cannot be empty');\n }\n if (!schema || typeof schema !== 'object') {\n throw new Error('schema must be a JSON Schema object');\n }\n\n const maxRepairAttempts = Math.max(0, options?.maxRepairAttempts ?? 2);\n const instruction = buildSchemaInstruction(schema);\n\n // Inject the schema instruction. If the caller supplied a system message we\n // append to it (sendMessage reads system from the array); otherwise we carry\n // the instruction via the systemPrompt option, which sendMessage applies when\n // the array has no system message — including on the repair turns we append.\n const sysIdx = messages.findIndex((m) => m.role === 'system');\n let working: LLMMessage[];\n let systemPrompt: string | undefined;\n if (sysIdx >= 0) {\n working = messages.map((m, i) =>\n i === sysIdx ? { role: m.role, content: `${m.content}\\n\\n${instruction}` } : m\n );\n systemPrompt = undefined; // the array carries the system message\n } else {\n working = [...messages];\n systemPrompt = `${options?.systemPrompt ?? DEFAULT_OBJECT_SYSTEM_PROMPT}\\n\\n${instruction}`;\n }\n\n let lastText = '';\n for (let attempt = 0; attempt <= maxRepairAttempts; attempt++) {\n const { text } = await sendMessage(working, { systemPrompt, signal: options?.signal });\n lastText = text;\n\n const parsed = extractJson(text);\n if (parsed.ok) {\n const errors = validateAgainstSchema(parsed.value, schema);\n if (errors.length === 0) {\n return { object: parsed.value as T, text };\n }\n if (attempt < maxRepairAttempts) {\n working = [\n ...working,\n { role: 'assistant', content: text },\n { role: 'user', content: buildSchemaRepair(errors) },\n ];\n }\n } else if (attempt < maxRepairAttempts) {\n working = [\n ...working,\n { role: 'assistant', content: text },\n { role: 'user', content: REPAIR_INVALID_JSON },\n ];\n }\n }\n\n throw new ModelError(\n 'INFERENCE_FAILED',\n getActiveModel(),\n `generateObject: model did not return schema-valid JSON after ${maxRepairAttempts + 1} attempt(s). ` +\n `Last output: ${lastText.slice(0, 200)}`\n );\n}\n\n/**\n * Generate text, optionally letting the model call tools (functions) you provide.\n *\n * Unlike {@link generateObject} (where the JSON *is* the answer), tool calling is\n * a loop: the model proposes a call, expo-ai-kit validates the arguments against\n * the tool's `parameters`, runs your `execute`, feeds the result back, and lets\n * the model continue — until it produces a plain-text answer or the `maxSteps`\n * budget is reached. With no `tools`, this is a single text generation.\n *\n * Orchestrated in JS over {@link sendMessage}, so it works on every backend\n * (Apple Foundation Models, ML Kit, Gemma) and inherits the single-flight guard,\n * `AbortSignal`, and `systemPrompt` semantics. On-device models are imperfect at\n * tool selection, so the loop is defensive: malformed calls, unknown tool names,\n * and schema-invalid arguments are re-prompted up to `maxRepairAttempts` times,\n * and a tool with no `execute` stops the loop and returns the proposed call for\n * you to gate. Keep tool sets small and `parameters` flat for best reliability.\n *\n * @param messages - The conversation, same shape as {@link sendMessage}.\n * @param options - Tools, `maxSteps`, `systemPrompt`, `signal`, `maxRepairAttempts`.\n * @returns `{ text, steps, toolCalls, toolResults, finishReason }`.\n * @throws {ModelError} INFERENCE_FAILED if the model keeps proposing an unknown\n * tool or schema-invalid arguments after the repair attempts. Also propagates\n * INFERENCE_BUSY / INFERENCE_CANCELLED from the underlying generation.\n *\n * @example\n * ```ts\n * const { text } = await generateText(\n * [{ role: 'user', content: 'What should I wear in Paris today?' }],\n * {\n * tools: {\n * getWeather: {\n * description: 'Get the current weather for a city.',\n * parameters: {\n * type: 'object',\n * properties: { city: { type: 'string' } },\n * required: ['city'],\n * },\n * execute: async ({ city }: { city: string }) => fetchWeather(city),\n * },\n * },\n * },\n * );\n * ```\n *\n * @example\n * ```ts\n * // Human-in-the-loop: omit `execute` to gate the call yourself.\n * const res = await generateText(messages, {\n * tools: { deleteAccount: { description: '…', parameters: { type: 'object' } } },\n * });\n * if (res.finishReason === 'tool-calls') {\n * const call = res.toolCalls[0]; // confirm with the user before running\n * }\n * ```\n */\nexport async function generateText(\n messages: LLMMessage[],\n options?: GenerateTextOptions\n): Promise<GenerateTextResult> {\n if (Platform.OS !== 'ios' && Platform.OS !== 'android') {\n throw new ModelError(\n 'DEVICE_NOT_SUPPORTED',\n '',\n 'generateText is only available on iOS and Android'\n );\n }\n if (!messages || messages.length === 0) {\n throw new Error('messages array cannot be empty');\n }\n\n const tools = options?.tools ?? {};\n const toolNames = Object.keys(tools);\n const maxSteps = Math.max(1, options?.maxSteps ?? 5);\n const maxRepairAttempts = Math.max(0, options?.maxRepairAttempts ?? 2);\n\n // Inject the tool instruction the same way generateObject injects its schema\n // instruction: into the array's system message if present, else via the\n // systemPrompt option. With no tools, this is a plain single-shot generation.\n const instruction = toolNames.length > 0 ? buildToolInstruction(tools) : '';\n const sysIdx = messages.findIndex((m) => m.role === 'system');\n let working: LLMMessage[];\n let systemPrompt: string | undefined;\n if (instruction === '') {\n working = [...messages];\n systemPrompt = options?.systemPrompt;\n } else if (sysIdx >= 0) {\n working = messages.map((m, i) =>\n i === sysIdx ? { role: m.role, content: `${m.content}\\n\\n${instruction}` } : m\n );\n systemPrompt = undefined; // the array carries the system message\n } else {\n working = [...messages];\n systemPrompt = `${options?.systemPrompt ?? DEFAULT_SYSTEM_PROMPT}\\n\\n${instruction}`;\n }\n\n const steps: StepResult[] = [];\n const allToolCalls: ToolCall[] = [];\n const allToolResults: ToolResult[] = [];\n\n for (let step = 0; step < maxSteps; step++) {\n // One model round-trip, with an inner repair loop for malformed/invalid calls.\n let call: ToolCall | null = null;\n let text = '';\n\n for (let repair = 0; ; repair++) {\n const r = await sendMessage(working, { systemPrompt, signal: options?.signal });\n text = r.text;\n\n if (toolNames.length === 0) break; // no tools → this is the final answer\n\n const parsed = parseToolCall(text, toolNames);\n if (parsed.kind === 'text') break; // plain answer, no tool call\n\n if (parsed.kind === 'unknown-tool') {\n if (repair >= maxRepairAttempts) {\n throw new ModelError(\n 'INFERENCE_FAILED',\n getActiveModel(),\n `generateText: model called unknown tool \"${parsed.toolName}\" after ${maxRepairAttempts + 1} attempt(s).`\n );\n }\n working = [\n ...working,\n { role: 'assistant', content: text },\n { role: 'user', content: buildUnknownToolRepair(parsed.toolName, toolNames) },\n ];\n continue;\n }\n\n // parsed.kind === 'tool' — validate the proposed args before executing.\n const errors = validateAgainstSchema(parsed.args, tools[parsed.toolName].parameters);\n if (errors.length === 0) {\n call = { toolName: parsed.toolName, args: parsed.args };\n break;\n }\n if (repair >= maxRepairAttempts) {\n throw new ModelError(\n 'INFERENCE_FAILED',\n getActiveModel(),\n `generateText: arguments for \"${parsed.toolName}\" failed schema validation after ` +\n `${maxRepairAttempts + 1} attempt(s): ${errors.slice(0, 4).join('; ')}`\n );\n }\n working = [\n ...working,\n { role: 'assistant', content: text },\n { role: 'user', content: buildToolArgsRepair(parsed.toolName, errors) },\n ];\n }\n\n // No tool call this step → the model produced its final text answer.\n if (!call) {\n steps.push({ text, toolCalls: [], toolResults: [] });\n return {\n text,\n steps,\n toolCalls: allToolCalls,\n toolResults: allToolResults,\n finishReason: 'stop',\n };\n }\n\n allToolCalls.push(call);\n const tool = tools[call.toolName];\n\n // No execute → hand the proposed call back to the caller (human-in-the-loop).\n if (typeof tool.execute !== 'function') {\n steps.push({ text, toolCalls: [call], toolResults: [] });\n return {\n text,\n steps,\n toolCalls: allToolCalls,\n toolResults: allToolResults,\n finishReason: 'tool-calls',\n };\n }\n\n // Run the tool. A thrown error is fed back as the result so the model can recover.\n let result: unknown;\n try {\n result = await tool.execute(call.args);\n } catch (e) {\n result = { error: String((e as any)?.message ?? e) };\n }\n const toolResult: ToolResult = { toolName: call.toolName, args: call.args, result };\n allToolResults.push(toolResult);\n steps.push({ text, toolCalls: [call], toolResults: [toolResult] });\n\n // Feed the call + result back into the conversation for the next step.\n working = [\n ...working,\n { role: 'assistant', content: text },\n { role: 'user', content: formatToolResult(call.toolName, result) },\n ];\n }\n\n // Step budget exhausted while still calling tools — no final answer was\n // produced. Signal it via finishReason so the caller can raise maxSteps.\n return {\n text: '',\n steps,\n toolCalls: allToolCalls,\n toolResults: allToolResults,\n finishReason: 'max-steps',\n };\n}\n\n// ============================================================================\n// Embeddings API\n// ============================================================================\n\n/**\n * Turn text into embedding vectors for semantic search / on-device RAG.\n *\n * Returns one vector per input string (in order), which you can compare with\n * {@link cosineSimilarity} or store in a {@link createVectorStore} to retrieve\n * the most relevant chunks before a {@link sendMessage} / {@link generateText}\n * call. Pair with {@link chunkText} to split documents first.\n *\n * **iOS-only for now**, backed by Apple's `NLContextualEmbedding` — a zero-\n * download, OS-maintained model (no app-size cost, works even where Apple\n * Intelligence isn't enabled, iOS 17+). On Android/web it throws\n * `DEVICE_NOT_SUPPORTED`; the RAG toolkit (`chunkText`, `cosineSimilarity`,\n * `createVectorStore`) still works there with any vector source you bring.\n *\n * Embeddings don't use the generation KV-cache, so `embed()` is **not** subject\n * to the single-flight `INFERENCE_BUSY` guard — it can run alongside other work.\n *\n * @param texts - Non-empty array of strings to embed.\n * @returns `{ embeddings, dimensions }` — `embeddings[i]` is the vector for `texts[i]`.\n * @throws {ModelError} DEVICE_NOT_SUPPORTED off iOS, or if no embedding model is\n * available on the device.\n *\n * @example\n * ```ts\n * import { embed, chunkText, createVectorStore } from 'expo-ai-kit';\n *\n * const chunks = chunkText(document);\n * const { embeddings } = await embed(chunks);\n *\n * const store = createVectorStore<{ text: string }>();\n * store.addMany(chunks.map((text, i) => ({ id: `c${i}`, vector: embeddings[i], metadata: { text } })));\n *\n * const { embeddings: [q] } = await embed([question]);\n * const context = store.search(q, { topK: 4 }).map((h) => h.metadata!.text).join('\\n\\n');\n * const { text } = await sendMessage([\n * { role: 'system', content: `Answer using only this context:\\n${context}` },\n * { role: 'user', content: question },\n * ]);\n * ```\n */\nexport async function embed(texts: string[]): Promise<EmbedResult> {\n if (Platform.OS !== 'ios') {\n throw new ModelError(\n 'DEVICE_NOT_SUPPORTED',\n '',\n Platform.OS === 'android'\n ? 'embed() is iOS-only for now (Apple NLContextualEmbedding); Android support via MediaPipe is planned. ' +\n 'The RAG toolkit (chunkText, cosineSimilarity, createVectorStore) works on Android with any vector source.'\n : 'embed() is only available on iOS'\n );\n }\n if (!Array.isArray(texts) || texts.length === 0) {\n throw new Error('texts array cannot be empty');\n }\n if (!texts.every((t) => typeof t === 'string')) {\n throw new Error('texts must be an array of strings');\n }\n return wrapNative(() => ExpoAiKitModule.embed(texts));\n}\n\n// ============================================================================\n// Model Management API\n// ============================================================================\n\n/**\n * Get all built-in models available on the current platform.\n *\n * Built-in models are provided by the OS and require no download.\n * On iOS this returns Apple Foundation Models; on Android, ML Kit.\n *\n * @returns Array of built-in models with availability status\n */\nexport async function getBuiltInModels(): Promise<BuiltInModel[]> {\n if (Platform.OS !== 'ios' && Platform.OS !== 'android') {\n return [];\n }\n return ExpoAiKitModule.getBuiltInModels();\n}\n\n/**\n * Get all downloadable models from the registry, enriched with on-device status.\n *\n * Reads from the hardcoded MODEL_REGISTRY and queries the native layer\n * for the current download/load status of each model.\n *\n * @returns Array of downloadable models with their current status\n */\nexport async function getDownloadableModels(): Promise<DownloadableModel[]> {\n if (Platform.OS !== 'ios' && Platform.OS !== 'android') {\n return [];\n }\n\n const platformModels = getAllModels().filter((entry) =>\n entry.supportedPlatforms.includes(Platform.OS as 'ios' | 'android')\n );\n\n let deviceRamBytes = 0;\n try {\n deviceRamBytes = ExpoAiKitModule.getDeviceRamBytes();\n } catch {\n // Native call unavailable -- default to 0 (all models will show meetsRequirements: false)\n }\n\n return Promise.all(\n platformModels.map(async (entry) => {\n // Await: on iOS this bridges as a Promise (reads actor state); on Android\n // it's synchronous and awaiting a plain value is a no-op.\n const status = await ExpoAiKitModule.getDownloadableModelStatus(entry.id);\n return {\n id: entry.id,\n name: entry.name,\n parameterCount: entry.parameterCount,\n license: entry.license,\n sizeBytes: entry.sizeBytes,\n contextWindow: entry.contextWindow,\n minRamBytes: entry.minRamBytes,\n meetsRequirements: deviceRamBytes >= entry.minRamBytes,\n status,\n };\n })\n );\n}\n\n/**\n * Pick the best downloadable model the current device can run.\n *\n * Returns the most capable model (largest, by RAM requirement) whose\n * `meetsRequirements` is true — e.g. Gemma 4 E4B on high-spec phones, falling\n * back to E2B on more constrained ones — or `null` if the device can't run any.\n *\n * This is a convenience over {@link getDownloadableModels}; the caller still\n * downloads + activates explicitly. Pass `platform` is implicit (current OS).\n *\n * @example\n * ```ts\n * const best = await getRecommendedModel();\n * if (best) {\n * await downloadModel(best.id, { onProgress });\n * await setModel(best.id);\n * }\n * ```\n */\nexport async function getRecommendedModel(): Promise<DownloadableModel | null> {\n const models = await getDownloadableModels();\n const runnable = models.filter((m) => m.meetsRequirements);\n if (runnable.length === 0) return null;\n // Higher RAM requirement ⇒ larger/more capable model. Prefer the biggest that fits.\n return runnable.sort((a, b) => b.minRamBytes - a.minRamBytes)[0];\n}\n\n/**\n * Download a model to the device.\n *\n * Looks up the model in the registry, validates platform support and\n * device requirements, then initiates the download with integrity verification.\n *\n * @param modelId - ID of the model to download (e.g. 'gemma-e2b')\n * @param options - Optional download configuration\n * @param options.onProgress - Callback with download progress (0-1)\n * @throws {ModelError} MODEL_NOT_FOUND if modelId is not in the registry\n * @throws {ModelError} DEVICE_NOT_SUPPORTED if platform is not supported\n * @throws {ModelError} DOWNLOAD_FAILED on network error\n * @throws {ModelError} DOWNLOAD_STORAGE_FULL if insufficient disk space\n * @throws {ModelError} DOWNLOAD_CORRUPT if SHA256 hash doesn't match\n */\nexport async function downloadModel(\n modelId: string,\n options?: { onProgress?: (progress: number) => void }\n): Promise<void> {\n const entry = getRegistryEntry(modelId);\n if (!entry) {\n throw new ModelError('MODEL_NOT_FOUND', modelId);\n }\n\n if (!entry.supportedPlatforms.includes(Platform.OS as 'ios' | 'android')) {\n throw new ModelError(\n 'DEVICE_NOT_SUPPORTED',\n modelId,\n `Model ${modelId} is not supported on ${Platform.OS}`\n );\n }\n\n try {\n const deviceRamBytes = ExpoAiKitModule.getDeviceRamBytes();\n if (deviceRamBytes < entry.minRamBytes) {\n throw new ModelError(\n 'DEVICE_NOT_SUPPORTED',\n modelId,\n `Device has ${Math.round(deviceRamBytes / 1e9)}GB RAM, model requires ${Math.round(entry.minRamBytes / 1e9)}GB`\n );\n }\n } catch (e) {\n if (e instanceof ModelError) throw e;\n // If getDeviceRamBytes is unavailable, skip the check\n }\n\n let subscription: ReturnType<typeof ExpoAiKitModule.addListener> | undefined;\n if (options?.onProgress) {\n subscription = ExpoAiKitModule.addListener(\n 'onDownloadProgress',\n (event) => {\n if (event.modelId === modelId) {\n options.onProgress!(event.progress);\n }\n }\n );\n }\n\n try {\n await wrapNative(() =>\n ExpoAiKitModule.downloadModel(modelId, entry.downloadUrl, entry.sha256)\n );\n } finally {\n subscription?.remove();\n }\n}\n\n/**\n * Cancel an in-flight download for a model.\n *\n * The in-progress {@link downloadModel} promise rejects with a\n * DOWNLOAD_CANCELLED {@link ModelError}. No-op if the model isn't downloading.\n *\n * @param modelId - ID of the model whose download should be cancelled\n */\nexport async function cancelDownload(modelId: string): Promise<void> {\n if (Platform.OS !== 'ios' && Platform.OS !== 'android') {\n return;\n }\n await wrapNative(() => ExpoAiKitModule.cancelDownload(modelId));\n}\n\n/**\n * Delete a downloaded model from the device.\n *\n * If the model is currently loaded, it will be unloaded first.\n *\n * @param modelId - ID of the model to delete\n * @throws {ModelError} MODEL_NOT_FOUND if modelId is not in the registry\n */\nexport async function deleteModel(modelId: string): Promise<void> {\n const entry = getRegistryEntry(modelId);\n if (!entry) {\n throw new ModelError('MODEL_NOT_FOUND', modelId);\n }\n\n await wrapNative(() => ExpoAiKitModule.deleteModel(modelId));\n}\n\n/**\n * Set the active model for inference.\n *\n * This is the sole gatekeeper for model validity. If setModel succeeds,\n * the model is loaded and ready -- sendMessage never needs its own check.\n *\n * For downloadable models, this loads the model into memory (status\n * transitions: loading -> ready). Only one downloadable model can be\n * loaded at a time; the previous one is auto-unloaded.\n *\n * For built-in models, this simply switches the active backend.\n *\n * If setModel was never called, sendMessage uses the platform built-in\n * model (today's behavior, no error).\n *\n * @param modelId - ID of the model to activate (e.g. 'gemma-e2b', 'apple-fm', 'mlkit')\n * @param options - Optional configuration for model loading\n * @param options.backend - Hardware backend: 'auto' (default, GPU with CPU fallback), 'gpu', or 'cpu'\n * @throws {ModelError} MODEL_NOT_FOUND if modelId is invalid\n * @throws {ModelError} MODEL_NOT_DOWNLOADED if the downloadable model file is not on disk\n * @throws {ModelError} MODEL_LOAD_FAILED if loading into memory fails\n * @throws {ModelError} INFERENCE_OOM if device can't fit model in memory\n */\nexport async function setModel(modelId: string, options?: SetModelOptions): Promise<void> {\n const entry = getRegistryEntry(modelId);\n const minRamBytes = entry?.minRamBytes ?? 0;\n const backend = options?.backend ?? 'auto';\n const generation = toNativeGeneration(options?.generation);\n await wrapNative(() =>\n ExpoAiKitModule.setModel(modelId, minRamBytes, backend, generation)\n );\n}\n\n/**\n * Get the ID of the currently active model.\n *\n * @returns The active model ID (e.g. 'apple-fm', 'mlkit', 'gemma-e2b')\n */\nexport function getActiveModel(): string {\n return ExpoAiKitModule.getActiveModel();\n}\n\n/**\n * Explicitly unload the current downloadable model from memory.\n *\n * Frees memory and reverts to the platform built-in model.\n * No-op if no downloadable model is currently loaded.\n */\nexport async function unloadModel(): Promise<void> {\n await wrapNative(() => ExpoAiKitModule.unloadModel());\n}\n\n"]}