expo-ai-kit 0.4.0 → 0.5.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.
Files changed (196) hide show
  1. package/README.md +28 -96
  2. package/android/src/main/java/expo/modules/aikit/ExpoAiKitModule.kt +26 -13
  3. package/android/src/main/java/expo/modules/aikit/GemmaInferenceClient.kt +47 -2
  4. package/build/ExpoAiKitModule.d.ts +12 -3
  5. package/build/ExpoAiKitModule.d.ts.map +1 -1
  6. package/build/ExpoAiKitModule.js.map +1 -1
  7. package/build/index.d.ts +31 -5
  8. package/build/index.d.ts.map +1 -1
  9. package/build/index.js +239 -34
  10. package/build/index.js.map +1 -1
  11. package/build/models.js +6 -6
  12. package/build/models.js.map +1 -1
  13. package/build/types.d.ts +66 -2
  14. package/build/types.d.ts.map +1 -1
  15. package/build/types.js.map +1 -1
  16. package/ios/ExpoAiKit.podspec +11 -5
  17. package/ios/ExpoAiKitModule.swift +255 -95
  18. package/ios/GemmaInferenceClient.swift +408 -0
  19. package/ios/Vendor/LiteRTLM/Benchmark.swift +83 -0
  20. package/ios/Vendor/LiteRTLM/Capabilities.swift +41 -0
  21. package/ios/Vendor/LiteRTLM/Config.swift +172 -0
  22. package/ios/Vendor/LiteRTLM/Conversation.swift +450 -0
  23. package/ios/Vendor/LiteRTLM/Engine.swift +208 -0
  24. package/ios/Vendor/LiteRTLM/ExperimentalFlags.swift +142 -0
  25. package/ios/Vendor/LiteRTLM/LICENSE +201 -0
  26. package/ios/Vendor/LiteRTLM/LiteRTLMError.swift +156 -0
  27. package/ios/Vendor/LiteRTLM/Message.swift +225 -0
  28. package/ios/Vendor/LiteRTLM/Tool.swift +291 -0
  29. package/ios/Vendor/LiteRTLM/ToolManager.swift +152 -0
  30. package/package.json +7 -3
  31. package/scripts/install-litertlm.sh +63 -0
  32. package/src/ExpoAiKitModule.ts +25 -3
  33. package/src/index.ts +287 -58
  34. package/src/models.ts +6 -6
  35. package/src/types.ts +72 -1
  36. package/android/build/.transforms/05637efea134638df3d3fc7b19d5dfdb/results.bin +0 -1
  37. package/android/build/.transforms/05637efea134638df3d3fc7b19d5dfdb/transformed/classes/classes_dex/classes.dex +0 -0
  38. package/android/build/.transforms/cd4ecc077e8795b855097bce5bf059b1/results.bin +0 -1
  39. package/android/build/.transforms/cd4ecc077e8795b855097bce5bf059b1/transformed/classes/classes_dex/classes.dex +0 -0
  40. package/android/build/generated/source/buildConfig/debug/expo/modules/aikit/BuildConfig.java +0 -10
  41. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +0 -7
  42. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +0 -18
  43. package/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +0 -6
  44. package/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +0 -1
  45. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  46. package/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
  47. package/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -0
  48. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +0 -1
  49. package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +0 -2
  50. package/android/build/intermediates/incremental/mergeDebugAssets/merger.xml +0 -2
  51. package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +0 -2
  52. package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +0 -2
  53. package/android/build/intermediates/java_res/debug/processDebugJavaRes/out/META-INF/expo-ai-kit_debug.kotlin_module +0 -0
  54. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/expo/modules/aikit/BuildConfig.class +0 -0
  55. package/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +0 -2
  56. package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +0 -7
  57. package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +0 -7
  58. package/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +0 -1
  59. package/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +0 -1
  60. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  61. package/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +0 -1
  62. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
  63. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
  64. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
  65. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len +0 -0
  66. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
  67. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
  68. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i.len +0 -0
  69. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
  70. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
  71. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
  72. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
  73. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
  74. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
  75. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i.len +0 -0
  76. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
  77. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
  78. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
  79. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
  80. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
  81. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
  82. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len +0 -0
  83. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
  84. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
  85. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
  86. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
  87. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
  88. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
  89. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len +0 -0
  90. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
  91. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
  92. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
  93. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
  94. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
  95. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
  96. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i.len +0 -0
  97. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
  98. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
  99. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
  100. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len +0 -0
  101. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
  102. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
  103. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len +0 -0
  104. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
  105. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream +0 -0
  106. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len +0 -0
  107. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len +0 -0
  108. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
  109. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i +0 -0
  110. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i.len +0 -0
  111. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
  112. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
  113. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len +0 -0
  114. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len +0 -0
  115. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
  116. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
  117. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i.len +0 -0
  118. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +0 -2
  119. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
  120. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
  121. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
  122. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len +0 -0
  123. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
  124. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
  125. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i.len +0 -0
  126. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
  127. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
  128. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
  129. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
  130. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
  131. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
  132. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len +0 -0
  133. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
  134. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
  135. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
  136. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
  137. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
  138. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
  139. package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i.len +0 -0
  140. package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
  141. package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
  142. package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
  143. package/android/build/outputs/logs/manifest-merger-debug-report.txt +0 -14
  144. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  145. package/android/build/tmp/kotlin-classes/debug/META-INF/expo-ai-kit_debug.kotlin_module +0 -0
  146. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$1$11$1.class +0 -0
  147. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$1$2$conversationPrompt$2.class +0 -0
  148. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$1$3$conversationPrompt$2.class +0 -0
  149. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$1$3$job$1$streamCallback$1.class +0 -0
  150. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$1$3$job$1.class +0 -0
  151. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$AsyncFunction$1.class +0 -0
  152. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$AsyncFunction$2.class +0 -0
  153. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$AsyncFunction$3.class +0 -0
  154. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$AsyncFunction$4.class +0 -0
  155. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$AsyncFunction$5.class +0 -0
  156. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$AsyncFunction$6.class +0 -0
  157. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$AsyncFunction$7.class +0 -0
  158. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$1.class +0 -0
  159. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$10.class +0 -0
  160. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$11.class +0 -0
  161. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$12.class +0 -0
  162. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$2.class +0 -0
  163. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$3.class +0 -0
  164. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$4.class +0 -0
  165. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$5.class +0 -0
  166. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$6.class +0 -0
  167. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$7.class +0 -0
  168. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$8.class +0 -0
  169. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Coroutine$9.class +0 -0
  170. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Function$1.class +0 -0
  171. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$Function$2.class +0 -0
  172. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$FunctionWithoutArgs$1.class +0 -0
  173. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$FunctionWithoutArgs$2.class +0 -0
  174. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$FunctionWithoutArgs$3.class +0 -0
  175. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule$definition$lambda$20$$inlined$FunctionWithoutArgs$4.class +0 -0
  176. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/ExpoAiKitModule.class +0 -0
  177. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$deleteModelFile$1.class +0 -0
  178. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$downloadModelFile$1.class +0 -0
  179. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$downloadModelFile$2.class +0 -0
  180. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$generateText$1.class +0 -0
  181. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$generateText$2$1$1$1.class +0 -0
  182. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$generateText$2$1.class +0 -0
  183. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$generateTextStream$1.class +0 -0
  184. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$generateTextStream$2$1$1$1.class +0 -0
  185. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$generateTextStream$2$1.class +0 -0
  186. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$loadModel$1.class +0 -0
  187. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$loadModel$2$1.class +0 -0
  188. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient$unloadModel$1.class +0 -0
  189. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/GemmaInferenceClient.class +0 -0
  190. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/PromptApiClient$generateText$2.class +0 -0
  191. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/PromptApiClient$generateTextStream$2$1.class +0 -0
  192. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/PromptApiClient$generateTextStream$2.class +0 -0
  193. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/PromptApiClient$isAvailable$1.class +0 -0
  194. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/PromptApiClient$isAvailableBlocking$1.class +0 -0
  195. package/android/build/tmp/kotlin-classes/debug/expo/modules/aikit/PromptApiClient.class +0 -0
  196. package/ios/.xcode.env +0 -11
package/README.md CHANGED
@@ -1,18 +1,13 @@
1
1
  # expo-ai-kit
2
2
 
3
- On-device AI for Expo & React Native. Run LLMs locally no API keys, no cloud, no cost.
3
+ On-device AI for Expo & React Native run LLMs locally, no API keys, no cloud, no cost.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/expo-ai-kit.svg)](https://www.npmjs.com/package/expo-ai-kit)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
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.
10
-
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
8
+ Runs **Apple Foundation Models** (iOS 26+), **ML Kit** (Android), and downloadable
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.
16
11
 
17
12
  ## Install
18
13
 
@@ -20,111 +15,48 @@ entirely on-device — chat, streaming, and downloadable models, all local.
20
15
  npx expo install expo-ai-kit
21
16
  ```
22
17
 
23
- Bare React Native projects: run `npx pod-install` afterwards. Android needs
24
- `minSdkVersion 26` — set it via `expo-build-properties` in `app.json`.
18
+ Bare RN: run `npx pod-install`. Android needs `minSdkVersion 26`. Requires Expo SDK 54+.
25
19
 
26
20
  ## Quick start
27
21
 
28
22
  ```tsx
29
- import { isAvailable, sendMessage } from 'expo-ai-kit';
23
+ import { isAvailable, sendMessage, streamMessage } from 'expo-ai-kit';
30
24
 
31
25
  if (await isAvailable()) {
32
- const { text } = await sendMessage([
33
- { role: 'user', content: 'What is the capital of France?' },
34
- ]);
35
- console.log(text); // "Paris"
36
- }
37
- ```
38
-
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.
41
-
42
- ```tsx
43
- const { text } = await sendMessage(
44
- [{ role: 'user', content: 'Tell me a joke' }],
45
- { systemPrompt: 'You are a stand-up comedian.' }
46
- );
47
- ```
26
+ const { text } = await sendMessage([{ role: 'user', content: 'Capital of France?' }]);
48
27
 
49
- ## Streaming
50
-
51
- ```tsx
52
- import { streamMessage } from 'expo-ai-kit';
53
-
54
- const { promise, stop } = streamMessage(
55
- [{ role: 'user', content: 'Write a short story' }],
56
- (event) => setText(event.accumulatedText), // fired per token
57
- );
58
-
59
- await promise; // resolves with the final { text }
60
- // stop(); // cancel at any point
28
+ const { promise, stop } = streamMessage(
29
+ [{ role: 'user', content: 'Write a short story' }],
30
+ (e) => setText(e.accumulatedText),
31
+ );
32
+ await promise; // stop() to cancel
33
+ }
61
34
  ```
62
35
 
63
- ## Downloadable models (Gemma 4)
36
+ `messages` is `{ role: 'system' | 'user' | 'assistant'; content: string }[]`. On-device
37
+ models are stateless — pass the full history each call.
64
38
 
65
- On Android, download and run Gemma 4 models on top of the built-in OS model.
39
+ ## Downloadable Gemma 4
66
40
 
67
41
  ```tsx
68
- import {
69
- getDownloadableModels, downloadModel, setModel, sendMessage,
70
- } from 'expo-ai-kit';
71
-
72
- // List models with their on-device status
73
- const models = await getDownloadableModels();
42
+ import { getRecommendedModel, downloadModel, setModel } from 'expo-ai-kit';
74
43
 
75
- // Download with progress, then activate
76
- await downloadModel('gemma-e2b', {
77
- onProgress: (p) => console.log(`${Math.round(p * 100)}%`),
78
- });
79
- await setModel('gemma-e2b', { backend: 'auto' }); // 'auto' | 'gpu' | 'cpu'
80
-
81
- // sendMessage / streamMessage now use the active model
82
- const { text } = await sendMessage([{ role: 'user', content: 'Hi!' }]);
44
+ const best = await getRecommendedModel(); // E4B on high-RAM phones, else E2B
45
+ if (best) {
46
+ await downloadModel(best.id, { onProgress: (p) => console.log(p) });
47
+ await setModel(best.id, { generation: { temperature: 0.7 } });
48
+ // sendMessage / streamMessage now use it; unloadModel() reverts to the OS model
49
+ }
83
50
  ```
84
51
 
85
- `unloadModel()` frees memory and reverts to the OS model; `deleteModel(id)` removes the file.
86
-
87
- | Model | Params | Size | Platforms |
88
- |-------|--------|------|-----------|
89
- | `gemma-e2b` | 2.3B | ~2.6 GB | Android |
90
- | `gemma-e4b` | 4.5B | ~3.7 GB | Android |
91
-
92
- > iOS downloadable models are planned, pending LiteRT-LM Swift APIs from Google.
93
-
94
- ## Platform support
95
-
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` |
101
-
102
- Requires Expo SDK 54+.
103
-
104
52
  ## API
105
53
 
106
- **Inference**
107
-
108
- - `isAvailable()` `Promise<boolean>`
109
- - `sendMessage(messages, options?)` → `Promise<{ text }>`
110
- - `streamMessage(messages, onToken, options?)` → `{ promise, stop }`
111
-
112
- **Models**
113
-
114
- - `getBuiltInModels()` → `Promise<BuiltInModel[]>`
115
- - `getDownloadableModels()` → `Promise<DownloadableModel[]>`
116
- - `downloadModel(id, { onProgress? })` / `deleteModel(id)`
117
- - `setModel(id, { backend? })` / `unloadModel()` / `getActiveModel()`
118
-
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.
123
-
124
- ## Links
54
+ Inference: `isAvailable`, `sendMessage`, `streamMessage`.
55
+ Models: `getBuiltInModels`, `getDownloadableModels`, `getRecommendedModel`,
56
+ `downloadModel`, `cancelDownload`, `deleteModel`, `setModel`, `unloadModel`, `getActiveModel`.
125
57
 
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)
58
+ Failures throw `ModelError` with a typed `.code`. Full TypeScript definitions ship with
59
+ the package see [the docs](https://expo-ai-kit.dev) for the complete reference.
128
60
 
129
61
  ## License
130
62
 
@@ -40,7 +40,9 @@ class ExpoAiKitModule : Module() {
40
40
  promptClient.isAvailableBlocking()
41
41
  }
42
42
 
43
- AsyncFunction("sendMessage") Coroutine { messages: List<Map<String, Any>>, fallbackSystemPrompt: String ->
43
+ // sessionId is accepted for API parity with iOS. Non-streaming generation on
44
+ // Android isn't separately cancellable (best-effort), so the id is unused here.
45
+ AsyncFunction("sendMessage") Coroutine { messages: List<Map<String, Any>>, fallbackSystemPrompt: String, sessionId: String ->
44
46
  // Extract system prompt from messages, or use fallback
45
47
  val systemPrompt = messages
46
48
  .firstOrNull { it["role"] == "system" }
@@ -144,11 +146,12 @@ class ExpoAiKitModule : Module() {
144
146
  }
145
147
 
146
148
  Function("getDownloadableModelStatus") { modelId: String ->
147
- // Status reflects runtime state: "ready" if loaded in memory,
148
- // "not-downloaded" otherwise (even if file is on disk -- setModel
149
- // is the gatekeeper that transitions through loading -> ready).
149
+ // "ready" if loaded in memory; "downloaded" if the file is on disk but not
150
+ // loaded (survives restarts -- use it to skip a redundant re-download);
151
+ // "not-downloaded" if no file is present.
150
152
  when {
151
153
  gemmaClient.getLoadedModelId() == modelId && gemmaClient.isModelLoaded() -> "ready"
154
+ gemmaClient.isModelFileDownloaded(modelId) -> "downloaded"
152
155
  else -> "not-downloaded"
153
156
  }
154
157
  }
@@ -168,7 +171,7 @@ class ExpoAiKitModule : Module() {
168
171
  // Model selection & memory management
169
172
  // ==================================================================
170
173
 
171
- AsyncFunction("setModel") Coroutine { modelId: String, minRamBytes: Long, backend: String ->
174
+ AsyncFunction("setModel") Coroutine { modelId: String, minRamBytes: Long, backend: String, generation: Map<String, Double> ->
172
175
  if (modelId == "mlkit") {
173
176
  // Switch to built-in: unload any Gemma model
174
177
  if (gemmaClient.isModelLoaded()) {
@@ -177,7 +180,7 @@ class ExpoAiKitModule : Module() {
177
180
  if (previousId != "mlkit") {
178
181
  sendEvent("onModelStateChange", mapOf(
179
182
  "modelId" to previousId,
180
- "status" to "not-downloaded"
183
+ "status" to if (gemmaClient.isModelFileDownloaded(previousId)) "downloaded" else "not-downloaded"
181
184
  ))
182
185
  }
183
186
  }
@@ -198,7 +201,12 @@ class ExpoAiKitModule : Module() {
198
201
 
199
202
  try {
200
203
  val modelPath = gemmaClient.getModelFilePath(modelId)
201
- gemmaClient.loadModel(modelId, modelPath, minRamBytes, backend)
204
+ gemmaClient.loadModel(
205
+ modelId, modelPath, minRamBytes, backend,
206
+ temperature = generation["temperature"],
207
+ topK = generation["topK"]?.toInt(),
208
+ topP = generation["topP"]
209
+ )
202
210
  activeModelId = modelId
203
211
 
204
212
  // Emit ready state
@@ -207,10 +215,10 @@ class ExpoAiKitModule : Module() {
207
215
  "status" to "ready"
208
216
  ))
209
217
  } catch (e: Exception) {
210
- // Emit failure -- revert status
218
+ // Load failed, but the file is still on disk -> "downloaded", not "not-downloaded".
211
219
  sendEvent("onModelStateChange", mapOf(
212
220
  "modelId" to modelId,
213
- "status" to "not-downloaded"
221
+ "status" to if (gemmaClient.isModelFileDownloaded(modelId)) "downloaded" else "not-downloaded"
214
222
  ))
215
223
  throw e
216
224
  }
@@ -227,7 +235,7 @@ class ExpoAiKitModule : Module() {
227
235
  activeModelId = "mlkit"
228
236
  sendEvent("onModelStateChange", mapOf(
229
237
  "modelId" to previousId,
230
- "status" to "not-downloaded"
238
+ "status" to if (gemmaClient.isModelFileDownloaded(previousId)) "downloaded" else "not-downloaded"
231
239
  ))
232
240
  }
233
241
  }
@@ -250,20 +258,25 @@ class ExpoAiKitModule : Module() {
250
258
  ))
251
259
  }
252
260
 
253
- // Download complete -- file is on disk but not loaded
261
+ // Download succeeded: file is on disk, awaiting setModel() to load it.
254
262
  sendEvent("onModelStateChange", mapOf(
255
263
  "modelId" to modelId,
256
- "status" to "not-downloaded"
264
+ "status" to "downloaded"
257
265
  ))
258
266
  } catch (e: Exception) {
267
+ // On failure, report whatever is actually on disk (a prior good copy may remain).
259
268
  sendEvent("onModelStateChange", mapOf(
260
269
  "modelId" to modelId,
261
- "status" to "not-downloaded"
270
+ "status" to if (gemmaClient.isModelFileDownloaded(modelId)) "downloaded" else "not-downloaded"
262
271
  ))
263
272
  throw e
264
273
  }
265
274
  }
266
275
 
276
+ AsyncFunction("cancelDownload") Coroutine { modelId: String ->
277
+ gemmaClient.cancelDownload(modelId)
278
+ }
279
+
267
280
  AsyncFunction("deleteModel") Coroutine { modelId: String ->
268
281
  // If this model is active, switch back to mlkit first
269
282
  if (activeModelId == modelId) {
@@ -10,6 +10,7 @@ import com.google.ai.edge.litertlm.Backend
10
10
  import com.google.ai.edge.litertlm.Message
11
11
  import com.google.ai.edge.litertlm.MessageCallback
12
12
  import com.google.ai.edge.litertlm.Contents
13
+ import com.google.ai.edge.litertlm.SamplerConfig
13
14
  import kotlinx.coroutines.Dispatchers
14
15
  import kotlinx.coroutines.sync.Mutex
15
16
  import kotlinx.coroutines.sync.withLock
@@ -45,6 +46,9 @@ class GemmaInferenceClient(private val context: Context) {
45
46
  @Volatile
46
47
  private var isDownloading = false
47
48
 
49
+ @Volatile
50
+ private var cancelDownloadRequested = false
51
+
48
52
  // -------------------------------------------------------------------------
49
53
  // Model lifecycle
50
54
  // -------------------------------------------------------------------------
@@ -54,7 +58,15 @@ class GemmaInferenceClient(private val context: Context) {
54
58
  * Unloads any previously loaded model first.
55
59
  * Caller is responsible for emitting onModelStateChange events.
56
60
  */
57
- suspend fun loadModel(modelId: String, modelPath: String, minRamBytes: Long = 0, backend: String = "auto") = mutex.withLock {
61
+ suspend fun loadModel(
62
+ modelId: String,
63
+ modelPath: String,
64
+ minRamBytes: Long = 0,
65
+ backend: String = "auto",
66
+ temperature: Double? = null,
67
+ topK: Int? = null,
68
+ topP: Double? = null
69
+ ) = mutex.withLock {
58
70
  // Unload previous model if different
59
71
  if (loadedModelId != null && loadedModelId != modelId) {
60
72
  conversation?.close()
@@ -117,7 +129,21 @@ class GemmaInferenceClient(private val context: Context) {
117
129
  }
118
130
  }
119
131
 
120
- val newConversation = newEngine.createConversation(ConversationConfig())
132
+ // Sampling knobs are fixed at conversation creation by LiteRT-LM. If any
133
+ // is provided, build a SamplerConfig (filling unspecified values with
134
+ // Gemma-typical defaults); otherwise use the engine/model defaults.
135
+ val convConfig = if (temperature != null || topK != null || topP != null) {
136
+ ConversationConfig(
137
+ samplerConfig = SamplerConfig(
138
+ topK = topK ?: 64,
139
+ topP = topP ?: 0.95,
140
+ temperature = temperature ?: 1.0
141
+ )
142
+ )
143
+ } else {
144
+ ConversationConfig()
145
+ }
146
+ val newConversation = newEngine.createConversation(convConfig)
121
147
 
122
148
  engine = newEngine
123
149
  conversation = newConversation
@@ -191,6 +217,9 @@ class GemmaInferenceClient(private val context: Context) {
191
217
  )
192
218
  }
193
219
  }
220
+ } catch (e: kotlinx.coroutines.CancellationException) {
221
+ // Cooperative cancellation — propagate, don't mask as an inference failure.
222
+ throw e
194
223
  } catch (e: OutOfMemoryError) {
195
224
  throw RuntimeException("INFERENCE_OOM:${loadedModelId ?: "unknown"}:Out of memory during inference")
196
225
  } catch (e: Exception) {
@@ -260,6 +289,9 @@ class GemmaInferenceClient(private val context: Context) {
260
289
  )
261
290
  }
262
291
  }
292
+ } catch (e: kotlinx.coroutines.CancellationException) {
293
+ // Cooperative cancellation — propagate, don't mask as an inference failure.
294
+ throw e
263
295
  } catch (e: OutOfMemoryError) {
264
296
  throw RuntimeException("INFERENCE_OOM:${loadedModelId ?: "unknown"}:Out of memory during inference")
265
297
  } catch (e: Exception) {
@@ -288,6 +320,7 @@ class GemmaInferenceClient(private val context: Context) {
288
320
  throw RuntimeException("DOWNLOAD_FAILED:$modelId:Download already in progress")
289
321
  }
290
322
  isDownloading = true
323
+ cancelDownloadRequested = false
291
324
 
292
325
  try {
293
326
  withContext(Dispatchers.IO) {
@@ -308,6 +341,9 @@ class GemmaInferenceClient(private val context: Context) {
308
341
  val buffer = ByteArray(8192)
309
342
  var read: Int
310
343
  while (input.read(buffer).also { read = it } != -1) {
344
+ if (cancelDownloadRequested) {
345
+ throw RuntimeException("DOWNLOAD_CANCELLED:$modelId:Download cancelled")
346
+ }
311
347
  output.write(buffer, 0, read)
312
348
  bytesRead += read
313
349
  if (totalBytes > 0) {
@@ -336,6 +372,7 @@ class GemmaInferenceClient(private val context: Context) {
336
372
  tempFile.delete()
337
373
  when {
338
374
  e is RuntimeException && e.message?.startsWith("DOWNLOAD_CORRUPT") == true -> throw e
375
+ e is RuntimeException && e.message?.startsWith("DOWNLOAD_CANCELLED") == true -> throw e
339
376
  context.filesDir.freeSpace < 100_000_000 ->
340
377
  throw RuntimeException("DOWNLOAD_STORAGE_FULL:$modelId:Insufficient disk space")
341
378
  else ->
@@ -372,6 +409,14 @@ class GemmaInferenceClient(private val context: Context) {
372
409
  }
373
410
  }
374
411
 
412
+ /**
413
+ * Request cancellation of the in-flight download, if any. The download loop
414
+ * checks this flag and throws DOWNLOAD_CANCELLED. No-op if nothing is downloading.
415
+ */
416
+ fun cancelDownload(modelId: String) {
417
+ cancelDownloadRequested = true
418
+ }
419
+
375
420
  /**
376
421
  * Check if a model file exists on disk.
377
422
  */
@@ -5,18 +5,27 @@ export type ExpoAiKitModuleEvents = {
5
5
  onDownloadProgress: (event: ModelDownloadProgressEvent) => void;
6
6
  onModelStateChange: (event: ModelStateChangeEvent) => void;
7
7
  };
8
+ /** Generation parameters passed to native. All fields optional; -1 / absent means "unset". */
9
+ export type NativeGenerationConfig = {
10
+ temperature?: number;
11
+ topK?: number;
12
+ topP?: number;
13
+ seed?: number;
14
+ maxTokens?: number;
15
+ };
8
16
  export interface ExpoAiKitNativeModule {
9
17
  isAvailable(): boolean;
10
- sendMessage(messages: LLMMessage[], systemPrompt: string): Promise<LLMResponse>;
18
+ sendMessage(messages: LLMMessage[], systemPrompt: string, sessionId: string): Promise<LLMResponse>;
11
19
  startStreaming(messages: LLMMessage[], systemPrompt: string, sessionId: string): Promise<void>;
12
20
  stopStreaming(sessionId: string): Promise<void>;
13
21
  getBuiltInModels(): BuiltInModel[];
14
- getDownloadableModelStatus(modelId: string): DownloadableModelStatus;
22
+ getDownloadableModelStatus(modelId: string): Promise<DownloadableModelStatus>;
15
23
  getDeviceRamBytes(): number;
16
- setModel(modelId: string, minRamBytes: number, backend: string): Promise<void>;
24
+ setModel(modelId: string, minRamBytes: number, backend: string, generation: NativeGenerationConfig): Promise<void>;
17
25
  getActiveModel(): string;
18
26
  unloadModel(): Promise<void>;
19
27
  downloadModel(modelId: string, url: string, sha256: string): Promise<void>;
28
+ cancelDownload(modelId: string): Promise<void>;
20
29
  deleteModel(modelId: string): Promise<void>;
21
30
  addListener<K extends keyof ExpoAiKitModuleEvents>(eventName: K, listener: ExpoAiKitModuleEvents[K]): EventSubscription;
22
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoAiKitModule.d.ts","sourceRoot":"","sources":["../src/ExpoAiKitModule.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EACL,YAAY,EACZ,uBAAuB,EACvB,UAAU,EACV,WAAW,EACX,cAAc,EACd,0BAA0B,EAC1B,qBAAqB,EACtB,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,qBAAqB,GAAG;IAClC,aAAa,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC/C,kBAAkB,EAAE,CAAC,KAAK,EAAE,0BAA0B,KAAK,IAAI,CAAC;IAChE,kBAAkB,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAC5D,CAAC;AAEF,MAAM,WAAW,qBAAqB;IAEpC,WAAW,IAAI,OAAO,CAAC;IACvB,WAAW,CACT,QAAQ,EAAE,UAAU,EAAE,EACtB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,WAAW,CAAC,CAAC;IACxB,cAAc,CACZ,QAAQ,EAAE,UAAU,EAAE,EACtB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGhD,gBAAgB,IAAI,YAAY,EAAE,CAAC;IACnC,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,uBAAuB,CAAC;IACrE,iBAAiB,IAAI,MAAM,CAAC;IAK5B,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,cAAc,IAAI,MAAM,CAAC;IAGzB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAG7B,aAAa,CACX,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAG5C,WAAW,CAAC,CAAC,SAAS,MAAM,qBAAqB,EAC/C,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,qBAAqB,CAAC,CAAC,CAAC,GACjC,iBAAiB,CAAC;CACtB;AAED,QAAA,MAAM,eAAe,uBACoC,CAAC;AAE1D,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"ExpoAiKitModule.d.ts","sourceRoot":"","sources":["../src/ExpoAiKitModule.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EACL,YAAY,EACZ,uBAAuB,EACvB,UAAU,EACV,WAAW,EACX,cAAc,EACd,0BAA0B,EAC1B,qBAAqB,EACtB,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,qBAAqB,GAAG;IAClC,aAAa,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC/C,kBAAkB,EAAE,CAAC,KAAK,EAAE,0BAA0B,KAAK,IAAI,CAAC;IAChE,kBAAkB,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAC5D,CAAC;AAEF,8FAA8F;AAC9F,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,WAAW,qBAAqB;IAEpC,WAAW,IAAI,OAAO,CAAC;IAEvB,WAAW,CACT,QAAQ,EAAE,UAAU,EAAE,EACtB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC,CAAC;IACxB,cAAc,CACZ,QAAQ,EAAE,UAAU,EAAE,EACtB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGhD,gBAAgB,IAAI,YAAY,EAAE,CAAC;IAGnC,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC9E,iBAAiB,IAAI,MAAM,CAAC;IAM5B,QAAQ,CACN,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,sBAAsB,GACjC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,cAAc,IAAI,MAAM,CAAC;IAGzB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAG7B,aAAa,CACX,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAG5C,WAAW,CAAC,CAAC,SAAS,MAAM,qBAAqB,EAC/C,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,qBAAqB,CAAC,CAAC,CAAC,GACjC,iBAAiB,CAAC;CACtB;AAED,QAAA,MAAM,eAAe,uBACoC,CAAC;AAE1D,eAAe,eAAe,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoAiKitModule.js","sourceRoot":"","sources":["../src/ExpoAiKitModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AA6DxD,MAAM,eAAe,GACnB,mBAAmB,CAAwB,WAAW,CAAC,CAAC;AAE1D,eAAe,eAAe,CAAC","sourcesContent":["import { requireNativeModule } from 'expo-modules-core';\nimport type { EventSubscription } from 'expo-modules-core';\nimport {\n BuiltInModel,\n DownloadableModelStatus,\n LLMMessage,\n LLMResponse,\n LLMStreamEvent,\n ModelDownloadProgressEvent,\n ModelStateChangeEvent,\n} from './types';\n\nexport type ExpoAiKitModuleEvents = {\n onStreamToken: (event: LLMStreamEvent) => void;\n onDownloadProgress: (event: ModelDownloadProgressEvent) => void;\n onModelStateChange: (event: ModelStateChangeEvent) => void;\n};\n\nexport interface ExpoAiKitNativeModule {\n // Existing inference API\n isAvailable(): boolean;\n sendMessage(\n messages: LLMMessage[],\n systemPrompt: string\n ): Promise<LLMResponse>;\n startStreaming(\n messages: LLMMessage[],\n systemPrompt: string,\n sessionId: string\n ): Promise<void>;\n stopStreaming(sessionId: string): Promise<void>;\n\n // Model discovery\n getBuiltInModels(): BuiltInModel[];\n getDownloadableModelStatus(modelId: string): DownloadableModelStatus;\n getDeviceRamBytes(): number;\n\n // Model selection & memory management\n // setModel is async: switching to a downloadable model loads it into memory.\n // Auto-unloads the previous downloadable model (only one loaded at a time).\n setModel(modelId: string, minRamBytes: number, backend: string): Promise<void>;\n getActiveModel(): string;\n // Explicitly free memory from the loaded downloadable model.\n // Reverts to the platform built-in model.\n unloadModel(): Promise<void>;\n\n // Model lifecycle (downloadable models only)\n downloadModel(\n modelId: string,\n url: string,\n sha256: string\n ): Promise<void>;\n deleteModel(modelId: string): Promise<void>;\n\n // Event subscription\n addListener<K extends keyof ExpoAiKitModuleEvents>(\n eventName: K,\n listener: ExpoAiKitModuleEvents[K]\n ): EventSubscription;\n}\n\nconst ExpoAiKitModule =\n requireNativeModule<ExpoAiKitNativeModule>('ExpoAiKit');\n\nexport default ExpoAiKitModule;\n"]}
1
+ {"version":3,"file":"ExpoAiKitModule.js","sourceRoot":"","sources":["../src/ExpoAiKitModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAmFxD,MAAM,eAAe,GACnB,mBAAmB,CAAwB,WAAW,CAAC,CAAC;AAE1D,eAAe,eAAe,CAAC","sourcesContent":["import { requireNativeModule } from 'expo-modules-core';\nimport type { EventSubscription } from 'expo-modules-core';\nimport {\n BuiltInModel,\n DownloadableModelStatus,\n LLMMessage,\n LLMResponse,\n LLMStreamEvent,\n ModelDownloadProgressEvent,\n ModelStateChangeEvent,\n} from './types';\n\nexport type ExpoAiKitModuleEvents = {\n onStreamToken: (event: LLMStreamEvent) => void;\n onDownloadProgress: (event: ModelDownloadProgressEvent) => void;\n onModelStateChange: (event: ModelStateChangeEvent) => void;\n};\n\n/** Generation parameters passed to native. All fields optional; -1 / absent means \"unset\". */\nexport type NativeGenerationConfig = {\n temperature?: number;\n topK?: number;\n topP?: number;\n seed?: number;\n maxTokens?: number;\n};\n\nexport interface ExpoAiKitNativeModule {\n // Existing inference API\n isAvailable(): boolean;\n // sessionId lets stopStreaming() cancel an in-flight (non-streaming) generation too.\n sendMessage(\n messages: LLMMessage[],\n systemPrompt: string,\n sessionId: string\n ): Promise<LLMResponse>;\n startStreaming(\n messages: LLMMessage[],\n systemPrompt: string,\n sessionId: string\n ): Promise<void>;\n // Cancels either a streaming session or a sendMessage session by id.\n stopStreaming(sessionId: string): Promise<void>;\n\n // Model discovery\n getBuiltInModels(): BuiltInModel[];\n // Async: iOS reads actor-isolated state (so it bridges as a Promise); Android\n // returns synchronously. Callers must await — see getDownloadableModels.\n getDownloadableModelStatus(modelId: string): Promise<DownloadableModelStatus>;\n getDeviceRamBytes(): number;\n\n // Model selection & memory management\n // setModel is async: switching to a downloadable model loads it into memory.\n // Auto-unloads the previous downloadable model (only one loaded at a time).\n // `generation` carries best-effort sampling defaults for the session.\n setModel(\n modelId: string,\n minRamBytes: number,\n backend: string,\n generation: NativeGenerationConfig\n ): Promise<void>;\n getActiveModel(): string;\n // Explicitly free memory from the loaded downloadable model.\n // Reverts to the platform built-in model.\n unloadModel(): Promise<void>;\n\n // Model lifecycle (downloadable models only)\n downloadModel(\n modelId: string,\n url: string,\n sha256: string\n ): Promise<void>;\n // Cancels an in-flight download for the given model (no-op if none).\n cancelDownload(modelId: string): Promise<void>;\n deleteModel(modelId: string): Promise<void>;\n\n // Event subscription\n addListener<K extends keyof ExpoAiKitModuleEvents>(\n eventName: K,\n listener: ExpoAiKitModuleEvents[K]\n ): EventSubscription;\n}\n\nconst ExpoAiKitModule =\n requireNativeModule<ExpoAiKitNativeModule>('ExpoAiKit');\n\nexport default ExpoAiKitModule;\n"]}
package/build/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { LLMMessage, LLMSendOptions, LLMResponse, LLMStreamOptions, LLMStreamCallback, BuiltInModel, DownloadableModel, SetModelOptions } from './types';
1
+ import { LLMMessage, LLMSendOptions, LLMResponse, LLMStreamOptions, LLMStreamCallback, LLMStreamHandle, BuiltInModel, DownloadableModel, SetModelOptions } from './types';
2
2
  export * from './types';
3
3
  export * from './models';
4
4
  /**
@@ -75,10 +75,7 @@ export declare function sendMessage(messages: LLMMessage[], options?: LLMSendOpt
75
75
  * setTimeout(() => stop(), 5000);
76
76
  * ```
77
77
  */
78
- export declare function streamMessage(messages: LLMMessage[], onToken: LLMStreamCallback, options?: LLMStreamOptions): {
79
- promise: Promise<LLMResponse>;
80
- stop: () => void;
81
- };
78
+ export declare function streamMessage(messages: LLMMessage[], onToken: LLMStreamCallback, options?: LLMStreamOptions): LLMStreamHandle;
82
79
  /**
83
80
  * Get all built-in models available on the current platform.
84
81
  *
@@ -97,6 +94,26 @@ export declare function getBuiltInModels(): Promise<BuiltInModel[]>;
97
94
  * @returns Array of downloadable models with their current status
98
95
  */
99
96
  export declare function getDownloadableModels(): Promise<DownloadableModel[]>;
97
+ /**
98
+ * Pick the best downloadable model the current device can run.
99
+ *
100
+ * Returns the most capable model (largest, by RAM requirement) whose
101
+ * `meetsRequirements` is true — e.g. Gemma 4 E4B on high-spec phones, falling
102
+ * back to E2B on more constrained ones — or `null` if the device can't run any.
103
+ *
104
+ * This is a convenience over {@link getDownloadableModels}; the caller still
105
+ * downloads + activates explicitly. Pass `platform` is implicit (current OS).
106
+ *
107
+ * @example
108
+ * ```ts
109
+ * const best = await getRecommendedModel();
110
+ * if (best) {
111
+ * await downloadModel(best.id, { onProgress });
112
+ * await setModel(best.id);
113
+ * }
114
+ * ```
115
+ */
116
+ export declare function getRecommendedModel(): Promise<DownloadableModel | null>;
100
117
  /**
101
118
  * Download a model to the device.
102
119
  *
@@ -115,6 +132,15 @@ export declare function getDownloadableModels(): Promise<DownloadableModel[]>;
115
132
  export declare function downloadModel(modelId: string, options?: {
116
133
  onProgress?: (progress: number) => void;
117
134
  }): Promise<void>;
135
+ /**
136
+ * Cancel an in-flight download for a model.
137
+ *
138
+ * The in-progress {@link downloadModel} promise rejects with a
139
+ * DOWNLOAD_CANCELLED {@link ModelError}. No-op if the model isn't downloading.
140
+ *
141
+ * @param modelId - ID of the model whose download should be cancelled
142
+ */
143
+ export declare function cancelDownload(modelId: string): Promise<void>;
118
144
  /**
119
145
  * Delete a downloaded model from the device.
120
146
  *
@@ -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,YAAY,EACZ,iBAAiB,EAEjB,eAAe,EAChB,MAAM,SAAS,CAAC;AAGjB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AAczB;;;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,CAgBtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,UAAU,EAAE,EACtB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,CAAC,EAAE,gBAAgB,GACzB;IAAE,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,IAAI,CAAA;CAAE,CAiErD;AAMD;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAKhE;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA6B1E;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,CAiDf;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,CAKxF;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAEjD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,UAAU,EACV,cAAc,EACd,WAAW,EACX,gBAAgB,EAEhB,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,iBAAiB,EAIjB,eAAe,EAChB,MAAM,SAAS,CAAC;AAGjB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AAuHzB;;;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;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"}