-
Notifications
You must be signed in to change notification settings - Fork 101
[Kotlin-SDK] [Kotlin-Sample] TTS + STT android UI/UX updates #203
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…ponding ViewModels - Added SpeechToTextScreen and TextToSpeechScreen components, mirroring iOS functionality. - Introduced SpeechToTextViewModel and TextToSpeechViewModel for managing UI state and interactions. - Enhanced AppNavigation to include new STT and TTS routes, replacing previous Storage functionality. - Updated SettingsScreen to combine settings and storage management, aligning with iOS design. - Refactored BottomNavigationBar to match iOS tab structure, ensuring consistent user experience across platforms. - Integrated model selection dialogs for STT and TTS, improving user interaction for model management. This commit enhances the overall functionality and user experience of the application, aligning with the iOS architecture.
|
Caution Review failedThe pull request is closed. Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughThis PR significantly expands the RunAnywhere Kotlin SDK with a new native ONNX module via JNI integration and substantially refactors the Android RunAnywhereAI app UI and state management. It adds STT/TTS screens, reorganizes navigation, enriches settings and voice assistant flows, and introduces new public SDK APIs for model loading, token counting, and generation result modeling. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as SpeechToTextScreen /<br/>TextToSpeechScreen
participant ViewModel as STT/TTS ViewModel
participant SDK as RunAnywhereSDK
participant Service as ONNXCoreService
participant JNI as RunAnywhereBridge
participant Native as ONNX Native<br/>Backend
UI->>ViewModel: loadModel(name, id)
ViewModel->>SDK: loadSTTModel() / loadTTSModel()
SDK->>Service: loadSTTModel(path) / loadTTSModel(path)
Service->>Service: ensureInitialized()
Service->>JNI: nativeSTTLoadModel(...)<br/>nativeTTSLoadModel(...)
JNI->>Native: Call via JNI
Native-->>JNI: Status code
JNI-->>Service: Result
Service->>Service: Update model state
Service-->>SDK: Success
SDK-->>ViewModel: Return component
ViewModel->>ViewModel: Update isModelLoaded state
ViewModel-->>UI: Emit state update
UI->>UI: Show ready UI
alt STT Flow
UI->>ViewModel: toggleRecording()
ViewModel->>Service: transcribe(audioSamples)
Service->>JNI: nativeSTTTranscribe(...)
JNI->>Native: Transcribe
Native-->>JNI: Transcription text
JNI-->>Service: Text result
Service-->>ViewModel: Transcription
ViewModel-->>UI: Update transcription state
else TTS Flow
UI->>ViewModel: generateSpeech(text)
ViewModel->>Service: synthesize(text, voice, speed, pitch)
Service->>JNI: nativeTTSSynthesize(...)
JNI->>Native: Synthesize
Native-->>JNI: Audio samples
JNI-->>Service: NativeTTSSynthesisResult
Service-->>ViewModel: Audio data
ViewModel-->>UI: Update playback state
end
sequenceDiagram
participant Screen as VoiceAssistantScreen
participant ViewModel as VoiceAssistantViewModel
participant STTComp as STTComponent
participant LLMComp as LLMComponent
participant TTSComp as TTSComponent
Screen->>ViewModel: setSTTModel(framework, name, id)
ViewModel->>ViewModel: Update sttLoadState → LOADING
ViewModel->>STTComp: (Simulate load)
ViewModel->>ViewModel: sttLoadState → LOADED
Screen->>ViewModel: setLLMModel(...)
ViewModel->>LLMComp: (Load)
ViewModel->>ViewModel: llmLoadState → LOADED
Screen->>ViewModel: setTTSModel(...)
ViewModel->>TTSComp: (Load)
ViewModel->>ViewModel: ttsLoadState → LOADED
Screen->>Screen: Check allModelsReady (all LOADED)
activate Screen
Screen->>ViewModel: startSession()
ViewModel->>ViewModel: isListening → true
ViewModel-->>Screen: Emit ready UI
Screen->>Screen: Show MainVoiceAssistantUI
deactivate Screen
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related issues
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (22)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…UI components - Implemented ConversationListSheet and ChatDetailsSheet in ChatScreen for improved conversation management. - Updated ChatViewModel to support loading and managing conversations, including new conversation creation and deletion. - Refactored StorageViewModel to manage stored model information and integrate with the UI for better user experience. - Added error handling and loading states in StorageViewModel for improved data management. - Removed unused Color.kt file to streamline the project structure. This commit enhances the application's chat and storage capabilities, aligning with the overall architecture and improving user interaction.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@greptile review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
examples/flutter/RunAnywhereAI/ios/Flutter/Generated.xcconfig (1)
1-14: Generated.xcconfig is tracked in git and contains machine-specific paths that will break builds for other developers.Verification confirms this is a critical issue:
- The file is tracked in git (confirmed via
git ls-files)- It is not gitignored (
git check-ignorereturned no match)- The
.gitignorepattern only covers**/ios/Flutter/ephemeral/, missingGenerated.xcconfig- The file contains hardcoded user paths (
/Users/sanchitmonga/...)Remove this file from the commit and add it to
.gitignore:# In examples/flutter/RunAnywhereAI/.gitignore or root .gitignore, add: **/ios/Flutter/Generated.xcconfigThen run:
git rm --cached examples/flutter/RunAnywhereAI/ios/Flutter/Generated.xcconfigexamples/flutter/RunAnywhereAI/ios/Flutter/flutter_export_environment.sh (1)
1-13: Auto-generated Flutter file with user-specific paths is committed to version control and should be removed.Verification confirms this is a critical issue. The file
flutter_export_environment.shis currently tracked in git (and not gitignored), alongsideGenerated.xcconfig. Both contain machine-specific and build-specific paths that will differ across developers' environments, causing:
- Build failures for developers with different path structures
- Merge conflicts on every build regeneration
- Violation of the file's own header directive
Both files must be removed from the commit and added to
.gitignorewith a pattern like**/ios/Flutter/flutter_export_environment.shand**/ios/Flutter/Generated.xcconfig.examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/VoiceAssistantViewModel.kt (1)
358-363:onClearedcoroutine may not complete.The coroutine launched in
onCleared()may be cancelled immediately sinceviewModelScopeis cancelled when the ViewModel is cleared. CallstopSession()synchronously or use a non-cancellable context if cleanup must complete.override fun onCleared() { super.onCleared() - viewModelScope.launch { - stopSession() - } + // Cancel the pipeline job directly - stopSession's coroutine work + // won't complete reliably in onCleared + pipelineJob?.cancel() + pipelineJob = null }
🧹 Nitpick comments (30)
sdk/runanywhere-swift/ARCHITECTURE.md (1)
11-22: Specify language identifiers for all fenced code blocks.Multiple code blocks lack language specifiers, triggering markdown linting warnings (MD040). Add appropriate language tags to help with syntax highlighting and linting compliance.
Apply this diff to add language specifiers:
-``` +```text ┌─────────────────────────────────────────────────────────────────┐-``` +```text Sources/-``` +```text Sources/CRunAnywhereONNX/-module CRunAnywhereONNX { +```modulemap +module CRunAnywhereONNX {-``` +```text ┌──────────────────────────────────────────────────────────────┐-``` +```text ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐-``` +```text runanywhere-core/Also applies to: 26-49, 69-74, 77-83, 134-149, 394-402, 506-519
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/tts/TextToSpeechScreen.kt (2)
612-620: Remove no-op modifier chain.The
.then(if (isSystemTTS) Modifier else Modifier)on line 615 is a no-op since both branches return an emptyModifier. This appears to be leftover scaffolding.modifier = Modifier .width(140.dp) - .height(50.dp) - .then(if (isSystemTTS) Modifier else Modifier), + .height(50.dp),
716-723: Consider extracting sharedformatBytesutility.This function duplicates
formatBytesinSettingsScreen.kt(lines 670-677), but with differences: this version takesIntinstead ofLongand doesn't handle the< 1024 bytesor>= 1 GBcases. Consider extracting to a shared utility for consistency.-private fun formatBytes(bytes: Int): String { - val kb = bytes / 1024.0 - return if (kb < 1024) { - String.format("%.1f KB", kb) - } else { - String.format("%.1f MB", kb / 1024.0) - } -} +private fun formatBytes(bytes: Int): String = formatBytes(bytes.toLong()) + +private fun formatBytes(bytes: Long): String { + return when { + bytes < 1024 -> "$bytes B" + bytes < 1024 * 1024 -> String.format("%.1f KB", bytes / 1024.0) + bytes < 1024 * 1024 * 1024 -> String.format("%.1f MB", bytes / (1024.0 * 1024.0)) + else -> String.format("%.1f GB", bytes / (1024.0 * 1024.0 * 1024.0)) + } +}examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/tts/TextToSpeechViewModel.kt (1)
68-75: Consider removing empty coroutine launch.The
initialize()function launches an empty coroutine. Until the actual audio session configuration is implemented, consider simplifying to avoid unnecessary coroutine overhead.fun initialize() { - viewModelScope.launch { - // TODO: Configure audio session for playback - // iOS equivalent: - // try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default) - // try AVAudioSession.sharedInstance().setActive(true) - } + // TODO: Configure audio session for playback + // iOS equivalent: + // try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default) + // try AVAudioSession.sharedInstance().setActive(true) }examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/VoiceAssistantViewModel.kt (1)
104-122: Consider lazy derivation for convenience StateFlows.Creating 6 derived
StateFlows eagerly withSharingStarted.Eagerlyconsumes memory even if they're not observed. Since these are "backward compatibility" accessors, consider usingSharingStarted.WhileSubscribed()or lazy initialization to reduce overhead.val sessionState: StateFlow<SessionState> = _uiState.map { it.sessionState }.stateIn( - viewModelScope, SharingStarted.Eagerly, SessionState.DISCONNECTED + viewModelScope, SharingStarted.WhileSubscribed(5000), SessionState.DISCONNECTED )Apply similarly to other derived flows (
isListening,error,currentTranscript,assistantResponse,audioLevel).examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/storage/StorageViewModel.kt (2)
200-208: Redundant state update beforerefreshData().The state update to remove the model and recalculate
modelStorageSizeis immediately overwritten byrefreshData()which loads mock data. This creates a brief UI flicker. Consider either removing the redundant update or havingrefreshData()preserve the deletion.fun deleteModel(modelId: String) { viewModelScope.launch { try { // TODO: Replace with actual SDK integration // iOS equivalent: try await RunAnywhere.deleteStoredModel(modelId) - _uiState.update { state -> - state.copy( - storedModels = state.storedModels.filter { it.id != modelId }, - modelStorageSize = state.storedModels - .filter { it.id != modelId } - .sumOf { it.size } - ) - } - refreshData() + // TODO: When SDK is integrated, call delete then refresh + // For now, just update the local state (mock behavior) + _uiState.update { state -> + val updatedModels = state.storedModels.filter { it.id != modelId } + state.copy( + storedModels = updatedModels, + modelStorageSize = updatedModels.sumOf { it.size }, + totalStorageSize = updatedModels.sumOf { it.size } + 50_000_000L + ) + } } catch (e: Exception) {
18-28: Consider consolidatingStoredModelInfowithSettingsViewModel.Per the AI summary,
StoredModelInfois duplicated in bothStorageViewModel.ktandSettingsViewModel.kt. Consider extracting to a shared models file to avoid drift between implementations.sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/components/stt/STTModels.kt (1)
65-73: Consider platform-specific icon mapping for Android.The
iconproperty uses SF Symbol names (waveform.badge.mic,waveform) which are iOS-specific. Android doesn't have these icons natively. Consider adding platform-specific icon resolution or using a cross-platform icon abstraction./** * Icon identifier for the mode (matches iOS icon) - * Uses SF Symbol names for cross-platform icon lookup + * Uses SF Symbol names - Android consumers should map to Material icons + * (e.g., "waveform.badge.mic" → R.drawable.ic_mic, "waveform" → R.drawable.ic_waveform) */ val icon: String get() = when (this) { BATCH -> "waveform.badge.mic" LIVE -> "waveform" }sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/BridgeResults.kt (1)
30-37: Consider adding validation for probability range.The
probabilityfield should logically be constrained to[0.0, 1.0]. Other result types in the codebase (e.g.,WordTimestamp,TranscriptionAlternativein STTModels.kt) validate confidence ranges in theirinitblocks.data class VADResult( val isSpeech: Boolean, val probability: Float -) +) { + init { + require(probability in 0.0f..1.0f) { "Probability must be between 0.0 and 1.0" } + } +}examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/chat/ChatScreen.kt (1)
1164-1164: Consider using thread-safe date formatting.
SimpleDateFormatis not thread-safe. Whilerememberprovides instance stability, consider usingDateTimeFormatter(API 26+) or the format at call-site for safer recomposition:// Option 1: Format inline without caching the formatter val formattedDate = remember(conversation.updatedAt) { SimpleDateFormat("MMM d", Locale.getDefault()).format(Date(conversation.updatedAt)) }examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/settings/SettingsScreen.kt (4)
89-93: Use explicit locale for consistent number formatting.
String.formatwithout an explicitLocalecan produce inconsistent decimal separators across devices (e.g.,.vs,). For UI display, consider usingLocale.USorLocale.ROOTfor consistency.- Text( - text = String.format("%.2f", uiState.temperature), + Text( + text = String.format(java.util.Locale.US, "%.2f", uiState.temperature),
440-440: Replace deprecatedvalues()withentries.
Enum.values()is deprecated in Kotlin 1.9+. Useentriesfor better performance and type safety.- RoutingPolicy.values().forEach { policy -> + RoutingPolicy.entries.forEach { policy ->
670-678: Use explicit locale informatBytesfor consistent formatting.Static analysis flagged implicit default locale usage. For byte formatting shown in UI, use an explicit locale.
private fun formatBytes(bytes: Long): String { return when { bytes < 1024 -> "$bytes B" - bytes < 1024 * 1024 -> String.format("%.1f KB", bytes / 1024.0) - bytes < 1024 * 1024 * 1024 -> String.format("%.1f MB", bytes / (1024.0 * 1024.0)) - else -> String.format("%.1f GB", bytes / (1024.0 * 1024.0 * 1024.0)) + bytes < 1024 * 1024 -> String.format(java.util.Locale.US, "%.1f KB", bytes / 1024.0) + bytes < 1024 * 1024 * 1024 -> String.format(java.util.Locale.US, "%.1f MB", bytes / (1024.0 * 1024.0)) + else -> String.format(java.util.Locale.US, "%.1f GB", bytes / (1024.0 * 1024.0 * 1024.0)) } }
313-316: TODO: Implement documentation link.This TODO should be tracked. Consider opening an issue or using Android's
Intent.ACTION_VIEWwith a URI to open the documentation URL.Would you like me to generate the implementation for opening the documentation URL, or should I open an issue to track this?
sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts (1)
128-138: Silent failure when ONNX distribution directory is missing.If
dist/android/onnxdoesn't exist, the build proceeds silently without native libraries, leading to runtime failures. Consider logging a warning or failing the build if required libraries are absent.sourceSets { getByName("main") { val runAnywhereCoreDir = rootProject.projectDir.resolve("../../../runanywhere-core") val distDir = runAnywhereCoreDir.resolve("dist/android/onnx") if (distDir.exists()) { jniLibs.srcDirs(distDir) + } else { + logger.warn("ONNX native libraries not found at: $distDir. Build may fail at runtime.") } } }examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/VoiceAssistantScreen.kt (3)
796-831: Consider extractingModelBadgeto a shared component.This
ModelBadgediffers fromChatScreen.kt'sModelBadge(lines 560-605 in relevant snippets). Having two different implementations with the same name can cause confusion. Consider either:
- Extracting a shared
ModelBadgecomponent to a common location- Renaming this one to
VoiceModelBadgeto distinguish it
82-86: Empty callback with unclear purpose.The
onStartVoicecallback is empty with a comment saying the view auto-switches. If this callback isn't needed, consider removing the parameter fromVoicePipelineSetupViewto avoid confusion.VoicePipelineSetupView( ... onSelectTTS = { showTTSModelSelection = true }, - onStartVoice = { - // All models loaded, nothing to do here - // The view will automatically switch to main voice UI - } + onStartVoice = { /* View auto-switches when models are loaded */ } )Or remove the
onStartVoiceparameter entirely if it's never used meaningfully.
948-1016: MockModelSelectionDialog should be replaced before release.The TODO indicates this is a temporary mock. Ensure this is tracked for replacement with the actual
ModelSelectionSheetbefore the feature ships.Would you like me to open an issue to track replacing the mock model selection dialogs with the actual SDK-integrated implementation?
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/stt/SpeechToTextScreen.kt (3)
329-331: Replace deprecatedvalues()withentries.
Enum.values()is deprecated in Kotlin 1.9+. Useentriesinstead.- STTMode.values().forEach { mode -> + STTMode.entries.forEach { mode ->
3-3: Unused import.
animateContentSizeis imported but not used in this file.-import androidx.compose.animation.animateContentSize
161-216: Mock model picker should be tracked for replacement.Similar to the VoiceAssistantScreen, this uses a temporary mock dialog. The TODO at line 162 indicates SDK integration is pending.
Would you like me to open an issue to track replacing the mock STT model picker with the actual
ModelSelectionSheetimplementation?sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/Capability.kt (1)
15-17: Inconsistent nullability acrossfromValuemethods.
Capability.fromValuereturnsCapability?(nullable), whileDeviceType.fromValueandResultCode.fromValuereturn non-nullable defaults. This inconsistency could surprise callers expecting uniform behavior.Consider aligning the return types—either all nullable with explicit handling, or all with a sensible default/unknown variant.
Option A – Add an
UNKNOWNentry and return it as a default:enum class Capability(val value: Int) { TEXT_GENERATION(0), EMBEDDINGS(1), STT(2), TTS(3), VAD(4), - DIARIZATION(5); + DIARIZATION(5), + UNKNOWN(-1); companion object { - fun fromValue(value: Int): Capability? = entries.find { it.value == value } + fun fromValue(value: Int): Capability = entries.find { it.value == value } ?: UNKNOWN } }examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/stt/SpeechToTextViewModel.kt (1)
73-80: Remove empty coroutine launch.The
viewModelScope.launchblock contains only a comment. Remove the unnecessary coroutine until actual initialization logic is added.fun initialize() { - viewModelScope.launch { - // TODO: Configure audio session for recording - // iOS equivalent: - // try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default) - // try AVAudioSession.sharedInstance().setActive(true) - } + // TODO: Configure audio session for recording + // iOS equivalent: + // try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default) + // try AVAudioSession.sharedInstance().setActive(true) }examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/settings/SettingsViewModel.kt (2)
227-240: Unnecessary coroutine launch.
updateApiKeylaunches a coroutine but only performs synchronous state updates. Either remove the launch for consistency with other update methods, or make it suspend if async storage is planned.fun updateApiKey(apiKey: String) { - viewModelScope.launch { - // TODO: Save to encrypted storage - // Android: EncryptedSharedPreferences - // iOS: KeychainService - - _uiState.update { - it.copy( - apiKey = apiKey, - isApiKeyConfigured = apiKey.isNotEmpty() - ) - } + // TODO: Save to encrypted storage + // Android: EncryptedSharedPreferences + // iOS: KeychainService + + _uiState.update { + it.copy( + apiKey = apiKey, + isApiKeyConfigured = apiKey.isNotEmpty() + ) } + saveConfiguration() }
324-335: Replaceprintlnwith proper logging.For Android, use
android.util.Logor a logging library like Timber instead ofprintln.- println("Configuration saved - Temperature: ${state.temperature}, MaxTokens: ${state.maxTokens}") + android.util.Log.d("SettingsViewModel", "Configuration saved - Temperature: ${state.temperature}, MaxTokens: ${state.maxTokens}")sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreService.kt (1)
3-4: Remove unused imports.
DispatchersandwithContextare imported but not used in thisexpectdeclaration file. The actual implementation will need them.package com.runanywhere.sdk.core.bridge -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext - /** * ONNXCoreService - High-level service wrapper for RunAnywhere Core ONNX backend.sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreServiceImpl.kt (2)
206-213: Inconsistent initialization check ingetVoices().Unlike other methods that call
ensureInitialized()and throw when the backend isn't ready,getVoices()silently returns"[]". This inconsistency could mask initialization bugs.Consider aligning with other methods:
actual suspend fun getVoices(): String { return withContext(Dispatchers.IO) { mutex.withLock { - if (backendHandle == 0L) return@withContext "[]" + ensureInitialized() RunAnywhereBridge.nativeTTSGetVoices(backendHandle) } } }
335-361: Companion utility functions perform blocking JNI calls on the calling thread.
getAvailableBackends(),getVersion(), andextractArchive()execute native calls synchronously. On Android, if called from the main thread, these could cause ANR. Consider making them suspend functions dispatched toDispatchers.IOfor consistency with the instance methods.- fun getAvailableBackends(): List<String> { + suspend fun getAvailableBackends(): List<String> = withContext(Dispatchers.IO) { RunAnywhereBridge.loadLibrary() - return RunAnywhereBridge.nativeGetAvailableBackends().toList() + RunAnywhereBridge.nativeGetAvailableBackends().toList() }examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/TranscriptionViewModel.kt (1)
169-206: Scaffold implementation with extensive TODOs.The transcription control methods contain substantial placeholder logic. While the state transitions are implemented, the actual audio capture and pipeline integration remain stubbed. This is acceptable for a draft PR, but ensure these TODOs are tracked.
Would you like me to open an issue to track the completion of the audio pipeline integration, including:
- Microphone permission handling
- ModularPipelineConfig integration
- Audio capture stream processing
sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/RunAnywhereBridge.kt (1)
28-49: Swallowed exceptions should log for debugging.The catch blocks at lines 35 and 41 intentionally swallow
UnsatisfiedLinkErrorfor optional/pre-loaded dependencies, but silent failures can make debugging difficult. Consider adding debug logging.try { System.loadLibrary("runanywhere_bridge") } catch (e: UnsatisfiedLinkError) { // May already be loaded or linked statically + // Log at debug level for troubleshooting + android.util.Log.d("RunAnywhereBridge", "runanywhere_bridge not loaded separately: ${e.message}") } try { System.loadLibrary("onnxruntime") } catch (e: UnsatisfiedLinkError) { // May already be loaded + android.util.Log.d("RunAnywhereBridge", "onnxruntime not loaded separately: ${e.message}") }Note: Since this is in
jvmAndroidMain, you may want to use a platform-agnostic logging approach orprintlnfor JVM compatibility.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (29)
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/MainActivity.kt(0 hunks)examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/chat/ChatScreen.kt(4 hunks)examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/chat/ChatViewModel.kt(0 hunks)examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/navigation/AppNavigation.kt(6 hunks)examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/settings/SettingsScreen.kt(1 hunks)examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/settings/SettingsViewModel.kt(1 hunks)examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/storage/StorageViewModel.kt(1 hunks)examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/stt/SpeechToTextScreen.kt(1 hunks)examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/stt/SpeechToTextViewModel.kt(1 hunks)examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/tts/TextToSpeechScreen.kt(1 hunks)examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/tts/TextToSpeechViewModel.kt(1 hunks)examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/TranscriptionScreen.kt(5 hunks)examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/TranscriptionViewModel.kt(1 hunks)examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/VoiceAssistantScreen.kt(11 hunks)examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/VoiceAssistantViewModel.kt(3 hunks)examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/ui/theme/Color.kt(0 hunks)examples/flutter/RunAnywhereAI/ios/Flutter/Generated.xcconfig(1 hunks)examples/flutter/RunAnywhereAI/ios/Flutter/flutter_export_environment.sh(1 hunks)sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts(1 hunks)sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/proguard-rules.pro(1 hunks)sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/BridgeResults.kt(1 hunks)sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/Capability.kt(1 hunks)sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreService.kt(1 hunks)sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreServiceImpl.kt(1 hunks)sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/RunAnywhereBridge.kt(1 hunks)sdk/runanywhere-kotlin/settings.gradle.kts(1 hunks)sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/components/stt/STTComponent.kt(1 hunks)sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/components/stt/STTModels.kt(1 hunks)sdk/runanywhere-swift/ARCHITECTURE.md(1 hunks)
💤 Files with no reviewable changes (3)
- examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/MainActivity.kt
- examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/chat/ChatViewModel.kt
- examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/ui/theme/Color.kt
🧰 Additional context used
📓 Path-based instructions (3)
sdk/runanywhere-kotlin/**/src/**/*.kt
📄 CodeRabbit inference engine (CLAUDE.md)
sdk/runanywhere-kotlin/**/src/**/*.kt: All business logic, protocols, interfaces, and structures MUST be defined incommonMain/for Kotlin Multiplatform projects. Platform-specific implementations must use clear prefixes likeAndroidTTSService.kt,JvmTTSService.kt, etc.
NEVER make assumptions when implementing KMP code. ALWAYS refer to the iOS implementation as the definitive source of truth. Check the iOS implementation, copy the logic exactly, and adapt only for Kotlin syntax.
Useexpect/actualONLY for platform-specific implementations, not for business logic. Put all business logic incommonMain/.
Use Flow instead of AsyncSequence for reactive streams in Kotlin Multiplatform code.
Use coroutines and suspend functions instead of async/await patterns for asynchronous operations.
Use sealed classes for type-safe error handling in Kotlin code.
Always use data classes and structured types (enums, sealed classes) instead of strings for models and configuration.
Use theModuleRegistryprovider pattern for extensibility and plugin architecture instead of hard-coded dependencies.
Use EventBus for component communication instead of direct coupling between components.
Use Service Container pattern for centralized dependency injection with lazy initialization.
Use lazy initialization for service dependencies to avoid memory pressure and allow garbage collection.
Files:
sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/BridgeResults.ktsdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/components/stt/STTModels.ktsdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/components/stt/STTComponent.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/Capability.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreServiceImpl.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreService.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/RunAnywhereBridge.kt
sdk/runanywhere-kotlin/**/src/**/components/**/*.kt
📄 CodeRabbit inference engine (CLAUDE.md)
Implement proper component lifecycle management with initialization, state tracking, and cleanup in BaseComponent.
Files:
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/components/stt/STTModels.ktsdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/components/stt/STTComponent.kt
sdk/runanywhere-kotlin/**/*.gradle.kts
📄 CodeRabbit inference engine (CLAUDE.md)
sdk/runanywhere-kotlin/**/*.gradle.kts: Kotlin version must be 2.1.21 or later for the Kotlin Multiplatform SDK.
JVM target must be 17 or later for Kotlin Multiplatform SDK.
Android minSdk must be 24 or later for Kotlin Multiplatform SDK.
Files:
sdk/runanywhere-kotlin/settings.gradle.ktssdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts
🧠 Learnings (17)
📓 Common learnings
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/androidMain/**/*.kt : Use platform-specific optimizations in their respective source directories: `androidMain/` for Android optimizations, `jvmMain/` for JVM optimizations.
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Use coroutines and suspend functions instead of async/await patterns for asynchronous operations.
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Use the `ModuleRegistry` provider pattern for extensibility and plugin architecture instead of hard-coded dependencies.
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/components/**/*.kt : Implement proper component lifecycle management with initialization, state tracking, and cleanup in BaseComponent.
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/jvmMain/**/*.kt : Use platform-specific optimizations in their respective source directories: `androidMain/` for Android optimizations, `jvmMain/` for JVM optimizations.
📚 Learning: 2025-11-26T22:49:40.343Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Use sealed classes for type-safe error handling in Kotlin code.
Applied to files:
sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/BridgeResults.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/Capability.kt
📚 Learning: 2025-11-26T22:49:40.343Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : All business logic, protocols, interfaces, and structures MUST be defined in `commonMain/` for Kotlin Multiplatform projects. Platform-specific implementations must use clear prefixes like `AndroidTTSService.kt`, `JvmTTSService.kt`, etc.
Applied to files:
sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/BridgeResults.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.ktssdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreServiceImpl.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreService.kt
📚 Learning: 2025-11-26T22:49:40.343Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/components/**/*.kt : Implement proper component lifecycle management with initialization, state tracking, and cleanup in BaseComponent.
Applied to files:
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/settings/SettingsScreen.ktexamples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/storage/StorageViewModel.ktexamples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/settings/SettingsViewModel.ktsdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/components/stt/STTComponent.kt
📚 Learning: 2025-11-26T22:49:40.343Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Use the `ModuleRegistry` provider pattern for extensibility and plugin architecture instead of hard-coded dependencies.
Applied to files:
sdk/runanywhere-kotlin/settings.gradle.ktssdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.ktssdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreServiceImpl.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/RunAnywhereBridge.kt
📚 Learning: 2025-11-26T22:49:40.343Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/androidMain/**/*.kt : Use platform-specific optimizations in their respective source directories: `androidMain/` for Android optimizations, `jvmMain/` for JVM optimizations.
Applied to files:
sdk/runanywhere-kotlin/settings.gradle.ktssdk/runanywhere-kotlin/modules/runanywhere-core-onnx/proguard-rules.prosdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.ktssdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreServiceImpl.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/RunAnywhereBridge.kt
📚 Learning: 2025-11-26T22:49:40.343Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/jvmMain/**/*.kt : Use platform-specific optimizations in their respective source directories: `androidMain/` for Android optimizations, `jvmMain/` for JVM optimizations.
Applied to files:
sdk/runanywhere-kotlin/settings.gradle.ktssdk/runanywhere-kotlin/modules/runanywhere-core-onnx/proguard-rules.prosdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.ktssdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreServiceImpl.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/RunAnywhereBridge.kt
📚 Learning: 2025-11-26T22:49:40.343Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/*.gradle.kts : Android minSdk must be 24 or later for Kotlin Multiplatform SDK.
Applied to files:
sdk/runanywhere-kotlin/settings.gradle.ktssdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts
📚 Learning: 2025-11-26T22:49:40.343Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/*.gradle.kts : Kotlin version must be 2.1.21 or later for the Kotlin Multiplatform SDK.
Applied to files:
sdk/runanywhere-kotlin/settings.gradle.ktssdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts
📚 Learning: 2025-11-26T22:49:40.343Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/*.gradle.kts : JVM target must be 17 or later for Kotlin Multiplatform SDK.
Applied to files:
sdk/runanywhere-kotlin/settings.gradle.ktssdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts
📚 Learning: 2025-10-17T22:19:36.568Z
Learnt from: shubhammalhotra28
Repo: RunanywhereAI/runanywhere-sdks PR: 119
File: README.md:176-176
Timestamp: 2025-10-17T22:19:36.568Z
Learning: The RunAnywhere SDK package repository is located at `https://github.com/RunanywhereAI/runanywhere-sdks`. The repository was moved from `sdks` to `runanywhere-sdks`, so the correct URL to reference in documentation and installation instructions is `https://github.com/RunanywhereAI/runanywhere-sdks`.
Applied to files:
sdk/runanywhere-swift/ARCHITECTURE.md
📚 Learning: 2025-11-26T22:49:40.343Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-swift/**/Package.swift : Swift minimum version must be 5.9 or later for iOS SDK.
Applied to files:
sdk/runanywhere-swift/ARCHITECTURE.md
📚 Learning: 2025-11-26T22:49:40.343Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Use Service Container pattern for centralized dependency injection with lazy initialization.
Applied to files:
sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.ktsexamples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/storage/StorageViewModel.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreServiceImpl.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreService.kt
📚 Learning: 2025-11-26T22:49:40.343Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Use `expect/actual` ONLY for platform-specific implementations, not for business logic. Put all business logic in `commonMain/`.
Applied to files:
sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.ktssdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreService.kt
📚 Learning: 2025-11-26T22:49:40.343Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Always use data classes and structured types (enums, sealed classes) instead of strings for models and configuration.
Applied to files:
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/storage/StorageViewModel.ktexamples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/settings/SettingsViewModel.kt
📚 Learning: 2025-11-26T22:49:40.343Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Use lazy initialization for service dependencies to avoid memory pressure and allow garbage collection.
Applied to files:
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/storage/StorageViewModel.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreServiceImpl.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreService.kt
📚 Learning: 2025-11-26T22:49:40.343Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.343Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Use coroutines and suspend functions instead of async/await patterns for asynchronous operations.
Applied to files:
sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreServiceImpl.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreService.kt
🧬 Code graph analysis (3)
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/tts/TextToSpeechScreen.kt (1)
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/settings/SettingsScreen.kt (1)
formatBytes(671-678)
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/VoiceAssistantViewModel.kt (1)
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/TranscriptionViewModel.kt (1)
subscribeToModelLifecycle(139-149)
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/VoiceAssistantScreen.kt (1)
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/chat/ChatScreen.kt (1)
ModelBadge(561-606)
🪛 detekt (1.23.8)
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/settings/SettingsScreen.kt
[warning] 90-90: String.format("%.2f", uiState.temperature) uses implicitly default locale for string formatting.
(detekt.potential-bugs.ImplicitDefaultLocale)
[warning] 674-674: String.format("%.1f KB", bytes / 1024.0) uses implicitly default locale for string formatting.
(detekt.potential-bugs.ImplicitDefaultLocale)
[warning] 675-675: String.format("%.1f MB", bytes / (1024.0 * 1024.0)) uses implicitly default locale for string formatting.
(detekt.potential-bugs.ImplicitDefaultLocale)
[warning] 676-676: String.format("%.1f GB", bytes / (1024.0 * 1024.0 * 1024.0)) uses implicitly default locale for string formatting.
(detekt.potential-bugs.ImplicitDefaultLocale)
sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/RunAnywhereBridge.kt
[warning] 35-35: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
[warning] 41-41: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
🪛 markdownlint-cli2 (0.18.1)
sdk/runanywhere-swift/ARCHITECTURE.md
11-11: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
26-26: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
69-69: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
134-134: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
394-394: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
506-506: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (swift)
🔇 Additional comments (43)
sdk/runanywhere-swift/ARCHITECTURE.md (2)
87-124: Swift code examples are well-structured and aligned with SDK architecture.The usage patterns shown for consuming the C API via
CRunAnywhereONNXmodule and the async/await handling match best practices outlined in the learnings for Kotlin (coroutines/suspend functions carry over conceptually to Swift concurrency).
167-185: ModuleRegistry pattern aligns with learnings on plugin architecture.The provider registry implementation for STT/TTS/VAD/LLM backends matches the
ModuleRegistrypattern referenced in learnings for extensibility and pluggable architecture. Priority-based provider selection is a clean design choice.examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/tts/TextToSpeechScreen.kt (1)
40-46: Good lifecycle-aware state collection.Using
collectAsStateWithLifecycleensures proper lifecycle handling and prevents unnecessary recompositions when the screen is not visible.examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/tts/TextToSpeechViewModel.kt (1)
53-59: Well-structured ViewModel with proper state management.Good use of
MutableStateFlowwithasStateFlow()for encapsulation, and proper cleanup inonCleared(). The playback job management pattern is appropriate for managing the simulated playback lifecycle.examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/VoiceAssistantViewModel.kt (1)
17-25: Good use of enum with computed properties.
ModelLoadStateenum withisLoadedandisLoadingcomputed properties provides a clean API for state checking without exposing implementation details.examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/storage/StorageViewModel.kt (1)
56-65: Well-structured ViewModel following data class guidelines.Good use of data classes (
StoredModelInfo,StorageUiState) for structured types as per coding guidelines. The StateFlow pattern and error handling are properly implemented.sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/components/stt/STTComponent.kt (1)
381-394: Perfect! I've completed the verification. Let me provide the rewritten review comment:
STTMode enum properly defined and accessible—implementation is solid.
The new
supportsStreamingandrecommendedModeproperties provide a clean public API for querying service capabilities. The safe navigation with fallback defaults (?: false) ensures robustness when the service is not yet initialized.Both
STTComponent.ktandSTTModeenum (defined inSTTModels.kt) are in the same package (com.runanywhere.sdk.components.stt), soSTTModeis automatically accessible without explicit imports. The enum includes all necessary utilities:BATCHandLIVEvalues, computed properties (displayName,description,icon), and a factory method (fromValue()).sdk/runanywhere-kotlin/settings.gradle.kts (1)
44-47: LGTM!The new module inclusion follows the same unconditional pattern as other core modules (whisperkit, llm-llamacpp, llm-mlc). The comments clearly document the module's purpose as an ONNX Runtime backend via JNI, analogous to Swift's
CRunAnywhereONNX.sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/components/stt/STTModels.kt (1)
75-81: LGTM!The
fromValue()factory method correctly usesentries.find()(Kotlin 1.9+) and returns a nullable type for graceful handling of unknown values.sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/BridgeResults.kt (2)
39-45: LGTM - design is appropriate for bridge-level exceptions.While coding guidelines recommend sealed classes for error handling, this exception wraps
ResultCodewhich provides type-safe error categorization. A sealed hierarchy would add complexity without benefit at the JNI bridge layer.
7-28: LGTM!Correctly implements
equals()andhashCode()usingcontentEquals()andcontentHashCode()for theFloatArrayfield - essential for proper data class behavior with array types.examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/TranscriptionScreen.kt (3)
26-30: LGTM - improved naming consistency.The state variable renaming (
isRecording→isTranscribing,error→errorMessage) better reflects the actual UI state semantics and aligns with the ViewModel API.
74-99: LGTM!Recording controls correctly use the updated ViewModel methods (
startTranscription/stopTranscription/clearTranscripts) and properly toggle based onisTranscribingstate.
182-211: LGTM!Error display correctly handles the nullable
errorMessagestate and provides a dismiss action viaclearError().examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/chat/ChatScreen.kt (4)
262-284: LGTM - Sheet integration follows iOS patterns.The conversation list sheet correctly integrates with
ConversationStoreviaLocalContext, handles selection/creation/deletion callbacks, and properly dismisses on interaction completion.
1027-1036: LGTM!Search filtering correctly uses case-insensitive matching on both conversation title and message content, with proper null-safety for the optional title.
1320-1365: LGTM - Analytics calculations are defensive.The performance summary correctly handles edge cases:
takeIf { !it.isNaN() }guards against empty list averages, andsumOfsafely returns 0 for empty collections.
1438-1520: LGTM!
MessageAnalyticsCardprovides a clean, information-dense display of per-message analytics with proper formatting and conditional thinking mode indicator.examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/settings/SettingsScreen.kt (1)
646-651: Clarify or verify the "stored securely" claim.The text states "Your API key is stored securely," but this depends on the ViewModel's implementation. Ensure the API key is actually stored using Android's EncryptedSharedPreferences or Keystore. If not yet implemented, consider rewording to avoid misleading users.
sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/proguard-rules.pro (1)
1-35: LGTM!The ProGuard rules appropriately preserve JNI-related classes, native methods, and the public API surface. Keeping all members for JNI bridge classes and result types is correct since JNI accesses fields by name/reflection.
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/stt/SpeechToTextScreen.kt (1)
44-218: Overall implementation looks good.The STT screen follows the iOS reference pattern well, with clear separation of concerns between the main screen, status banner, mode selector, recording button, and transcription display. The UI states are handled appropriately.
sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts (2)
68-73: Build configuration fully complies with all SDK requirements.Verification confirms:
- Kotlin version: 2.1.21 ✓ (from
libs.versions.toml, meets requirement of 2.1.21 or later)- JVM target: 17 ✓ (lines 23, 29, 114-115 in build.gradle.kts)
- Android minSdk: 24 ✓ (line 73 in build.gradle.kts)
The build configuration meets all Kotlin Multiplatform SDK guidelines.
36-38: The suggested fix is incorrect and would break the build.The project path
:runanywhere-kotlindoes not exist insettings.gradle.kts. The root project is registered as"RunAnywhereKotlinSDK", and modules are included as:modules:runanywhere-core-onnx, not:runanywhere-kotlin.The current pattern
api(project.parent!!.parent!!)is correct and follows standard Gradle multiproject conventions. The structure (module → modules directory → root) is guaranteed bysettings.gradle.kts, making the!!operator appropriate. This pattern is consistently used across other modules (runanywhere-llm-llamacpp,runanywhere-llm-mlc), and an alternative patternapi(project(":"))is used inrunanywhere-whisperkit, both achieving the same result.No changes are needed.
Likely an incorrect or invalid review comment.
sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/Capability.kt (2)
24-38: LGTM!The
DeviceTypeenum correctly maps to native values with a sensible CPU default for unrecognized values.
44-63: LGTM!Good design with negative error codes, the
isSuccessconvenience property, and a safe default toERROR_UNKNOWNfor unrecognized values.examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/stt/SpeechToTextViewModel.kt (7)
25-29: LGTM!Clear state enum for the recording state machine.
35-46: LGTM!Well-structured data class with sensible defaults for all fields.
98-135: LGTM!Good state management pattern with proper error handling. The mock implementation is clearly marked with TODOs for future SDK integration.
143-151: LGTM!Correct state machine pattern for toggling recording. The empty
PROCESSINGbranch appropriately prevents state changes during processing.
159-179: LGTM!Clear state transitions with appropriate placeholders for future audio capture integration.
187-223: LGTM!Proper state management with error handling that correctly resets to
IDLEstate on failure.
230-263: LGTM!Clean implementation of helper methods with consistent state update patterns.
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/navigation/AppNavigation.kt (3)
36-72: LGTM!Clean Scaffold-based navigation with proper NavHost configuration. The 5-tab structure aligns with the iOS reference.
170-186: LGTM!Clean route constants and data class for navigation items.
84-163: AppColors.primaryBlue is properly defined and available for use.The
primaryBluecolor constant (value0xFF007AFF) is correctly defined inAppColors.ktat line 16 and properly imported in theAppNavigation.ktfile. The implementation follows consistent patterns across the codebase.examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/settings/SettingsViewModel.kt (3)
16-21: LGTM!Good use of enum with both display name and raw value for serialization, following coding guidelines for structured types.
27-69: LGTM!Well-structured data classes with appropriate types and defaults. Good separation of concerns between model metadata and UI state.
91-185: LGTM!Good initialization pattern with proper loading state management in
loadStorageData(). The mock implementations are clearly marked for future SDK integration.sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreService.kt (1)
27-235: LGTM!Excellent API design following KMP best practices:
expectclass incommonMainwith platform-specificactualimplementations- Consistent use of
suspendfunctions for async operations (per coding guidelines)- Structured return types (
TTSSynthesisResult,VADResult) instead of raw primitives- Clear capability groupings (STT, TTS, VAD, Embedding)
- Comprehensive KDoc with usage example
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/TranscriptionViewModel.kt (2)
25-44: Well-structured data classes with serialization support.Good use of
@Serializabledata classes matching the iOS structure. The default values foridandtimestampprovide sensible defaults while keeping the classes flexible.
91-94:ModelLoadStateis properly accessible without an explicit import.Both
TranscriptionViewModel.ktandVoiceAssistantViewModel.ktare in the same package (com.runanywhere.runanywhereai.presentation.voice). In Kotlin, symbols defined in the same package are automatically accessible, so no import statement is required. The code at lines 91-94 will compile without issues.sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/bridge/RunAnywhereBridge.kt (2)
56-125: Well-organized JNI bindings with comprehensive documentation.The backend lifecycle bindings are well-documented with clear parameter descriptions and return value semantics. The use of
@JvmStaticis correct for JNI external functions.
191-226: STT streaming API bindings look complete.The streaming STT API (
nativeSTTCreateStream,nativeSTTFeedAudio,nativeSTTDecode, etc.) provides a comprehensive interface for real-time transcription. The documentation note about destroying stream handles on the creation thread is important—consider adding this to the individual method KDoc as well.
...I/app/src/main/java/com/runanywhere/runanywhereai/presentation/settings/SettingsViewModel.kt
Show resolved
Hide resolved
| ModelStatusBannerSTT( | ||
| framework = uiState.selectedFramework, | ||
| modelName = uiState.selectedModelName, | ||
| isLoading = uiState.recordingState == RecordingState.PROCESSING && uiState.selectedModelName == null, | ||
| onSelectModel = { showModelPicker = true } | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unusual loading state condition.
The isLoading condition checks recordingState == RecordingState.PROCESSING && selectedModelName == null. This seems contradictory—how can processing occur without a model loaded? This may cause the loading indicator to never display as intended.
Consider revising the condition. If you want to show loading during model initialization:
ModelStatusBannerSTT(
framework = uiState.selectedFramework,
modelName = uiState.selectedModelName,
- isLoading = uiState.recordingState == RecordingState.PROCESSING && uiState.selectedModelName == null,
+ isLoading = uiState.isModelLoading, // Add a dedicated loading state to ViewModel
onSelectModel = { showModelPicker = true }
)Or clarify the intended behavior if this condition is correct.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/stt/SpeechToTextScreen.kt
around lines 73 to 78, the isLoading condition uses && which only shows loading
when processing and no model is selected (contradictory); change the condition
to use || so the banner shows when either processing is happening or when no
model is selected (i.e., isLoading = recordingState == RecordingState.PROCESSING
|| selectedModelName == null) to reflect intended loading behavior during model
initialization or processing.
| enum class STTMode { | ||
| BATCH, // Record full audio then transcribe | ||
| LIVE // Real-time streaming transcription | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for all STTMode enum definitions
rg -n "enum class STTMode" --type=kotlinRepository: RunanywhereAI/runanywhere-sdks
Length of output: 354
🏁 Script executed:
#!/bin/bash
# Also search for STTMode references more broadly
rg -n "STTMode" --type=kotlin -C2Repository: RunanywhereAI/runanywhere-sdks
Length of output: 22038
🏁 Script executed:
#!/bin/bash
# Find STTModels.kt file mentioned in the AI summary
fd "STTModels.kt" --type fRepository: RunanywhereAI/runanywhere-sdks
Length of output: 166
🏁 Script executed:
#!/bin/bash
# Read the SpeechToTextViewModel.kt file to see imports and full definition
cat -n "examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/stt/SpeechToTextViewModel.kt" 2>/dev/null || echo "File not found, searching for it..."Repository: RunanywhereAI/runanywhere-sdks
Length of output: 10122
🏁 Script executed:
#!/bin/bash
# Search for the file if the direct path doesn't work
fd "SpeechToTextViewModel.kt" --type fRepository: RunanywhereAI/runanywhere-sdks
Length of output: 194
🏁 Script executed:
#!/bin/bash
# Read SDK's STTModels.kt to see full definition
cat -n "sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/components/stt/STTModels.kt" | head -90Repository: RunanywhereAI/runanywhere-sdks
Length of output: 2957
🏁 Script executed:
#!/bin/bash
# Check package structure and exports in SDK
grep -n "^package\|^import\|^object\|^public" "sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/components/stt/STTModels.kt" | head -20Repository: RunanywhereAI/runanywhere-sdks
Length of output: 363
🏁 Script executed:
#!/bin/bash
# Check if app has any dependency on SDK in build files
fd "build.gradle\|build.gradle.kts" "examples/android" --type f | xargs grep -l "runanywhere" 2>/dev/null | head -3Repository: RunanywhereAI/runanywhere-sdks
Length of output: 56
🏁 Script executed:
#!/bin/bash
# Find and read app's build.gradle or build.gradle.kts
find examples/android -name "build.gradle.kts" -o -name "build.gradle" | head -5Repository: RunanywhereAI/runanywhere-sdks
Length of output: 173
🏁 Script executed:
#!/bin/bash
# Check the main app build file
cat examples/android/RunAnywhereAI/app/build.gradle.kts 2>/dev/null || cat examples/android/RunAnywhereAI/app/build.gradle 2>/dev/null | head -80Repository: RunanywhereAI/runanywhere-sdks
Length of output: 10405
🏁 Script executed:
#!/bin/bash
# Check if there's a settings.gradle that includes SDK modules
find examples/android -name "settings.gradle*" -exec cat {} \;Repository: RunanywhereAI/runanywhere-sdks
Length of output: 1441
Import STTMode from the SDK instead of redefining it locally.
The app already has sdk:runanywhere-kotlin as a dependency (build.gradle.kts line: implementation(project(":sdk:runanywhere-kotlin"))). The SDK's STTMode enum in STTModels.kt is richer—it includes serialization (value property), UI properties (displayName, description, icon), and a fromValue() companion function. Redefining it locally loses these features and creates maintenance burden.
Replace the local enum definition with an import:
import com.runanywhere.sdk.components.stt.STTModeRemove lines 12-19 from SpeechToTextViewModel.kt and update SpeechToTextScreen.kt to use the SDK's STTMode.
🤖 Prompt for AI Agents
In
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/stt/SpeechToTextViewModel.kt
around lines 16 to 19, the local STTMode enum is redefined; remove lines 12-19
to eliminate the duplicate definition, add an import for the SDK enum
(com.runanywhere.sdk.components.stt.STTMode) at the top of the file, and update
any usages in SpeechToTextViewModel and SpeechToTextScreen to reference the
SDK's STTMode (including using its value/displayName/description/icon or
fromValue() where appropriate) so the app uses the richer, serialized SDK type.
...AI/app/src/main/java/com/runanywhere/runanywhereai/presentation/tts/TextToSpeechViewModel.kt
Show resolved
Hide resolved
| // Initialize SDK | ||
| RunAnywhere.initialize( | ||
| apiKey = "demo-api-key", | ||
| baseURL = "https://api.runanywhere.ai", | ||
| environment = com.runanywhere.sdk.data.models.SDKEnvironment.DEVELOPMENT | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hardcoded API key should be externalized.
The hardcoded "demo-api-key" is acceptable for development, but ensure this doesn't ship to production. Consider using BuildConfig fields or a secure configuration mechanism.
// Example: Use BuildConfig for API key
RunAnywhere.initialize(
apiKey = BuildConfig.RUNANYWHERE_API_KEY,
baseURL = BuildConfig.RUNANYWHERE_BASE_URL,
environment = ...
)🤖 Prompt for AI Agents
In
examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/TranscriptionViewModel.kt
around lines 112-117, the API key is hardcoded ("demo-api-key"); replace it with
a configurable BuildConfig field (or other secure config) and update
app/build.gradle to define RUNANYWHERE_API_KEY and RUNANYWHERE_BASE_URL as
buildConfigField values for debug/release variants, then reference
BuildConfig.RUNANYWHERE_API_KEY and BuildConfig.RUNANYWHERE_BASE_URL in the
RunAnywhere.initialize call and ensure real production keys are injected via
CI/secrets and not committed to source control.
...app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/TranscriptionViewModel.kt
Show resolved
Hide resolved
...I/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/VoiceAssistantScreen.kt
Show resolved
Hide resolved
...I/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/VoiceAssistantScreen.kt
Show resolved
Hide resolved
| actual val isInitialized: Boolean | ||
| get() = backendHandle != 0L && RunAnywhereBridge.nativeIsInitialized(backendHandle) | ||
|
|
||
| actual val supportedCapabilities: List<Capability> | ||
| get() { | ||
| if (backendHandle == 0L) return emptyList() | ||
| return RunAnywhereBridge.nativeGetCapabilities(backendHandle) | ||
| .mapNotNull { Capability.fromValue(it) } | ||
| } | ||
|
|
||
| actual fun supportsCapability(capability: Capability): Boolean { | ||
| if (backendHandle == 0L) return false | ||
| return RunAnywhereBridge.nativeSupportsCapability(backendHandle, capability.value) | ||
| } | ||
|
|
||
| actual val deviceType: DeviceType | ||
| get() { | ||
| if (backendHandle == 0L) return DeviceType.CPU | ||
| return DeviceType.fromValue(RunAnywhereBridge.nativeGetDevice(backendHandle)) | ||
| } | ||
|
|
||
| actual val memoryUsage: Long | ||
| get() { | ||
| if (backendHandle == 0L) return 0 | ||
| return RunAnywhereBridge.nativeGetMemoryUsage(backendHandle) | ||
| } | ||
|
|
||
| actual fun destroy() { | ||
| if (backendHandle != 0L) { | ||
| RunAnywhereBridge.nativeDestroy(backendHandle) | ||
| backendHandle = 0 | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Race condition: property getters and destroy() access backendHandle without mutex protection.
The suspend functions correctly use mutex.withLock, but these property getters and destroy() read/write backendHandle without synchronization. This can lead to use-after-free if destroy() is called concurrently with another operation, or inconsistent reads during initialization.
Consider making destroy() a suspend function with mutex protection, and either:
- Mark the class as not thread-safe for property access, or
- Use
@VolatileonbackendHandlefor visibility guarantees on reads, and protectdestroy()with the mutex:
+ actual suspend fun destroy() {
+ withContext(Dispatchers.IO) {
+ mutex.withLock {
- actual fun destroy() {
- if (backendHandle != 0L) {
- RunAnywhereBridge.nativeDestroy(backendHandle)
- backendHandle = 0
- }
+ if (backendHandle != 0L) {
+ RunAnywhereBridge.nativeDestroy(backendHandle)
+ backendHandle = 0
+ }
+ }
+ }
}For property getters, if the expect declaration requires non-suspend properties, document the thread-safety contract clearly or use @Volatile:
+ @Volatile
private var backendHandle: Long = 0Committable suggestion skipped: line range outside the PR's diff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
29 files reviewed, 25 comments
| // This is a generated file; do not edit or check into version control. | ||
| FLUTTER_ROOT=/Users/programming.com/flutter | ||
| FLUTTER_APPLICATION_PATH=/Users/programming.com/Downloads/runanywhere-sdks-main/examples/flutter/RunAnywhereAI | ||
| FLUTTER_ROOT=/Users/sanchitmonga/flutter | ||
| FLUTTER_APPLICATION_PATH=/Users/sanchitmonga/development/ODLM/runanywhere-all/sdks/examples/flutter/RunAnywhereAI |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: This auto-generated file contains developer-specific local paths and should not be committed to version control. The comment on line 1 explicitly states this. Add ios/Flutter/Generated.xcconfig to .gitignore and remove this file from the repository.
Prompt To Fix With AI
This is a comment left during a code review.
Path: examples/flutter/RunAnywhereAI/ios/Flutter/Generated.xcconfig
Line: 1:3
Comment:
**logic:** This auto-generated file contains developer-specific local paths and should not be committed to version control. The comment on line 1 explicitly states this. Add `ios/Flutter/Generated.xcconfig` to .gitignore and remove this file from the repository.
How can I resolve this? If you propose a fix, please make it concise.| * Exception thrown when a RunAnywhere operation fails. | ||
| */ | ||
| class RunAnywhereException( | ||
| val resultCode: ResultCode, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: ResultCode enum is referenced but not defined - this will cause compilation errors
Prompt To Fix With AI
This is a comment left during a code review.
Path: sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/BridgeResults.kt
Line: 43:43
Comment:
**logic:** `ResultCode` enum is referenced but not defined - this will cause compilation errors
How can I resolve this? If you propose a fix, please make it concise.| @@ -1,14 +1,18 @@ | |||
| package com.runanywhere.runanywhereai.presentation.navigation | |||
|
|
|||
| import androidx.compose.foundation.background | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Import background is added but never used
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Prompt To Fix With AI
This is a comment left during a code review.
Path: examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/navigation/AppNavigation.kt
Line: 3:3
Comment:
**style:** Import `background` is added but never used
<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>
How can I resolve this? If you propose a fix, please make it concise.| modelStorageSize = state.downloadedModels | ||
| .filter { it.id != modelId } | ||
| .sumOf { it.size } | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Bug in modelStorageSize calculation - uses original list instead of filtered list. Should use the filtered models for size calculation.
| modelStorageSize = state.downloadedModels | |
| .filter { it.id != modelId } | |
| .sumOf { it.size } | |
| ) | |
| modelStorageSize = state.downloadedModels | |
| .filter { it.id != modelId } | |
| .sumOf { it.size } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/settings/SettingsViewModel.kt
Line: 278:281
Comment:
**logic:** Bug in modelStorageSize calculation - uses original list instead of filtered list. Should use the filtered models for size calculation.
```suggestion
modelStorageSize = state.downloadedModels
.filter { it.id != modelId }
.sumOf { it.size }
```
How can I resolve this? If you propose a fix, please make it concise.| val mockTranscription = when (_uiState.value.mode) { | ||
| STTMode.BATCH -> "This is a mock batch transcription. In production, this would be the actual transcribed text from the recorded audio using WhisperKit or ONNX Runtime models." | ||
| STTMode.LIVE -> "This is a mock live transcription. In production, this would show real-time streaming transcription results as you speak." | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: mock transcription strings are very long and could be extracted to constants for better maintainability
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Prompt To Fix With AI
This is a comment left during a code review.
Path: examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/stt/SpeechToTextViewModel.kt
Line: 204:207
Comment:
**style:** mock transcription strings are very long and could be extracted to constants for better maintainability
<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>
How can I resolve this? If you propose a fix, please make it concise.| /** | ||
| * Get device type being used. | ||
| */ | ||
| val deviceType: DeviceType |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
syntax: DeviceType is not defined - need to import or define this enum
Prompt To Fix With AI
This is a comment left during a code review.
Path: sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreService.kt
Line: 55:55
Comment:
**syntax:** `DeviceType` is not defined - need to import or define this enum
How can I resolve this? If you propose a fix, please make it concise.| voiceId: String? = null, | ||
| speedRate: Float = 1.0f, | ||
| pitchShift: Float = 0.0f | ||
| ): TTSSynthesisResult |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
syntax: TTSSynthesisResult is not defined - need to import or define this data class
Prompt To Fix With AI
This is a comment left during a code review.
Path: sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreService.kt
Line: 145:145
Comment:
**syntax:** `TTSSynthesisResult` is not defined - need to import or define this data class
How can I resolve this? If you propose a fix, please make it concise.| * @param sampleRate Sample rate | ||
| * @return VADResult with speech status and probability | ||
| */ | ||
| suspend fun processVAD(audioSamples: FloatArray, sampleRate: Int): VADResult |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
syntax: VADResult is not defined - need to import or define this data class
Prompt To Fix With AI
This is a comment left during a code review.
Path: sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/commonMain/kotlin/com/runanywhere/sdk/core/bridge/ONNXCoreService.kt
Line: 181:181
Comment:
**syntax:** `VADResult` is not defined - need to import or define this data class
How can I resolve this? If you propose a fix, please make it concise.| while (true) { | ||
| delay(100) | ||
| // Simulate audio level changes | ||
| val randomLevel = (Math.random() * 0.5f).toFloat() | ||
| _uiState.update { it.copy(audioLevel = randomLevel) } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Infinite while loop without cancellation handling could cause resource leaks if coroutine scope cleanup fails.
Prompt To Fix With AI
This is a comment left during a code review.
Path: examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/VoiceAssistantViewModel.kt
Line: 292:297
Comment:
**logic:** Infinite while loop without cancellation handling could cause resource leaks if coroutine scope cleanup fails.
How can I resolve this? If you propose a fix, please make it concise.| .background(MaterialTheme.colorScheme.surfaceVariant) | ||
| ) { | ||
| Icon( | ||
| imageVector = if (showModelInfo) Icons.Default.Info else Icons.Default.Info, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Icon vector condition uses same icon for both states
| imageVector = if (showModelInfo) Icons.Default.Info else Icons.Default.Info, | |
| imageVector = if (showModelInfo) Icons.Default.InfoOutlined else Icons.Default.Info, |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Prompt To Fix With AI
This is a comment left during a code review.
Path: examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/VoiceAssistantScreen.kt
Line: 571:571
Comment:
**style:** Icon vector condition uses same icon for both states
```suggestion
imageVector = if (showModelInfo) Icons.Default.InfoOutlined else Icons.Default.Info,
```
<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>
How can I resolve this? If you propose a fix, please make it concise.- Update build.gradle.kts to download pre-built native libs from GitHub releases - Add download-native-libs.sh script for manual downloads - Add VERSION file to track native library version - Add .gitignore to exclude downloaded jniLibs - Move generic bridge types to main SDK commonMain - Refactor ONNX module to use downloaded libraries by default Build modes: - Remote (default): Downloads from GitHub releases - Local: Uses locally built libs (-Prunanywhere.native.local=true) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Changed version from 0.0.1-dev to 0.0.1-dev.e2ac4eb to reflect the latest build metadata, ensuring accurate version tracking for the ONNX module.
|
@ellipsis review this pull request |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Caution
Changes requested ❌
Reviewed everything up to d608d01 in 4 minutes and 14 seconds. Click for details.
- Reviewed
8807lines of code in34files - Skipped
0files when reviewing. - Skipped posting
18draft comments. View those below. - Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/tts/TextToSpeechViewModel.kt:190
- Draft comment:
Mock delay (delay(2000)) is used to simulate TTS generation. Ensure you replace this with actual TTS synthesis integration before production. - Reason this comment was not posted:
Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% This comment is asking the author to "Ensure you replace this with actual TTS synthesis integration before production." This violates the rule about not asking the PR author to confirm, ensure, or double-check things. The code already has a TODO comment on line 185 saying "TODO: Replace with actual SDK integration" and line 190 explicitly labels it as "Mock speech generation delay". The entire file is clearly a work-in-progress with mock implementations, as evidenced by the numerous TODO comments throughout. The comment doesn't provide any new information or actionable code change - it's just restating what's already obvious from the code itself. Could this comment be valuable for someone who might miss all the TODO comments? Perhaps it's highlighting a specific production readiness concern that needs tracking? Even if someone missed the TODO comments, this comment doesn't provide an actionable code change - it's just asking the author to "ensure" something is done later. The rules explicitly state not to make comments that ask the author to ensure, verify, or confirm things. The existing TODO comments already serve as reminders for what needs to be implemented. This comment should be deleted. It violates the rule against asking the author to "ensure" things, and it's redundant with the existing TODO comment on line 185 and the explicit "Mock speech generation delay" comment on line 190. It doesn't suggest any specific code change.
2. examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/TranscriptionScreen.kt:133
- Draft comment:
Consider using a LazyColumn instead of a Box with verticalScroll for the transcript display to improve performance on long transcripts. - Reason this comment was not posted:
Comment was not on a location in the diff, so it can't be submitted as a review comment.
3. examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/VoiceAssistantScreen.kt:46
- Draft comment:
The VoiceAssistantScreen composable is quite lengthy. Consider refactoring it into smaller subcomponents to improve readability and maintainability. - Reason this comment was not posted:
Comment was not on a location in the diff, so it can't be submitted as a review comment.
4. examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/VoiceAssistantViewModel.kt:291
- Draft comment:
The infinite loop in startSession() (lines 291-297) may lead to resource issues if not properly cancelled. Ensure a robust cancellation mechanism is in place. - Reason this comment was not posted:
Comment looked like it was already resolved.
5. examples/flutter/RunAnywhereAI/ios/Flutter/Generated.xcconfig:2
- Draft comment:
This auto-generated configuration file contains user-specific absolute paths. Consider parameterizing these paths or removing them to avoid committing developer-specific settings. - Reason this comment was not posted:
Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% The file itself says "do not edit or check into version control" at line 1, which means this is an auto-generated file that shouldn't be committed at all. The comment is pointing out that user-specific paths are being committed, which is indeed happening in this PR. However, the real issue is that this entire file shouldn't be in version control in the first place. The comment is about changes that were made (the paths changed), so it is about the diff. But the comment is somewhat informative/advisory rather than actionable - it's asking the author to "consider" doing something. The rules state comments should not be purely informative and must clearly require a code change. This comment doesn't clearly state what action to take - should they gitignore the file? Should they revert the commit? It's vague. The comment does identify a real problem - user-specific paths are being committed to version control when the file itself says not to commit it. This could be considered actionable if the intent is to have the author add this file to .gitignore or revert the changes. The comment is about actual changes in the diff, not unchanged code. While the comment identifies a real issue, it uses weak language like "Consider" which makes it advisory rather than directive. The rules explicitly state comments should clearly require a code change, not be speculative or ask the author to consider things. The comment doesn't clearly state what action should be taken. Additionally, this is a generated file that the first line explicitly says should not be checked into version control, so this should probably be caught by standard practices or .gitignore configuration. The comment should be deleted. While it identifies that user-specific paths are being committed, it uses advisory language ("Consider") rather than being directive, and doesn't clearly specify what action to take. This type of issue (committing generated files) should be caught by standard development practices.
6. examples/flutter/RunAnywhereAI/ios/Flutter/flutter_export_environment.sh:3
- Draft comment:
The export script contains absolute paths that are specific to a developer’s environment. Consider using environment variables or relative paths to avoid potential configuration issues. - Reason this comment was not posted:
Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% The file header says "do not edit or check into version control" which means the real issue is that this file shouldn't be in the PR at all, not that the paths need to be changed. The comment is addressing a symptom rather than the root cause. However, according to the rules, I should not comment on things that are obvious or that would be caught by standard practices. The file itself already warns not to check it in. Additionally, the comment doesn't provide a clear, actionable fix - it says "consider using environment variables or relative paths" but this is a generated file, so the developer can't really change how it's structured. The comment is somewhat useful but not actionable given the nature of the file. The comment does identify a real problem (developer-specific paths in version control), and maybe the reviewer intended to suggest that the file should be gitignored rather than suggesting code changes. Perhaps I'm being too strict in interpreting the actionability of the comment. While the comment identifies a real issue, it suggests changing the content of the file ("use environment variables or relative paths") rather than the more appropriate action (don't commit this generated file). The file's own header already warns against checking it into version control, making this comment somewhat redundant. The suggested fix is also not actionable since this is a generated file. The comment should be deleted. It's commenting on a generated file that explicitly states it should not be checked into version control. The suggested fix (using environment variables or relative paths) is not actionable since developers don't control the content of generated files. The real issue is that the file shouldn't be committed at all, which is already stated in the file header.
7. sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts:32
- Draft comment:
The build script handles downloading pre-built native libraries. Ensure that network issues and version mismatches are properly handled in CI environments. - Reason this comment was not posted:
Comment did not seem useful. Confidence is useful =0%<= threshold50%This comment is asking the PR author to ensure that network issues and version mismatches are handled, which is a form of asking them to double-check things. It doesn't provide a specific suggestion or point out a specific issue in the code.
8. sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/proguard-rules.pro:9
- Draft comment:
Ensure that these ProGuard keep rules stay updated with any changes in package names or class restructuring to avoid runtime issues. - Reason this comment was not posted:
Comment did not seem useful. Confidence is useful =0%<= threshold50%The comment is asking the PR author to ensure that ProGuard keep rules are updated with changes in package names or class restructuring. This is a general reminder to maintain compatibility, which falls under the rule of not asking the author to ensure behavior is intended or tested. It doesn't provide a specific suggestion or point out a specific issue in the code.
9. sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/scripts/download-native-libs.sh:124
- Draft comment:
The download script verifies checksums which is good. Consider adding timeout handling and more robust error messages for network failures. - Reason this comment was not posted:
Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% This is a new file being added (the entire script is new). The comment is about line 104 where curl downloads a file. The script already has error handling - it captures HTTP codes, checks for failures, and provides detailed error messages (lines 106-118). The comment suggests "consider adding timeout handling and more robust error messages" but doesn't specify what's missing or inadequate about the current implementation. This feels like a speculative suggestion rather than identifying a concrete problem. The error messages are already quite detailed. While adding a timeout flag to curl might be a valid enhancement, the comment doesn't clearly articulate why it's necessary or what specific problem it solves. This violates the rule about not making speculative comments and being actionable. The script does handle network failures and provides error messages, but perhaps the comment has merit - curl without a timeout could hang indefinitely on slow networks. Maybe the error messages could distinguish between different types of failures (timeout vs 404 vs network unreachable). The comment might be pointing to a legitimate improvement even if not perfectly articulated. While timeouts could be useful, the comment doesn't identify a specific problem with the current implementation. The error handling is already present and reasonably robust. The comment is too vague ("consider adding", "more robust") without explaining what's inadequate. This is a suggestion for potential improvement rather than identifying a clear issue that needs fixing. This comment should be deleted. It's a vague, speculative suggestion that doesn't identify a concrete problem with the code. The script already has error handling and detailed error messages. The comment doesn't provide actionable guidance on what specifically needs to be improved or why.
10. sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/ONNXCoreService.kt:112
- Draft comment:
Ensure that backend destruction and cleanup in ONNXCoreService are robust. Consider adding logging for memory usage changes to aid performance debugging. - Reason this comment was not posted:
Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% This comment violates multiple rules. First, it starts with "Ensure that..." which is explicitly called out as a pattern to avoid in the rules. Second, it uses "Consider adding..." which is speculative and not pointing to a definite issue. The destroy() method appears straightforward - it checks the handle and calls the native destroy function. Without evidence of a specific bug or issue (like missing mutex protection, or a race condition), this is just a general suggestion. The comment doesn't point to any specific problem with the current implementation. The logging suggestion is also not about fixing a bug, but about adding optional debugging features. Could there be a legitimate concern about thread safety in the destroy method? I notice other methods use mutex.withLock, but destroy() doesn't. That could be a real issue if destroy() is called concurrently with other operations. However, the comment doesn't specifically mention this - it just vaguely says "ensure robustness" and suggests adding logging. While there might be a legitimate thread safety concern with the destroy() method not using the mutex, the comment doesn't identify this specific issue. Instead, it makes vague statements about "ensuring robustness" and suggests optional logging. If the tool had identified the specific mutex issue, that would be actionable, but this generic comment doesn't meet that bar. This comment should be deleted. It violates the "Ensure that..." rule and makes vague, non-actionable suggestions. It doesn't identify a specific code problem that needs to be fixed. The logging suggestion is optional and not a required change.
11. sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/RunAnywhereBridge.kt:25
- Draft comment:
The RunAnywhereBridge object’s external declarations rely on native libraries. Validate that all required native libraries are packaged and loaded correctly in all target environments. - Reason this comment was not posted:
Comment did not seem useful. Confidence is useful =0%<= threshold50%This comment is asking the PR author to validate that native libraries are packaged and loaded correctly, which falls under the rule of not asking the author to ensure behavior is intended or to double-check things. It doesn't provide a specific code suggestion or point out a specific issue.
12. sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/components/stt/STTComponent.kt:35
- Draft comment:
STTComponent relies on a registered provider from ModuleRegistry. Ensure that STT service providers are properly registered and handle model management robustly. - Reason this comment was not posted:
Comment was not on a location in the diff, so it can't be submitted as a review comment.
13. sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/components/stt/STTModels.kt:105
- Draft comment:
STTOptions parameters align well with iOS. Consider adding extra validation for newly added parameters if not already enforced elsewhere. - Reason this comment was not posted:
Comment was not on a location in the diff, so it can't be submitted as a review comment.
14. sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/BridgeResults.kt:11
- Draft comment:
The equals and hashCode implementations for NativeTTSSynthesisResult are correctly implemented to handle array comparisons. - Reason this comment was not posted:
Comment did not seem useful. Confidence is useful =0%<= threshold50%This comment is purely informative, as it simply states that theequalsandhashCodeimplementations are correctly implemented. It does not provide any actionable feedback or suggestions for improvement.
15. sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/Capability.kt:1
- Draft comment:
The enums for NativeCapability, NativeDeviceType, and NativeResultCode are well defined and map directly to native types. This consistency is excellent. - Reason this comment was not posted:
Comment did not seem useful. Confidence is useful =0%<= threshold50%This comment is purely informative and does not provide any actionable feedback or suggestions for improvement. It simply praises the existing code without offering any constructive criticism or guidance.
16. sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/NativeCoreService.kt:27
- Draft comment:
The NativeCoreService interface provides a comprehensive abstraction for native backends. Verify that all implementations adhere strictly to this contract. - Reason this comment was not posted:
Comment did not seem useful. Confidence is useful =0%<= threshold50%The comment is asking the PR author to verify adherence to an interface contract, which falls under asking the author to double-check or ensure something. This violates the rules.
17. examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/TranscriptionScreen.kt:182
- Draft comment:
Typographical Notice: The variable naming in the error display section is inconsistent. Previously, the nullable error variable was named 'error' (usingerror?.let { errorMessage -> ... }), but in the new change it's renamed to 'errorMessage' and then the lambda parameter is called 'error'. This swap of names can lead to confusion. Consider using consistent variable names (e.g., either always 'error' or 'errorMessage'). - Reason this comment was not posted:
Comment looked like it was already resolved.
18. sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts:8
- Draft comment:
Typographical error: In the comment on line 8, "RunAnywhareBridge" appears to be a typo. It should likely read "RunAnywhereBridge". - Reason this comment was not posted:
Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% This is a typo in a documentation comment. The rules state "Do NOT comment unless there is clearly a code change required" and "Do NOT make comments that are obvious or unimportant." While this is technically a typo, it's in a comment/documentation, not in actual code. The typo doesn't affect functionality at all - it's purely cosmetic in documentation. The rules emphasize not making obvious or unimportant comments. A single-letter typo in a comment explaining architecture seems like it falls into the "unimportant" category. However, the comment does suggest a clear, actionable fix. But given the emphasis on only keeping comments with STRONG EVIDENCE they are correct and important, a documentation typo seems too minor. While the typo is real and the fix is correct, documentation typos are generally low-priority and might be considered "obvious or unimportant" per the rules. The comment doesn't affect code functionality, and the author likely knows their own naming conventions. This might be too pedantic for a PR review. That's a fair point. This is purely a cosmetic issue in documentation that has zero impact on functionality. While technically correct, it's the kind of minor issue that doesn't warrant blocking or cluttering a PR review. The rules explicitly say not to make obvious or unimportant comments, and a single-letter typo in a comment qualifies as unimportant. This comment should be deleted. While the typo is real, it's a minor cosmetic issue in documentation that doesn't affect functionality. The rules emphasize not making obvious or unimportant comments, and a single-letter typo in a comment falls into that category.
Workflow ID: wflow_b7PRe6bCISsnZ5fW
You can customize by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.
|
|
||
| // MARK: - SDK Event Observation | ||
|
|
||
| private fun observeSDKEvents() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function observeSDKEvents() is defined but never invoked. Consider invoking it to handle SDK events for transcription.
…timation utilities - Added TokenCounter object for accurate token counting in text, mirroring iOS functionality. - Introduced methods for estimating tokens, calculating tokens per second, and splitting token counts in TokenCounter. - Updated RunAnywhereSDK interface to include token estimation methods, aligning with iOS SDK. - Added GenerationResult and StreamingResult models for structured output and streaming generation, including performance metrics and validation results. This commit enhances the SDK's capabilities for text generation and token management, improving overall functionality and user experience.
|
@ellipsis please review |
|
@sanchitmonga22: I'll review the changes in this pull request right away. ✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🧹 Nitpick comments (9)
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/models/GenerationResult.kt (1)
87-91: Consider whether empty text always indicates failure.
isSuccessfulreturnsfalsewhentextis empty. However, some generation scenarios (e.g., structured output that validates correctly but produces no text, or intentionally empty responses) might still be considered successful.Consider also checking for error states or adding a separate success indicator field if the iOS implementation handles this differently.
sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/scripts/download-native-libs.sh (3)
130-142: Use portable checksum command.
shasummay not be available on all Linux systems (e.g., Alpine usessha256sum). Consider adding a fallback:- ACTUAL_CHECKSUM=$(shasum -a 256 "$TEMP_ZIP" | awk '{print $1}') + if command -v sha256sum &>/dev/null; then + ACTUAL_CHECKSUM=$(sha256sum "$TEMP_ZIP" | awk '{print $1}') + elif command -v shasum &>/dev/null; then + ACTUAL_CHECKSUM=$(shasum -a 256 "$TEMP_ZIP" | awk '{print $1}') + else + print_error "No SHA256 checksum tool available" + exit 1 + fi
163-166: Silent copy failure may mask issues.The
2>/dev/null || truesuppresses all errors, including real failures (e.g., disk full). Consider logging a warning when no.sofiles are found:- cp "${ABI_DIR}"/*.so "${JNILIBS_DIR}/${ABI}/" 2>/dev/null || true + if ls "${ABI_DIR}"/*.so &>/dev/null; then + cp "${ABI_DIR}"/*.so "${JNILIBS_DIR}/${ABI}/" + else + print_step "Warning: No .so files found in ${ABI_DIR}" + fi
14-18: Add cleanup trap for failed downloads.If the script fails mid-execution,
TEMP_DIRis left behind. Add a trap after creating the temp directory:set -e +cleanup() { + [ -n "${TEMP_DIR:-}" ] && rm -rf "$TEMP_DIR" +} +trap cleanup EXIT + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/BridgeResults.kt (1)
42-45: Consider sealed class hierarchy for native exceptions.Per coding guidelines, sealed classes are preferred for type-safe error handling. If you anticipate multiple exception types for native operations, consider:
sealed class NativeBridgeException( message: String ) : Exception(message) { class OperationFailed(val resultCode: NativeResultCode, message: String? = null) : NativeBridgeException(message ?: "Native operation failed with code: ${resultCode.name}") // Future exception types can be added here }This is optional if only one exception type is needed. Based on learnings, use sealed classes for error handling.
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.kt (1)
289-293: Consider adding unload methods for STT/TTS components.The SDK has
unloadModel()for LLM but no equivalent for STT/TTS. When users load multiple STT/TTS models sequentially, previous components remain in memory. Consider adding:suspend fun unloadSTTModel() suspend fun unloadTTSModel()Or automatically unload the previous component in
loadSTTModel/loadTTSModelbefore loading a new one.Also applies to: 1378-1393
sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/ONNXCoreService.kt (1)
37-38: Consider using@VolatileforbackendHandle.Since
backendHandleis accessed from multiple threads (both within mutex-protected sections and in property getters), marking it@Volatileensures visibility of writes across threads.- private var backendHandle: Long = 0 + @Volatile + private var backendHandle: Long = 0sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/NativeCoreService.kt (1)
232-235: Consider makingdestroy()a suspend function.Making
destroy()suspend would allow implementations to properly synchronize cleanup without blocking (e.g., using mutex in coroutine context). The current non-suspend signature forces implementations likeONNXCoreServiceto either skip synchronization or userunBlocking./** * Destroy the backend and release all resources. */ - fun destroy() + suspend fun destroy()sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/RunAnywhereBridge.kt (1)
19-19: Consider@VolatileforisLibraryLoaded.While
@SynchronizedonloadLibrary()ensures safe writes, reads viaisLoaded()aren't synchronized. Adding@Volatileensures visibility of the write to other threads reading outside the synchronized block.- private var isLibraryLoaded = false + @Volatile + private var isLibraryLoaded = false
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
examples/android/RunAnywhereAI/app/build.gradle.kts(2 hunks)examples/android/RunAnywhereAI/settings.gradle.kts(1 hunks)sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/.gitignore(1 hunks)sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/VERSION(1 hunks)sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts(1 hunks)sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/scripts/download-native-libs.sh(1 hunks)sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/ONNXCoreService.kt(1 hunks)sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/RunAnywhereBridge.kt(1 hunks)sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/generation/TokenCounter.kt(1 hunks)sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/BridgeResults.kt(1 hunks)sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/Capability.kt(1 hunks)sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/NativeCoreService.kt(1 hunks)sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.kt(6 hunks)sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/models/GenerationResult.kt(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/VERSION
- sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/.gitignore
🚧 Files skipped from review as they are similar to previous changes (1)
- sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts
🧰 Additional context used
📓 Path-based instructions (1)
sdk/runanywhere-kotlin/**/src/**/*.kt
📄 CodeRabbit inference engine (CLAUDE.md)
sdk/runanywhere-kotlin/**/src/**/*.kt: All business logic, protocols, interfaces, and structures MUST be defined incommonMain/for Kotlin Multiplatform projects. Platform-specific implementations must use clear prefixes likeAndroidTTSService.kt,JvmTTSService.kt, etc.
NEVER make assumptions when implementing KMP code. ALWAYS refer to the iOS implementation as the definitive source of truth. Check the iOS implementation, copy the logic exactly, and adapt only for Kotlin syntax.
Useexpect/actualONLY for platform-specific implementations, not for business logic. Put all business logic incommonMain/.
Use Flow instead of AsyncSequence for reactive streams in Kotlin Multiplatform code.
Use coroutines and suspend functions instead of async/await patterns for asynchronous operations.
Use sealed classes for type-safe error handling in Kotlin code.
Always use data classes and structured types (enums, sealed classes) instead of strings for models and configuration.
Use theModuleRegistryprovider pattern for extensibility and plugin architecture instead of hard-coded dependencies.
Use EventBus for component communication instead of direct coupling between components.
Use Service Container pattern for centralized dependency injection with lazy initialization.
Use lazy initialization for service dependencies to avoid memory pressure and allow garbage collection.
Files:
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/generation/TokenCounter.ktsdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/BridgeResults.ktsdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/Capability.ktsdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/NativeCoreService.ktsdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/models/GenerationResult.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/ONNXCoreService.ktsdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/RunAnywhereBridge.kt
🧠 Learnings (16)
📚 Learning: 2025-11-26T22:49:40.358Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.358Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Use the `ModuleRegistry` provider pattern for extensibility and plugin architecture instead of hard-coded dependencies.
Applied to files:
examples/android/RunAnywhereAI/app/build.gradle.ktsexamples/android/RunAnywhereAI/settings.gradle.ktssdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/RunAnywhereBridge.kt
📚 Learning: 2025-11-26T22:49:40.358Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.358Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/androidMain/**/*.kt : Use platform-specific optimizations in their respective source directories: `androidMain/` for Android optimizations, `jvmMain/` for JVM optimizations.
Applied to files:
examples/android/RunAnywhereAI/app/build.gradle.ktsexamples/android/RunAnywhereAI/settings.gradle.ktssdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/Capability.ktsdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/RunAnywhereBridge.kt
📚 Learning: 2025-11-26T22:49:40.358Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.358Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/jvmMain/**/*.kt : Use platform-specific optimizations in their respective source directories: `androidMain/` for Android optimizations, `jvmMain/` for JVM optimizations.
Applied to files:
examples/android/RunAnywhereAI/app/build.gradle.ktsexamples/android/RunAnywhereAI/settings.gradle.ktssdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/RunAnywhereBridge.kt
📚 Learning: 2025-11-26T22:49:40.358Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.358Z
Learning: Applies to sdk/runanywhere-kotlin/**/*.gradle.kts : Android minSdk must be 24 or later for Kotlin Multiplatform SDK.
Applied to files:
examples/android/RunAnywhereAI/app/build.gradle.ktsexamples/android/RunAnywhereAI/settings.gradle.kts
📚 Learning: 2025-11-26T22:49:40.358Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.358Z
Learning: Applies to sdk/runanywhere-kotlin/**/*.gradle.kts : JVM target must be 17 or later for Kotlin Multiplatform SDK.
Applied to files:
examples/android/RunAnywhereAI/app/build.gradle.ktsexamples/android/RunAnywhereAI/settings.gradle.kts
📚 Learning: 2025-11-26T22:49:40.358Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.358Z
Learning: Applies to sdk/runanywhere-kotlin/**/*.gradle.kts : Kotlin version must be 2.1.21 or later for the Kotlin Multiplatform SDK.
Applied to files:
examples/android/RunAnywhereAI/app/build.gradle.ktsexamples/android/RunAnywhereAI/settings.gradle.kts
📚 Learning: 2025-11-26T22:49:40.358Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.358Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Use lazy initialization for service dependencies to avoid memory pressure and allow garbage collection.
Applied to files:
examples/android/RunAnywhereAI/app/build.gradle.ktssdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/NativeCoreService.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/ONNXCoreService.ktsdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/RunAnywhereBridge.kt
📚 Learning: 2025-11-26T22:49:40.358Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.358Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Use coroutines and suspend functions instead of async/await patterns for asynchronous operations.
Applied to files:
examples/android/RunAnywhereAI/app/build.gradle.ktsexamples/android/RunAnywhereAI/settings.gradle.ktssdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/RunAnywhereBridge.kt
📚 Learning: 2025-11-26T22:49:40.358Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.358Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : All business logic, protocols, interfaces, and structures MUST be defined in `commonMain/` for Kotlin Multiplatform projects. Platform-specific implementations must use clear prefixes like `AndroidTTSService.kt`, `JvmTTSService.kt`, etc.
Applied to files:
examples/android/RunAnywhereAI/app/build.gradle.ktsexamples/android/RunAnywhereAI/settings.gradle.ktssdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/NativeCoreService.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/ONNXCoreService.ktsdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/RunAnywhereBridge.kt
📚 Learning: 2025-11-26T22:49:40.358Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.358Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Use `expect/actual` ONLY for platform-specific implementations, not for business logic. Put all business logic in `commonMain/`.
Applied to files:
examples/android/RunAnywhereAI/app/build.gradle.ktsexamples/android/RunAnywhereAI/settings.gradle.kts
📚 Learning: 2025-11-26T22:49:40.358Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.358Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Use Service Container pattern for centralized dependency injection with lazy initialization.
Applied to files:
examples/android/RunAnywhereAI/app/build.gradle.ktssdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/NativeCoreService.ktsdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/ONNXCoreService.ktsdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.kt
📚 Learning: 2025-11-26T22:49:40.358Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.358Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/components/**/*.kt : Implement proper component lifecycle management with initialization, state tracking, and cleanup in BaseComponent.
Applied to files:
examples/android/RunAnywhereAI/app/build.gradle.ktssdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.kt
📚 Learning: 2025-10-17T22:19:36.568Z
Learnt from: shubhammalhotra28
Repo: RunanywhereAI/runanywhere-sdks PR: 119
File: README.md:176-176
Timestamp: 2025-10-17T22:19:36.568Z
Learning: The RunAnywhere SDK package repository is located at `https://github.com/RunanywhereAI/runanywhere-sdks`. The repository was moved from `sdks` to `runanywhere-sdks`, so the correct URL to reference in documentation and installation instructions is `https://github.com/RunanywhereAI/runanywhere-sdks`.
Applied to files:
examples/android/RunAnywhereAI/settings.gradle.kts
📚 Learning: 2025-11-26T22:49:40.358Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.358Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Use sealed classes for type-safe error handling in Kotlin code.
Applied to files:
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/Capability.kt
📚 Learning: 2025-11-26T22:49:40.358Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.358Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Always use data classes and structured types (enums, sealed classes) instead of strings for models and configuration.
Applied to files:
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/models/GenerationResult.ktsdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.kt
📚 Learning: 2025-11-26T22:49:40.358Z
Learnt from: CR
Repo: RunanywhereAI/runanywhere-sdks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T22:49:40.358Z
Learning: Applies to sdk/runanywhere-kotlin/**/src/**/*.kt : Use EventBus for component communication instead of direct coupling between components.
Applied to files:
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.kt
🧬 Code graph analysis (1)
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/generation/TokenCounter.kt (1)
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.kt (2)
estimateTokenCount(257-257)estimateTokenCount(1554-1556)
🪛 detekt (1.23.8)
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.kt
[warning] 1426-1426: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
[warning] 1465-1465: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/RunAnywhereBridge.kt
[warning] 36-36: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
[warning] 42-42: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
🔇 Additional comments (17)
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/models/GenerationResult.kt (3)
32-36: LGTM!Well-structured data class with appropriate defaults and immutable properties.
106-127: Good factory method for testing and simple use cases.The
simple()factory provides reasonable defaults and correctly calculates tokens per second. The hardcodedExecutionTarget.ON_DEVICEis appropriate for the stated testing use case.
154-173: LGTM!Good use of
Flow<String>for streaming as per coding guidelines. ThecollectText()implementation is straightforward and efficient withStringBuilder. The documentation example clearly demonstrates the intended usage pattern.examples/android/RunAnywhereAI/app/build.gradle.kts (2)
33-36: Verify device compatibility impact of arm64-v8a only ABI filter.Restricting to
arm64-v8aexcludes 32-bit ARM devices (armeabi-v7a) and x86 emulators. This is fine for development, but ensure this limitation is documented for users and consider addingx86_64for emulator testing.
191-193: LGTM!The ONNX module dependency is correctly added alongside other SDK modules.
examples/android/RunAnywhereAI/settings.gradle.kts (1)
41-44: LGTM!Module inclusion follows the established pattern with clear documentation of its purpose.
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/BridgeResults.kt (1)
7-28: LGTM!Correct implementation of
equals/hashCodefor data class containingFloatArray. UsingcontentEqualsandcontentHashCodeensures proper value-based comparison.sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/generation/TokenCounter.kt (1)
22-55: LGTM - Token estimation heuristic is well-documented.The approximation approach is reasonable for pre-tokenizer usage with clear documentation of assumptions (GPT-like tokenization patterns).
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/Capability.kt (2)
17-19: InconsistentfromValuenull-safety behavior across enums.
NativeCapability.fromValuereturnsnullfor unknown valuesNativeDeviceType.fromValuereturnsCPUas defaultNativeResultCode.fromValuereturnsERROR_UNKNOWNas defaultThis inconsistency requires callers to handle each enum differently. Consider documenting the rationale or unifying the approach. If intentional (e.g., unknown capability is a hard error, but unknown device defaults to CPU), add KDoc comments explaining why.
Also applies to: 37-39, 62-64
46-65: LGTM - Well-structured result code enum.Clear mapping to C API codes with convenient
isSuccessproperty.sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.kt (2)
157-190: LGTM - STT/TTS model management API surface.Clean interface additions matching iOS API patterns with proper KDoc documentation.
1544-1557: LGTM!Clean delegation to
TokenCounterutility following the established pattern.sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/ONNXCoreService.kt (2)
353-379: Companion object utilities are well-structured.The static-like utilities (
getAvailableBackends,getVersion,extractArchive) correctly ensure the library is loaded before each call, making them safe for standalone usage.
40-43: Thread safety and suspend function design looks good.The pattern of
withContext(Dispatchers.IO)+mutex.withLock+ensureInitialized()is consistently applied across model loading and inference operations. This provides proper thread safety and ensures native I/O doesn't block the main dispatcher.Also applies to: 119-131
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/native/bridge/NativeCoreService.kt (1)
27-236: Well-designed interface correctly placed incommonMain/.The
NativeCoreServiceinterface follows Kotlin Multiplatform best practices:
- Placed in
commonMain/as the central contract (per coding guidelines)- Uses
suspendfunctions for I/O-bound operations- Uses structured types (
NativeCapability,NativeDeviceType, etc.) instead of primitives- Comprehensive KDoc documentation
Based on learnings, this correctly follows the guideline that "All business logic, protocols, interfaces, and structures MUST be defined in
commonMain/."sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/RunAnywhereBridge.kt (2)
17-17: Good JNI bridge design with proper visibility.The
internalvisibility correctly encapsulates this as an implementation detail. The organized grouping of external functions by feature area (Backend Lifecycle, Text Generation, STT, TTS, VAD, Embeddings, Diarization, Utility) makes the API surface clear and maintainable.Also applies to: 61-299
25-50: Idempotent library loading pattern is correct.The
@Synchronizedannotation combined with the early return onisLibraryLoadedensures thread-safe, idempotent library loading. The exception propagation for the primary library (runanywhere_jni) while allowing optional dependencies to fail silently is a reasonable approach.
| override val isInitialized: Boolean | ||
| get() = backendHandle != 0L && RunAnywhereBridge.nativeIsInitialized(backendHandle) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unsynchronized access to backendHandle in property getter.
isInitialized reads backendHandle and calls a native method without mutex protection. If destroy() is called concurrently, this could read a stale handle or pass an invalidated handle to native code.
Consider either:
- Making this property access synchronized
- Using
@VolatileonbackendHandle(provides visibility but not atomicity for the compound check) - Documenting that callers must not call property getters concurrently with
destroy()
The same concern applies to other property getters: supportedCapabilities (line 83-89), deviceType (line 96-100), memoryUsage (line 102-106), isSTTModelLoaded (line 133-134), isTTSModelLoaded (line 188-189), isVADModelLoaded (line 251-252), isEmbeddingModelLoaded (line 308-309), supportsSTTStreaming (line 167-168), and embeddingDimensions (line 334-338).
...nywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/ONNXCoreService.kt
Show resolved
Hide resolved
...nywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/ONNXCoreService.kt
Show resolved
Hide resolved
| try { | ||
| System.loadLibrary("runanywhere_bridge") | ||
| } catch (e: UnsatisfiedLinkError) { | ||
| // May already be loaded or linked statically | ||
| } | ||
|
|
||
| try { | ||
| System.loadLibrary("onnxruntime") | ||
| } catch (e: UnsatisfiedLinkError) { | ||
| // May already be loaded | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Swallowed exceptions lose debugging context.
Static analysis correctly flags that caught exceptions are swallowed. While the intent to handle "already loaded" cases is valid, silently ignoring these errors makes debugging harder when library loading actually fails for other reasons.
Consider logging the exception or distinguishing between expected and unexpected failures:
// Also load dependencies if needed
try {
System.loadLibrary("runanywhere_bridge")
} catch (e: UnsatisfiedLinkError) {
- // May already be loaded or linked statically
+ // May already be loaded or linked statically - log for debugging
+ // Log.d("RunAnywhereBridge", "runanywhere_bridge not loaded separately: ${e.message}")
}
try {
System.loadLibrary("onnxruntime")
} catch (e: UnsatisfiedLinkError) {
- // May already be loaded
+ // May already be loaded - log for debugging
+ // Log.d("RunAnywhereBridge", "onnxruntime not loaded separately: ${e.message}")
}Alternatively, check if the library is already loaded before attempting to load it, if the platform provides such a mechanism.
Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 detekt (1.23.8)
[warning] 36-36: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
[warning] 42-42: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
🤖 Prompt for AI Agents
In
sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/src/jvmAndroidMain/kotlin/com/runanywhere/sdk/core/onnx/RunAnywhereBridge.kt
around lines 34–44, the catch blocks currently swallow UnsatisfiedLinkError
which loses debugging context; modify each catch to log the exception (including
message and stacktrace) and only suppress it when you can positively determine
the error is the expected "already loaded or statically linked" case (for
example by checking the exception message or using a platform API to test if the
library is already loaded), otherwise rethrow the exception so real load
failures surface; ensure logs include clear context (which library failed) and
use the project logger or Android Log as appropriate.
| fun splitTokenCounts( | ||
| fullText: String, | ||
| thinkingContent: String?, | ||
| responseContent: String | ||
| ): Triple<Int?, Int, Int> { | ||
| val responseTokens = estimateTokenCount(responseContent) | ||
|
|
||
| return if (!thinkingContent.isNullOrEmpty()) { | ||
| val thinkingTokens = estimateTokenCount(thinkingContent) | ||
| val totalTokens = thinkingTokens + responseTokens | ||
| Triple(thinkingTokens, responseTokens, totalTokens) | ||
| } else { | ||
| Triple(null, responseTokens, responseTokens) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove unused fullText parameter.
The fullText parameter is never used in splitTokenCounts. This may indicate incomplete implementation or a refactoring artifact.
fun splitTokenCounts(
- fullText: String,
thinkingContent: String?,
responseContent: String
): Triple<Int?, Int, Int> {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| fun splitTokenCounts( | |
| fullText: String, | |
| thinkingContent: String?, | |
| responseContent: String | |
| ): Triple<Int?, Int, Int> { | |
| val responseTokens = estimateTokenCount(responseContent) | |
| return if (!thinkingContent.isNullOrEmpty()) { | |
| val thinkingTokens = estimateTokenCount(thinkingContent) | |
| val totalTokens = thinkingTokens + responseTokens | |
| Triple(thinkingTokens, responseTokens, totalTokens) | |
| } else { | |
| Triple(null, responseTokens, responseTokens) | |
| } | |
| } | |
| fun splitTokenCounts( | |
| thinkingContent: String?, | |
| responseContent: String | |
| ): Triple<Int?, Int, Int> { | |
| val responseTokens = estimateTokenCount(responseContent) | |
| return if (!thinkingContent.isNullOrEmpty()) { | |
| val thinkingTokens = estimateTokenCount(thinkingContent) | |
| val totalTokens = thinkingTokens + responseTokens | |
| Triple(thinkingTokens, responseTokens, totalTokens) | |
| } else { | |
| Triple(null, responseTokens, responseTokens) | |
| } | |
| } |
🤖 Prompt for AI Agents
In
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/generation/TokenCounter.kt
around lines 77 to 91, the function splitTokenCounts declares an unused fullText
parameter; remove fullText from the function signature and update the
implementation signature to only accept thinkingContent and responseContent (or
reorder/rename as needed), and then update all call sites across the codebase to
stop passing fullText (or pass the appropriate value into the remaining
parameters). Run a compile to find and fix any remaining references and adjust
any tests or documentation accordingly.
| companion object { | ||
| fun fromValue(value: String): HardwareAcceleration { | ||
| return values().find { it.value == value } ?: CPU | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
Kotlin enum values() vs entries deprecation Kotlin 1.9
💡 Result:
Short answer
- Kotlin 1.9 makes enum class.entries the stable, preferred replacement for the synthetic values() function. Use entries (a List/EnumEntries) instead of values() (an Array) for better performance and safer semantics. [1][2]
Key details
- entries was stabilized in 1.9; values() continues to work but you should migrate to entries. Example:
- Before: MyEnum.values()
- After: MyEnum.entries
Note: entries is a List (EnumEntries), not an Array—if you need an Array, call .toTypedArray(). [1][2]
- For Java callers, Kotlin generates getEntries() as the recommended replacement for values(). IDE quick-fixes can convert usages. [3]
- A related change: the generic enumValues() replacement is enumEntries() (experimental in 1.9.20); enumValues() still works but enumEntries is more efficient (returns a shared list instead of allocating a new array each call). [3]
- Also watch related 1.9 enum compatibility changes (e.g., external enums deprecation, decls like declaringClass). See migration notes if you maintain cross-language APIs. [1][2]
Sources
- Kotlin 1.9 "What's new" (entries stabilization & migration notes). [1]
- Kotlin 1.9.20 notes (enumEntries() experimental). [2]
- IntelliJ/JetBrains inspection docs showing automatic replacement and Java getEntries recommendation. [3]
🏁 Script executed:
# Check the project's Kotlin version requirement
cd sdk/runanywhere-kotlin
find . -name "build.gradle" -o -name "build.gradle.kts" -o -name "gradle.properties" | head -5Repository: RunanywhereAI/runanywhere-sdks
Length of output: 261
🏁 Script executed:
# Check Kotlin version in main build.gradle.kts
head -50 build.gradle.ktsRepository: RunanywhereAI/runanywhere-sdks
Length of output: 1746
🏁 Script executed:
# Also check gradle.properties for version info
cat gradle.propertiesRepository: RunanywhereAI/runanywhere-sdks
Length of output: 407
🏁 Script executed:
# Check Kotlin version in SDK module
cat sdk/runanywhere-kotlin/build.gradle.kts | head -80Repository: RunanywhereAI/runanywhere-sdks
Length of output: 2488
🏁 Script executed:
# Check the version catalog for Kotlin version
find . -name "libs.versions.toml" -o -name "versions.toml" | xargs cat 2>/dev/nullRepository: RunanywhereAI/runanywhere-sdks
Length of output: 18097
Use entries instead of values() for enum iteration.
values() is deprecated in Kotlin 1.9+, and the project uses Kotlin 2.1.21. Use entries (a List) instead of values() (an Array) for better performance and to align with current best practices.
Additionally, silently defaulting to CPU for unknown values may mask configuration errors. Consider throwing an IllegalArgumentException or returning null to make invalid input explicit.
companion object {
fun fromValue(value: String): HardwareAcceleration {
- return values().find { it.value == value } ?: CPU
+ return entries.find { it.value == value } ?: CPU
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| companion object { | |
| fun fromValue(value: String): HardwareAcceleration { | |
| return values().find { it.value == value } ?: CPU | |
| } | |
| } | |
| companion object { | |
| fun fromValue(value: String): HardwareAcceleration { | |
| return entries.find { it.value == value } ?: CPU | |
| } | |
| } |
🤖 Prompt for AI Agents
In
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/models/GenerationResult.kt
around lines 21 to 25, replace the deprecated values() enum iteration with
entries and stop silently defaulting to CPU for unknown inputs: change the
function to search HardwareAcceleration.entries for a matching .value and, if
none found, throw an IllegalArgumentException (or alternatively return null if
you prefer nullable API) with a clear message including the invalid value so
invalid configuration is explicit.
| override suspend fun loadSTTModel(modelId: String) { | ||
| requireInitialized() | ||
|
|
||
| EventBus.publish(SDKModelEvent.LoadStarted(modelId)) | ||
|
|
||
| try { | ||
| // Get model info for lifecycle tracking | ||
| val modelInfo = serviceContainer.modelRegistry?.getModel(modelId) | ||
| val modelName = modelInfo?.name ?: modelId | ||
|
|
||
| logger.info("Loading STT model: $modelName ($modelId)") | ||
|
|
||
| // Create STT configuration | ||
| val sttConfig = com.runanywhere.sdk.components.stt.STTConfiguration(modelId = modelId) | ||
|
|
||
| // Create and initialize STT component | ||
| val sttComponent = com.runanywhere.sdk.components.stt.STTComponent(sttConfig) | ||
| sttComponent.initialize() | ||
|
|
||
| // Store the component for later use | ||
| _loadedSTTComponent = sttComponent | ||
|
|
||
| logger.info("✅ STT model loaded successfully: $modelName") | ||
| EventBus.publish(SDKModelEvent.LoadCompleted(modelId)) | ||
|
|
||
| } catch (e: Exception) { | ||
| logger.error("Failed to load STT model: $modelId", e) | ||
| EventBus.publish(SDKModelEvent.LoadFailed(modelId, e)) | ||
| throw SDKError.ModelLoadingFailed("Failed to load STT model: ${e.message}") | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Preserve original exception as cause for debugging.
The caught exception is logged and used in the error message, but the original stack trace is lost when wrapping in SDKError.ModelLoadingFailed. Chain the original exception as the cause:
- throw SDKError.ModelLoadingFailed("Failed to load STT model: ${e.message}")
+ throw SDKError.ModelLoadingFailed("Failed to load STT model: ${e.message}", e)This requires SDKError.ModelLoadingFailed to accept a cause parameter. If it doesn't, consider adding one.
Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 detekt (1.23.8)
[warning] 1426-1426: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
🤖 Prompt for AI Agents
In
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.kt
around lines 1401 to 1431, preserve the original exception when wrapping it by
updating the thrown SDKError.ModelLoadingFailed to accept and include the caught
exception as its cause; if the SDKError.ModelLoadingFailed constructor does not
currently accept a cause, add an overload or parameter to accept a Throwable
cause, then change the throw to pass the caught exception (e) as that cause
while keeping the existing message and logging/Events intact.
| override suspend fun loadTTSModel(modelId: String) { | ||
| requireInitialized() | ||
|
|
||
| EventBus.publish(SDKModelEvent.LoadStarted(modelId)) | ||
|
|
||
| try { | ||
| // Get model info for lifecycle tracking | ||
| val modelInfo = serviceContainer.modelRegistry?.getModel(modelId) | ||
| val modelName = modelInfo?.name ?: modelId | ||
|
|
||
| logger.info("Loading TTS model: $modelName ($modelId)") | ||
|
|
||
| // Create TTS configuration | ||
| val ttsConfig = com.runanywhere.sdk.components.TTSConfiguration(modelId = modelId) | ||
|
|
||
| // Create and initialize TTS component | ||
| val ttsComponent = com.runanywhere.sdk.components.TTSComponent(ttsConfig) | ||
| ttsComponent.initialize() | ||
|
|
||
| // Store the component for later use | ||
| _loadedTTSComponent = ttsComponent | ||
|
|
||
| logger.info("✅ TTS model loaded successfully: $modelName") | ||
| EventBus.publish(SDKModelEvent.LoadCompleted(modelId)) | ||
|
|
||
| } catch (e: Exception) { | ||
| logger.error("Failed to load TTS model: $modelId", e) | ||
| EventBus.publish(SDKModelEvent.LoadFailed(modelId, e)) | ||
| throw SDKError.ModelLoadingFailed("Failed to load TTS model: ${e.message}") | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue: Preserve exception cause in TTS model loading.
Apply the same fix as STT:
- throw SDKError.ModelLoadingFailed("Failed to load TTS model: ${e.message}")
+ throw SDKError.ModelLoadingFailed("Failed to load TTS model: ${e.message}", e)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| override suspend fun loadTTSModel(modelId: String) { | |
| requireInitialized() | |
| EventBus.publish(SDKModelEvent.LoadStarted(modelId)) | |
| try { | |
| // Get model info for lifecycle tracking | |
| val modelInfo = serviceContainer.modelRegistry?.getModel(modelId) | |
| val modelName = modelInfo?.name ?: modelId | |
| logger.info("Loading TTS model: $modelName ($modelId)") | |
| // Create TTS configuration | |
| val ttsConfig = com.runanywhere.sdk.components.TTSConfiguration(modelId = modelId) | |
| // Create and initialize TTS component | |
| val ttsComponent = com.runanywhere.sdk.components.TTSComponent(ttsConfig) | |
| ttsComponent.initialize() | |
| // Store the component for later use | |
| _loadedTTSComponent = ttsComponent | |
| logger.info("✅ TTS model loaded successfully: $modelName") | |
| EventBus.publish(SDKModelEvent.LoadCompleted(modelId)) | |
| } catch (e: Exception) { | |
| logger.error("Failed to load TTS model: $modelId", e) | |
| EventBus.publish(SDKModelEvent.LoadFailed(modelId, e)) | |
| throw SDKError.ModelLoadingFailed("Failed to load TTS model: ${e.message}") | |
| } | |
| } | |
| override suspend fun loadTTSModel(modelId: String) { | |
| requireInitialized() | |
| EventBus.publish(SDKModelEvent.LoadStarted(modelId)) | |
| try { | |
| // Get model info for lifecycle tracking | |
| val modelInfo = serviceContainer.modelRegistry?.getModel(modelId) | |
| val modelName = modelInfo?.name ?: modelId | |
| logger.info("Loading TTS model: $modelName ($modelId)") | |
| // Create TTS configuration | |
| val ttsConfig = com.runanywhere.sdk.components.TTSConfiguration(modelId = modelId) | |
| // Create and initialize TTS component | |
| val ttsComponent = com.runanywhere.sdk.components.TTSComponent(ttsConfig) | |
| ttsComponent.initialize() | |
| // Store the component for later use | |
| _loadedTTSComponent = ttsComponent | |
| logger.info("✅ TTS model loaded successfully: $modelName") | |
| EventBus.publish(SDKModelEvent.LoadCompleted(modelId)) | |
| } catch (e: Exception) { | |
| logger.error("Failed to load TTS model: $modelId", e) | |
| EventBus.publish(SDKModelEvent.LoadFailed(modelId, e)) | |
| throw SDKError.ModelLoadingFailed("Failed to load TTS model: ${e.message}", e) | |
| } | |
| } |
🧰 Tools
🪛 detekt (1.23.8)
[warning] 1465-1465: The caught exception is swallowed. The original exception could be lost.
(detekt.exceptions.SwallowedException)
🤖 Prompt for AI Agents
In
sdk/runanywhere-kotlin/src/commonMain/kotlin/com/runanywhere/sdk/public/RunAnywhere.kt
around lines 1440 to 1470, the catch block logs and rethrows
SDKError.ModelLoadingFailed without preserving the original exception as the
cause; update the catch to pass the caught exception into both the log/event (if
event supports it) and into the thrown SDKError.ModelLoadingFailed so the
original stacktrace is preserved (e.g., include e as the cause/inner exception
when constructing SDKError.ModelLoadingFailed and keep logger.error(..., e)
as-is).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
37 files reviewed, no comments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Important
Looks good to me! 👍
Reviewed everything up to 65d34f5 in 13 minutes and 40 seconds. Click for details.
- Reviewed
9291lines of code in37files - Skipped
0files when reviewing. - Skipped posting
1draft comments. View those below. - Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts:8
- Draft comment:
Typo: 'RunAnywhareBridge' appears to be misspelled. Consider changing it to 'RunAnywhereBridge' for consistency with the module naming. - Reason this comment was not posted:
Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 30% vs. threshold = 50% This is a comment about a typo in documentation (a comment block). The file is entirely new (all additions), so technically this is "about changes" since the whole file is new. However, I need to consider: 1) Is this actionable? Yes, it's a simple typo fix. 2) Is it important? It's a documentation typo, relatively minor but does affect clarity. 3) Does it require code changes? Yes, but only to a comment. 4) Is it clearly correct? Looking at the pattern, "RunAnywhere" is used everywhere else, so "RunAnywhareBridge" does appear to be a typo. However, the rules say "Do NOT comment unless there is clearly a code change required" and "Do NOT make comments that are obvious or unimportant." A typo in a comment is relatively unimportant and might be considered obvious. The rules also emphasize only keeping comments with STRONG EVIDENCE of correctness and actionable issues. While this is technically a valid typo, it's only in a documentation comment, not in actual code. The rules emphasize not making obvious or unimportant comments. A typo in a comment that doesn't affect functionality might fall into the "unimportant" category. Additionally, without seeing the actual implementation files, I can't be 100% certain what the correct name should be - maybe "RunAnywhareBridge" is intentional, though unlikely. The typo is in documentation that describes the architecture, which is important for developers understanding the system. However, it's still just a comment typo and not a functional issue. Given the rules emphasize removing comments that aren't clearly important and the instruction to err on the side of deletion when unsure, this comment about a documentation typo should probably be removed as it's relatively minor. This comment identifies a likely typo in documentation, but it's a minor issue in a comment rather than functional code. Given the rules to avoid obvious/unimportant comments and to default to deletion when uncertain, this comment should be removed.
Workflow ID: wflow_RGiuUrqn0JiOgBO7
You can customize by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Important
Looks good to me! 👍
Reviewed everything up to 65d34f5 in 13 minutes and 41 seconds. Click for details.
- Reviewed
9291lines of code in37files - Skipped
0files when reviewing. - Skipped posting
1draft comments. View those below. - Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. sdk/runanywhere-kotlin/modules/runanywhere-core-onnx/build.gradle.kts:8
- Draft comment:
Typo: "RunAnywhareBridge" should likely be "RunAnywhereBridge" for consistency. - Reason this comment was not posted:
Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% This is a comment about documentation/comments, not actual code. The rules state I should not comment on things that are "obvious or unimportant." A typo in a comment is relatively minor. However, I need to consider: 1) Is this actually a typo? Looking at the context, "RunAnywhere" is the product name, so "RunAnywhereBridge" would be the expected spelling. "RunAnywhareBridge" does look like a typo. 2) But this is just in a documentation comment explaining architecture - it's not in actual code that would cause bugs. 3) The rules say comments should be about code changes that are required, not just informative. A typo in documentation is more of a "nice to have" fix rather than a required code change. 4) Without seeing other files, I cannot verify what the actual class name is - maybe it really is "RunAnywhareBridge" intentionally? I don't have strong evidence either way. I cannot see the actual implementation files to verify what the correct name of the bridge class actually is. It's possible "RunAnywhareBridge" is intentional, or it could be that the actual class also has this typo. Without cross-file context, I cannot be certain this is actually wrong. Additionally, this is just documentation/comments, not functional code, making it lower priority. While I cannot verify the correct spelling without seeing other files, "RunAnywhareBridge" does appear to be inconsistent with the "RunAnywhere" branding used throughout the rest of the file. However, the rules explicitly state to ignore issues that require cross-file context, and I should only keep comments with strong evidence they're correct. Since this is just documentation and I lack definitive proof, I should delete it. This comment is about a potential typo in documentation, not functional code. I cannot verify the correct spelling without seeing other files (the rules say to ignore cross-file issues). The comment doesn't point to a clearly required code change - it's more of a minor documentation improvement. Following the principle that I need strong evidence to keep a comment, I should delete this.
Workflow ID: wflow_3rr2wOf5qoayreyc
You can customize by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.
- Added Flutter auto-generated files to .gitignore to prevent local paths from being tracked. - Refactored SettingsViewModel to optimize model filtering and storage size calculation. - Updated SpeechToTextScreen to improve loading state logic based on model status. - Adjusted TextToSpeechViewModel to dynamically calculate character count from input text. - Enhanced TranscriptionViewModel to start observing SDK events upon initialization. - Modified VoiceAssistantScreen to improve icon handling and animation behavior. These changes streamline the project structure and enhance the functionality of various components.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Important
Looks good to me! 👍
Reviewed 14ae81c in 1 minute and 36 seconds. Click for details.
- Reviewed
131lines of code in7files - Skipped
1files when reviewing. - Skipped posting
8draft comments. View those below. - Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/settings/SettingsViewModel.kt:275
- Draft comment:
Using an intermediate 'filteredModels' variable improves readability and ensures the model storage size is calculated consistently. - Reason this comment was not posted:
Confidence changes required:0%<= threshold50%None
2. examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/stt/SpeechToTextScreen.kt:73
- Draft comment:
Replacing a null check on selectedModelName with '!uiState.isModelLoaded' gives a more direct indication of the model’s readiness. - Reason this comment was not posted:
Confidence changes required:0%<= threshold50%None
3. examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/tts/TextToSpeechViewModel.kt:19
- Draft comment:
Computing the characterCount using the length of the default input text improves maintainability if the default string changes. - Reason this comment was not posted:
Confidence changes required:0%<= threshold50%None
4. examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/TranscriptionViewModel.kt:122
- Draft comment:
Calling observeSDKEvents() during initialization ensures the ViewModel starts receiving SDK events promptly. - Reason this comment was not posted:
Confidence changes required:0%<= threshold50%None
5. examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/VoiceAssistantScreen.kt:568
- Draft comment:
Differentiating between Icons.Filled.Info and Icons.Outlined.Info improves visual feedback for toggling model info. - Reason this comment was not posted:
Confidence changes required:0%<= threshold50%None
6. examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/presentation/voice/VoiceAssistantScreen.kt:895
- Draft comment:
Switching the repeatMode from Restart to Reverse produces a smoother pulsing effect for the recording button. - Reason this comment was not posted:
Confidence changes required:0%<= threshold50%None
7. examples/flutter/RunAnywhereAI/ios/Flutter/Generated.xcconfig:1
- Draft comment:
Auto-generated Flutter config file has been removed; ensure it is added to .gitignore to prevent future accidental commits. - Reason this comment was not posted:
Confidence changes required:0%<= threshold50%None
8. examples/flutter/RunAnywhereAI/ios/Flutter/flutter_export_environment.sh:1
- Draft comment:
Removed auto-generated Flutter export environment script; confirm such generated files are ignored by version control. - Reason this comment was not posted:
Confidence changes required:0%<= threshold50%None
Workflow ID: wflow_fUmmeNbfTSUPnJ2D
You can customize by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.
…ponding ViewModels
This commit enhances the overall functionality and user experience of the application, aligning with the iOS architecture.
Description
Brief description of the changes made.
Type of Change
Testing
Labels
Please add the appropriate label(s):
iOS SDK- Changes to iOS/Swift SDKAndroid SDK- Changes to Android/Kotlin SDKiOS Sample- Changes to iOS example appAndroid Sample- Changes to Android example appChecklist
Screenshots - Attach all the relevant UI changes screenshots for iOS/Android and MacOS/Tablet/large screen sizes
Summary by CodeRabbit
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.
Important
This PR updates the Android SDK with new STT and TTS UI components, aligns navigation with iOS, and integrates ONNX Runtime for native ML operations.
SpeechToTextScreenandTextToSpeechScreencomponents for Android, mirroring iOS functionality.AppNavigationto include new STT and TTS routes, replacing previous Storage functionality.BottomNavigationBarto match iOS tab structure.SpeechToTextViewModelandTextToSpeechViewModelfor managing UI state and interactions.SettingsScreento combine settings and storage management, aligning with iOS design.ONNXCoreService.kt.Generated.xcconfig.This description was created by
for 14ae81c. You can customize this summary. It will automatically update as commits are pushed.
Greptile Overview
Greptile Summary
This PR successfully implements Speech-to-Text and Text-to-Speech features for Android, mirroring the iOS implementation. The changes introduce new UI screens (
SpeechToTextScreen,TextToSpeechScreen) with corresponding ViewModels, along with foundational ONNX Runtime backend support through a newrunanywhere-core-onnxmodule.Key Changes:
Implementation Notes:
Issues Found:
Confidence Score: 4/5
Important Files Changed
File Analysis
Sequence Diagram
sequenceDiagram participant User participant UI as STT/TTS Screen participant ViewModel as STT/TTS ViewModel participant SDK as RunAnywhere SDK participant ONNX as ONNXCoreService participant JNI as RunAnywhereBridge participant Native as Native C++ Backend Note over User,Native: Model Selection Flow User->>UI: Select Model UI->>ViewModel: loadModel(name, id) ViewModel->>ViewModel: Update state (PROCESSING) ViewModel->>SDK: Initialize STT/TTS Component SDK->>ONNX: loadSTTModel/loadTTSModel ONNX->>JNI: nativeSTTLoadModel/nativeTTSLoadModel JNI->>Native: Load ONNX model Native-->>JNI: Success JNI-->>ONNX: ResultCode ONNX-->>SDK: Model loaded SDK-->>ViewModel: Component ready ViewModel->>ViewModel: Update state (IDLE, model loaded) ViewModel-->>UI: UI state updated UI-->>User: Show model loaded banner Note over User,Native: STT Recording & Transcription Flow User->>UI: Tap record button UI->>ViewModel: toggleRecording() ViewModel->>ViewModel: startRecording() ViewModel->>ViewModel: Update state (RECORDING) ViewModel-->>UI: UI shows recording animation User->>UI: Tap stop button UI->>ViewModel: toggleRecording() ViewModel->>ViewModel: stopRecording() ViewModel->>ViewModel: Update state (PROCESSING) ViewModel->>SDK: transcribe(audioData) SDK->>ONNX: transcribe(samples, sampleRate) ONNX->>JNI: nativeSTTTranscribe JNI->>Native: Process audio with ONNX Native-->>JNI: Transcription text JNI-->>ONNX: String result ONNX-->>SDK: Transcription SDK-->>ViewModel: Transcription result ViewModel->>ViewModel: Update state (IDLE, transcription) ViewModel-->>UI: Display transcription UI-->>User: Show transcribed text Note over User,Native: TTS Generation & Playback Flow User->>UI: Enter text and tap generate UI->>ViewModel: generateSpeech() ViewModel->>ViewModel: Update state (GENERATING) ViewModel->>SDK: synthesize(text) SDK->>ONNX: synthesize(text, voiceId, speed, pitch) ONNX->>JNI: nativeTTSSynthesize JNI->>Native: Generate audio with ONNX Native-->>JNI: Audio samples + sample rate JNI-->>ONNX: NativeTTSSynthesisResult ONNX-->>SDK: Audio data SDK-->>ViewModel: Audio ready ViewModel->>ViewModel: Update state (audio generated) ViewModel-->>UI: Enable playback controls User->>UI: Tap play button UI->>ViewModel: togglePlayback() ViewModel->>ViewModel: startPlayback() ViewModel-->>UI: Show playback progress UI-->>User: Play audio Note over User,Native: Settings & Storage Management User->>UI: Navigate to Settings UI->>ViewModel: Load settings ViewModel->>SDK: Get stored models SDK-->>ViewModel: Model list ViewModel->>ViewModel: Calculate storage sizes ViewModel-->>UI: Display storage overview User->>UI: Delete model UI->>ViewModel: deleteModel(modelId) ViewModel->>SDK: Delete model files SDK-->>ViewModel: Deletion complete ViewModel->>ViewModel: Update model list & sizes ViewModel-->>UI: Refresh UI