From b84d395c283bdb7610c32a4ca519e7133a6afa35 Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Mon, 2 Feb 2026 14:30:59 -0800 Subject: [PATCH 1/4] Chat history fix --- .../executorchllamademo/AppSettings.kt | 3 +- .../ui/screens/AppSettingsScreen.kt | 40 ++++++++++++++ .../ui/viewmodel/ChatViewModel.kt | 55 ++++++++++++++----- 3 files changed, 84 insertions(+), 14 deletions(-) diff --git a/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/AppSettings.kt b/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/AppSettings.kt index 6f2cbecac6..75cdc79cd2 100644 --- a/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/AppSettings.kt +++ b/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/AppSettings.kt @@ -12,5 +12,6 @@ package com.example.executorchllamademo * Holds app-wide settings that are independent of the current module/model. */ data class AppSettings( - val appearanceMode: AppearanceMode = AppearanceMode.SYSTEM + val appearanceMode: AppearanceMode = AppearanceMode.SYSTEM, + val saveChatHistory: Boolean = false ) diff --git a/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/screens/AppSettingsScreen.kt b/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/screens/AppSettingsScreen.kt index 29d53901b0..0c89f0d559 100644 --- a/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/screens/AppSettingsScreen.kt +++ b/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/screens/AppSettingsScreen.kt @@ -30,6 +30,8 @@ import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.RadioButton +import androidx.compose.material3.Switch +import androidx.compose.material3.SwitchDefaults import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -141,6 +143,42 @@ fun AppSettingsScreen( Spacer(modifier = Modifier.height(8.dp)) + // Save Chat History toggle + Row( + modifier = Modifier + .fillMaxWidth() + .background(appColors.settingsRowBackground, RoundedCornerShape(8.dp)) + .padding(horizontal = 16.dp, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Column(modifier = Modifier.weight(1f)) { + Text( + text = "Save Chat History", + fontSize = 14.sp, + color = appColors.settingsText + ) + Text( + text = "Persist conversations between sessions", + fontSize = 12.sp, + color = appColors.settingsText.copy(alpha = 0.6f) + ) + } + Switch( + checked = appSettings.saveChatHistory, + onCheckedChange = { enabled -> + appSettings = appSettings.copy(saveChatHistory = enabled) + val prefs = DemoSharedPreferences(context) + prefs.saveAppSettings(appSettings) + }, + colors = SwitchDefaults.colors( + checkedThumbColor = Color.White, + checkedTrackColor = BtnEnabled + ) + ) + } + + Spacer(modifier = Modifier.height(12.dp)) + // Clear Chat button Button( onClick = { showClearChatDialog = true }, @@ -188,6 +226,8 @@ fun AppSettingsScreen( val prefs = DemoSharedPreferences(context) moduleSettings = moduleSettings.copy(isClearChatHistory = true) prefs.saveModuleSettings(moduleSettings) + // Also clear the saved messages immediately + prefs.removeExistingMessages() showClearChatDialog = false } ) { diff --git a/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt b/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt index 09d5f8d688..2ee9517c89 100644 --- a/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt +++ b/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt @@ -82,10 +82,27 @@ class ChatViewModel(application: Application) : AndroidViewModel(application), L private val contentResolver = application.contentResolver init { - loadSavedMessages() + // Check for clear chat history flag BEFORE loading saved messages + val moduleSettings = demoSharedPreferences.getModuleSettings() + if (moduleSettings.isClearChatHistory) { + // Clear the flag and don't load messages + demoSharedPreferences.removeExistingMessages() + demoSharedPreferences.saveModuleSettings(moduleSettings.copy(isClearChatHistory = false)) + currentSettingsFields = moduleSettings.copy(isClearChatHistory = false) + } else { + loadSavedMessages() + } } private fun loadSavedMessages() { + val appSettings = demoSharedPreferences.getAppSettings() + // Only load saved messages if saveChatHistory is enabled + if (!appSettings.saveChatHistory) { + // Clear any existing saved messages since saving is disabled + demoSharedPreferences.removeExistingMessages() + return + } + val existingMsgJSON = demoSharedPreferences.getSavedMessages() if (existingMsgJSON.isNotEmpty()) { val gson = Gson() @@ -99,7 +116,14 @@ class ChatViewModel(application: Application) : AndroidViewModel(application), L } fun saveMessages() { - demoSharedPreferences.addMessages(_messages.toList()) + val appSettings = demoSharedPreferences.getAppSettings() + // Only save messages if saveChatHistory is enabled + if (appSettings.saveChatHistory) { + demoSharedPreferences.addMessages(_messages.toList()) + } else { + // Make sure no messages are persisted + demoSharedPreferences.removeExistingMessages() + } } private val systemPromptMessage = "To get started, select your desired model and tokenizer from the top right corner" @@ -109,27 +133,27 @@ class ChatViewModel(application: Application) : AndroidViewModel(application), L val isUpdated = currentSettingsFields != updatedSettingsFields val isLoadModel = updatedSettingsFields.isLoadModel if (isUpdated) { - checkForClearChatHistory(updatedSettingsFields) + val settingsAfterClear = checkForClearChatHistory(updatedSettingsFields) if (isLoadModel) { // Update local copy BEFORE checking media capabilities - val settingsWithLoadFlagCleared = updatedSettingsFields.copy(isLoadModel = false) + val settingsWithLoadFlagCleared = settingsAfterClear.copy(isLoadModel = false) currentSettingsFields = settingsWithLoadFlagCleared demoSharedPreferences.saveModuleSettings(settingsWithLoadFlagCleared) // Update media capabilities after settings are updated - setBackendMode(updatedSettingsFields.backendType) + setBackendMode(settingsAfterClear.backendType) loadLocalModelAndParameters( - updatedSettingsFields.modelFilePath, - updatedSettingsFields.tokenizerFilePath, - updatedSettingsFields.dataPath, - updatedSettingsFields.temperature.toFloat() + settingsAfterClear.modelFilePath, + settingsAfterClear.tokenizerFilePath, + settingsAfterClear.dataPath, + settingsAfterClear.temperature.toFloat() ) } else { - currentSettingsFields = updatedSettingsFields.copy() + currentSettingsFields = settingsAfterClear.copy() // Update media capabilities after settings are updated - setBackendMode(updatedSettingsFields.backendType) + setBackendMode(settingsAfterClear.backendType) if (module == null) { addSystemMessage(systemPromptMessage) } @@ -175,13 +199,18 @@ class ChatViewModel(application: Application) : AndroidViewModel(application), L } } - private fun checkForClearChatHistory(updatedSettingsFields: ModuleSettings) { + private fun checkForClearChatHistory(updatedSettingsFields: ModuleSettings): ModuleSettings { if (updatedSettingsFields.isClearChatHistory) { _messages.clear() demoSharedPreferences.removeExistingMessages() - demoSharedPreferences.saveModuleSettings(updatedSettingsFields.copy(isClearChatHistory = false)) + val clearedSettings = updatedSettingsFields.copy(isClearChatHistory = false) + demoSharedPreferences.saveModuleSettings(clearedSettings) module?.resetContext() + shouldAddSystemPrompt = true + promptID = 0 + return clearedSettings } + return updatedSettingsFields } private fun loadLocalModelAndParameters( From f756707f09b74e5b61d06d7ee1113c88e4a57111 Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Mon, 2 Feb 2026 14:41:23 -0800 Subject: [PATCH 2/4] update --- .../example/executorchllamademo/ui/viewmodel/ChatViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt b/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt index 2ee9517c89..dfc3ea09fa 100644 --- a/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt +++ b/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt @@ -102,7 +102,7 @@ class ChatViewModel(application: Application) : AndroidViewModel(application), L demoSharedPreferences.removeExistingMessages() return } - + val existingMsgJSON = demoSharedPreferences.getSavedMessages() if (existingMsgJSON.isNotEmpty()) { val gson = Gson() From 9c60da8332abb32599030d3da292387d392d88e8 Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Mon, 2 Feb 2026 16:02:58 -0800 Subject: [PATCH 3/4] Fix --- .../executorchllamademo/ui/viewmodel/ChatViewModel.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt b/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt index dfc3ea09fa..201564a938 100644 --- a/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt +++ b/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt @@ -86,9 +86,11 @@ class ChatViewModel(application: Application) : AndroidViewModel(application), L val moduleSettings = demoSharedPreferences.getModuleSettings() if (moduleSettings.isClearChatHistory) { // Clear the flag and don't load messages + // Keep isLoadModel flag so model still loads in checkAndLoadSettings() demoSharedPreferences.removeExistingMessages() demoSharedPreferences.saveModuleSettings(moduleSettings.copy(isClearChatHistory = false)) - currentSettingsFields = moduleSettings.copy(isClearChatHistory = false) + // Don't update currentSettingsFields here - let checkAndLoadSettings() handle it + // so it detects the change and loads the model if needed } else { loadSavedMessages() } @@ -102,7 +104,7 @@ class ChatViewModel(application: Application) : AndroidViewModel(application), L demoSharedPreferences.removeExistingMessages() return } - + val existingMsgJSON = demoSharedPreferences.getSavedMessages() if (existingMsgJSON.isNotEmpty()) { val gson = Gson() From c6afd1002a59e00d9bf930ebb867417bf6ca992e Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Mon, 2 Feb 2026 16:04:15 -0800 Subject: [PATCH 4/4] Fix --- .../example/executorchllamademo/ui/viewmodel/ChatViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt b/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt index 201564a938..3c907aacec 100644 --- a/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt +++ b/llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/ui/viewmodel/ChatViewModel.kt @@ -104,7 +104,7 @@ class ChatViewModel(application: Application) : AndroidViewModel(application), L demoSharedPreferences.removeExistingMessages() return } - + val existingMsgJSON = demoSharedPreferences.getSavedMessages() if (existingMsgJSON.isNotEmpty()) { val gson = Gson()