From 98b35ca8bfc51456012afad569cae869285df76b Mon Sep 17 00:00:00 2001 From: AlexDev_ <56083016+alexdev03@users.noreply.github.com> Date: Sat, 8 Aug 2026 22:38:07 +0200 Subject: [PATCH] fix(chat): open the selected history session (#856) --- .../hermescontrol/ui/chat/ChatViewModel.kt | 33 ++----------------- .../ui/chat/ChatViewModelTest.kt | 10 +++++- 2 files changed, 11 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatViewModel.kt b/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatViewModel.kt index 66a681a6..fc5051fa 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatViewModel.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatViewModel.kt @@ -1823,46 +1823,17 @@ class ChatViewModel( val title = _uiState.value.sessions.find { it.id == sessionId }?.title ?: "Hermes" val generation = resetSessionState(sessionId, title, isLoading = true) viewModelScope.launch { - // Desktop parity (issue #787): a branched session's "current" row - // is its newest child leaf (/model, /branch) — resume THAT instead - // of the stale parent. Best-effort: on any failure (404 for a - // missing session, network blip) fall back to the requested id. - val effectiveId = resolveLatestDescendant(sessionId) ?: sessionId - val effectiveGeneration = - if (effectiveId != sessionId) { - resetSessionState(effectiveId, title, isLoading = true) - } else { - generation - } // Warm-cache fast-path (desktop parity): paint the cached Room // transcript immediately so the screen never sits blank, then load // the fresh server transcript in parallel. If the cache is empty // the spinner stays up until the server page lands. - loadCachedMessages(effectiveId, effectiveGeneration) + loadCachedMessages(sessionId, generation) // Resume the selected desktop session and hydrate its transcript. - resumeSession(effectiveId, effectiveGeneration) + resumeSession(sessionId, generation) loadSessions() } } - /** - * Resolve the newest descendant of a session (issue #787, desktop parity). - * A branched session continues in a child leaf; resuming the parent would - * open a stale branch. Returns null on any failure (sessions without - * descendants report `changed=false`; missing sessions 404) so callers - * fall back to the requested id. - */ - private suspend fun resolveLatestDescendant(sessionId: String): String? = - withContext(ioDispatcher) { - val result = - runCatching { - safeApiCall { ApiClient.hermesApi.getLatestDescendant(sessionId) } - }.getOrNull() - (result as? NetworkResult.Success)?.data - ?.takeIf { it.changed } - ?.session_id - } - private fun loadCachedMessages( sessionId: String, generation: Long, diff --git a/app/src/test/java/com/m57/hermescontrol/ui/chat/ChatViewModelTest.kt b/app/src/test/java/com/m57/hermescontrol/ui/chat/ChatViewModelTest.kt index f8c954ab..e8504e5c 100644 --- a/app/src/test/java/com/m57/hermescontrol/ui/chat/ChatViewModelTest.kt +++ b/app/src/test/java/com/m57/hermescontrol/ui/chat/ChatViewModelTest.kt @@ -1278,9 +1278,17 @@ class ChatViewModelTest { // ── Session switch ─────────────────────────────────────────────────────── @Test - fun testSwitchSession() = + fun testSwitchSession_opensSelectedHistorySessionInsteadOfLatestDescendant() = runTest { val (viewModel, sessionId) = createViewModelWithSession() + coEvery { ApiClient.hermesApi.getLatestDescendant("session-456") } returns + retrofit2.Response.success( + com.m57.hermescontrol.data.model.LatestDescendantResponse( + requested_session_id = "session-456", + session_id = "unrelated-descendant", + changed = true, + ), + ) viewModel.switchSession("session-456") advanceUntilIdle()