Skip to content

Commit 1adc212

Browse files
shubhammalhotra28cursoragentsanchitmonga22Siddhesh2377
authored
Aligning / upstream update for dev (#442)
* chore: add AGENTS.md with Cursor Cloud specific instructions * chore: update AGENTS.md with Linux backend build and voice assistant instructions * minor fixes * fix: Android app UI improvements, SDK concurrency bug fixes, and LoRA download support Android App: - Redesign intro screen with minimal layout and linear progress bar - Improve VLM screen: use shared ModelRequiredOverlay, theme-consistent colors, fix button clipping (replace IconButton with clickable Column) - Fix keyboard handling: hide bottom bar when keyboard open, apply imePadding correctly - Add scrollable auto-scroll prompt suggestions in ChatScreen - Add shimmer typing indicator with "Thinking..." label - Fix 9 app-level bugs: think tag leak, CancellationException handling, VoiceAssistant lifecycle, ConversationStore ANR, TTS sample rate parsing, LoRA download mutex deadlock KMP SDK (10 bug fixes): - Fix cancel() deadlock: move JNI calls outside synchronized(lock) in CppBridgeLLM - Fix orphaned CoroutineScope leak in generateStream using callbackFlow - Fix initializeServices() holding lock across network I/O - Fix loraDownloadDir lazy val caching wrong path before pathProvider set - Fix setBaseDirCallback TOCTOU race condition - Add @volatile to DownloadTask mutable fields for thread visibility - Fix unescapeJson() replacement order (process \\\\ before \\n) - Add downloadLock for atomic cancel/pause/resume operations - Fix checkNativeLibrary() to actually call native method - Add ensureServicesReady() to generateStream - Add LoRA adapter download/delete/path SDK functions Known issue: Tool-calling may show unexpected behavior when a LoRA adapter is applied — the model detects the tool call but responds with "I can assist with this" instead of executing it. Tested with Qwen 2.5 0.5B. This only occurs when the model has a LoRA adapter loaded. * fix(tts): scan WAV data chunk instead of hardcoding 44-byte header offset WAV files with extra chunks (LIST, fact, bext) had metadata bytes fed into AudioTrack as PCM, causing distorted playback. Now walks the chunk structure to find the actual "data" chunk start. * fix: Android app UI bug fixes, responsive dimensions, LoRA example prompts, and darker dark mode - Fix nested verticalScroll inside LazyColumn (ThinkingToggle) causing broken scroll - Fix weight(1f) + verticalScroll overflow in VLMScreen DescriptionPanel - Add verticalScroll to MoreHubScreen to prevent clipping on small screens - Add imePadding to ConversationListSheet so keyboard doesn't cover search - Fix auto-scroll wrap logic in EmptyStateView using canScrollForward - Replace collectAsState with collectAsStateWithLifecycle in 3 screens - Replace deprecated STTMode.values() with .entries - Replace hardcoded Color.Gray with AppColors.statusGray for dark mode contrast - Remove redundant Color.White inside buttons with contentColor set - Replace hardcoded 300.dp bubble width with responsive Dimensions.messageBubbleMaxWidth - Add accessibility semantics role to VLMScreen clickable Column - Disable Image Generation card (placeholder feature) - Add responsive rDp/rSp utilities and convert Dimensions/AppSpacing to use them - Add LoRA example prompts with copy button to adapter picker and manager screens - Darken dark mode background colors * fix: Android app bug fixes - race conditions, ANR, pixel corruption, scroll, and memory safety - VoiceAssistantViewModel: replace runBlocking with GlobalScope.launch in onCleared to prevent ANR - VoiceAssistantViewModel: add synchronized audioBufferLock for thread-safe ByteArrayOutputStream access - VoiceAssistantViewModel: scan WAV data chunk instead of hardcoding 44-byte header offset - ConversationStore: use MutableStateFlow.update {} for atomic compare-and-set on all mutations - ToolSettingsViewModel: clear static singleton in onCleared to prevent stale references - VLMViewModel: advance rgbIdx by 3 in else branch to prevent pixel corruption on out-of-bounds skip - ChatViewModel: use CopyOnWriteArrayList for tokensPerSecondHistory thread safety - VoiceAssistantParticleView: remove wasted transparent drawPoints call - RunAnywhereApplication: capture volatile initializationError to local val before null check - VLMScreen: add verticalScroll to description panel for long text overflow - ResponsiveUtils: add designWidth <= 0 guard to prevent division by zero in rDp/rSp --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Sanchit Monga <sanchitmonga22@gmail.com> Co-authored-by: Sanchit Monga <sm3468@g.rit.edu> Co-authored-by: Siddhesh2377 <siddheshsonar2377@gmail.com> Co-authored-by: RunAnywhere <>
1 parent 9e4f2df commit 1adc212

36 files changed

Lines changed: 1664 additions & 1235 deletions

AGENTS.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# AGENTS.md
2+
3+
## Cursor Cloud specific instructions
4+
5+
### Environment Overview
6+
7+
This is a cross-platform SDK monorepo. On a Linux cloud VM, the buildable services are:
8+
9+
| Component | Build | Test | Lint | Notes |
10+
|-----------|-------|------|------|-------|
11+
| Kotlin SDK (Android target) | `./gradlew :runanywhere-kotlin:compileDebugKotlinAndroid -Prunanywhere.testLocal=false` | Android unit tests require device/emulator | `./gradlew :runanywhere-kotlin:runKtlintCheckOverCommonMainSourceSet` | JVM target has a known issue: `RAGBridge.kt` in `jvmAndroidMain` imports `@Keep` from `androidx.annotation` which is unavailable for JVM compilation |
12+
| Web SDK (TypeScript) | `npm run build -w packages/core` (from `sdk/runanywhere-web/`) | N/A | `npm run typecheck -w packages/core` | `llamacpp` package has a pre-existing duplicate index signature TS error |
13+
| Web Example App | `npm run dev` (from `examples/web/RunAnywhereAI/`) | Manual browser testing at `localhost:5173` | N/A | Full Vite app, works in demo mode without WASM |
14+
| C++ Commons (core) | `cmake -B build ... && cmake --build build` (from `sdk/runanywhere-commons/`) | `./build/tests/test_core --run-all` (13 tests, no models needed) | N/A | Must use `gcc`/`g++` via `CC=gcc CXX=g++` (clang lacks C++ stdlib headers). Pass `-DRAC_BUILD_PLATFORM=OFF` on Linux |
15+
| C++ Commons (full backends) | `CC=gcc CXX=g++ bash scripts/build-linux.sh --shared` | Backend tests need downloaded models | N/A | Builds onnx+llamacpp. RAG backend has pre-existing zero-size array bug; use `-DRAC_BACKEND_RAG=OFF`. Sherpa-ONNX v1.12.23 URL changed: use `sherpa-onnx-v{VER}-linux-x64-shared.tar.bz2` (no `-cpu` suffix) |
16+
| Linux Voice Assistant | `cmake -B build && cmake --build build` (from `Playground/linux-voice-assistant/`) | `./build/test-pipeline <audio.wav>` runs full VAD→STT→LLM→TTS pipeline | N/A | Requires: ALSA headers (`libasound2-dev`), built commons with backends, downloaded models (`./scripts/download-models.sh`). Audio capture needs real hardware; `test-pipeline` works headless |
17+
| iOS/Swift SDK | Not buildable | Not buildable | Not available | Requires macOS + Xcode |
18+
| Android emulator | Not runnable | Not runnable | N/A | No KVM support in cloud VM |
19+
20+
### Key Gotchas
21+
22+
- **Android SDK**: Installed at `/opt/android-sdk`. `ANDROID_HOME` and `JAVA_HOME` are set in `~/.bashrc`.
23+
- **JDK 17**: Required by Gradle JVM toolchain. Both JDK 17 and JDK 21 are installed.
24+
- **`testLocal` flag**: Set to `true` in `gradle.properties`. Pass `-Prunanywhere.testLocal=false` to Gradle to avoid needing Android NDK (downloads pre-built JNI libs from GitHub releases instead of building locally).
25+
- **C++ compiler**: Default clang on this VM lacks `libc++` headers. Use `gcc`/`g++` via `-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++`.
26+
- **`local.properties`**: Auto-created at root, `sdk/runanywhere-kotlin/`, and `examples/android/RunAnywhereAI/` with `sdk.dir=/opt/android-sdk`.
27+
- **pre-commit hooks**: Installed via `pre-commit install`. Requires `git config --unset-all core.hooksPath` first if `core.hooksPath` is set.
28+
29+
### Linux Voice Assistant Quick Start
30+
31+
```bash
32+
# 1. Build commons with backends
33+
cd sdk/runanywhere-commons
34+
CC=gcc CXX=g++ cmake -B build-linux-x86_64 -DCMAKE_BUILD_TYPE=Release \
35+
-DRAC_BUILD_BACKENDS=ON -DRAC_BACKEND_ONNX=ON -DRAC_BACKEND_LLAMACPP=ON \
36+
-DRAC_BACKEND_RAG=OFF -DRAC_BUILD_SHARED=ON -DRAC_BUILD_PLATFORM=OFF
37+
cmake --build build-linux-x86_64 -j$(nproc)
38+
39+
# 2. Copy libs to dist
40+
# (see build-linux.sh for full dist copy steps)
41+
42+
# 3. Build voice assistant
43+
cd Playground/linux-voice-assistant
44+
CC=gcc CXX=g++ cmake -B build && cmake --build build
45+
46+
# 4. Run test pipeline (headless, no mic needed)
47+
export LD_LIBRARY_PATH="../../sdk/runanywhere-commons/dist/linux/x86_64:../../sdk/runanywhere-commons/third_party/sherpa-onnx-linux/lib"
48+
./build/test-pipeline /path/to/audio.wav
49+
```
50+
51+
### Standard commands
52+
53+
See `CLAUDE.md` for comprehensive build/test/lint commands for all SDK platforms. See `CONTRIBUTING.md` for contributor setup flow.

examples/android/RunAnywhereAI/app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
<activity
4141
android:name=".MainActivity"
4242
android:exported="true"
43-
android:windowSoftInputMode="adjustResize"
43+
android:windowSoftInputMode="adjustNothing"
4444
android:theme="@style/Theme.RunAnywhereAI">
4545
<intent-filter>
4646
<action android:name="android.intent.action.MAIN" />

examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/RunAnywhereApplication.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,12 @@ class RunAnywhereApplication : Application() {
208208
isSDKInitialized = RunAnywhere.isInitialized
209209

210210
// Update observable state for Compose UI
211+
val error = initializationError
211212
if (isSDKInitialized) {
212213
_initializationState.value = SDKInitializationState.Ready
213214
Timber.i("🎉 App is ready to use!")
214-
} else if (initializationError != null) {
215-
_initializationState.value = SDKInitializationState.Error(initializationError!!)
215+
} else if (error != null) {
216+
_initializationState.value = SDKInitializationState.Error(error)
216217
} else {
217218
// SDK reported not initialized but no error - treat as ready for offline mode
218219
_initializationState.value = SDKInitializationState.Ready

examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/data/ConversationStore.kt

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@ import timber.log.Timber
66
import com.runanywhere.runanywhereai.domain.models.ChatMessage
77
import com.runanywhere.runanywhereai.domain.models.Conversation
88
import com.runanywhere.runanywhereai.domain.models.MessageRole
9+
import kotlinx.coroutines.CoroutineScope
10+
import kotlinx.coroutines.Dispatchers
11+
import kotlinx.coroutines.SupervisorJob
912
import kotlinx.coroutines.flow.MutableStateFlow
1013
import kotlinx.coroutines.flow.StateFlow
1114
import kotlinx.coroutines.flow.asStateFlow
15+
import kotlinx.coroutines.flow.update
16+
import kotlinx.coroutines.launch
1217
import kotlinx.serialization.decodeFromString
1318
import kotlinx.serialization.encodeToString
1419
import kotlinx.serialization.json.Json
@@ -42,6 +47,7 @@ class ConversationStore private constructor(context: Context) {
4247
val currentConversation: StateFlow<Conversation?> = _currentConversation.asStateFlow()
4348

4449
private val conversationsDirectory: File
50+
private val ioScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
4551
private val json =
4652
Json {
4753
prettyPrint = true
@@ -53,7 +59,7 @@ class ConversationStore private constructor(context: Context) {
5359
if (!conversationsDirectory.exists()) {
5460
conversationsDirectory.mkdirs()
5561
}
56-
loadConversations()
62+
ioScope.launch { loadConversations() }
5763
}
5864

5965
// MARK: - Public Methods
@@ -74,9 +80,7 @@ class ConversationStore private constructor(context: Context) {
7480
performanceSummary = null,
7581
)
7682

77-
val updated = _conversations.value.toMutableList()
78-
updated.add(0, conversation)
79-
_conversations.value = updated
83+
_conversations.update { list -> listOf(conversation) + list }
8084
_currentConversation.value = conversation
8185

8286
saveConversation(conversation)
@@ -88,31 +92,36 @@ class ConversationStore private constructor(context: Context) {
8892
* If not present (by id), adds it at the front so it appears in history.
8993
*/
9094
fun ensureConversationInList(conversation: Conversation) {
91-
val index = _conversations.value.indexOfFirst { it.id == conversation.id }
92-
if (index == -1) {
93-
val list = _conversations.value.toMutableList()
94-
list.add(0, conversation)
95-
_conversations.value = list
96-
saveConversation(conversation)
95+
var wasAdded = false
96+
_conversations.update { list ->
97+
if (list.any { it.id == conversation.id }) {
98+
list
99+
} else {
100+
wasAdded = true
101+
listOf(conversation) + list
102+
}
97103
}
104+
if (wasAdded) saveConversation(conversation)
98105
}
99106

100107
/**
101108
* Update an existing conversation
102109
*/
103110
fun updateConversation(conversation: Conversation) {
104111
val updated = conversation.copy(updatedAt = System.currentTimeMillis())
105-
106-
val index = _conversations.value.indexOfFirst { it.id == conversation.id }
107-
if (index != -1) {
108-
val list = _conversations.value.toMutableList()
109-
list[index] = updated
110-
_conversations.value = list
111-
112+
var found = false
113+
_conversations.update { list ->
114+
list.map {
115+
if (it.id == conversation.id) {
116+
found = true
117+
updated
118+
} else it
119+
}
120+
}
121+
if (found) {
112122
if (_currentConversation.value?.id == conversation.id) {
113123
_currentConversation.value = updated
114124
}
115-
116125
saveConversation(updated)
117126
}
118127
}
@@ -121,16 +130,18 @@ class ConversationStore private constructor(context: Context) {
121130
* Delete a conversation
122131
*/
123132
fun deleteConversation(conversation: Conversation) {
124-
_conversations.value = _conversations.value.filter { it.id != conversation.id }
133+
_conversations.update { list -> list.filter { it.id != conversation.id } }
125134

126135
if (_currentConversation.value?.id == conversation.id) {
127136
_currentConversation.value = _conversations.value.firstOrNull()
128137
}
129138

130-
// Delete file
131-
val file = conversationFileURL(conversation.id)
132-
if (file.exists()) {
133-
file.delete()
139+
// Delete file off main thread
140+
ioScope.launch {
141+
val file = conversationFileURL(conversation.id)
142+
if (file.exists()) {
143+
file.delete()
144+
}
134145
}
135146
}
136147

@@ -176,9 +187,7 @@ class ConversationStore private constructor(context: Context) {
176187
try {
177188
val jsonString = file.readText()
178189
val loaded = json.decodeFromString<Conversation>(jsonString)
179-
val list = _conversations.value.toMutableList()
180-
list.add(loaded)
181-
_conversations.value = list
190+
_conversations.update { list -> list + loaded }
182191
_currentConversation.value = loaded
183192
return loaded
184193
} catch (e: Exception) {
@@ -246,12 +255,14 @@ class ConversationStore private constructor(context: Context) {
246255
* Save a conversation to disk
247256
*/
248257
private fun saveConversation(conversation: Conversation) {
249-
try {
250-
val file = conversationFileURL(conversation.id)
251-
val jsonString = json.encodeToString(conversation)
252-
file.writeText(jsonString)
253-
} catch (e: Exception) {
254-
Timber.e(e, "Failed to save conversation")
258+
ioScope.launch {
259+
try {
260+
val file = conversationFileURL(conversation.id)
261+
val jsonString = json.encodeToString(conversation)
262+
file.writeText(jsonString)
263+
} catch (e: Exception) {
264+
Timber.e(e, "Failed to save conversation")
265+
}
255266
}
256267
}
257268

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.runanywhere.runanywhereai.data
2+
3+
/**
4+
* Example prompts for each LoRA adapter, keyed by adapter filename.
5+
* These are shown in the active LoRA card so users can quickly test the adapter.
6+
*/
7+
object LoraExamplePrompts {
8+
9+
private val promptsByFilename: Map<String, List<String>> = mapOf(
10+
"code-assistant-Q8_0.gguf" to listOf(
11+
"Write a Python function to reverse a linked list",
12+
"Explain the difference between a stack and a queue with code examples",
13+
),
14+
"reasoning-logic-Q8_0.gguf" to listOf(
15+
"If all roses are flowers and some flowers fade quickly, can we conclude some roses fade quickly?",
16+
"A farmer has 17 sheep. All but 9 die. How many are left?",
17+
),
18+
"medical-qa-Q8_0.gguf" to listOf(
19+
"What are the common symptoms of vitamin D deficiency?",
20+
"Explain the difference between Type 1 and Type 2 diabetes",
21+
),
22+
"creative-writing-Q8_0.gguf" to listOf(
23+
"Write a short story about a robot discovering emotions for the first time",
24+
"Describe a sunset over the ocean using vivid sensory language",
25+
),
26+
)
27+
28+
/**
29+
* Get example prompts for a loaded adapter by its file path.
30+
* Extracts the filename from the path and looks up prompts.
31+
*/
32+
fun forAdapterPath(path: String): List<String> {
33+
val filename = path.substringAfterLast("/")
34+
return promptsByFilename[filename] ?: emptyList()
35+
}
36+
}

examples/android/RunAnywhereAI/app/src/main/java/com/runanywhere/runanywhereai/data/ModelList.kt

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ object ModelList {
3232
AppModel(id = "qwen2.5-0.5b-instruct-q6_k", name = "Qwen 2.5 0.5B Instruct Q6_K",
3333
url = "https://huggingface.co/Triangle104/Qwen2.5-0.5B-Instruct-Q6_K-GGUF/resolve/main/qwen2.5-0.5b-instruct-q6_k.gguf",
3434
framework = InferenceFramework.LLAMA_CPP, category = ModelCategory.LANGUAGE,
35-
memoryRequirement = 600_000_000),
35+
memoryRequirement = 600_000_000, supportsLoraAdapters = true),
3636
AppModel(id = "lfm2-350m-q4_k_m", name = "LiquidAI LFM2 350M Q4_K_M",
3737
url = "https://huggingface.co/LiquidAI/LFM2-350M-GGUF/resolve/main/LFM2-350M-Q4_K_M.gguf",
3838
framework = InferenceFramework.LLAMA_CPP, category = ModelCategory.LANGUAGE,
39-
memoryRequirement = 250_000_000, supportsLoraAdapters = true),
39+
memoryRequirement = 250_000_000),
4040
AppModel(id = "lfm2-350m-q8_0", name = "LiquidAI LFM2 350M Q8_0",
4141
url = "https://huggingface.co/LiquidAI/LFM2-350M-GGUF/resolve/main/LFM2-350M-Q8_0.gguf",
4242
framework = InferenceFramework.LLAMA_CPP, category = ModelCategory.LANGUAGE,
43-
memoryRequirement = 400_000_000, supportsLoraAdapters = true),
43+
memoryRequirement = 400_000_000),
4444
AppModel(id = "lfm2-1.2b-tool-q4_k_m", name = "LiquidAI LFM2 1.2B Tool Q4_K_M",
4545
url = "https://huggingface.co/LiquidAI/LFM2-1.2B-Tool-GGUF/resolve/main/LFM2-1.2B-Tool-Q4_K_M.gguf",
4646
framework = InferenceFramework.LLAMA_CPP, category = ModelCategory.LANGUAGE,
@@ -81,46 +81,46 @@ object ModelList {
8181
)),
8282
)
8383

84-
// LoRA Adapters (from Void2377/Qwen on HuggingFace — real standalone LoRA GGUF files)
84+
// LoRA Adapters
8585
private val loraAdapters = listOf(
8686
LoraAdapterCatalogEntry(
87-
id = "chat-assistant-lora",
88-
name = "Chat Assistant",
89-
description = "Enhances conversational chat ability",
90-
downloadUrl = "https://huggingface.co/Void2377/Qwen/resolve/main/lora/chat_assistant-lora-Q8_0.gguf",
91-
filename = "chat_assistant-lora-Q8_0.gguf",
92-
compatibleModelIds = listOf("lfm2-350m-q4_k_m", "lfm2-350m-q8_0"),
93-
fileSize = 690_176,
87+
id = "code-assistant-lora",
88+
name = "Code Assistant",
89+
description = "Enhances code generation and programming assistance",
90+
downloadUrl = "https://huggingface.co/Void2377/Qwen/resolve/main/lora/code-assistant-Q8_0.gguf",
91+
filename = "code-assistant-Q8_0.gguf",
92+
compatibleModelIds = listOf("qwen2.5-0.5b-instruct-q6_k"),
93+
fileSize = 765_952,
9494
defaultScale = 1.0f,
9595
),
9696
LoraAdapterCatalogEntry(
97-
id = "summarizer-lora",
98-
name = "Summarizer",
99-
description = "Specialized for text summarization tasks",
100-
downloadUrl = "https://huggingface.co/Void2377/Qwen/resolve/main/lora/summarizer-lora-Q8_0.gguf",
101-
filename = "summarizer-lora-Q8_0.gguf",
102-
compatibleModelIds = listOf("lfm2-350m-q4_k_m", "lfm2-350m-q8_0"),
103-
fileSize = 690_176,
97+
id = "reasoning-logic-lora",
98+
name = "Reasoning Logic",
99+
description = "Improves logical reasoning and step-by-step problem solving",
100+
downloadUrl = "https://huggingface.co/Void2377/Qwen/resolve/main/lora/reasoning-logic-Q8_0.gguf",
101+
filename = "reasoning-logic-Q8_0.gguf",
102+
compatibleModelIds = listOf("qwen2.5-0.5b-instruct-q6_k"),
103+
fileSize = 765_952,
104104
defaultScale = 1.0f,
105105
),
106106
LoraAdapterCatalogEntry(
107-
id = "translator-lora",
108-
name = "Translator",
109-
description = "Improves translation between languages",
110-
downloadUrl = "https://huggingface.co/Void2377/Qwen/resolve/main/lora/translator-lora-Q8_0.gguf",
111-
filename = "translator-lora-Q8_0.gguf",
112-
compatibleModelIds = listOf("lfm2-350m-q4_k_m", "lfm2-350m-q8_0"),
113-
fileSize = 690_176,
107+
id = "medical-qa-lora",
108+
name = "Medical QA",
109+
description = "Enhances medical question answering and health-related responses",
110+
downloadUrl = "https://huggingface.co/Void2377/Qwen/resolve/main/lora/medical-qa-Q8_0.gguf",
111+
filename = "medical-qa-Q8_0.gguf",
112+
compatibleModelIds = listOf("qwen2.5-0.5b-instruct-q6_k"),
113+
fileSize = 765_952,
114114
defaultScale = 1.0f,
115115
),
116116
LoraAdapterCatalogEntry(
117-
id = "sentiment-lora",
118-
name = "Sentiment Analysis",
119-
description = "Fine-tuned for sentiment analysis tasks",
120-
downloadUrl = "https://huggingface.co/Void2377/Qwen/resolve/main/lora/sentiment-lora-Q8_0.gguf",
121-
filename = "sentiment-lora-Q8_0.gguf",
122-
compatibleModelIds = listOf("lfm2-350m-q4_k_m", "lfm2-350m-q8_0"),
123-
fileSize = 690_176,
117+
id = "creative-writing-lora",
118+
name = "Creative Writing",
119+
description = "Improves creative writing, storytelling, and literary style",
120+
downloadUrl = "https://huggingface.co/Void2377/Qwen/resolve/main/lora/creative-writing-Q8_0.gguf",
121+
filename = "creative-writing-Q8_0.gguf",
122+
compatibleModelIds = listOf("qwen2.5-0.5b-instruct-q6_k"),
123+
fileSize = 765_952,
124124
defaultScale = 1.0f,
125125
),
126126
)

0 commit comments

Comments
 (0)