expo-ai-kit 0.3.6 → 0.4.1

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.
Files changed (186) hide show
  1. package/README.md +68 -1106
  2. package/build/ExpoAiKitModule.d.ts +1 -1
  3. package/build/ExpoAiKitModule.d.ts.map +1 -1
  4. package/build/ExpoAiKitModule.js.map +1 -1
  5. package/build/index.d.ts +1 -436
  6. package/build/index.d.ts.map +1 -1
  7. package/build/index.js +1 -737
  8. package/build/index.js.map +1 -1
  9. package/build/types.d.ts +3 -244
  10. package/build/types.d.ts.map +1 -1
  11. package/build/types.js.map +1 -1
  12. package/package.json +3 -2
  13. package/src/ExpoAiKitModule.ts +2 -2
  14. package/src/index.ts +1 -943
  15. package/src/types.ts +3 -284
  16. package/android/build/.transforms/05637efea134638df3d3fc7b19d5dfdb/results.bin +0 -1
  17. package/android/build/.transforms/05637efea134638df3d3fc7b19d5dfdb/transformed/classes/classes_dex/classes.dex +0 -0
  18. package/android/build/.transforms/cd4ecc077e8795b855097bce5bf059b1/results.bin +0 -1
  19. package/android/build/.transforms/cd4ecc077e8795b855097bce5bf059b1/transformed/classes/classes_dex/classes.dex +0 -0
  20. package/android/build/generated/source/buildConfig/debug/expo/modules/aikit/BuildConfig.java +0 -10
  21. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +0 -7
  22. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +0 -18
  23. package/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +0 -6
  24. package/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +0 -1
  25. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  26. package/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
  27. package/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -0
  28. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +0 -1
  29. package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +0 -2
  30. package/android/build/intermediates/incremental/mergeDebugAssets/merger.xml +0 -2
  31. package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +0 -2
  32. package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +0 -2
  33. package/android/build/intermediates/java_res/debug/processDebugJavaRes/out/META-INF/expo-ai-kit_debug.kotlin_module +0 -0
  34. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/expo/modules/aikit/BuildConfig.class +0 -0
  35. package/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +0 -2
  36. package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +0 -7
  37. package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +0 -7
  38. package/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +0 -1
  39. package/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +0 -1
  40. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  41. package/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +0 -1
  42. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
  43. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
  44. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
  45. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len +0 -0
  46. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
  47. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
  48. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i.len +0 -0
  49. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
  50. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
  51. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
  52. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
  53. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
  54. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
  55. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i.len +0 -0
  56. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
  57. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
  58. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
  59. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
  60. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
  61. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
  62. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len +0 -0
  63. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
  64. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
  65. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
  66. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
  67. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
  68. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
  69. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len +0 -0
  70. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
  71. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
  72. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
  73. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
  74. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
  75. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
  76. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i.len +0 -0
  77. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
  78. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
  79. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
  80. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len +0 -0
  81. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
  82. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
  83. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len +0 -0
  84. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
  85. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream +0 -0
  86. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len +0 -0
  87. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len +0 -0
  88. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
  89. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i +0 -0
  90. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i.len +0 -0
  91. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
  92. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
  93. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len +0 -0
  94. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len +0 -0
  95. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
  96. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
  97. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i.len +0 -0
  98. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +0 -2
  99. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
  100. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
  101. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
  102. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len +0 -0
  103. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
  104. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
  105. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i.len +0 -0
  106. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
  107. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
  108. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
  109. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
  110. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
  111. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
  112. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len +0 -0
  113. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
  114. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
  115. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
  116. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
  117. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
  118. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
  119. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i.len +0 -0
  120. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  121. package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
  122. package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
  123. package/android/build/outputs/logs/manifest-merger-debug-report.txt +0 -14
  124. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  125. package/android/build/tmp/kotlin-classes/debug/META-INF/expo-ai-kit_debug.kotlin_module +0 -0
  126. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$1$11$1.class +0 -0
  127. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$1$2$conversationPrompt$2.class +0 -0
  128. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$1$3$conversationPrompt$2.class +0 -0
  129. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$1$3$job$1$streamCallback$1.class +0 -0
  130. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$1$3$job$1.class +0 -0
  131. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$AsyncFunction$1.class +0 -0
  132. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$AsyncFunction$2.class +0 -0
  133. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$AsyncFunction$3.class +0 -0
  134. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$AsyncFunction$4.class +0 -0
  135. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$AsyncFunction$5.class +0 -0
  136. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$AsyncFunction$6.class +0 -0
  137. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$AsyncFunction$7.class +0 -0
  138. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$1.class +0 -0
  139. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$10.class +0 -0
  140. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$11.class +0 -0
  141. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$12.class +0 -0
  142. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$2.class +0 -0
  143. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$3.class +0 -0
  144. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$4.class +0 -0
  145. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$5.class +0 -0
  146. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$6.class +0 -0
  147. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$7.class +0 -0
  148. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$8.class +0 -0
  149. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$9.class +0 -0
  150. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Function$1.class +0 -0
  151. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Function$2.class +0 -0
  152. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$FunctionWithoutArgs$1.class +0 -0
  153. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$FunctionWithoutArgs$2.class +0 -0
  154. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$FunctionWithoutArgs$3.class +0 -0
  155. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$FunctionWithoutArgs$4.class +0 -0
  156. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule.class +0 -0
  157. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$deleteModelFile$1.class +0 -0
  158. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$downloadModelFile$1.class +0 -0
  159. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$downloadModelFile$2.class +0 -0
  160. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$generateText$1.class +0 -0
  161. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$generateText$2$1$1$1.class +0 -0
  162. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$generateText$2$1.class +0 -0
  163. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$generateTextStream$1.class +0 -0
  164. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$generateTextStream$2$1$1$1.class +0 -0
  165. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$generateTextStream$2$1.class +0 -0
  166. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$loadModel$1.class +0 -0
  167. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$loadModel$2$1.class +0 -0
  168. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$unloadModel$1.class +0 -0
  169. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient.class +0 -0
  170. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/PromptApiClient$generateText$2.class +0 -0
  171. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/PromptApiClient$generateTextStream$2$1.class +0 -0
  172. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/PromptApiClient$generateTextStream$2.class +0 -0
  173. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/PromptApiClient$isAvailable$1.class +0 -0
  174. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/PromptApiClient$isAvailableBlocking$1.class +0 -0
  175. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/PromptApiClient.class +0 -0
  176. package/build/hooks.d.ts +0 -147
  177. package/build/hooks.d.ts.map +0 -1
  178. package/build/hooks.js +0 -426
  179. package/build/hooks.js.map +0 -1
  180. package/build/memory.d.ts +0 -235
  181. package/build/memory.d.ts.map +0 -1
  182. package/build/memory.js +0 -353
  183. package/build/memory.js.map +0 -1
  184. package/src/__tests__/index.test.js +0 -630
  185. package/src/hooks.ts +0 -502
  186. package/src/memory.ts +0 -394
package/README.md CHANGED
@@ -1,1169 +1,131 @@
1
1
  # expo-ai-kit
2
2
 
3
- On-device AI for Expo apps. Run language models locally—no API keys, no cloud, just native intelligence.
4
-
5
- **Now with Gemma 4 support** — Download and run Google's [Gemma 4](https://blog.google/innovation-and-ai/technology/developers-tools/gemma-4/) E2B (2.3B) and E4B (4.5B) models directly on Android devices via [LiteRT-LM](https://ai.google.dev/edge/litert-lm). Full on-device inference with GPU acceleration, streaming, and zero cloud dependency.
3
+ On-device AI for Expo & React Native. Run LLMs locally no API keys, no cloud, no cost.
6
4
 
7
5
  [![npm version](https://img.shields.io/npm/v/expo-ai-kit.svg)](https://www.npmjs.com/package/expo-ai-kit)
8
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
7
 
10
- ## Platform Support
11
-
12
- ### Supported
13
-
14
- | Platform | Details |
15
- |----------|---------|
16
- | iOS 26+ | [Apple Foundation Models](https://developer.apple.com/documentation/FoundationModels) |
17
- | Android (supported devices) | [ML Kit Prompt API](https://developers.google.com/ml-kit/genai#prompt-device) |
18
-
19
- ### Downloadable Models (Gemma 4)
20
-
21
- | Platform | Status |
22
- |----------|--------|
23
- | Android | Gemma 4 E2B (2.3B) and E4B (4.5B) via [LiteRT-LM](https://ai.google.dev/edge/litert-lm) |
24
- | iOS | Coming soon — waiting for LiteRT-LM Swift APIs from Google |
25
-
26
- > **Note:** iOS downloadable model support (Gemma 4 E2B/E4B) is planned for a future release. We are waiting for Google to ship native Swift APIs for LiteRT-LM. Built-in Apple Foundation Models work on iOS 26+ today.
27
-
28
- ### Unsupported
29
-
30
- | Platform | Fallback Behavior |
31
- |----------|-------------------|
32
- | iOS < 26 | Returns fallback message |
33
- | Android (unsupported devices) | Returns empty string |
34
-
35
- ## Features
36
-
37
- - **Privacy-first** — All inference happens on-device; no data leaves the user's device
38
- - **Zero latency** — No network round-trips required
39
- - **Free forever** — No API costs, rate limits, or subscriptions
40
- - **Gemma 4 on-device** — Download and run Gemma 4 E2B/E4B models directly on Android with GPU acceleration
41
- - **Native performance** — Built on Apple Foundation Models (iOS), ML Kit (Android), and LiteRT-LM (Gemma 4)
42
- - **Multi-turn conversations** — Full conversation context support
43
- - **Streaming support** — Progressive token streaming for responsive UIs
44
- - **Simple API** — Core functions plus prompt helpers for common tasks
45
- - **Prompt helpers** — Built-in `summarize()`, `translate()`, `rewrite()`, and more
46
- - **Smart suggestions** — `suggest()`, `smartReply()`, and `autocomplete()` for predictive text
47
- - **React Hooks** — `useChat`, `useCompletion`, and `useOnDeviceAI` for plug-and-play integration
48
- - **Chat memory** — Built-in `ChatMemoryManager` for managing conversation history
49
-
50
- ## Requirements
8
+ Run Google's **Gemma 4** (E2B / E4B), **Apple Foundation Models**, and **ML Kit**
9
+ entirely on-device — chat, streaming, and downloadable models, all local.
51
10
 
52
- - Expo SDK 54+
53
- - **iOS:** iOS 26.0+ (full support), iOS 15.1+ (limited)
54
- - **Android:** API 26+, [Supported devices](https://developers.google.com/ml-kit/genai#prompt-device)
11
+ - **Private** inference never leaves the device
12
+ - **Free** no API costs, rate limits, or subscriptions
13
+ - **Native** Apple Foundation Models (iOS 26+), ML Kit (Android), Gemma 4 via [LiteRT-LM](https://ai.google.dev/edge/litert-lm)
14
+ - **Streaming** — progressive token output with cancellation
15
+ - **Model management** — download, load, and switch Gemma 4 models at runtime
55
16
 
56
- ## Installation
17
+ ## Install
57
18
 
58
19
  ```bash
59
20
  npx expo install expo-ai-kit
60
21
  ```
61
22
 
62
- For bare React Native projects, run `npx pod-install` after installing.
23
+ Bare React Native projects: run `npx pod-install` afterwards. Android needs
24
+ `minSdkVersion 26` — set it via `expo-build-properties` in `app.json`.
63
25
 
64
- ### Android Configuration
65
-
66
- For Android, ensure your `app.json` includes the minimum SDK version:
67
-
68
- ```json
69
- {
70
- "expo": {
71
- "plugins": [
72
- [
73
- "expo-build-properties",
74
- {
75
- "android": {
76
- "minSdkVersion": 26
77
- }
78
- }
79
- ]
80
- ]
81
- }
82
- }
83
- ```
84
-
85
- ## Quick Start
26
+ ## Quick start
86
27
 
87
28
  ```tsx
88
29
  import { isAvailable, sendMessage } from 'expo-ai-kit';
89
30
 
90
- // Check if on-device AI is available
91
- const available = await isAvailable();
92
-
93
- if (available) {
94
- const response = await sendMessage([
95
- { role: 'user', content: 'Hello! What can you do?' }
31
+ if (await isAvailable()) {
32
+ const { text } = await sendMessage([
33
+ { role: 'user', content: 'What is the capital of France?' },
96
34
  ]);
97
- console.log(response.text);
35
+ console.log(text); // "Paris"
98
36
  }
99
37
  ```
100
38
 
101
- ## Usage
102
-
103
- ### Simple Prompt
104
-
105
- The simplest way to use on-device AI:
39
+ Add a system prompt, or include `system`/`assistant` messages for multi-turn context.
40
+ On-device models are stateless — pass the full message history on every call.
106
41
 
107
42
  ```tsx
108
- import { isAvailable, sendMessage } from 'expo-ai-kit';
109
-
110
- async function askAI(question: string) {
111
- const available = await isAvailable();
112
-
113
- if (!available) {
114
- console.log('On-device AI not available');
115
- return null;
116
- }
117
-
118
- const response = await sendMessage([
119
- { role: 'user', content: question }
120
- ]);
121
- return response.text;
122
- }
123
-
124
- const answer = await askAI('What is the capital of France?');
125
- ```
126
-
127
- ### With Custom System Prompt
128
-
129
- Customize the AI's behavior with a system prompt:
130
-
131
- ```tsx
132
- import { sendMessage } from 'expo-ai-kit';
133
-
134
- const response = await sendMessage(
43
+ const { text } = await sendMessage(
135
44
  [{ role: 'user', content: 'Tell me a joke' }],
136
- { systemPrompt: 'You are a comedian who specializes in dad jokes.' }
137
- );
138
-
139
- console.log(response.text);
140
- ```
141
-
142
- ### Multi-turn Conversations
143
-
144
- For conversations with context, use `ChatMemoryManager` to manage history:
145
-
146
- ```tsx
147
- import { ChatMemoryManager, streamMessage } from 'expo-ai-kit';
148
-
149
- // Create a memory manager (handles history automatically)
150
- const memory = new ChatMemoryManager({
151
- maxTurns: 10,
152
- systemPrompt: 'You are a helpful assistant.',
153
- });
154
-
155
- // Add user message and get response
156
- memory.addUserMessage('My name is Alice.');
157
- const { promise } = streamMessage(
158
- memory.getAllMessages(),
159
- (event) => console.log(event.accumulatedText)
160
- );
161
- const response = await promise;
162
-
163
- // Store assistant response in memory
164
- memory.addAssistantMessage(response.text);
165
-
166
- // Continue the conversation (memory includes full history)
167
- memory.addUserMessage('What is my name?');
168
- const { promise: p2 } = streamMessage(
169
- memory.getAllMessages(),
170
- (event) => console.log(event.accumulatedText)
45
+ { systemPrompt: 'You are a stand-up comedian.' }
171
46
  );
172
- // Response: "Your name is Alice."
173
47
  ```
174
48
 
175
- Or manually manage the conversation array:
176
-
177
- ```tsx
178
- import { sendMessage, type LLMMessage } from 'expo-ai-kit';
179
-
180
- const conversation: LLMMessage[] = [
181
- { role: 'user', content: 'My name is Alice.' },
182
- { role: 'assistant', content: 'Nice to meet you, Alice!' },
183
- { role: 'user', content: 'What is my name?' },
184
- ];
185
-
186
- const response = await sendMessage(conversation, {
187
- systemPrompt: 'You are a helpful assistant.',
188
- });
189
-
190
- console.log(response.text); // "Your name is Alice."
191
- ```
192
-
193
- ### Streaming Responses
194
-
195
- For a ChatGPT-like experience where text appears progressively:
49
+ ## Streaming
196
50
 
197
51
  ```tsx
198
52
  import { streamMessage } from 'expo-ai-kit';
199
53
 
200
- const [responseText, setResponseText] = useState('');
201
-
202
54
  const { promise, stop } = streamMessage(
203
- [{ role: 'user', content: 'Tell me a story' }],
204
- (event) => {
205
- // Update UI with each token
206
- setResponseText(event.accumulatedText);
207
-
208
- // event.token - the new token/chunk
209
- // event.accumulatedText - full text so far
210
- // event.isDone - whether streaming is complete
211
- },
212
- { systemPrompt: 'You are a creative storyteller.' }
55
+ [{ role: 'user', content: 'Write a short story' }],
56
+ (event) => setText(event.accumulatedText), // fired per token
213
57
  );
214
58
 
215
- // Optionally cancel the stream
216
- // stop();
217
-
218
- // Wait for completion
219
- await promise;
59
+ await promise; // resolves with the final { text }
60
+ // stop(); // cancel at any point
220
61
  ```
221
62
 
222
- ### Prompt Helpers
63
+ ## Downloadable models (Gemma 4)
223
64
 
224
- Use built-in helpers for common AI tasks without crafting prompts:
65
+ On Android, download and run Gemma 4 models on top of the built-in OS model.
225
66
 
226
67
  ```tsx
227
- import { summarize, translate, rewrite, extractKeyPoints, answerQuestion } from 'expo-ai-kit';
68
+ import {
69
+ getDownloadableModels, downloadModel, setModel, sendMessage,
70
+ } from 'expo-ai-kit';
228
71
 
229
- // Summarize text
230
- const summary = await summarize(longArticle, { length: 'short', style: 'bullets' });
231
-
232
- // Translate text
233
- const translated = await translate('Hello, world!', { to: 'Spanish' });
234
-
235
- // Rewrite in a different style
236
- const formal = await rewrite('hey whats up', { style: 'formal' });
237
-
238
- // Extract key points
239
- const points = await extractKeyPoints(article, { maxPoints: 5 });
240
-
241
- // Answer questions about content
242
- const answer = await answerQuestion('What is the main topic?', documentText);
243
- ```
72
+ // List models with their on-device status
73
+ const models = await getDownloadableModels();
244
74
 
245
- ### Smart Suggestions
246
-
247
- Generate text completions, smart replies, and autocomplete suggestions — all on-device:
248
-
249
- ```tsx
250
- import { suggest, smartReply, autocomplete } from 'expo-ai-kit';
251
-
252
- // Text suggestions — continue partial text
253
- const suggestions = await suggest('I think we should', {
254
- count: 3,
255
- tone: 'professional',
256
- context: 'team meeting notes'
257
- });
258
- suggestions.suggestions.forEach(s => console.log(s.text));
259
- // "schedule a follow-up meeting to discuss next steps"
260
- // "prioritize the Q2 deliverables before moving forward"
261
- // "assign clear owners for each action item"
262
-
263
- // Smart replies — Gmail/iMessage-style reply suggestions
264
- const replies = await smartReply([
265
- { role: 'user', content: 'Hey, are you free for lunch tomorrow?' }
266
- ], { tone: 'friendly' });
267
- replies.suggestions.forEach(s => console.log(s.text));
268
- // "Sure, what time works for you?"
269
- // "Sorry, I already have plans tomorrow."
270
- // "Let me check my schedule and get back to you!"
271
-
272
- // Autocomplete — short, instant completions for search bars and inputs
273
- const completions = await autocomplete('How do I', {
274
- context: 'cooking app',
275
- maxWords: 8
75
+ // Download with progress, then activate
76
+ await downloadModel('gemma-e2b', {
77
+ onProgress: (p) => console.log(`${Math.round(p * 100)}%`),
276
78
  });
277
- completions.suggestions.forEach(s => console.log(s.text));
278
- // "make pasta from scratch"
279
- // "preheat the oven correctly"
280
- // "chop onions without crying"
281
- ```
282
-
283
- All smart suggestion functions also have streaming variants (`streamSuggest`, `streamSmartReply`, `streamAutocomplete`). Use `parseSuggestResponse()` to parse streaming results:
284
-
285
- ```tsx
286
- const { promise } = streamSuggest(
287
- 'The best way to',
288
- (event) => setRawText(event.accumulatedText),
289
- { count: 3 }
290
- );
291
- const result = await promise;
292
- const parsed = parseSuggestResponse(result.text);
293
- // parsed.suggestions = [{ text: "..." }, { text: "..." }, { text: "..." }]
294
- ```
295
-
296
- All helpers also have streaming variants (`streamSummarize`, `streamTranslate`, etc.):
297
-
298
- ```tsx
299
- const { promise, stop } = streamSummarize(
300
- longArticle,
301
- (event) => setSummary(event.accumulatedText),
302
- { style: 'bullets' }
303
- );
304
- ```
305
-
306
- ### React Hooks
307
-
308
- expo-ai-kit provides React hooks that handle state management, streaming, and conversation memory automatically.
79
+ await setModel('gemma-e2b', { backend: 'auto' }); // 'auto' | 'gpu' | 'cpu'
309
80
 
310
- #### `useChat` Full Chat Interface
311
-
312
- The easiest way to build a chat UI. Manages messages, input, streaming, and memory for you:
313
-
314
- ```tsx
315
- import { useChat } from 'expo-ai-kit';
316
-
317
- function ChatScreen() {
318
- const { messages, input, setInput, sendMessage, isStreaming, stop, clear, error } = useChat({
319
- systemPrompt: 'You are a helpful assistant.',
320
- maxTurns: 10,
321
- });
322
-
323
- return (
324
- <View style={{ flex: 1 }}>
325
- <FlatList
326
- data={messages}
327
- keyExtractor={(_, i) => i.toString()}
328
- renderItem={({ item }) => (
329
- <Text>{item.role}: {item.content}</Text>
330
- )}
331
- />
332
- <TextInput value={input} onChangeText={setInput} />
333
- {isStreaming ? (
334
- <Button title="Stop" onPress={stop} />
335
- ) : (
336
- <Button title="Send" onPress={() => sendMessage()} />
337
- )}
338
- <Button title="Clear" onPress={clear} />
339
- </View>
340
- );
341
- }
342
- ```
343
-
344
- You can also send a message programmatically:
345
-
346
- ```tsx
347
- // Send custom text instead of current input
348
- sendMessage('What is the weather today?');
349
- ```
350
-
351
- #### `useCompletion` — Single-shot Completions
352
-
353
- For one-off tasks like summarization, translation, or content generation (no conversation history):
354
-
355
- ```tsx
356
- import { useCompletion } from 'expo-ai-kit';
357
-
358
- function Summarizer() {
359
- const { completion, isLoading, complete, stop, error } = useCompletion({
360
- systemPrompt: 'Summarize the given text concisely.',
361
- });
362
-
363
- return (
364
- <View>
365
- <Button
366
- title="Summarize"
367
- onPress={() => complete('Long article text here...')}
368
- />
369
- {isLoading && <Button title="Stop" onPress={stop} />}
370
- <Text>{completion}</Text>
371
- </View>
372
- );
373
- }
374
- ```
375
-
376
- #### `useOnDeviceAI` — Availability Check
377
-
378
- A simple hook to check if on-device AI is available, with caching across components:
379
-
380
- ```tsx
381
- import { useOnDeviceAI } from 'expo-ai-kit';
382
-
383
- function App() {
384
- const { isAvailable, isChecking } = useOnDeviceAI();
385
-
386
- if (isChecking) return <Text>Checking AI availability...</Text>;
387
- if (!isAvailable) return <Text>On-device AI not available</Text>;
388
-
389
- return <ChatScreen />;
390
- }
391
- ```
392
-
393
- ---
394
-
395
- ### Streaming with Cancel Button
396
-
397
- ```tsx
398
- import { useState, useRef } from 'react';
399
- import { streamMessage } from 'expo-ai-kit';
400
-
401
- function ChatWithStreaming() {
402
- const [text, setText] = useState('');
403
- const [isStreaming, setIsStreaming] = useState(false);
404
- const stopRef = useRef<(() => void) | null>(null);
405
-
406
- const handleSend = async () => {
407
- setIsStreaming(true);
408
- setText('');
409
-
410
- const { promise, stop } = streamMessage(
411
- [{ role: 'user', content: 'Write a long story' }],
412
- (event) => setText(event.accumulatedText)
413
- );
414
-
415
- stopRef.current = stop;
416
- await promise;
417
- stopRef.current = null;
418
- setIsStreaming(false);
419
- };
420
-
421
- const handleStop = () => {
422
- stopRef.current?.();
423
- setIsStreaming(false);
424
- };
425
-
426
- return (
427
- <View>
428
- <Text>{text}</Text>
429
- {isStreaming ? (
430
- <Button title="Stop" onPress={handleStop} />
431
- ) : (
432
- <Button title="Send" onPress={handleSend} />
433
- )}
434
- </View>
435
- );
436
- }
437
- ```
438
-
439
- ### Complete Chat Example
440
-
441
- Here's a full cross-platform chat component:
442
-
443
- ```tsx
444
- import React, { useState, useEffect } from 'react';
445
- import { View, TextInput, Button, Text, FlatList } from 'react-native';
446
- import { isAvailable, sendMessage, type LLMMessage } from 'expo-ai-kit';
447
-
448
- export default function ChatScreen() {
449
- const [messages, setMessages] = useState<LLMMessage[]>([]);
450
- const [input, setInput] = useState('');
451
- const [loading, setLoading] = useState(false);
452
- const [available, setAvailable] = useState(false);
453
-
454
- useEffect(() => {
455
- isAvailable().then(setAvailable);
456
- }, []);
457
-
458
- const handleSend = async () => {
459
- if (!input.trim() || loading || !available) return;
460
-
461
- const userMessage: LLMMessage = { role: 'user', content: input.trim() };
462
- const newMessages = [...messages, userMessage];
463
- setMessages(newMessages);
464
- setInput('');
465
- setLoading(true);
466
-
467
- try {
468
- const response = await sendMessage(newMessages, {
469
- systemPrompt: 'You are a helpful assistant.',
470
- });
471
- setMessages(prev => [...prev, { role: 'assistant', content: response.text }]);
472
- } catch (error) {
473
- console.error('Error:', error);
474
- } finally {
475
- setLoading(false);
476
- }
477
- };
478
-
479
- if (!available) {
480
- return (
481
- <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
482
- <Text>On-device AI is not available on this device</Text>
483
- </View>
484
- );
485
- }
486
-
487
- return (
488
- <View style={{ flex: 1, padding: 16 }}>
489
- <FlatList
490
- data={messages}
491
- keyExtractor={(_, i) => i.toString()}
492
- renderItem={({ item }) => (
493
- <View style={{
494
- padding: 12,
495
- marginVertical: 4,
496
- backgroundColor: item.role === 'user' ? '#007AFF' : '#E5E5EA',
497
- borderRadius: 16,
498
- alignSelf: item.role === 'user' ? 'flex-end' : 'flex-start',
499
- maxWidth: '80%',
500
- }}>
501
- <Text style={{ color: item.role === 'user' ? '#fff' : '#000' }}>
502
- {item.content}
503
- </Text>
504
- </View>
505
- )}
506
- />
507
- <View style={{ flexDirection: 'row', gap: 8 }}>
508
- <TextInput
509
- value={input}
510
- onChangeText={setInput}
511
- placeholder="Type a message..."
512
- style={{ flex: 1, borderWidth: 1, borderRadius: 8, padding: 12 }}
513
- />
514
- <Button title={loading ? '...' : 'Send'} onPress={handleSend} />
515
- </View>
516
- </View>
517
- );
518
- }
519
- ```
520
-
521
- ## API Reference
522
-
523
- ### `isAvailable()`
524
-
525
- Checks if on-device AI is available on the current device.
526
-
527
- ```typescript
528
- function isAvailable(): Promise<boolean>
81
+ // sendMessage / streamMessage now use the active model
82
+ const { text } = await sendMessage([{ role: 'user', content: 'Hi!' }]);
529
83
  ```
530
84
 
531
- **Returns:** `Promise<boolean>` `true` if on-device AI is supported and ready
85
+ `unloadModel()` frees memory and reverts to the OS model; `deleteModel(id)` removes the file.
532
86
 
533
- ---
87
+ | Model | Params | Size | Platforms |
88
+ |-------|--------|------|-----------|
89
+ | `gemma-e2b` | 2.3B | ~2.6 GB | Android |
90
+ | `gemma-e4b` | 4.5B | ~3.7 GB | Android |
534
91
 
535
- ### `sendMessage(messages, options?)`
92
+ > iOS downloadable models are planned, pending LiteRT-LM Swift APIs from Google.
536
93
 
537
- Sends a conversation and gets a response from the on-device model.
94
+ ## Platform support
538
95
 
539
- ```typescript
540
- function sendMessage(messages: LLMMessage[], options?: LLMSendOptions): Promise<LLMResponse>
541
- ```
96
+ | Platform | Engine | Models |
97
+ |----------|--------|--------|
98
+ | iOS 26+ | [Apple Foundation Models](https://developer.apple.com/documentation/FoundationModels) | Built-in |
99
+ | Android ([supported devices](https://developers.google.com/ml-kit/genai#prompt-device)) | [ML Kit Prompt API](https://developers.google.com/ml-kit/genai#prompt-device) | Built-in + downloadable Gemma 4 |
100
+ | iOS < 26 / unsupported Android | — | `isAvailable()` returns `false` |
542
101
 
543
- | Parameter | Type | Description |
544
- |-----------|------|-------------|
545
- | `messages` | `LLMMessage[]` | Array of conversation messages |
546
- | `options.systemPrompt` | `string` | Fallback system prompt (ignored if messages contain a system message) |
102
+ Requires Expo SDK 54+.
547
103
 
548
- **Returns:** `Promise<LLMResponse>` — Object with `text` property containing the response
104
+ ## API
549
105
 
550
- **Example:**
551
- ```tsx
552
- const response = await sendMessage([
553
- { role: 'system', content: 'You are a pirate.' },
554
- { role: 'user', content: 'Hello!' },
555
- ]);
556
- console.log(response.text); // "Ahoy, matey!"
557
- ```
106
+ **Inference**
558
107
 
559
- ---
108
+ - `isAvailable()` → `Promise<boolean>`
109
+ - `sendMessage(messages, options?)` → `Promise<{ text }>`
110
+ - `streamMessage(messages, onToken, options?)` → `{ promise, stop }`
560
111
 
561
- ### `streamMessage(messages, onToken, options?)`
112
+ **Models**
562
113
 
563
- Streams a conversation response with progressive token updates. Ideal for responsive chat UIs.
114
+ - `getBuiltInModels()` `Promise<BuiltInModel[]>`
115
+ - `getDownloadableModels()` → `Promise<DownloadableModel[]>`
116
+ - `downloadModel(id, { onProgress? })` / `deleteModel(id)`
117
+ - `setModel(id, { backend? })` / `unloadModel()` / `getActiveModel()`
564
118
 
565
- ```typescript
566
- function streamMessage(
567
- messages: LLMMessage[],
568
- onToken: LLMStreamCallback,
569
- options?: LLMStreamOptions
570
- ): { promise: Promise<LLMResponse>; stop: () => void }
571
- ```
119
+ `messages` is `{ role: 'system' | 'user' | 'assistant'; content: string }[]` and
120
+ `options` accepts `{ systemPrompt?: string }`. Model operations throw `ModelError`
121
+ with a `.code` (e.g. `MODEL_NOT_FOUND`, `DOWNLOAD_CORRUPT`, `INFERENCE_OOM`).
122
+ Full TypeScript definitions ship with the package.
572
123
 
573
- | Parameter | Type | Description |
574
- |-----------|------|-------------|
575
- | `messages` | `LLMMessage[]` | Array of conversation messages |
576
- | `onToken` | `LLMStreamCallback` | Callback called for each token received |
577
- | `options.systemPrompt` | `string` | Fallback system prompt (ignored if messages contain a system message) |
578
-
579
- **Returns:** Object with:
580
- - `promise: Promise<LLMResponse>` — Resolves when streaming completes
581
- - `stop: () => void` — Function to cancel the stream
582
-
583
- **Example:**
584
- ```tsx
585
- const { promise, stop } = streamMessage(
586
- [{ role: 'user', content: 'Hello!' }],
587
- (event) => {
588
- console.log(event.token); // New token: "Hi"
589
- console.log(event.accumulatedText); // Full text: "Hi there!"
590
- console.log(event.isDone); // false until complete
591
- }
592
- );
593
-
594
- // Cancel if needed
595
- setTimeout(() => stop(), 5000);
596
-
597
- // Wait for completion
598
- const response = await promise;
599
- ```
600
-
601
- ---
602
-
603
- ### `summarize(text, options?)`
604
-
605
- Summarizes text using on-device AI.
606
-
607
- ```typescript
608
- function summarize(text: string, options?: LLMSummarizeOptions): Promise<LLMResponse>
609
- ```
610
-
611
- | Parameter | Type | Description |
612
- |-----------|------|-------------|
613
- | `text` | `string` | Text to summarize |
614
- | `options.length` | `'short' \| 'medium' \| 'long'` | Summary length (default: `'medium'`) |
615
- | `options.style` | `'paragraph' \| 'bullets' \| 'tldr'` | Output format (default: `'paragraph'`) |
616
-
617
- **Streaming:** `streamSummarize(text, onToken, options?)`
618
-
619
- ---
620
-
621
- ### `translate(text, options)`
622
-
623
- Translates text to another language.
624
-
625
- ```typescript
626
- function translate(text: string, options: LLMTranslateOptions): Promise<LLMResponse>
627
- ```
628
-
629
- | Parameter | Type | Description |
630
- |-----------|------|-------------|
631
- | `text` | `string` | Text to translate |
632
- | `options.to` | `string` | Target language (required) |
633
- | `options.from` | `string` | Source language (auto-detected if omitted) |
634
- | `options.tone` | `'formal' \| 'informal' \| 'neutral'` | Translation tone (default: `'neutral'`) |
635
-
636
- **Streaming:** `streamTranslate(text, onToken, options)`
637
-
638
- ---
639
-
640
- ### `rewrite(text, options)`
641
-
642
- Rewrites text in a different style.
643
-
644
- ```typescript
645
- function rewrite(text: string, options: LLMRewriteOptions): Promise<LLMResponse>
646
- ```
647
-
648
- | Parameter | Type | Description |
649
- |-----------|------|-------------|
650
- | `text` | `string` | Text to rewrite |
651
- | `options.style` | `string` | Target style (required) |
652
-
653
- **Available styles:** `'formal'`, `'casual'`, `'professional'`, `'friendly'`, `'concise'`, `'detailed'`, `'simple'`, `'academic'`
654
-
655
- **Streaming:** `streamRewrite(text, onToken, options)`
656
-
657
- ---
658
-
659
- ### `extractKeyPoints(text, options?)`
660
-
661
- Extracts key points from text as bullet points.
662
-
663
- ```typescript
664
- function extractKeyPoints(text: string, options?: LLMExtractKeyPointsOptions): Promise<LLMResponse>
665
- ```
666
-
667
- | Parameter | Type | Description |
668
- |-----------|------|-------------|
669
- | `text` | `string` | Text to analyze |
670
- | `options.maxPoints` | `number` | Maximum points to extract (default: `5`) |
671
-
672
- **Streaming:** `streamExtractKeyPoints(text, onToken, options?)`
673
-
674
- ---
675
-
676
- ### `answerQuestion(question, context, options?)`
677
-
678
- Answers a question based on provided context.
679
-
680
- ```typescript
681
- function answerQuestion(question: string, context: string, options?: LLMAnswerQuestionOptions): Promise<LLMResponse>
682
- ```
683
-
684
- | Parameter | Type | Description |
685
- |-----------|------|-------------|
686
- | `question` | `string` | Question to answer |
687
- | `context` | `string` | Context/document to base answer on |
688
- | `options.detail` | `'brief' \| 'medium' \| 'detailed'` | Answer detail level (default: `'medium'`) |
689
-
690
- **Streaming:** `streamAnswerQuestion(question, context, onToken, options?)`
691
-
692
- ---
693
-
694
- ### `suggest(partialText, options?)`
695
-
696
- Generates text continuation suggestions based on partial input.
697
-
698
- ```typescript
699
- function suggest(partialText: string, options?: LLMSuggestOptions): Promise<LLMSuggestResponse>
700
- ```
701
-
702
- | Parameter | Type | Description |
703
- |-----------|------|-------------|
704
- | `partialText` | `string` | The text the user has typed so far |
705
- | `options.count` | `number` | Number of suggestions (default: `3`) |
706
- | `options.context` | `string` | Optional context to inform suggestions |
707
- | `options.tone` | `'formal' \| 'casual' \| 'professional' \| 'friendly' \| 'neutral'` | Tone of suggestions (default: `'neutral'`) |
708
-
709
- **Returns:** `Promise<LLMSuggestResponse>` — Object with `suggestions` array and `raw` text
710
-
711
- **Streaming:** `streamSuggest(partialText, onToken, options?)`
712
-
713
- ---
714
-
715
- ### `smartReply(messages, options?)`
716
-
717
- Generates contextually appropriate reply suggestions for a conversation, similar to Gmail or iMessage smart replies.
718
-
719
- ```typescript
720
- function smartReply(messages: LLMMessage[], options?: LLMSmartReplyOptions): Promise<LLMSuggestResponse>
721
- ```
722
-
723
- | Parameter | Type | Description |
724
- |-----------|------|-------------|
725
- | `messages` | `LLMMessage[]` | Conversation history to generate replies for |
726
- | `options.count` | `number` | Number of reply suggestions (default: `3`) |
727
- | `options.tone` | `'formal' \| 'casual' \| 'professional' \| 'friendly' \| 'neutral'` | Reply tone (default: `'neutral'`) |
728
- | `options.persona` | `string` | Optional persona for the replier (e.g., `'customer support agent'`) |
729
-
730
- **Returns:** `Promise<LLMSuggestResponse>` — Object with `suggestions` array and `raw` text
731
-
732
- **Streaming:** `streamSmartReply(messages, onToken, options?)`
733
-
734
- ---
735
-
736
- ### `autocomplete(partialText, options?)`
737
-
738
- Generates short, natural completions for the user's current text. Ideal for search bars, form fields, and real-time typing suggestions.
739
-
740
- ```typescript
741
- function autocomplete(partialText: string, options?: LLMAutocompleteOptions): Promise<LLMSuggestResponse>
742
- ```
743
-
744
- | Parameter | Type | Description |
745
- |-----------|------|-------------|
746
- | `partialText` | `string` | The text the user has typed so far |
747
- | `options.count` | `number` | Number of completions (default: `3`) |
748
- | `options.maxWords` | `number` | Maximum words per completion (default: `10`) |
749
- | `options.context` | `string` | Optional context to inform completions |
750
-
751
- **Returns:** `Promise<LLMSuggestResponse>` — Object with `suggestions` array and `raw` text
752
-
753
- **Streaming:** `streamAutocomplete(partialText, onToken, options?)`
754
-
755
- ---
756
-
757
- ### `parseSuggestResponse(raw)`
758
-
759
- Parses raw text from streaming suggestion responses into structured suggestions.
760
-
761
- ```typescript
762
- function parseSuggestResponse(raw: string): LLMSuggestResponse
763
- ```
764
-
765
- | Parameter | Type | Description |
766
- |-----------|------|-------------|
767
- | `raw` | `string` | Raw text response from the model |
768
-
769
- **Returns:** `LLMSuggestResponse` — Object with `suggestions` array and `raw` text
770
-
771
- ---
772
-
773
- ### `useChat(options?)`
774
-
775
- React hook for building chat interfaces. Manages messages, input, streaming, and conversation memory automatically.
776
-
777
- ```typescript
778
- function useChat(options?: UseChatOptions): UseChatReturn
779
- ```
780
-
781
- | Option | Type | Description |
782
- |--------|------|-------------|
783
- | `systemPrompt` | `string` | System prompt for the AI assistant |
784
- | `maxTurns` | `number` | Maximum conversation turns to keep in memory (default: `10`) |
785
- | `initialMessages` | `LLMMessage[]` | Initial messages to populate the chat |
786
- | `onFinish` | `(response: LLMResponse) => void` | Callback when a response is complete |
787
- | `onError` | `(error: Error) => void` | Callback when an error occurs |
788
-
789
- **Returns:**
790
-
791
- | Property | Type | Description |
792
- |----------|------|-------------|
793
- | `messages` | `LLMMessage[]` | All messages in the conversation |
794
- | `input` | `string` | Current input text value |
795
- | `setInput` | `(input: string) => void` | Set the input text value |
796
- | `sendMessage` | `(text?: string) => Promise<void>` | Send the current input (or provided text) |
797
- | `isStreaming` | `boolean` | Whether the AI is currently streaming |
798
- | `stop` | `() => void` | Stop the current streaming response |
799
- | `clear` | `() => void` | Clear all messages and reset |
800
- | `error` | `Error \| null` | The most recent error, if any |
801
-
802
- ---
803
-
804
- ### `useCompletion(options?)`
805
-
806
- React hook for single-shot AI completions (summarization, translation, etc.).
807
-
808
- ```typescript
809
- function useCompletion(options?: UseCompletionOptions): UseCompletionReturn
810
- ```
811
-
812
- | Option | Type | Description |
813
- |--------|------|-------------|
814
- | `systemPrompt` | `string` | System prompt for the AI |
815
- | `onFinish` | `(response: LLMResponse) => void` | Callback when completion is done |
816
- | `onError` | `(error: Error) => void` | Callback when an error occurs |
817
-
818
- **Returns:**
819
-
820
- | Property | Type | Description |
821
- |----------|------|-------------|
822
- | `completion` | `string` | The current completion text |
823
- | `isLoading` | `boolean` | Whether a completion is in progress |
824
- | `complete` | `(prompt: string) => Promise<string>` | Request a completion |
825
- | `stop` | `() => void` | Stop the current completion |
826
- | `error` | `Error \| null` | The most recent error, if any |
827
-
828
- ---
829
-
830
- ### `useOnDeviceAI()`
831
-
832
- React hook to check if on-device AI is available. Caches the result across components.
833
-
834
- ```typescript
835
- function useOnDeviceAI(): UseOnDeviceAIReturn
836
- ```
837
-
838
- **Returns:**
839
-
840
- | Property | Type | Description |
841
- |----------|------|-------------|
842
- | `isAvailable` | `boolean` | Whether on-device AI is available |
843
- | `isChecking` | `boolean` | Whether the check is still in progress |
844
-
845
- ---
846
-
847
- ### `ChatMemoryManager`
848
-
849
- Manages conversation history for stateless on-device AI models. Automatically handles turn limits and provides the full message array for each request.
850
-
851
- ```typescript
852
- class ChatMemoryManager {
853
- constructor(options?: ChatMemoryOptions);
854
-
855
- addUserMessage(content: string): void;
856
- addAssistantMessage(content: string): void;
857
- addMessage(message: LLMMessage): void;
858
-
859
- getAllMessages(): LLMMessage[];
860
- getMessages(): LLMMessage[];
861
- getPrompt(): string;
862
- getSnapshot(): ChatMemorySnapshot;
863
- getTurnCount(): number;
864
-
865
- setSystemPrompt(prompt: string | undefined): void;
866
- getSystemPrompt(): string | undefined;
867
- setMaxTurns(maxTurns: number): void;
868
-
869
- clear(): void;
870
- reset(): void;
871
- }
872
- ```
873
-
874
- | Option | Type | Description |
875
- |--------|------|-------------|
876
- | `maxTurns` | `number` | Maximum conversation turns to keep (default: `10`) |
877
- | `systemPrompt` | `string` | System prompt to include in every request |
878
-
879
- **Why use ChatMemoryManager?**
880
-
881
- On-device models are stateless — they have no built-in memory. Each request must include the full conversation history. `ChatMemoryManager` handles this automatically:
882
-
883
- - Stores messages client-side
884
- - Automatically trims old messages when limit is reached
885
- - Preserves the system prompt (never trimmed)
886
- - Provides `getAllMessages()` for API calls
887
-
888
- **Example with React:**
889
-
890
- ```tsx
891
- import { useRef } from 'react';
892
- import { ChatMemoryManager, streamMessage } from 'expo-ai-kit';
893
-
894
- function Chat() {
895
- const memoryRef = useRef(new ChatMemoryManager({
896
- maxTurns: 10,
897
- systemPrompt: 'You are a helpful assistant.',
898
- }));
899
-
900
- const sendMessage = async (text: string) => {
901
- memoryRef.current.addUserMessage(text);
902
-
903
- const { promise } = streamMessage(
904
- memoryRef.current.getAllMessages(),
905
- (event) => setResponse(event.accumulatedText)
906
- );
907
-
908
- const response = await promise;
909
- memoryRef.current.addAssistantMessage(response.text);
910
- };
911
-
912
- const clearChat = () => memoryRef.current.clear();
913
- }
914
- ```
915
-
916
- ---
917
-
918
- ### `buildPrompt(messages)`
919
-
920
- Converts a message array to a single prompt string. Useful for debugging or custom implementations.
921
-
922
- ```typescript
923
- function buildPrompt(messages: LLMMessage[]): string
924
- ```
925
-
926
- **Example:**
927
- ```tsx
928
- import { buildPrompt } from 'expo-ai-kit';
929
-
930
- const prompt = buildPrompt([
931
- { role: 'system', content: 'You are helpful.' },
932
- { role: 'user', content: 'Hi!' },
933
- { role: 'assistant', content: 'Hello!' },
934
- ]);
935
- // "SYSTEM: You are helpful.\nUSER: Hi!\nASSISTANT: Hello!"
936
- ```
937
-
938
- ---
939
-
940
- ### Types
941
-
942
- ```typescript
943
- type LLMRole = 'system' | 'user' | 'assistant';
944
-
945
- type LLMMessage = {
946
- role: LLMRole;
947
- content: string;
948
- };
949
-
950
- type LLMSendOptions = {
951
- /** Fallback system prompt if no system message in messages array */
952
- systemPrompt?: string;
953
- };
954
-
955
- type LLMStreamOptions = {
956
- /** Fallback system prompt if no system message in messages array */
957
- systemPrompt?: string;
958
- };
959
-
960
- type LLMResponse = {
961
- /** The generated response text */
962
- text: string;
963
- };
964
-
965
- type LLMStreamEvent = {
966
- /** Unique identifier for this streaming session */
967
- sessionId: string;
968
- /** The token/chunk of text received */
969
- token: string;
970
- /** Accumulated text so far */
971
- accumulatedText: string;
972
- /** Whether this is the final chunk */
973
- isDone: boolean;
974
- };
975
-
976
- type LLMStreamCallback = (event: LLMStreamEvent) => void;
977
-
978
- // Prompt Helper Types
979
- type LLMSummarizeOptions = {
980
- length?: 'short' | 'medium' | 'long';
981
- style?: 'paragraph' | 'bullets' | 'tldr';
982
- };
983
-
984
- type LLMTranslateOptions = {
985
- to: string;
986
- from?: string;
987
- tone?: 'formal' | 'informal' | 'neutral';
988
- };
989
-
990
- type LLMRewriteOptions = {
991
- style: 'formal' | 'casual' | 'professional' | 'friendly' | 'concise' | 'detailed' | 'simple' | 'academic';
992
- };
993
-
994
- type LLMExtractKeyPointsOptions = {
995
- maxPoints?: number;
996
- };
997
-
998
- type LLMAnswerQuestionOptions = {
999
- detail?: 'brief' | 'medium' | 'detailed';
1000
- };
1001
-
1002
- // Smart Suggestions Types
1003
- type LLMSuggestOptions = {
1004
- count?: number;
1005
- context?: string;
1006
- tone?: 'formal' | 'casual' | 'professional' | 'friendly' | 'neutral';
1007
- };
1008
-
1009
- type LLMSmartReplyOptions = {
1010
- count?: number;
1011
- tone?: 'formal' | 'casual' | 'professional' | 'friendly' | 'neutral';
1012
- persona?: string;
1013
- };
1014
-
1015
- type LLMAutocompleteOptions = {
1016
- count?: number;
1017
- maxWords?: number;
1018
- context?: string;
1019
- };
1020
-
1021
- type LLMSuggestion = {
1022
- text: string;
1023
- };
1024
-
1025
- type LLMSuggestResponse = {
1026
- suggestions: LLMSuggestion[];
1027
- raw: string;
1028
- };
1029
-
1030
- // Hook Types
1031
- type UseChatOptions = {
1032
- systemPrompt?: string;
1033
- maxTurns?: number;
1034
- initialMessages?: LLMMessage[];
1035
- onFinish?: (response: LLMResponse) => void;
1036
- onError?: (error: Error) => void;
1037
- };
1038
-
1039
- type UseChatReturn = {
1040
- messages: LLMMessage[];
1041
- input: string;
1042
- setInput: (input: string) => void;
1043
- sendMessage: (text?: string) => Promise<void>;
1044
- isStreaming: boolean;
1045
- stop: () => void;
1046
- clear: () => void;
1047
- error: Error | null;
1048
- };
1049
-
1050
- type UseCompletionOptions = {
1051
- systemPrompt?: string;
1052
- onFinish?: (response: LLMResponse) => void;
1053
- onError?: (error: Error) => void;
1054
- };
1055
-
1056
- type UseCompletionReturn = {
1057
- completion: string;
1058
- isLoading: boolean;
1059
- complete: (prompt: string) => Promise<string>;
1060
- stop: () => void;
1061
- error: Error | null;
1062
- };
1063
-
1064
- type UseOnDeviceAIReturn = {
1065
- isAvailable: boolean;
1066
- isChecking: boolean;
1067
- };
1068
-
1069
- // Chat Memory Types
1070
- type ChatMemoryOptions = {
1071
- /** Maximum conversation turns to keep (default: 10) */
1072
- maxTurns?: number;
1073
- /** System prompt to include in every request */
1074
- systemPrompt?: string;
1075
- };
1076
-
1077
- type ChatMemorySnapshot = {
1078
- messages: LLMMessage[];
1079
- systemPrompt: string | undefined;
1080
- turnCount: number;
1081
- maxTurns: number;
1082
- };
1083
- ```
1084
-
1085
- ## Feature Comparison
1086
-
1087
- | Feature | iOS 26+ | Android (Supported) |
1088
- |---------|---------|---------------------|
1089
- | `isAvailable()` | ✅ | ✅ |
1090
- | `sendMessage()` | ✅ | ✅ |
1091
- | `streamMessage()` | ✅ | ✅ |
1092
- | Prompt helpers | ✅ | ✅ |
1093
- | Smart suggestions | ✅ | ✅ |
1094
- | `ChatMemoryManager` | ✅ | ✅ |
1095
- | React Hooks (`useChat`, etc.) | ✅ | ✅ |
1096
- | System prompts | ✅ Native | ✅ Prepended |
1097
- | Multi-turn context | ✅ | ✅ |
1098
- | Cancel streaming | ✅ | ✅ |
1099
-
1100
- ## How It Works
1101
-
1102
- ### iOS
1103
- Uses Apple's Foundation Models framework introduced in iOS 26. The on-device language model runs entirely locally with no internet connection required.
1104
-
1105
- ### Android
1106
- Uses Google's ML Kit Prompt API. The model may need to be downloaded on first use on supported devices. Check [supported devices](https://developers.google.com/ml-kit/genai#prompt-device) for compatibility.
1107
-
1108
- ## Troubleshooting
1109
-
1110
- ### iOS
1111
- - **AI not available**: Ensure you're running iOS 26.0 or later on a supported device
1112
- - **Fallback responses**: On iOS < 26, the module returns a fallback message
1113
-
1114
- ### Android
1115
- - **Empty responses**: The device may not support ML Kit Prompt API. Check the [supported devices list](https://developers.google.com/ml-kit/genai#prompt-device)
1116
- - **Model downloading**: On first use, the model may need to download. Use `isAvailable()` to check status
1117
-
1118
- ## Migration from v0.1.4
1119
-
1120
- If you're upgrading from an earlier version, here are the breaking changes:
1121
-
1122
- | Old API | New API |
1123
- |---------|---------|
1124
- | `sendPrompt(prompt)` | `sendMessage([{ role: 'user', content: prompt }])` |
1125
- | `createSession(options)` | **Removed** — no longer needed |
1126
- | `sendMessage(sessionId, messages, options)` | `sendMessage(messages, options)` — no session ID |
1127
- | `prepareModel(options)` | **Removed** |
1128
- | `{ reply: string }` | `{ text: string }` |
1129
-
1130
- **Before:**
1131
- ```tsx
1132
- const sessionId = await createSession({ systemPrompt: '...' });
1133
- const { reply } = await sendMessage(sessionId, messages, {});
1134
- ```
1135
-
1136
- **After:**
1137
- ```tsx
1138
- const { text } = await sendMessage(messages, { systemPrompt: '...' });
1139
- ```
1140
-
1141
- ## Roadmap
1142
-
1143
- | Feature | Status | Priority |
1144
- |---------|--------|----------|
1145
- | ✅ Streaming responses | Done | - |
1146
- | ✅ Prompt helpers (summarize, translate, etc.) | Done | - |
1147
- | ✅ Chat memory management | Done | - |
1148
- | ✅ Smart suggestions (suggest, smartReply, autocomplete) | Done | - |
1149
- | ✅ React Hooks (useChat, useCompletion, useOnDeviceAI) | Done | - |
1150
- | Web/generic fallback | Idea | Medium |
1151
- | Configurable hyperparameters (temperature, etc.) | Idea | Low |
124
+ ## Links
1152
125
 
1153
- Have a feature request? [Open an issue](https://github.com/saidkaban/expo-ai-kit/issues)!
126
+ - [Docs](https://expo-ai-kit.dev) · [npm](https://www.npmjs.com/package/expo-ai-kit) · [GitHub](https://github.com/saidkaban/expo-ai-kit) · [Issues](https://github.com/saidkaban/expo-ai-kit/issues)
127
+ - [Apple Foundation Models](https://developer.apple.com/documentation/foundationmodels) · [ML Kit GenAI](https://developers.google.com/ml-kit/genai) · [LiteRT-LM](https://ai.google.dev/edge/litert-lm)
1154
128
 
1155
129
  ## License
1156
130
 
1157
131
  MIT
1158
-
1159
- ## Contributing
1160
-
1161
- Contributions are welcome! Please refer to guidelines described in the [contributing guide](https://github.com/expo/expo#contributing).
1162
-
1163
- ## Links
1164
-
1165
- - [Documentation](https://expo-ai-kit.com)
1166
- - [npm package](https://www.npmjs.com/package/expo-ai-kit)
1167
- - [GitHub repository](https://github.com/saidkaban/expo-ai-kit)
1168
- - [Apple Foundation Models](https://developer.apple.com/documentation/foundationmodels)
1169
- - [Google ML Kit Prompt API](https://developers.google.com/ml-kit/genai)