expo-ai-kit 0.5.0 → 0.6.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 +35 -5
- package/build/index.d.ts +43 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +99 -0
- package/build/index.js.map +1 -1
- package/build/structured.d.ts +36 -0
- package/build/structured.d.ts.map +1 -0
- package/build/structured.js +190 -0
- package/build/structured.js.map +1 -0
- package/build/types.d.ts +62 -0
- package/build/types.d.ts.map +1 -1
- package/build/types.js.map +1 -1
- package/package.json +5 -2
- package/src/index.ts +128 -0
- package/src/structured.ts +202 -0
- package/src/types.ts +78 -0
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# expo-ai-kit
|
|
2
2
|
|
|
3
|
-
On-device AI for Expo & React Native — run LLMs locally
|
|
3
|
+
On-device AI for Expo & React Native — run LLMs locally. No API keys, no cloud, no cost.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/expo-ai-kit)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
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, cancellation, and runtime model switching, all on-device.
|
|
10
|
+
— with streaming, structured output, cancellation, and runtime model switching, all on-device.
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|
|
@@ -17,7 +17,7 @@ npx expo install expo-ai-kit
|
|
|
17
17
|
|
|
18
18
|
Bare RN: run `npx pod-install`. Android needs `minSdkVersion 26`. Requires Expo SDK 54+.
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## Text
|
|
21
21
|
|
|
22
22
|
```tsx
|
|
23
23
|
import { isAvailable, sendMessage, streamMessage } from 'expo-ai-kit';
|
|
@@ -36,6 +36,36 @@ if (await isAvailable()) {
|
|
|
36
36
|
`messages` is `{ role: 'system' | 'user' | 'assistant'; content: string }[]`. On-device
|
|
37
37
|
models are stateless — pass the full history each call.
|
|
38
38
|
|
|
39
|
+
## Structured output
|
|
40
|
+
|
|
41
|
+
Get a typed object back instead of a string. Pass a JSON Schema; expo-ai-kit prompts the
|
|
42
|
+
model, extracts the JSON (tolerating prose and code fences), validates it against the
|
|
43
|
+
schema, and repairs on a mismatch. Works on every backend.
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import { generateObject } from 'expo-ai-kit';
|
|
47
|
+
|
|
48
|
+
type Recipe = { title: string; minutes: number; ingredients: string[] };
|
|
49
|
+
|
|
50
|
+
const { object } = await generateObject<Recipe>(
|
|
51
|
+
[{ role: 'user', content: 'A quick weeknight pasta.' }],
|
|
52
|
+
{
|
|
53
|
+
type: 'object',
|
|
54
|
+
properties: {
|
|
55
|
+
title: { type: 'string' },
|
|
56
|
+
minutes: { type: 'integer' },
|
|
57
|
+
ingredients: { type: 'array', items: { type: 'string' } },
|
|
58
|
+
},
|
|
59
|
+
required: ['title', 'minutes', 'ingredients'],
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
object.title; // typed Recipe
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Throws `INFERENCE_FAILED` if the model can't produce schema-valid JSON after the repair
|
|
67
|
+
attempts (`maxRepairAttempts`, default 2). Keep schemas small and shallow for best results.
|
|
68
|
+
|
|
39
69
|
## Downloadable Gemma 4
|
|
40
70
|
|
|
41
71
|
```tsx
|
|
@@ -45,13 +75,13 @@ const best = await getRecommendedModel(); // E4B on high-RAM phones, el
|
|
|
45
75
|
if (best) {
|
|
46
76
|
await downloadModel(best.id, { onProgress: (p) => console.log(p) });
|
|
47
77
|
await setModel(best.id, { generation: { temperature: 0.7 } });
|
|
48
|
-
// sendMessage / streamMessage now use it; unloadModel() reverts to the OS model
|
|
78
|
+
// sendMessage / streamMessage / generateObject now use it; unloadModel() reverts to the OS model
|
|
49
79
|
}
|
|
50
80
|
```
|
|
51
81
|
|
|
52
82
|
## API
|
|
53
83
|
|
|
54
|
-
Inference: `isAvailable`, `sendMessage`, `streamMessage`.
|
|
84
|
+
Inference: `isAvailable`, `sendMessage`, `streamMessage`, `generateObject`.
|
|
55
85
|
Models: `getBuiltInModels`, `getDownloadableModels`, `getRecommendedModel`,
|
|
56
86
|
`downloadModel`, `cancelDownload`, `deleteModel`, `setModel`, `unloadModel`, `getActiveModel`.
|
|
57
87
|
|
package/build/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LLMMessage, LLMSendOptions, LLMResponse, LLMStreamOptions, LLMStreamCallback, LLMStreamHandle, BuiltInModel, DownloadableModel, SetModelOptions } from './types';
|
|
1
|
+
import { LLMMessage, LLMSendOptions, LLMResponse, LLMStreamOptions, LLMStreamCallback, LLMStreamHandle, BuiltInModel, DownloadableModel, SetModelOptions, JSONSchema, GenerateObjectOptions, GenerateObjectResult } from './types';
|
|
2
2
|
export * from './types';
|
|
3
3
|
export * from './models';
|
|
4
4
|
/**
|
|
@@ -76,6 +76,48 @@ export declare function sendMessage(messages: LLMMessage[], options?: LLMSendOpt
|
|
|
76
76
|
* ```
|
|
77
77
|
*/
|
|
78
78
|
export declare function streamMessage(messages: LLMMessage[], onToken: LLMStreamCallback, options?: LLMStreamOptions): LLMStreamHandle;
|
|
79
|
+
/**
|
|
80
|
+
* Generate a typed object instead of free text.
|
|
81
|
+
*
|
|
82
|
+
* You describe the shape you want with a JSON Schema. expo-ai-kit appends a
|
|
83
|
+
* strict instruction to the system prompt, runs the on-device model, extracts
|
|
84
|
+
* the JSON from its output (tolerating prose and ```json fences), validates it
|
|
85
|
+
* against the schema, and — on a parse error or schema mismatch — feeds the
|
|
86
|
+
* error back and re-prompts up to `maxRepairAttempts` times.
|
|
87
|
+
*
|
|
88
|
+
* Works on every backend (Apple Foundation Models, ML Kit, Gemma) because it is
|
|
89
|
+
* orchestrated over {@link sendMessage}: it honors the same single-flight guard,
|
|
90
|
+
* `AbortSignal`, and `systemPrompt` semantics. Keep schemas small and shallow —
|
|
91
|
+
* on-device models follow flat shapes far more reliably than deeply nested ones.
|
|
92
|
+
*
|
|
93
|
+
* @param messages - The conversation, same shape as {@link sendMessage}.
|
|
94
|
+
* @param schema - A JSON Schema describing the desired result.
|
|
95
|
+
* @param options - Optional settings (systemPrompt, signal, maxRepairAttempts).
|
|
96
|
+
* @returns `{ object, text }` — the validated value and the raw output.
|
|
97
|
+
* @throws {ModelError} INFERENCE_FAILED if no schema-valid JSON is produced
|
|
98
|
+
* after the repair attempts. Also propagates INFERENCE_BUSY / INFERENCE_CANCELLED
|
|
99
|
+
* from the underlying generation.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* type Recipe = { title: string; minutes: number; ingredients: string[] };
|
|
104
|
+
*
|
|
105
|
+
* const { object } = await generateObject<Recipe>(
|
|
106
|
+
* [{ role: 'user', content: 'A quick weeknight pasta.' }],
|
|
107
|
+
* {
|
|
108
|
+
* type: 'object',
|
|
109
|
+
* properties: {
|
|
110
|
+
* title: { type: 'string' },
|
|
111
|
+
* minutes: { type: 'integer' },
|
|
112
|
+
* ingredients: { type: 'array', items: { type: 'string' } },
|
|
113
|
+
* },
|
|
114
|
+
* required: ['title', 'minutes', 'ingredients'],
|
|
115
|
+
* },
|
|
116
|
+
* );
|
|
117
|
+
* object.title; // typed Recipe
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export declare function generateObject<T = unknown>(messages: LLMMessage[], schema: JSONSchema, options?: GenerateObjectOptions): Promise<GenerateObjectResult<T>>;
|
|
79
121
|
/**
|
|
80
122
|
* Get all built-in models available on the current platform.
|
|
81
123
|
*
|
package/build/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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,EACrB,MAAM,SAAS,CAAC;AAUjB,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;AAMD;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAKhE;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAiC1E;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
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import ExpoAiKitModule from './ExpoAiKitModule';
|
|
2
2
|
import { Platform } from 'react-native';
|
|
3
3
|
import { ModelError, } from './types';
|
|
4
|
+
import { buildSchemaInstruction, buildSchemaRepair, extractJson, validateAgainstSchema, REPAIR_INVALID_JSON, } from './structured';
|
|
4
5
|
import { MODEL_REGISTRY, getRegistryEntry } from './models';
|
|
5
6
|
export * from './types';
|
|
6
7
|
export * from './models';
|
|
7
8
|
const DEFAULT_SYSTEM_PROMPT = 'You are a helpful, friendly assistant. Answer the user directly and concisely.';
|
|
9
|
+
const DEFAULT_OBJECT_SYSTEM_PROMPT = 'You output structured data as JSON. Follow the provided JSON Schema exactly.';
|
|
8
10
|
let streamIdCounter = 0;
|
|
9
11
|
function generateSessionId() {
|
|
10
12
|
return `gen_${Date.now()}_${++streamIdCounter}`;
|
|
@@ -318,6 +320,103 @@ export function streamMessage(messages, onToken, options) {
|
|
|
318
320
|
};
|
|
319
321
|
return { promise, stop };
|
|
320
322
|
}
|
|
323
|
+
/**
|
|
324
|
+
* Generate a typed object instead of free text.
|
|
325
|
+
*
|
|
326
|
+
* You describe the shape you want with a JSON Schema. expo-ai-kit appends a
|
|
327
|
+
* strict instruction to the system prompt, runs the on-device model, extracts
|
|
328
|
+
* the JSON from its output (tolerating prose and ```json fences), validates it
|
|
329
|
+
* against the schema, and — on a parse error or schema mismatch — feeds the
|
|
330
|
+
* error back and re-prompts up to `maxRepairAttempts` times.
|
|
331
|
+
*
|
|
332
|
+
* Works on every backend (Apple Foundation Models, ML Kit, Gemma) because it is
|
|
333
|
+
* orchestrated over {@link sendMessage}: it honors the same single-flight guard,
|
|
334
|
+
* `AbortSignal`, and `systemPrompt` semantics. Keep schemas small and shallow —
|
|
335
|
+
* on-device models follow flat shapes far more reliably than deeply nested ones.
|
|
336
|
+
*
|
|
337
|
+
* @param messages - The conversation, same shape as {@link sendMessage}.
|
|
338
|
+
* @param schema - A JSON Schema describing the desired result.
|
|
339
|
+
* @param options - Optional settings (systemPrompt, signal, maxRepairAttempts).
|
|
340
|
+
* @returns `{ object, text }` — the validated value and the raw output.
|
|
341
|
+
* @throws {ModelError} INFERENCE_FAILED if no schema-valid JSON is produced
|
|
342
|
+
* after the repair attempts. Also propagates INFERENCE_BUSY / INFERENCE_CANCELLED
|
|
343
|
+
* from the underlying generation.
|
|
344
|
+
*
|
|
345
|
+
* @example
|
|
346
|
+
* ```ts
|
|
347
|
+
* type Recipe = { title: string; minutes: number; ingredients: string[] };
|
|
348
|
+
*
|
|
349
|
+
* const { object } = await generateObject<Recipe>(
|
|
350
|
+
* [{ role: 'user', content: 'A quick weeknight pasta.' }],
|
|
351
|
+
* {
|
|
352
|
+
* type: 'object',
|
|
353
|
+
* properties: {
|
|
354
|
+
* title: { type: 'string' },
|
|
355
|
+
* minutes: { type: 'integer' },
|
|
356
|
+
* ingredients: { type: 'array', items: { type: 'string' } },
|
|
357
|
+
* },
|
|
358
|
+
* required: ['title', 'minutes', 'ingredients'],
|
|
359
|
+
* },
|
|
360
|
+
* );
|
|
361
|
+
* object.title; // typed Recipe
|
|
362
|
+
* ```
|
|
363
|
+
*/
|
|
364
|
+
export async function generateObject(messages, schema, options) {
|
|
365
|
+
if (Platform.OS !== 'ios' && Platform.OS !== 'android') {
|
|
366
|
+
throw new ModelError('DEVICE_NOT_SUPPORTED', '', 'generateObject is only available on iOS and Android');
|
|
367
|
+
}
|
|
368
|
+
if (!messages || messages.length === 0) {
|
|
369
|
+
throw new Error('messages array cannot be empty');
|
|
370
|
+
}
|
|
371
|
+
if (!schema || typeof schema !== 'object') {
|
|
372
|
+
throw new Error('schema must be a JSON Schema object');
|
|
373
|
+
}
|
|
374
|
+
const maxRepairAttempts = Math.max(0, options?.maxRepairAttempts ?? 2);
|
|
375
|
+
const instruction = buildSchemaInstruction(schema);
|
|
376
|
+
// Inject the schema instruction. If the caller supplied a system message we
|
|
377
|
+
// append to it (sendMessage reads system from the array); otherwise we carry
|
|
378
|
+
// the instruction via the systemPrompt option, which sendMessage applies when
|
|
379
|
+
// the array has no system message — including on the repair turns we append.
|
|
380
|
+
const sysIdx = messages.findIndex((m) => m.role === 'system');
|
|
381
|
+
let working;
|
|
382
|
+
let systemPrompt;
|
|
383
|
+
if (sysIdx >= 0) {
|
|
384
|
+
working = messages.map((m, i) => i === sysIdx ? { role: m.role, content: `${m.content}\n\n${instruction}` } : m);
|
|
385
|
+
systemPrompt = undefined; // the array carries the system message
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
working = [...messages];
|
|
389
|
+
systemPrompt = `${options?.systemPrompt ?? DEFAULT_OBJECT_SYSTEM_PROMPT}\n\n${instruction}`;
|
|
390
|
+
}
|
|
391
|
+
let lastText = '';
|
|
392
|
+
for (let attempt = 0; attempt <= maxRepairAttempts; attempt++) {
|
|
393
|
+
const { text } = await sendMessage(working, { systemPrompt, signal: options?.signal });
|
|
394
|
+
lastText = text;
|
|
395
|
+
const parsed = extractJson(text);
|
|
396
|
+
if (parsed.ok) {
|
|
397
|
+
const errors = validateAgainstSchema(parsed.value, schema);
|
|
398
|
+
if (errors.length === 0) {
|
|
399
|
+
return { object: parsed.value, text };
|
|
400
|
+
}
|
|
401
|
+
if (attempt < maxRepairAttempts) {
|
|
402
|
+
working = [
|
|
403
|
+
...working,
|
|
404
|
+
{ role: 'assistant', content: text },
|
|
405
|
+
{ role: 'user', content: buildSchemaRepair(errors) },
|
|
406
|
+
];
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
else if (attempt < maxRepairAttempts) {
|
|
410
|
+
working = [
|
|
411
|
+
...working,
|
|
412
|
+
{ role: 'assistant', content: text },
|
|
413
|
+
{ role: 'user', content: REPAIR_INVALID_JSON },
|
|
414
|
+
];
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
throw new ModelError('INFERENCE_FAILED', getActiveModel(), `generateObject: model did not return schema-valid JSON after ${maxRepairAttempts + 1} attempt(s). ` +
|
|
418
|
+
`Last output: ${lastText.slice(0, 200)}`);
|
|
419
|
+
}
|
|
321
420
|
// ============================================================================
|
|
322
421
|
// Model Management API
|
|
323
422
|
// ============================================================================
|
package/build/index.js.map
CHANGED
|
@@ -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} from './types';\nimport { MODEL_REGISTRY, 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\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// 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 = MODEL_REGISTRY.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 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} from './types';\nimport {\n buildSchemaInstruction,\n buildSchemaRepair,\n extractJson,\n validateAgainstSchema,\n REPAIR_INVALID_JSON,\n} from './structured';\nimport { MODEL_REGISTRY, 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// 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 = MODEL_REGISTRY.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 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"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { JSONSchema } from './types';
|
|
2
|
+
/** Build the instruction appended to the system prompt to elicit schema-shaped JSON. */
|
|
3
|
+
export declare function buildSchemaInstruction(schema: JSONSchema): string;
|
|
4
|
+
/** Follow-up prompt when the model returned something that could not be parsed as JSON. */
|
|
5
|
+
export declare const REPAIR_INVALID_JSON: string;
|
|
6
|
+
/** Follow-up prompt when the model returned valid JSON that violated the schema. */
|
|
7
|
+
export declare function buildSchemaRepair(errors: string[]): string;
|
|
8
|
+
export type ParseResult = {
|
|
9
|
+
ok: true;
|
|
10
|
+
value: unknown;
|
|
11
|
+
} | {
|
|
12
|
+
ok: false;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Best-effort extraction of a JSON value from model output.
|
|
16
|
+
*
|
|
17
|
+
* On-device models often wrap JSON in a ```json fence or add a sentence of prose
|
|
18
|
+
* around it. We try, in order: a fenced block, the trimmed whole string, then the
|
|
19
|
+
* first balanced {...}/[...] block found anywhere in the text.
|
|
20
|
+
*/
|
|
21
|
+
export declare function extractJson(text: string): ParseResult;
|
|
22
|
+
/**
|
|
23
|
+
* Return the first balanced `{...}` or `[...]` substring, or null if none.
|
|
24
|
+
* Tracks string state so braces inside JSON strings are not counted.
|
|
25
|
+
*/
|
|
26
|
+
export declare function sliceBalanced(text: string): string | null;
|
|
27
|
+
/**
|
|
28
|
+
* Validate `value` against the supported subset of `schema`.
|
|
29
|
+
* Returns a list of human-readable error strings (empty ⇒ valid).
|
|
30
|
+
*
|
|
31
|
+
* Intentionally lenient: unknown keywords and extra object properties are
|
|
32
|
+
* allowed. The goal is to catch structural mistakes worth re-prompting over
|
|
33
|
+
* (wrong type, missing required field), not full JSON Schema conformance.
|
|
34
|
+
*/
|
|
35
|
+
export declare function validateAgainstSchema(value: unknown, schema: JSONSchema): string[];
|
|
36
|
+
//# sourceMappingURL=structured.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structured.d.ts","sourceRoot":"","sources":["../src/structured.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,SAAS,CAAC;AAU1D,wFAAwF;AACxF,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAWjE;AAED,2FAA2F;AAC3F,eAAO,MAAM,mBAAmB,QAE+C,CAAC;AAEhF,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAM1D;AAED,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAA;CAAE,CAAC;AAEvE;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAoBrD;AAWD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA0BzD;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAIlF"}
|