diff --git a/app/src/main/kotlin/fuck/andes/agent/memory/MemoryContext.kt b/app/src/main/kotlin/fuck/andes/agent/memory/MemoryContext.kt deleted file mode 100644 index a4c1ecc..0000000 --- a/app/src/main/kotlin/fuck/andes/agent/memory/MemoryContext.kt +++ /dev/null @@ -1,9 +0,0 @@ -package fuck.andes.agent.memory - -data class MemoryContext( - val memories: List = emptyList(), -) { - companion object { - val EMPTY = MemoryContext() - } -} diff --git a/app/src/main/kotlin/fuck/andes/agent/model/AgentPromptBuilder.kt b/app/src/main/kotlin/fuck/andes/agent/model/AgentPromptBuilder.kt index 2d373bd..0867210 100644 --- a/app/src/main/kotlin/fuck/andes/agent/model/AgentPromptBuilder.kt +++ b/app/src/main/kotlin/fuck/andes/agent/model/AgentPromptBuilder.kt @@ -1,6 +1,5 @@ package fuck.andes.agent.model -import fuck.andes.agent.memory.MemoryContext import fuck.andes.agent.skill.SkillContext import org.json.JSONArray import org.json.JSONObject @@ -103,25 +102,4 @@ internal object AgentPromptBuilder { JSONObject() .put("role", "system") .put("content", content) - - private const val MEMORY_CHAR_BUDGET = 1500 - - fun buildMemoryAppendText(memoryContext: MemoryContext): String? { - val budgeted = budgetedMemories(memoryContext.memories, MEMORY_CHAR_BUDGET) - if (budgeted.isEmpty()) return null - return "\u3010\u8bb0\u5fc6\u3011\n" + budgeted.joinToString("\n") { "- $it" } + - "\n\n\u4ee5\u4e0a\u662f\u5173\u4e8e\u7528\u6237\u7684\u5df2\u77e5\u4fe1\u606f\uff0c\u5728\u76f8\u5173\u65f6\u53c2\u8003\uff0c\u4f46\u4e0d\u8981\u4e3b\u52a8\u63d0\u53ca\u300c\u8bb0\u5fc6\u300d\u3002" - } - - private fun budgetedMemories(memories: List, budget: Int): List { - val result = mutableListOf() - var remaining = budget - for (memory in memories) { - val line = "- $memory\n" - if (line.length > remaining) break - result.add(memory) - remaining -= line.length - } - return result - } } diff --git a/app/src/main/kotlin/fuck/andes/data/db/FuckAndesDatabase.kt b/app/src/main/kotlin/fuck/andes/data/db/FuckAndesDatabase.kt index 81b923f..064009c 100644 --- a/app/src/main/kotlin/fuck/andes/data/db/FuckAndesDatabase.kt +++ b/app/src/main/kotlin/fuck/andes/data/db/FuckAndesDatabase.kt @@ -18,9 +18,8 @@ import androidx.room.migration.Migration RuntimeArchiveRunEntity::class, RuntimeArchiveEventEntity::class, SkillRegistryEntity::class, - MemoryEntity::class, ], - version = 13, + version = 14, exportSchema = false, ) internal abstract class FuckAndesDatabase : RoomDatabase() { @@ -28,7 +27,6 @@ internal abstract class FuckAndesDatabase : RoomDatabase() { abstract fun providerDao(): ProviderDao abstract fun runtimeRunDao(): RuntimeRunDao abstract fun skillDao(): SkillDao - abstract fun memoryDao(): MemoryDao companion object { @Volatile @@ -41,7 +39,7 @@ internal abstract class FuckAndesDatabase : RoomDatabase() { FuckAndesDatabase::class.java, "fuck_andes.db", ) - .addMigrations(MIGRATION_6_7, MIGRATION_7_8, MIGRATION_8_9, MIGRATION_9_10, MIGRATION_10_11, MIGRATION_11_12, MIGRATION_12_13) + .addMigrations(MIGRATION_6_7, MIGRATION_7_8, MIGRATION_8_9, MIGRATION_9_10, MIGRATION_10_11, MIGRATION_11_12, MIGRATION_12_13, MIGRATION_13_14) .fallbackToDestructiveMigration(dropAllTables = true) .build() .also { instance = it } @@ -163,5 +161,9 @@ internal abstract class FuckAndesDatabase : RoomDatabase() { internal val MIGRATION_12_13 = Migration(12, 13) { database -> database.execSQL("ALTER TABLE memories ADD COLUMN priority INTEGER NOT NULL DEFAULT 0") } + + internal val MIGRATION_13_14 = Migration(13, 14) { database -> + database.execSQL("DROP TABLE IF EXISTS memories") + } } } diff --git a/app/src/main/kotlin/fuck/andes/data/db/MemoryDao.kt b/app/src/main/kotlin/fuck/andes/data/db/MemoryDao.kt deleted file mode 100644 index 6609ba2..0000000 --- a/app/src/main/kotlin/fuck/andes/data/db/MemoryDao.kt +++ /dev/null @@ -1,39 +0,0 @@ -package fuck.andes.data.db - -import androidx.room.Dao -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query - -@Dao -internal interface MemoryDao { - @Query("SELECT * FROM memories WHERE scope = 'global' AND enabled = 1 ORDER BY priority ASC, updated_at DESC") - suspend fun enabledGlobalMemories(): List - - @Query("SELECT * FROM memories WHERE scope = :scope ORDER BY priority ASC, updated_at DESC") - suspend fun memoriesByScope(scope: String): List - - @Query("SELECT * FROM memories ORDER BY priority ASC, updated_at DESC") - suspend fun allMemories(): List - - @Insert(onConflict = OnConflictStrategy.REPLACE) - suspend fun upsert(memory: MemoryEntity) - - @Insert(onConflict = OnConflictStrategy.REPLACE) - suspend fun upsertAll(memories: List) - - @Query("UPDATE memories SET enabled = :enabled WHERE id = :id") - suspend fun setEnabled(id: String, enabled: Boolean) - - @Query("DELETE FROM memories WHERE id = :id") - suspend fun delete(id: String) - - @Query("SELECT COUNT(*) FROM memories WHERE scope = 'global' AND enabled = 1") - suspend fun enabledGlobalCount(): Int - - @Query("UPDATE memories SET priority = :priority WHERE id = :id") - suspend fun setPriority(id: String, priority: Int) - - @Query("SELECT MAX(priority) FROM memories WHERE scope = :scope") - suspend fun maxPriority(scope: String): Int? -} diff --git a/app/src/main/kotlin/fuck/andes/data/db/MemoryEntities.kt b/app/src/main/kotlin/fuck/andes/data/db/MemoryEntities.kt deleted file mode 100644 index ba37d52..0000000 --- a/app/src/main/kotlin/fuck/andes/data/db/MemoryEntities.kt +++ /dev/null @@ -1,22 +0,0 @@ -package fuck.andes.data.db - -import androidx.room.ColumnInfo -import androidx.room.Entity -import androidx.room.Index -import androidx.room.PrimaryKey - -@Entity( - tableName = "memories", - indices = [ - Index("scope"), - ], -) -internal data class MemoryEntity( - @PrimaryKey val id: String, - val content: String, - val scope: String, - val enabled: Boolean = true, - @ColumnInfo(name = "priority") val priority: Int = 0, - @ColumnInfo(name = "created_at") val createdAt: Long, - @ColumnInfo(name = "updated_at") val updatedAt: Long, -) diff --git a/app/src/main/kotlin/fuck/andes/data/repository/MemoryRepository.kt b/app/src/main/kotlin/fuck/andes/data/repository/MemoryRepository.kt deleted file mode 100644 index 6fe1393..0000000 --- a/app/src/main/kotlin/fuck/andes/data/repository/MemoryRepository.kt +++ /dev/null @@ -1,51 +0,0 @@ -package fuck.andes.data.repository - -import android.content.Context -import fuck.andes.data.db.FuckAndesDatabase -import fuck.andes.data.db.MemoryEntity -import java.util.concurrent.atomic.AtomicReference - -internal object MemoryRepository { - private val globalCache = AtomicReference>(null) - - suspend fun loadGlobalMemories(context: Context): List { - globalCache.get()?.let { return it } - val memories = FuckAndesDatabase.get(context).memoryDao().enabledGlobalMemories() - globalCache.set(memories) - return memories - } - - fun invalidateGlobalCache() { globalCache.set(null) } - - suspend fun upsert(context: Context, memory: MemoryEntity) { - FuckAndesDatabase.get(context).memoryDao().upsert(memory) - invalidateGlobalCache() - } - - suspend fun delete(context: Context, id: String) { - FuckAndesDatabase.get(context).memoryDao().delete(id) - invalidateGlobalCache() - } - - suspend fun setEnabled(context: Context, id: String, enabled: Boolean) { - FuckAndesDatabase.get(context).memoryDao().setEnabled(id, enabled) - invalidateGlobalCache() - } - - suspend fun allMemoriesForManagement(context: Context, scope: String): List = - FuckAndesDatabase.get(context).memoryDao().memoriesByScope(scope) - - suspend fun enabledGlobalCount(context: Context): Int = - FuckAndesDatabase.get(context).memoryDao().enabledGlobalCount() - - suspend fun setPriority(context: Context, id: String, priority: Int) { - FuckAndesDatabase.get(context).memoryDao().setPriority(id, priority) - invalidateGlobalCache() - } - - suspend fun maxPriority(context: Context, scope: String): Int? = - FuckAndesDatabase.get(context).memoryDao().maxPriority(scope) - - suspend fun totalEnabledCharCount(context: Context): Int = - loadGlobalMemories(context).sumOf { it.content.length } -} diff --git a/app/src/main/kotlin/fuck/andes/ui/SettingsScreen.kt b/app/src/main/kotlin/fuck/andes/ui/SettingsScreen.kt index 12614da..560c491 100644 --- a/app/src/main/kotlin/fuck/andes/ui/SettingsScreen.kt +++ b/app/src/main/kotlin/fuck/andes/ui/SettingsScreen.kt @@ -33,7 +33,6 @@ import androidx.lifecycle.compose.LocalLifecycleOwner import fuck.andes.FuckAndesApp import fuck.andes.agent.accessibility.AgentAccessibilityService import fuck.andes.config.Prefs -import fuck.andes.data.repository.MemoryRepository import fuck.andes.data.repository.ProviderRepository import fuck.andes.data.repository.RuntimeConfigRepository import fuck.andes.ui.components.MiuixBackButton @@ -237,18 +236,6 @@ internal fun SettingsScreen( onClick = { onNavigate(AppRoute.Skills) }, ) PrefDivider() - ArrowPreference( - title = "记忆管理", - summary = rememberMemorySummary(context), - startAction = { - TintedIcon( - icon = LucideR.drawable.lucide_ic_brain, - tint = ColorOSRoyalBlue, - ) - }, - onClick = { onNavigate(AppRoute.Memory) }, - ) - PrefDivider() ArrowPreference( title = "权限健康", startAction = { @@ -498,19 +485,3 @@ private fun isAgentAccessibilityEnabled(context: Context): Boolean { ).orEmpty() return enabledServices.split(':').any { it.equals(expected, ignoreCase = true) } } - -@Composable -private fun rememberMemorySummary(context: Context): String { - var summary by remember { mutableStateOf("AI 跨会话记忆用户偏好与事实") } - LaunchedEffect(Unit) { - val result = withContext(Dispatchers.IO) { - runCatching { - val count = MemoryRepository.enabledGlobalCount(context) - val chars = MemoryRepository.totalEnabledCharCount(context) - "$count 条记忆 / $chars / 1500 字预算" - }.getOrElse { "AI 跨会话记忆用户偏好与事实" } - } - summary = result - } - return summary -} diff --git a/app/src/main/kotlin/fuck/andes/ui/app/AgentAppRoot.kt b/app/src/main/kotlin/fuck/andes/ui/app/AgentAppRoot.kt index f49a20a..d602cd2 100644 --- a/app/src/main/kotlin/fuck/andes/ui/app/AgentAppRoot.kt +++ b/app/src/main/kotlin/fuck/andes/ui/app/AgentAppRoot.kt @@ -60,8 +60,6 @@ import fuck.andes.ui.model.AgentSkillsAction import fuck.andes.ui.model.AgentSystemEnhanceAction import fuck.andes.ui.model.AgentToolsAction import fuck.andes.ui.model.ConversationSearchAction -import fuck.andes.ui.model.MemoryDetailAction -import fuck.andes.ui.model.MemoryManagementAction import fuck.andes.ui.model.PermissionHealthAction import fuck.andes.ui.model.RunReplayAction import fuck.andes.ui.navigation.AgentNavigator @@ -72,8 +70,6 @@ import fuck.andes.ui.screens.enhance.SystemEnhanceScreen import fuck.andes.ui.screens.home.AgentHomeScreen import fuck.andes.ui.screens.permissions.PermissionHealthScreen import fuck.andes.ui.screens.search.ConversationSearchScreen -import fuck.andes.ui.screens.memory.MemoryDetailScreen -import fuck.andes.ui.screens.memory.MemoryManagementScreen import fuck.andes.ui.screens.replay.RunReplayScreen import fuck.andes.ui.screens.skills.AgentSkillsScreen import fuck.andes.ui.screens.terminal.LinuxEnvironmentScreen @@ -383,58 +379,6 @@ fun AgentAppRoot() { }, ) } - entry { - LaunchedEffect(Unit) { - agentState.refreshMemories() - } - MemoryManagementScreen( - state = agentState.memoryManagementState, - onAction = { action -> - when (action) { - MemoryManagementAction.NavigateBack -> popRoute() - is MemoryManagementAction.ToggleMemory -> agentState.toggleMemory(action.memoryId, action.enabled) - is MemoryManagementAction.DeleteMemory -> agentState.deleteMemory(action.memoryId) - is MemoryManagementAction.EditMemory -> agentState.editMemory(action.memoryId, action.content) - is MemoryManagementAction.AddMemory -> agentState.addMemory(action.content) - is MemoryManagementAction.OpenMemoryDetail -> pushRoute(AppRoute.MemoryDetail(action.memoryId)) - MemoryManagementAction.OpenMemoryNew -> pushRoute(AppRoute.MemoryDetail(null)) - } - }, - ) - } - entry { route -> - val memory = if (route.memoryId != null) { - agentState.memoryManagementState.memories.find { it.id == route.memoryId } - } else { - agentState.draftNewMemory - } - if (memory != null) { - MemoryDetailScreen( - memory = memory, - isNew = route.memoryId == null, - onAction = { action -> - when (action) { - MemoryDetailAction.NavigateBack -> popRoute() - is MemoryDetailAction.Save -> { - agentState.editMemory(route.memoryId!!, action.content) - } - is MemoryDetailAction.SaveNew -> { - agentState.addMemory(action.content) - } - MemoryDetailAction.Delete -> { - agentState.deleteMemory(route.memoryId!!) - } - MemoryDetailAction.MoveUp -> { - agentState.moveMemoryUp(route.memoryId!!) - } - MemoryDetailAction.MoveDown -> { - agentState.moveMemoryDown(route.memoryId!!) - } - } - }, - ) - } - } entry { route -> ConversationSearchScreen( state = agentState.conversationSearchState, diff --git a/app/src/main/kotlin/fuck/andes/ui/app/AgentAppShell.kt b/app/src/main/kotlin/fuck/andes/ui/app/AgentAppShell.kt index b93bf03..120cabb 100644 --- a/app/src/main/kotlin/fuck/andes/ui/app/AgentAppShell.kt +++ b/app/src/main/kotlin/fuck/andes/ui/app/AgentAppShell.kt @@ -146,10 +146,8 @@ private fun titleForRoute(route: AppRoute?): String = when (route) { is AppRoute.Settings -> "设置" is AppRoute.LinuxEnvironment -> "Linux 工具环境" is AppRoute.ModelProviders -> "模型提供商" - is AppRoute.Memory -> "记忆管理" is AppRoute.ConversationSearch -> "搜索对话" is AppRoute.RunReplay -> "执行回放" - is AppRoute.MemoryDetail -> if (route.memoryId == null) "添加记忆" else "编辑记忆" is AppRoute.ModelProviderDetail -> route.providerId.let { "Provider 详情" } is AppRoute.ModelProviderNew -> "新建提供商" null -> "Eta" diff --git a/app/src/main/kotlin/fuck/andes/ui/app/AgentAppState.kt b/app/src/main/kotlin/fuck/andes/ui/app/AgentAppState.kt index 40d0f85..ca7ea09 100644 --- a/app/src/main/kotlin/fuck/andes/ui/app/AgentAppState.kt +++ b/app/src/main/kotlin/fuck/andes/ui/app/AgentAppState.kt @@ -15,7 +15,6 @@ import fuck.andes.FuckAndesApp import fuck.andes.agent.accessibility.AgentAccessibilityService import fuck.andes.agent.device.DeviceLocationProvider import fuck.andes.agent.media.AgentImageCodec -import fuck.andes.agent.memory.MemoryContext import fuck.andes.agent.runtime.AgentEvent import fuck.andes.agent.runtime.AgentExternalArchivePayload import fuck.andes.agent.runtime.AgentRunArchiveStore @@ -30,8 +29,6 @@ import fuck.andes.config.Prefs import fuck.andes.core.AndroidAgentLogger import fuck.andes.core.safeLogType import fuck.andes.data.db.FuckAndesDatabase -import fuck.andes.data.db.MemoryEntity -import fuck.andes.data.repository.MemoryRepository import fuck.andes.data.repository.RuntimeConfigRepository import fuck.andes.ui.model.AgentChatHomeUiState import fuck.andes.ui.model.AgentChatMessageUi @@ -50,8 +47,6 @@ import fuck.andes.ui.model.ConversationSearchMatchUi import fuck.andes.ui.model.ConversationSearchUiState import fuck.andes.ui.model.ConversationPaneUiState import fuck.andes.ui.model.ConversationSummaryUi -import fuck.andes.ui.model.MemoryItemUi -import fuck.andes.ui.model.MemoryManagementUiState import fuck.andes.ui.model.PermissionHealthItemUi import fuck.andes.ui.model.PermissionHealthUiState import fuck.andes.ui.model.PermissionStatusUi @@ -140,20 +135,6 @@ internal class AgentAppState( var systemEnhanceState by mutableStateOf(buildSystemEnhanceState()) private set - var memoryManagementState by mutableStateOf(MemoryManagementUiState(isLoading = true)) - private set - - val draftNewMemory = MemoryItemUi( - id = "new", - content = "", - enabled = true, - createdAt = 0L, - priority = 0, - charCount = 0, - ) - - private var cachedGlobalMemoryContents: List = emptyList() - init { refreshConversationSummaries() runtimeRecoveryInProgress.set(true) @@ -404,15 +385,7 @@ internal class AgentAppState( terminalTools = remoteBooleanForUi(Prefs.Keys.AGENT_TERMINAL_TOOLS), browserTools = remoteBooleanForUi(Prefs.Keys.AGENT_BROWSER_TOOLS), thinkingEnabled = thinkingEnabled, - )?.let { cfg -> - val memoryContext = MemoryContext(memories = cachedGlobalMemoryContents) - val memoryAppendText = AgentPromptBuilder.buildMemoryAppendText(memoryContext) - if (memoryAppendText != null) { - cfg.copy(systemPrompt = cfg.systemPrompt + "\n\n" + memoryAppendText) - } else { - cfg - } - } + ) if (config == null) { withContext(Dispatchers.Main) { applyRunResult( @@ -516,101 +489,6 @@ internal class AgentAppState( permissionHealthState = buildPermissionHealthState(appContext, mediaProjectionGranted) } - fun refreshMemories() { - scope.launch(Dispatchers.IO) { - val memories = runCatching { - MemoryRepository.allMemoriesForManagement(appContext, "global") - }.getOrDefault(emptyList()) - val totalEnabledChars = memories.filter { it.enabled }.sumOf { it.content.length } - memoryManagementState = MemoryManagementUiState( - memories = memories.map { it.toItemUi() }, - isLoading = false, - totalEnabledChars = totalEnabledChars, - ) - refreshMemoryCache() - } - } - - fun toggleMemory(memoryId: String, enabled: Boolean) { - scope.launch(Dispatchers.IO) { - val item = memoryManagementState.memories.find { it.id == memoryId } ?: return@launch - MemoryRepository.setEnabled(appContext, memoryId, enabled) - refreshMemories() - } - } - - fun deleteMemory(memoryId: String) { - scope.launch(Dispatchers.IO) { - MemoryRepository.delete(appContext, memoryId) - refreshMemories() - } - } - - fun editMemory(memoryId: String, content: String) { - scope.launch(Dispatchers.IO) { - val item = memoryManagementState.memories.find { it.id == memoryId } ?: return@launch - val now = System.currentTimeMillis() - MemoryRepository.upsert(appContext, MemoryEntity( - id = memoryId, - content = content, - scope = "global", - enabled = item.enabled, - priority = item.priority, - createdAt = item.createdAt, - updatedAt = now, - )) - refreshMemories() - } - } - - fun addMemory(content: String) { - scope.launch(Dispatchers.IO) { - val now = System.currentTimeMillis() - val maxP = MemoryRepository.maxPriority(appContext, "global") ?: -1 - MemoryRepository.upsert(appContext, MemoryEntity( - id = java.util.UUID.randomUUID().toString(), - content = content, - scope = "global", - enabled = true, - priority = maxP + 1, - createdAt = now, - updatedAt = now, - )) - refreshMemories() - } - } - - fun moveMemoryUp(memoryId: String) { - val memories = memoryManagementState.memories - val index = memories.indexOfFirst { it.id == memoryId } - if (index <= 0) return - val current = memories[index] - val above = memories[index - 1] - scope.launch(Dispatchers.IO) { - MemoryRepository.setPriority(appContext, current.id, above.priority) - MemoryRepository.setPriority(appContext, above.id, current.priority) - refreshMemories() - } - } - - fun moveMemoryDown(memoryId: String) { - val memories = memoryManagementState.memories - val index = memories.indexOfFirst { it.id == memoryId } - if (index < 0 || index >= memories.lastIndex) return - val current = memories[index] - val below = memories[index + 1] - scope.launch(Dispatchers.IO) { - MemoryRepository.setPriority(appContext, current.id, below.priority) - MemoryRepository.setPriority(appContext, below.id, current.priority) - refreshMemories() - } - } - - private suspend fun refreshMemoryCache() { - val globalContents = MemoryRepository.loadGlobalMemories(appContext).map { it.content } - cachedGlobalMemoryContents = globalContents - } - var pendingShareIntent by mutableStateOf(null) private set @@ -1803,12 +1681,6 @@ private fun buildSystemEnhanceState(): AgentSystemEnhanceUiState = id = "future", title = "后续能力", items = listOf( - SystemEnhanceItemUi( - id = "memory", - title = "记忆系统", - summary = "长期记忆和定时触发器后续接入", - status = SystemEnhanceStatusUi.Inactive, - ), SystemEnhanceItemUi( id = "hook", title = "Hook 二级能力", @@ -1847,15 +1719,6 @@ private fun isRootAvailable(): Boolean { } } -private fun MemoryEntity.toItemUi() = MemoryItemUi( - id = id, - content = content, - enabled = enabled, - createdAt = createdAt, - priority = priority, - charCount = content.length, -) - private fun hasAppListAccess(context: Context): Boolean { return try { val pm = context.packageManager diff --git a/app/src/main/kotlin/fuck/andes/ui/model/AgentUiActions.kt b/app/src/main/kotlin/fuck/andes/ui/model/AgentUiActions.kt index 2e5a810..6b039b9 100644 --- a/app/src/main/kotlin/fuck/andes/ui/model/AgentUiActions.kt +++ b/app/src/main/kotlin/fuck/andes/ui/model/AgentUiActions.kt @@ -53,25 +53,6 @@ sealed interface AgentSystemEnhanceAction { data class ToggleItem(val itemId: String) : AgentSystemEnhanceAction } -sealed interface MemoryManagementAction { - data object NavigateBack : MemoryManagementAction - data class ToggleMemory(val memoryId: String, val enabled: Boolean) : MemoryManagementAction - data class DeleteMemory(val memoryId: String) : MemoryManagementAction - data class EditMemory(val memoryId: String, val content: String) : MemoryManagementAction - data class AddMemory(val content: String) : MemoryManagementAction - data class OpenMemoryDetail(val memoryId: String) : MemoryManagementAction - data object OpenMemoryNew : MemoryManagementAction -} - -sealed interface MemoryDetailAction { - data object NavigateBack : MemoryDetailAction - data class Save(val content: String) : MemoryDetailAction - data class SaveNew(val content: String) : MemoryDetailAction - data object Delete : MemoryDetailAction - data object MoveUp : MemoryDetailAction - data object MoveDown : MemoryDetailAction -} - sealed interface ConversationSearchAction { data object NavigateBack : ConversationSearchAction data class QueryChanged(val query: String) : ConversationSearchAction diff --git a/app/src/main/kotlin/fuck/andes/ui/model/MemoryUiState.kt b/app/src/main/kotlin/fuck/andes/ui/model/MemoryUiState.kt deleted file mode 100644 index 59aa9b1..0000000 --- a/app/src/main/kotlin/fuck/andes/ui/model/MemoryUiState.kt +++ /dev/null @@ -1,21 +0,0 @@ -package fuck.andes.ui.model - -import androidx.compose.runtime.Immutable - -@Immutable -data class MemoryManagementUiState( - val memories: List = emptyList(), - val isLoading: Boolean = false, - val totalEnabledChars: Int = 0, - val charBudget: Int = 1500, -) - -@Immutable -data class MemoryItemUi( - val id: String, - val content: String, - val enabled: Boolean, - val createdAt: Long, - val priority: Int = 0, - val charCount: Int = 0, -) diff --git a/app/src/main/kotlin/fuck/andes/ui/navigation/AppRoute.kt b/app/src/main/kotlin/fuck/andes/ui/navigation/AppRoute.kt index e92fb1d..ad87940 100644 --- a/app/src/main/kotlin/fuck/andes/ui/navigation/AppRoute.kt +++ b/app/src/main/kotlin/fuck/andes/ui/navigation/AppRoute.kt @@ -13,8 +13,6 @@ sealed interface AppRoute : NavKey { data object Settings : AppRoute data object LinuxEnvironment : AppRoute data object ModelProviders : AppRoute - data object Memory : AppRoute - data class MemoryDetail(val memoryId: String?) : AppRoute data class ConversationSearch(val initialQuery: String = "") : AppRoute data class RunReplay(val runId: String) : AppRoute data class ModelProviderDetail(val providerId: String) : AppRoute diff --git a/app/src/main/kotlin/fuck/andes/ui/screens/memory/MemoryDetailScreen.kt b/app/src/main/kotlin/fuck/andes/ui/screens/memory/MemoryDetailScreen.kt deleted file mode 100644 index 9720d5c..0000000 --- a/app/src/main/kotlin/fuck/andes/ui/screens/memory/MemoryDetailScreen.kt +++ /dev/null @@ -1,140 +0,0 @@ -package fuck.andes.ui.screens.memory - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import fuck.andes.ui.components.MiuixScaffoldPage -import fuck.andes.ui.components.PrefDivider -import fuck.andes.ui.model.MemoryDetailAction -import fuck.andes.ui.model.MemoryItemUi -import top.yukonga.miuix.kmp.basic.BasicComponent -import top.yukonga.miuix.kmp.basic.Button -import top.yukonga.miuix.kmp.basic.ButtonDefaults -import top.yukonga.miuix.kmp.basic.Card -import top.yukonga.miuix.kmp.basic.SmallTitle -import top.yukonga.miuix.kmp.basic.Text -import top.yukonga.miuix.kmp.basic.TextButton -import top.yukonga.miuix.kmp.basic.TextField -import top.yukonga.miuix.kmp.theme.MiuixTheme -import top.yukonga.miuix.kmp.window.WindowDialog - -@Composable -fun MemoryDetailScreen( - memory: MemoryItemUi, - isNew: Boolean, - onAction: (MemoryDetailAction) -> Unit, - modifier: Modifier = Modifier, -) { - var content by remember(memory.id) { mutableStateOf(memory.content) } - var showDeleteConfirm by remember { mutableStateOf(false) } - val hasChanged = content.trim() != memory.content - - MiuixScaffoldPage( - title = if (isNew) "添加记忆" else "编辑记忆", - onBack = { onAction(MemoryDetailAction.NavigateBack) }, - modifier = modifier, - ) { - item(key = "section_content") { - SmallTitle("内容") - } - item(key = "card_content") { - Card(modifier = Modifier.padding(horizontal = 12.dp)) { - TextField( - value = content, - onValueChange = { content = it }, - maxLines = 15, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 12.dp), - ) - Text( - text = "${content.length} 字", - fontSize = MiuixTheme.textStyles.body2.fontSize, - color = if (content.length > 1500) MiuixTheme.colorScheme.error - else MiuixTheme.colorScheme.onSurfaceVariantSummary, - modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp), - ) - } - } - - item(key = "section_actions") { - SmallTitle("操作") - } - item(key = "card_actions") { - Card(modifier = Modifier.padding(horizontal = 12.dp)) { - if (hasChanged || isNew) { - BasicComponent( - title = if (isNew) "添加" else "保存", - insideMargin = PaddingValues(16.dp), - onClick = { - if (isNew) { - onAction(MemoryDetailAction.SaveNew(content.trim())) - } else { - onAction(MemoryDetailAction.Save(content.trim())) - } - onAction(MemoryDetailAction.NavigateBack) - }, - ) - PrefDivider() - } - if (!isNew) { - BasicComponent( - title = "上移", - insideMargin = PaddingValues(16.dp), - onClick = { onAction(MemoryDetailAction.MoveUp) }, - ) - PrefDivider() - BasicComponent( - title = "下移", - insideMargin = PaddingValues(16.dp), - onClick = { onAction(MemoryDetailAction.MoveDown) }, - ) - PrefDivider() - BasicComponent( - title = "删除", - insideMargin = PaddingValues(16.dp), - onClick = { showDeleteConfirm = true }, - ) - } - } - } - } - - if (showDeleteConfirm) { - WindowDialog( - show = true, - title = "删除后,该记忆将不可恢复", - onDismissRequest = { showDeleteConfirm = false }, - ) { - Column( - modifier = Modifier.fillMaxWidth(), - verticalArrangement = Arrangement.spacedBy(8.dp), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Button( - onClick = { - onAction(MemoryDetailAction.Delete) - onAction(MemoryDetailAction.NavigateBack) - }, - colors = ButtonDefaults.buttonColorsPrimary(), - ) { - Text("删除该记忆") - } - TextButton( - text = "取消", - onClick = { showDeleteConfirm = false }, - ) - } - } - } -} diff --git a/app/src/main/kotlin/fuck/andes/ui/screens/memory/MemoryManagementScreen.kt b/app/src/main/kotlin/fuck/andes/ui/screens/memory/MemoryManagementScreen.kt deleted file mode 100644 index 83e11db..0000000 --- a/app/src/main/kotlin/fuck/andes/ui/screens/memory/MemoryManagementScreen.kt +++ /dev/null @@ -1,103 +0,0 @@ -package fuck.andes.ui.screens.memory - -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.unit.dp -import com.composables.icons.lucide.R as LucideR -import fuck.andes.ui.components.MiuixScaffoldPage -import fuck.andes.ui.components.PrefDivider -import fuck.andes.ui.model.MemoryItemUi -import fuck.andes.ui.model.MemoryManagementAction -import fuck.andes.ui.model.MemoryManagementUiState -import top.yukonga.miuix.kmp.basic.BasicComponent -import top.yukonga.miuix.kmp.basic.Card -import top.yukonga.miuix.kmp.basic.Icon -import top.yukonga.miuix.kmp.basic.SmallTitle -import top.yukonga.miuix.kmp.theme.MiuixTheme - -@Composable -fun MemoryManagementScreen( - state: MemoryManagementUiState, - onAction: (MemoryManagementAction) -> Unit, - modifier: Modifier = Modifier, -) { - MiuixScaffoldPage( - title = "记忆管理", - onBack = { onAction(MemoryManagementAction.NavigateBack) }, - modifier = modifier, - ) { - item(key = "section_title") { - SmallTitle("记忆") - } - item(key = "budget_summary") { - SmallTitle("${state.totalEnabledChars} / ${state.charBudget} 字") - } - item(key = "card_memories") { - Card(modifier = Modifier.padding(horizontal = 12.dp)) { - if (state.memories.isEmpty()) { - BasicComponent( - title = "暂无记忆", - summary = "手动添加记忆,AI 对话时会参考", - insideMargin = PaddingValues(16.dp), - ) - } else { - state.memories.forEachIndexed { index, memory -> - MemoryItemRow( - memory = memory, - onToggle = { onAction(MemoryManagementAction.ToggleMemory(memory.id, it)) }, - onClick = { onAction(MemoryManagementAction.OpenMemoryDetail(memory.id)) }, - onDelete = { onAction(MemoryManagementAction.DeleteMemory(memory.id)) }, - ) - if (index < state.memories.lastIndex) { - PrefDivider() - } - } - } - PrefDivider() - BasicComponent( - title = "添加记忆", - insideMargin = PaddingValues(16.dp), - onClick = { onAction(MemoryManagementAction.OpenMemoryNew) }, - ) - } - } - } -} - -@Composable -private fun MemoryItemRow( - memory: MemoryItemUi, - onToggle: (Boolean) -> Unit, - onClick: () -> Unit, - onDelete: () -> Unit, -) { - val firstLine = memory.content.lineSequence().firstOrNull().orEmpty() - - BasicComponent( - title = firstLine, - summary = buildString { - append("${memory.charCount} 字") - val secondLine = if (memory.content.lines().size > 1 || memory.content.length > firstLine.length) { - memory.content.drop(firstLine.length).trimStart().lineSequence().firstOrNull()?.take(40)?.plus("…")?.ifBlank { null } - } else null - if (secondLine != null) { - append(" · ") - append(secondLine) - } - }, - insideMargin = PaddingValues(16.dp), - endActions = { - Icon( - painter = painterResource(LucideR.drawable.lucide_ic_chevron_right), - contentDescription = null, - modifier = Modifier.size(16.dp), - tint = MiuixTheme.colorScheme.onSurfaceVariantSummary, - ) - }, - onClick = onClick, - ) -}