@runanywhere/llamacpp 0.18.0 → 0.19.13

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 (116) hide show
  1. package/README.md +85 -413
  2. package/RunAnywhereLlama.podspec +27 -13
  3. package/android/CMakeLists.txt +37 -20
  4. package/android/build.gradle +83 -8
  5. package/cpp/HybridRunAnywhereLlama.cpp +26 -269
  6. package/cpp/HybridRunAnywhereLlama.hpp +2 -58
  7. package/ios/{Frameworks → Binaries}/RABackendLLAMACPP.xcframework/Info.plist +8 -9
  8. package/ios/{Frameworks/RABackendLLAMACPP.xcframework/ios-arm64/RABackendLLAMACPP.framework/RABackendLLAMACPP → Binaries/RABackendLLAMACPP.xcframework/ios-arm64/librac_backend_llamacpp.a} +0 -0
  9. package/ios/{Frameworks/RABackendLLAMACPP.xcframework/ios-arm64_x86_64-simulator/RABackendLLAMACPP.framework/RABackendLLAMACPP → Binaries/RABackendLLAMACPP.xcframework/ios-arm64-simulator/librac_backend_llamacpp.a} +0 -0
  10. package/nitrogen/generated/android/kotlin/com/margelo/nitro/runanywhere/llama/runanywherellamaOnLoad.kt +1 -1
  11. package/nitrogen/generated/android/runanywherellama+autolinking.cmake +2 -2
  12. package/nitrogen/generated/android/runanywherellama+autolinking.gradle +1 -1
  13. package/nitrogen/generated/android/runanywherellamaOnLoad.cpp +23 -18
  14. package/nitrogen/generated/android/runanywherellamaOnLoad.hpp +14 -5
  15. package/nitrogen/generated/ios/RunAnywhereLlama+autolinking.rb +4 -2
  16. package/nitrogen/generated/ios/RunAnywhereLlama-Swift-Cxx-Bridge.cpp +2 -2
  17. package/nitrogen/generated/ios/RunAnywhereLlama-Swift-Cxx-Bridge.hpp +2 -2
  18. package/nitrogen/generated/ios/RunAnywhereLlama-Swift-Cxx-Umbrella.hpp +1 -1
  19. package/nitrogen/generated/ios/RunAnywhereLlamaAutolinking.mm +1 -1
  20. package/nitrogen/generated/ios/RunAnywhereLlamaAutolinking.swift +6 -2
  21. package/nitrogen/generated/shared/c++/HybridRunAnywhereLlamaSpec.cpp +1 -11
  22. package/nitrogen/generated/shared/c++/HybridRunAnywhereLlamaSpec.hpp +2 -15
  23. package/package.json +13 -10
  24. package/react-native.config.js +1 -3
  25. package/src/LlamaCPP.ts +32 -160
  26. package/src/LlamaCppProvider.ts +32 -36
  27. package/src/index.ts +18 -23
  28. package/src/native/NativeRunAnywhereLlama.ts +19 -5
  29. package/src/specs/RunAnywhereLlama.nitro.ts +17 -126
  30. package/android/src/main/AndroidManifest.xml +0 -3
  31. package/android/src/main/cpp/cpp-adapter.cpp +0 -14
  32. package/android/src/main/include/rac/backends/rac_llm_llamacpp.h +0 -218
  33. package/android/src/main/include/rac/backends/rac_stt_onnx.h +0 -99
  34. package/android/src/main/include/rac/backends/rac_stt_whispercpp.h +0 -153
  35. package/android/src/main/include/rac/backends/rac_tts_onnx.h +0 -71
  36. package/android/src/main/include/rac/backends/rac_vad_onnx.h +0 -84
  37. package/android/src/main/include/rac/core/capabilities/rac_lifecycle.h +0 -290
  38. package/android/src/main/include/rac/core/rac_analytics_events.h +0 -610
  39. package/android/src/main/include/rac/core/rac_audio_utils.h +0 -88
  40. package/android/src/main/include/rac/core/rac_component_types.h +0 -160
  41. package/android/src/main/include/rac/core/rac_core.h +0 -331
  42. package/android/src/main/include/rac/core/rac_error.h +0 -469
  43. package/android/src/main/include/rac/core/rac_events.h +0 -334
  44. package/android/src/main/include/rac/core/rac_logger.h +0 -416
  45. package/android/src/main/include/rac/core/rac_platform_adapter.h +0 -340
  46. package/android/src/main/include/rac/core/rac_sdk_state.h +0 -292
  47. package/android/src/main/include/rac/core/rac_structured_error.h +0 -594
  48. package/android/src/main/include/rac/core/rac_types.h +0 -264
  49. package/android/src/main/include/rac/features/llm/rac_llm.h +0 -17
  50. package/android/src/main/include/rac/features/llm/rac_llm_analytics.h +0 -188
  51. package/android/src/main/include/rac/features/llm/rac_llm_component.h +0 -228
  52. package/android/src/main/include/rac/features/llm/rac_llm_events.h +0 -215
  53. package/android/src/main/include/rac/features/llm/rac_llm_metrics.h +0 -402
  54. package/android/src/main/include/rac/features/llm/rac_llm_service.h +0 -163
  55. package/android/src/main/include/rac/features/llm/rac_llm_structured_output.h +0 -141
  56. package/android/src/main/include/rac/features/llm/rac_llm_types.h +0 -384
  57. package/android/src/main/include/rac/features/platform/rac_llm_platform.h +0 -204
  58. package/android/src/main/include/rac/features/platform/rac_tts_platform.h +0 -197
  59. package/android/src/main/include/rac/features/stt/rac_stt.h +0 -17
  60. package/android/src/main/include/rac/features/stt/rac_stt_analytics.h +0 -204
  61. package/android/src/main/include/rac/features/stt/rac_stt_component.h +0 -162
  62. package/android/src/main/include/rac/features/stt/rac_stt_events.h +0 -62
  63. package/android/src/main/include/rac/features/stt/rac_stt_service.h +0 -154
  64. package/android/src/main/include/rac/features/stt/rac_stt_types.h +0 -389
  65. package/android/src/main/include/rac/features/tts/rac_tts.h +0 -17
  66. package/android/src/main/include/rac/features/tts/rac_tts_analytics.h +0 -181
  67. package/android/src/main/include/rac/features/tts/rac_tts_component.h +0 -158
  68. package/android/src/main/include/rac/features/tts/rac_tts_events.h +0 -54
  69. package/android/src/main/include/rac/features/tts/rac_tts_service.h +0 -162
  70. package/android/src/main/include/rac/features/tts/rac_tts_types.h +0 -374
  71. package/android/src/main/include/rac/features/vad/rac_vad.h +0 -17
  72. package/android/src/main/include/rac/features/vad/rac_vad_analytics.h +0 -236
  73. package/android/src/main/include/rac/features/vad/rac_vad_component.h +0 -185
  74. package/android/src/main/include/rac/features/vad/rac_vad_energy.h +0 -443
  75. package/android/src/main/include/rac/features/vad/rac_vad_events.h +0 -76
  76. package/android/src/main/include/rac/features/vad/rac_vad_service.h +0 -167
  77. package/android/src/main/include/rac/features/vad/rac_vad_types.h +0 -244
  78. package/android/src/main/include/rac/features/voice_agent/rac_voice_agent.h +0 -612
  79. package/android/src/main/include/rac/infrastructure/device/rac_device_manager.h +0 -176
  80. package/android/src/main/include/rac/infrastructure/download/rac_download.h +0 -418
  81. package/android/src/main/include/rac/infrastructure/events/rac_events.h +0 -177
  82. package/android/src/main/include/rac/infrastructure/model_management/rac_model_assignment.h +0 -169
  83. package/android/src/main/include/rac/infrastructure/model_management/rac_model_paths.h +0 -258
  84. package/android/src/main/include/rac/infrastructure/model_management/rac_model_registry.h +0 -357
  85. package/android/src/main/include/rac/infrastructure/model_management/rac_model_strategy.h +0 -374
  86. package/android/src/main/include/rac/infrastructure/model_management/rac_model_types.h +0 -613
  87. package/android/src/main/include/rac/infrastructure/network/rac_api_types.h +0 -335
  88. package/android/src/main/include/rac/infrastructure/network/rac_auth_manager.h +0 -252
  89. package/android/src/main/include/rac/infrastructure/network/rac_dev_config.h +0 -85
  90. package/android/src/main/include/rac/infrastructure/network/rac_endpoints.h +0 -102
  91. package/android/src/main/include/rac/infrastructure/network/rac_environment.h +0 -220
  92. package/android/src/main/include/rac/infrastructure/network/rac_http_client.h +0 -233
  93. package/android/src/main/include/rac/infrastructure/storage/rac_storage_analyzer.h +0 -286
  94. package/android/src/main/include/rac/infrastructure/telemetry/rac_telemetry_manager.h +0 -206
  95. package/android/src/main/include/rac/infrastructure/telemetry/rac_telemetry_types.h +0 -234
  96. package/android/src/main/java/com/margelo/nitro/runanywhere/llama/RunAnywhereLlamaPackage.kt +0 -35
  97. package/android/src/main/jniLibs/arm64-v8a/libomp.so +0 -0
  98. package/android/src/main/jniLibs/arm64-v8a/librac_backend_llamacpp.so +0 -0
  99. package/android/src/main/jniLibs/arm64-v8a/librac_backend_llamacpp_jni.so +0 -0
  100. package/android/src/main/jniLibs/arm64-v8a/librac_commons.so +0 -0
  101. package/android/src/main/jniLibs/x86_64/libomp.so +0 -0
  102. package/android/src/main/jniLibs/x86_64/librac_backend_llamacpp.so +0 -0
  103. package/android/src/main/jniLibs/x86_64/librac_backend_llamacpp_jni.so +0 -0
  104. package/android/src/main/jniLibs/x86_64/librac_commons.so +0 -0
  105. package/cpp/bridges/LLMBridge.cpp +0 -209
  106. package/cpp/bridges/LLMBridge.hpp +0 -109
  107. package/cpp/bridges/StructuredOutputBridge.cpp +0 -151
  108. package/cpp/bridges/StructuredOutputBridge.hpp +0 -66
  109. package/cpp/rac_llm_llamacpp.h +0 -34
  110. package/ios/Frameworks/RABackendLLAMACPP.xcframework/ios-arm64/RABackendLLAMACPP.framework/Headers/RABackendLLAMACPP.h +0 -2
  111. package/ios/Frameworks/RABackendLLAMACPP.xcframework/ios-arm64/RABackendLLAMACPP.framework/Info.plist +0 -11
  112. package/ios/Frameworks/RABackendLLAMACPP.xcframework/ios-arm64/RABackendLLAMACPP.framework/Modules/module.modulemap +0 -5
  113. package/ios/Frameworks/RABackendLLAMACPP.xcframework/ios-arm64_x86_64-simulator/RABackendLLAMACPP.framework/Headers/RABackendLLAMACPP.h +0 -2
  114. package/ios/Frameworks/RABackendLLAMACPP.xcframework/ios-arm64_x86_64-simulator/RABackendLLAMACPP.framework/Info.plist +0 -11
  115. package/ios/Frameworks/RABackendLLAMACPP.xcframework/ios-arm64_x86_64-simulator/RABackendLLAMACPP.framework/Modules/module.modulemap +0 -5
  116. package/ios/LlamaCPPBackend.podspec +0 -127
@@ -1,5 +1,24 @@
1
+ # =============================================================================
2
+ # COUPLING NOTE: This file references librac_commons.so + RAC headers from the
3
+ # sibling @runanywhere/core npm package via a hard-coded relative path:
4
+ # ../../core/android/src/main/jniLibs/${ANDROID_ABI}/librac_commons.so
5
+ # ../../core/android/src/main/jniLibs/include/
6
+ # (computed via RN_NODE_MODULES → @runanywhere/core/android/src/main/jniLibs/).
7
+ #
8
+ # This is a known fragility — if the package directory structure changes,
9
+ # update the path here. Future improvement: migrate to Android Prefab module
10
+ # consumption (build.gradle: `prefab { commons { ... } }`) so the dependency
11
+ # is declared at the Gradle layer rather than the CMake layer.
12
+ #
13
+ # Prefab adoption was attempted but deferred because librac_commons.so is a
14
+ # pre-built binary downloaded by core's Gradle task (not produced by core's
15
+ # externalNativeBuild), so AGP's `prefabPublishing` publisher cannot
16
+ # auto-export it without additional manifest wiring. The relative-path
17
+ # coupling is therefore documented and intentionally preserved.
18
+ # =============================================================================
1
19
  project(runanywherellama)
2
- cmake_minimum_required(VERSION 3.9.0)
20
+ # Must match sdk/runanywhere-commons/VERSIONS::MIN_CMAKE_VERSION (3.24).
21
+ cmake_minimum_required(VERSION 3.24)
3
22
 
4
23
  set(PACKAGE_NAME runanywherellama)
5
24
  set(CMAKE_VERBOSE_MAKEFILE ON)
@@ -9,7 +28,7 @@ set(CMAKE_CXX_STANDARD 20)
9
28
  # 16KB Page Alignment for Android 15+ (API 35) Compliance
10
29
  # Required starting November 1, 2025 for Google Play submissions
11
30
  # =============================================================================
12
- set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384")
31
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,max-page-size=16384 -Wl,-z,common-page-size=16384")
13
32
 
14
33
  # Path to pre-built native libraries (downloaded from runanywhere-binaries)
15
34
  set(JNILIB_DIR ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})
@@ -19,12 +38,8 @@ set(JNILIB_DIR ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})
19
38
  # Downloaded via Gradle downloadNativeLibs task
20
39
  # =============================================================================
21
40
  if(NOT EXISTS "${JNILIB_DIR}/librac_backend_llamacpp.so")
22
- message(WARNING "[RunAnywhereLlama] RABackendLlamaCPP not found for ${ANDROID_ABI} at ${JNILIB_DIR}/librac_backend_llamacpp.so\n"
23
- "This ABI will not be functional. To fix, run: ./gradlew :runanywhere_llamacpp:downloadNativeLibs\n"
24
- "Or set reactNativeArchitectures=arm64-v8a in gradle.properties to skip this ABI.")
25
- file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/stub.cpp" "// Stub for missing ABI ${ANDROID_ABI}")
26
- add_library(${PACKAGE_NAME} SHARED "${CMAKE_CURRENT_BINARY_DIR}/stub.cpp")
27
- return()
41
+ message(FATAL_ERROR "[RunAnywhereLlama] RABackendLlamaCPP not found for ${ANDROID_ABI} at ${JNILIB_DIR}/librac_backend_llamacpp.so\n"
42
+ "Run ./scripts/build/build-core-android.sh from the repo root or set reactNativeArchitectures to an ABI with staged natives.")
28
43
  endif()
29
44
 
30
45
  add_library(rac_backend_llamacpp SHARED IMPORTED)
@@ -34,15 +49,9 @@ set_target_properties(rac_backend_llamacpp PROPERTIES
34
49
  )
35
50
  message(STATUS "[RunAnywhereLlama] Found RABackendLlamaCPP at ${JNILIB_DIR}/librac_backend_llamacpp.so")
36
51
 
37
- # =============================================================================
38
- # Source files - Llama bridges
39
- # =============================================================================
40
- file(GLOB BRIDGE_SOURCES "../cpp/bridges/*.cpp")
41
-
42
52
  add_library(${PACKAGE_NAME} SHARED
43
53
  src/main/cpp/cpp-adapter.cpp
44
54
  ../cpp/HybridRunAnywhereLlama.cpp
45
- ${BRIDGE_SOURCES}
46
55
  )
47
56
 
48
57
  # =============================================================================
@@ -70,13 +79,19 @@ include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/runanywherellama+autol
70
79
  # =============================================================================
71
80
  # Get core package include dir (for rac/*.h headers)
72
81
  get_filename_component(RN_NODE_MODULES "${CMAKE_SOURCE_DIR}/../../.." ABSOLUTE)
73
- set(CORE_INCLUDE_DIR "${RN_NODE_MODULES}/@runanywhere/core/android/src/main/include")
82
+ set(CORE_INCLUDE_DIR "${RN_NODE_MODULES}/@runanywhere/core/android/src/main/jniLibs/include")
74
83
  set(CORE_JNILIB_DIR "${RN_NODE_MODULES}/@runanywhere/core/android/src/main/jniLibs/${ANDROID_ABI}")
75
84
 
76
85
  include_directories(
77
86
  "src/main/cpp"
87
+ # Package-local hybrid headers (HybridRunAnywhereLlama.hpp etc.) — needed by the
88
+ # nitrogen-generated OnLoad + cpp-adapter. The forked rac_llm_llamacpp.h that used
89
+ # to live here was deleted (canonical commons header resolves via CORE_INCLUDE_DIR).
78
90
  "../cpp"
79
- "../cpp/bridges"
91
+ # nlohmann/json (header-only, vendored by sibling @runanywhere/core package).
92
+ # Sharing avoids re-fetching the dependency and keeps both packages on the
93
+ # same JSON version.
94
+ "${CMAKE_SOURCE_DIR}/../../core/cpp/third_party"
80
95
  "${CMAKE_SOURCE_DIR}/include"
81
96
  # RAC API headers from core package (flat access for all subdirectories)
82
97
  "${CORE_INCLUDE_DIR}"
@@ -88,8 +103,10 @@ include_directories(
88
103
  "${CORE_INCLUDE_DIR}/rac/features/stt"
89
104
  "${CORE_INCLUDE_DIR}/rac/features/tts"
90
105
  "${CORE_INCLUDE_DIR}/rac/features/vad"
106
+ "${CORE_INCLUDE_DIR}/rac/features/vlm"
91
107
  "${CORE_INCLUDE_DIR}/rac/features/voice_agent"
92
108
  "${CORE_INCLUDE_DIR}/rac/features/platform"
109
+ "${CORE_INCLUDE_DIR}/rac/backends"
93
110
  "${CORE_INCLUDE_DIR}/rac/infrastructure"
94
111
  "${CORE_INCLUDE_DIR}/rac/infrastructure/device"
95
112
  "${CORE_INCLUDE_DIR}/rac/infrastructure/download"
@@ -124,12 +141,12 @@ target_link_libraries(
124
141
  ${PACKAGE_NAME}
125
142
  ${LOG_LIB}
126
143
  android
144
+ c++_shared
127
145
  rac_commons
128
146
  rac_backend_llamacpp
129
147
  )
130
148
 
131
- # HAS_LLAMACPP and HAS_RACOMMONS are always defined since backends are required
132
- target_compile_definitions(${PACKAGE_NAME} PRIVATE HAS_LLAMACPP=1 HAS_RACOMMONS=1)
133
-
134
149
  # 16KB page alignment - MUST be on target for Android 15+ compliance
135
- target_link_options(${PACKAGE_NAME} PRIVATE -Wl,-z,max-page-size=16384)
150
+ target_link_options(${PACKAGE_NAME} PRIVATE
151
+ -Wl,-z,max-page-size=16384
152
+ -Wl,-z,common-page-size=16384)
@@ -13,7 +13,7 @@ def findNodeBinary() {
13
13
  return nodePath
14
14
  }
15
15
  }
16
-
16
+
17
17
  // Check common node installation paths
18
18
  def homeDir = System.getProperty("user.home")
19
19
  def nodePaths = [
@@ -29,7 +29,7 @@ def findNodeBinary() {
29
29
  return path
30
30
  }
31
31
  }
32
-
32
+
33
33
  // Fallback to 'node' (works if PATH is set correctly in terminal builds)
34
34
  return "node"
35
35
  }
@@ -82,10 +82,14 @@ def getExtOrIntegerDefault(name) {
82
82
  }
83
83
 
84
84
  // =============================================================================
85
- // Version Constants (MUST match Swift Package.swift and iOS Podspec)
85
+ // Version Constants read from sdk/runanywhere-commons/VERSION (single source of truth)
86
86
  // RABackendLlamaCPP from runanywhere-sdks
87
87
  // =============================================================================
88
- def coreVersion = "0.1.4"
88
+ // Resolve through canonicalPath so the relative lookup survives the node_modules
89
+ // symlink (node_modules/@runanywhere/llamacpp -> ../../sdk/runanywhere-react-native/packages/llamacpp);
90
+ // fall back to the pinned version if the commons VERSION file can't be located.
91
+ def coreVersionFile = file("${projectDir.canonicalPath}/../../../../runanywhere-commons/VERSION")
92
+ def coreVersion = coreVersionFile.exists() ? coreVersionFile.text.trim() : "0.19.13"
89
93
 
90
94
  // =============================================================================
91
95
  // Binary Source - RABackendLlamaCPP from runanywhere-sdks
@@ -94,15 +98,63 @@ def githubOrg = "RunanywhereAI"
94
98
  def coreRepo = "runanywhere-sdks"
95
99
 
96
100
  // =============================================================================
97
- // testLocal Toggle
101
+ // useLocalNatives Toggle (canonical name; testLocal kept as legacy alias)
98
102
  // =============================================================================
99
- def useLocalBuild = project.findProperty("runanywhere.testLocal")?.toBoolean() ?:
103
+ def useLocalBuild = project.findProperty("runanywhere.useLocalNatives")?.toBoolean() ?:
104
+ project.findProperty("runanywhere.testLocal")?.toBoolean() ?:
100
105
  System.getenv("RA_TEST_LOCAL") == "1" ?: false
101
106
 
102
107
  // Native libraries directory
103
108
  def jniLibsDir = file("src/main/jniLibs")
104
109
  def downloadedLibsDir = file("build/downloaded-libs")
105
110
 
111
+ def androidNdkHomeForRuntime() {
112
+ def explicitNdk = System.getenv("ANDROID_NDK_HOME") ?: System.getenv("NDK_HOME")
113
+ if (explicitNdk) {
114
+ return file(explicitNdk)
115
+ }
116
+
117
+ def androidSdk = System.getenv("ANDROID_HOME") ?:
118
+ System.getenv("ANDROID_SDK_ROOT") ?:
119
+ "${System.getProperty('user.home')}/Library/Android/sdk"
120
+ def ndkVersion = rootProject.ext.has("ndkVersion") ? rootProject.ext.ndkVersion : "27.0.12077973"
121
+ return file("${androidSdk}/ndk/${ndkVersion}")
122
+ }
123
+
124
+ def androidNdkHostTag() {
125
+ def osName = System.getProperty("os.name").toLowerCase(Locale.ROOT)
126
+ if (osName.contains("mac")) return "darwin-x86_64"
127
+ if (osName.contains("linux")) return "linux-x86_64"
128
+ throw new GradleException("Unsupported host for Android NDK runtime lookup: ${System.getProperty('os.name')}")
129
+ }
130
+
131
+ def androidNdkTripleForAbi(String abi) {
132
+ switch (abi) {
133
+ case 'arm64-v8a': return 'aarch64-linux-android'
134
+ case 'armeabi-v7a': return 'arm-linux-androideabi'
135
+ case 'x86_64': return 'x86_64-linux-android'
136
+ default: throw new GradleException("Unsupported Android ABI for libc++ runtime lookup: ${abi}")
137
+ }
138
+ }
139
+
140
+ def syncAndroidNdkRuntimeLibs(File outputDir) {
141
+ def ndkHome = androidNdkHomeForRuntime()
142
+ def prebuiltDir = new File(ndkHome, "toolchains/llvm/prebuilt/${androidNdkHostTag()}")
143
+ if (!prebuiltDir.isDirectory()) {
144
+ throw new GradleException("Android NDK prebuilt directory not found: ${prebuiltDir}")
145
+ }
146
+
147
+ ['arm64-v8a', 'armeabi-v7a', 'x86_64'].each { abi ->
148
+ def abiDir = new File(outputDir, abi)
149
+ def hasNativeLibs = abiDir.isDirectory() && abiDir.listFiles()?.any { it.name.endsWith(".so") }
150
+ if (!hasNativeLibs) return
151
+
152
+ def libcxx = new File(prebuiltDir, "sysroot/usr/lib/${androidNdkTripleForAbi(abi)}/libc++_shared.so")
153
+ if (!libcxx.isFile()) throw new GradleException("libc++_shared.so not found for ${abi} at ${libcxx}")
154
+ copy { from libcxx; into abiDir }
155
+ }
156
+ }
157
+
106
158
  android {
107
159
  namespace "com.margelo.nitro.runanywhere.llama"
108
160
 
@@ -113,7 +165,7 @@ android {
113
165
  targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
114
166
 
115
167
  ndk {
116
- abiFilters(*reactNativeArchitectures())
168
+ abiFilters 'arm64-v8a'
117
169
  }
118
170
 
119
171
  externalNativeBuild {
@@ -122,7 +174,7 @@ android {
122
174
  arguments "-DANDROID_STL=c++_shared",
123
175
  // Fix NitroModules prefab path - use app's build directory
124
176
  "-DREACT_NATIVE_NITRO_BUILD_DIR=${rootProject.buildDir}"
125
- abiFilters(*reactNativeArchitectures())
177
+ abiFilters 'arm64-v8a'
126
178
  }
127
179
  }
128
180
  }
@@ -130,6 +182,7 @@ android {
130
182
  externalNativeBuild {
131
183
  cmake {
132
184
  path "CMakeLists.txt"
185
+ version "3.30.5"
133
186
  }
134
187
  }
135
188
 
@@ -211,6 +264,12 @@ task downloadNativeLibs {
211
264
  return
212
265
  }
213
266
 
267
+ fileTree(dir: jniLibsDir, include: "**/libc++_shared.so").files.each { staleStdlib ->
268
+ if (staleStdlib.delete()) {
269
+ logger.lifecycle("[RunAnywhereLlama] Removed bundled libc++_shared.so: ${staleStdlib}")
270
+ }
271
+ }
272
+
214
273
  // Check if libs are already bundled for ALL requested ABIs (npm install case)
215
274
  def requestedAbis = reactNativeArchitectures()
216
275
  def allAbisBundled = requestedAbis.every { abi ->
@@ -382,6 +441,20 @@ task downloadNativeLibs {
382
441
  }
383
442
  }
384
443
 
444
+ task syncAndroidRuntimeLibs {
445
+ description = "Stages 16 KB-aligned Android NDK libc++"
446
+ group = "build setup"
447
+
448
+ if (!useLocalBuild) {
449
+ dependsOn downloadNativeLibs
450
+ }
451
+
452
+ doLast {
453
+ syncAndroidNdkRuntimeLibs(jniLibsDir)
454
+ logger.lifecycle("[RunAnywhereLlama] Synced 16 KB-aligned Android NDK libc++ into ${jniLibsDir}")
455
+ }
456
+ }
457
+
385
458
  if (!useLocalBuild) {
386
459
  preBuild.dependsOn downloadNativeLibs
387
460
 
@@ -394,6 +467,8 @@ if (!useLocalBuild) {
394
467
  }
395
468
  }
396
469
 
470
+ preBuild.dependsOn syncAndroidRuntimeLibs
471
+
397
472
  // NOTE: cleanNativeLibs is NOT attached to clean task because npm-bundled libs should persist
398
473
  // Only use this task manually when needed during development
399
474
  task cleanNativeLibs(type: Delete) {
@@ -3,98 +3,42 @@
3
3
  *
4
4
  * Nitrogen HybridObject implementation for RunAnywhere Llama backend.
5
5
  *
6
- * Llama-specific implementation for text generation using LlamaCPP.
6
+ * Llama-specific provider registration for LlamaCPP.
7
7
  *
8
8
  * NOTE: LlamaCPP backend is REQUIRED and always linked via the build system.
9
9
  */
10
10
 
11
11
  #include "HybridRunAnywhereLlama.hpp"
12
12
 
13
- // Llama bridges
14
- #include "bridges/LLMBridge.hpp"
15
- #include "bridges/StructuredOutputBridge.hpp"
16
-
17
- // Backend registration header - always available
13
+ // Backend registration headers - always available.
14
+ // Resolve the canonical commons header (RACommons xcframework / jniLibs) rather
15
+ // than a per-package fork, so the full published LlamaCPP ABI stays in sync.
18
16
  extern "C" {
19
- #include "rac_llm_llamacpp.h"
17
+ #include "rac/backends/rac_llm_llamacpp.h"
20
18
  }
21
19
 
20
+ #include "rac/core/rac_error.h"
21
+
22
22
  // Unified logging via rac_logger.h
23
23
  #include "rac_logger.h"
24
24
 
25
- #include <sstream>
26
- #include <chrono>
27
- #include <vector>
28
25
  #include <stdexcept>
26
+ #include <string>
29
27
 
30
28
  // Log category for this module
31
29
  #define LOG_CATEGORY "LLM.LlamaCpp"
32
30
 
33
31
  namespace margelo::nitro::runanywhere::llama {
34
32
 
35
- using namespace ::runanywhere::bridges;
36
-
37
- // ============================================================================
38
- // JSON Utilities
39
- // ============================================================================
40
-
41
33
  namespace {
42
34
 
43
- int extractIntValue(const std::string& json, const std::string& key, int defaultValue) {
44
- std::string searchKey = "\"" + key + "\":";
45
- size_t pos = json.find(searchKey);
46
- if (pos == std::string::npos) return defaultValue;
47
- pos += searchKey.length();
48
- while (pos < json.size() && (json[pos] == ' ' || json[pos] == '\t')) pos++;
49
- if (pos >= json.size()) return defaultValue;
50
- return std::stoi(json.substr(pos));
51
- }
52
-
53
- float extractFloatValue(const std::string& json, const std::string& key, float defaultValue) {
54
- std::string searchKey = "\"" + key + "\":";
55
- size_t pos = json.find(searchKey);
56
- if (pos == std::string::npos) return defaultValue;
57
- pos += searchKey.length();
58
- while (pos < json.size() && (json[pos] == ' ' || json[pos] == '\t')) pos++;
59
- if (pos >= json.size()) return defaultValue;
60
- return std::stof(json.substr(pos));
61
- }
62
-
63
- std::string extractStringValue(const std::string& json, const std::string& key, const std::string& defaultValue = "") {
64
- std::string searchKey = "\"" + key + "\":\"";
65
- size_t pos = json.find(searchKey);
66
- if (pos == std::string::npos) return defaultValue;
67
- pos += searchKey.length();
68
- size_t endPos = json.find("\"", pos);
69
- if (endPos == std::string::npos) return defaultValue;
70
- return json.substr(pos, endPos - pos);
71
- }
72
-
73
- std::string buildJsonObject(const std::vector<std::pair<std::string, std::string>>& keyValues) {
74
- std::string result = "{";
75
- for (size_t i = 0; i < keyValues.size(); i++) {
76
- if (i > 0) result += ",";
77
- result += "\"" + keyValues[i].first + "\":" + keyValues[i].second;
78
- }
79
- result += "}";
80
- return result;
81
- }
82
-
83
- std::string jsonString(const std::string& value) {
84
- std::string escaped = "\"";
85
- for (char c : value) {
86
- if (c == '"') escaped += "\\\"";
87
- else if (c == '\\') escaped += "\\\\";
88
- else if (c == '\n') escaped += "\\n";
89
- else if (c == '\r') escaped += "\\r";
90
- else if (c == '\t') escaped += "\\t";
91
- else escaped += c;
92
- }
93
- escaped += "\"";
94
- return escaped;
35
+ bool isRegistrationSuccess(rac_result_t result) {
36
+ return result == RAC_SUCCESS ||
37
+ result == RAC_ERROR_MODULE_ALREADY_REGISTERED ||
38
+ result == RAC_ERROR_PLUGIN_DUPLICATE;
95
39
  }
96
40
 
97
- } // anonymous namespace
41
+ } // namespace
98
42
 
99
43
  // ============================================================================
100
44
  // Constructor / Destructor
@@ -106,7 +50,6 @@ HybridRunAnywhereLlama::HybridRunAnywhereLlama() : HybridObject(TAG) {
106
50
 
107
51
  HybridRunAnywhereLlama::~HybridRunAnywhereLlama() {
108
52
  RAC_LOG_DEBUG(LOG_CATEGORY, "HybridRunAnywhereLlama destructor");
109
- LLMBridge::shared().destroy();
110
53
  }
111
54
 
112
55
  // ============================================================================
@@ -117,17 +60,23 @@ std::shared_ptr<Promise<bool>> HybridRunAnywhereLlama::registerBackend() {
117
60
  return Promise<bool>::async([this]() {
118
61
  RAC_LOG_DEBUG(LOG_CATEGORY, "Registering LlamaCPP backend with C++ registry");
119
62
 
63
+ // rac_backend_llamacpp_register() internally registers both the module and
64
+ // the plugin entry (rac_plugin_entry_llamacpp()) — see
65
+ // engines/llamacpp/rac_backend_llamacpp_register.cpp:462-478, which plugs
66
+ // the Android dynamic-loading gap where the RAC_STATIC_PLUGIN_REGISTER ctor
67
+ // never fires (Kotlin/JNI loads librac_backend_llamacpp_jni.so directly,
68
+ // not the carrier librunanywhere_llamacpp.so). Matches the iOS Swift
69
+ // source-of-truth in sdk/runanywhere-swift/Sources/LlamaCPPRuntime which
70
+ // also relies on the in-engine registration only.
120
71
  rac_result_t result = rac_backend_llamacpp_register();
121
- // RAC_SUCCESS (0) or RAC_ERROR_MODULE_ALREADY_REGISTERED (-4) are both OK
122
- if (result == RAC_SUCCESS || result == -4) {
123
- RAC_LOG_INFO(LOG_CATEGORY, "LlamaCPP backend registered successfully");
124
- isRegistered_ = true;
125
- return true;
126
- } else {
72
+ if (!isRegistrationSuccess(result)) {
127
73
  RAC_LOG_ERROR(LOG_CATEGORY, "LlamaCPP registration failed with code: %d", result);
128
- setLastError("LlamaCPP registration failed with error: " + std::to_string(result));
129
74
  throw std::runtime_error("LlamaCPP registration failed with error: " + std::to_string(result));
130
75
  }
76
+
77
+ RAC_LOG_INFO(LOG_CATEGORY, "LlamaCPP backend registered successfully");
78
+ isRegistered_ = true;
79
+ return true;
131
80
  });
132
81
  }
133
82
 
@@ -151,196 +100,4 @@ std::shared_ptr<Promise<bool>> HybridRunAnywhereLlama::isBackendRegistered() {
151
100
  });
152
101
  }
153
102
 
154
- // ============================================================================
155
- // Model Loading
156
- // ============================================================================
157
-
158
- std::shared_ptr<Promise<bool>> HybridRunAnywhereLlama::loadModel(
159
- const std::string& path,
160
- const std::optional<std::string>& modelId,
161
- const std::optional<std::string>& modelName,
162
- const std::optional<std::string>& configJson) {
163
- return Promise<bool>::async([this, path, modelId, modelName, configJson]() {
164
- std::lock_guard<std::mutex> lock(modelMutex_);
165
-
166
- RAC_LOG_INFO(LOG_CATEGORY, "Loading Llama model: %s", path.c_str());
167
-
168
- std::string id = modelId.value_or("");
169
- std::string name = modelName.value_or("");
170
-
171
- // Call with correct 4-arg signature (path, modelId, modelName)
172
- // LLMBridge::loadModel will throw on error
173
- auto result = LLMBridge::shared().loadModel(path, id, name);
174
- if (result != 0) {
175
- std::string error = "Failed to load Llama model: " + path + " (error: " + std::to_string(result) + ")";
176
- setLastError(error);
177
- throw std::runtime_error(error);
178
- }
179
- return true;
180
- });
181
- }
182
-
183
- std::shared_ptr<Promise<bool>> HybridRunAnywhereLlama::isModelLoaded() {
184
- return Promise<bool>::async([]() {
185
- return LLMBridge::shared().isLoaded();
186
- });
187
- }
188
-
189
- std::shared_ptr<Promise<bool>> HybridRunAnywhereLlama::unloadModel() {
190
- return Promise<bool>::async([this]() {
191
- std::lock_guard<std::mutex> lock(modelMutex_);
192
- auto result = LLMBridge::shared().unload();
193
- return result == 0;
194
- });
195
- }
196
-
197
- std::shared_ptr<Promise<std::string>> HybridRunAnywhereLlama::getModelInfo() {
198
- return Promise<std::string>::async([]() {
199
- if (!LLMBridge::shared().isLoaded()) {
200
- return std::string("{}");
201
- }
202
- return buildJsonObject({
203
- {"loaded", "true"},
204
- {"backend", jsonString("llamacpp")}
205
- });
206
- });
207
- }
208
-
209
- // ============================================================================
210
- // Text Generation
211
- // ============================================================================
212
-
213
- std::shared_ptr<Promise<std::string>> HybridRunAnywhereLlama::generate(
214
- const std::string& prompt,
215
- const std::optional<std::string>& optionsJson) {
216
- return Promise<std::string>::async([this, prompt, optionsJson]() {
217
- if (!LLMBridge::shared().isLoaded()) {
218
- setLastError("Model not loaded");
219
- throw std::runtime_error("LLMBridge: Model not loaded. Call loadModel() first.");
220
- }
221
-
222
- LLMOptions options;
223
- if (optionsJson.has_value()) {
224
- options.maxTokens = extractIntValue(*optionsJson, "max_tokens", 512);
225
- options.temperature = extractFloatValue(*optionsJson, "temperature", 0.7f);
226
- options.topP = extractFloatValue(*optionsJson, "top_p", 0.9f);
227
- options.topK = extractIntValue(*optionsJson, "top_k", 40);
228
- }
229
-
230
- RAC_LOG_DEBUG(LOG_CATEGORY, "Generating with prompt: %.50s...", prompt.c_str());
231
-
232
- auto startTime = std::chrono::high_resolution_clock::now();
233
- // LLMBridge::generate will throw on error
234
- auto result = LLMBridge::shared().generate(prompt, options);
235
- auto endTime = std::chrono::high_resolution_clock::now();
236
- auto durationMs = std::chrono::duration_cast<std::chrono::milliseconds>(
237
- endTime - startTime).count();
238
-
239
- return buildJsonObject({
240
- {"text", jsonString(result.text)},
241
- {"tokensUsed", std::to_string(result.tokenCount)},
242
- {"latencyMs", std::to_string(durationMs)},
243
- {"cancelled", result.cancelled ? "true" : "false"}
244
- });
245
- });
246
- }
247
-
248
- std::shared_ptr<Promise<std::string>> HybridRunAnywhereLlama::generateStream(
249
- const std::string& prompt,
250
- const std::string& optionsJson,
251
- const std::function<void(const std::string&, bool)>& callback) {
252
- return Promise<std::string>::async([this, prompt, optionsJson, callback]() {
253
- if (!LLMBridge::shared().isLoaded()) {
254
- setLastError("Model not loaded");
255
- throw std::runtime_error("LLMBridge: Model not loaded. Call loadModel() first.");
256
- }
257
-
258
- LLMOptions options;
259
- options.maxTokens = extractIntValue(optionsJson, "max_tokens", 512);
260
- options.temperature = extractFloatValue(optionsJson, "temperature", 0.7f);
261
-
262
- std::string fullResponse;
263
- std::string streamError;
264
-
265
- LLMStreamCallbacks streamCallbacks;
266
- streamCallbacks.onToken = [&callback, &fullResponse](const std::string& token) -> bool {
267
- fullResponse += token;
268
- if (callback) {
269
- callback(token, false);
270
- }
271
- return true;
272
- };
273
- streamCallbacks.onComplete = [&callback](const std::string&, int, double) {
274
- if (callback) {
275
- callback("", true);
276
- }
277
- };
278
- streamCallbacks.onError = [this, &streamError](int code, const std::string& message) {
279
- setLastError(message);
280
- streamError = message;
281
- };
282
-
283
- LLMBridge::shared().generateStream(prompt, options, streamCallbacks);
284
-
285
- if (!streamError.empty()) {
286
- throw std::runtime_error("LLMBridge: Stream generation failed: " + streamError);
287
- }
288
-
289
- return fullResponse;
290
- });
291
- }
292
-
293
- std::shared_ptr<Promise<bool>> HybridRunAnywhereLlama::cancelGeneration() {
294
- return Promise<bool>::async([]() {
295
- LLMBridge::shared().cancel();
296
- return true;
297
- });
298
- }
299
-
300
- // ============================================================================
301
- // Structured Output
302
- // ============================================================================
303
-
304
- std::shared_ptr<Promise<std::string>> HybridRunAnywhereLlama::generateStructured(
305
- const std::string& prompt,
306
- const std::string& schema,
307
- const std::optional<std::string>& optionsJson) {
308
- return Promise<std::string>::async([this, prompt, schema, optionsJson]() {
309
- auto result = StructuredOutputBridge::shared().generate(
310
- prompt, schema, optionsJson.value_or("")
311
- );
312
-
313
- if (result.success) {
314
- return result.json;
315
- } else {
316
- setLastError(result.error);
317
- return buildJsonObject({{"error", jsonString(result.error)}});
318
- }
319
- });
320
- }
321
-
322
- // ============================================================================
323
- // Utilities
324
- // ============================================================================
325
-
326
- std::shared_ptr<Promise<std::string>> HybridRunAnywhereLlama::getLastError() {
327
- return Promise<std::string>::async([this]() { return lastError_; });
328
- }
329
-
330
- std::shared_ptr<Promise<double>> HybridRunAnywhereLlama::getMemoryUsage() {
331
- return Promise<double>::async([]() {
332
- // TODO: Get memory usage from LlamaCPP
333
- return 0.0;
334
- });
335
- }
336
-
337
- // ============================================================================
338
- // Helper Methods
339
- // ============================================================================
340
-
341
- void HybridRunAnywhereLlama::setLastError(const std::string& error) {
342
- lastError_ = error;
343
- RAC_LOG_ERROR(LOG_CATEGORY, "Error: %s", error.c_str());
344
- }
345
-
346
103
  } // namespace margelo::nitro::runanywhere::llama