From 43d1e2df98144d59ddeb515c99d66fc29de467fa Mon Sep 17 00:00:00 2001 From: Derek <294233080+derek201759@users.noreply.github.com> Date: Fri, 7 Aug 2026 11:49:13 -0700 Subject: [PATCH] feat(chat): set new chat as selected on start - Ensure the UI correctly highlights the newly started chat in the sidebar. - This addresses a bug where the old chat remained selected after initiating a new one. - Implements pending state logic in SessionManager to manage session transitions correctly. Refs: feature/set-new-chat-selected-when-user-start-a-chat --- .../kotlin/io/askimo/ui/chat/ChatViewModel.kt | 7 ++++ .../io/askimo/ui/session/SessionManager.kt | 37 ++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/desktop-shared/src/main/kotlin/io/askimo/ui/chat/ChatViewModel.kt b/desktop-shared/src/main/kotlin/io/askimo/ui/chat/ChatViewModel.kt index 1e356d48..7f2086d5 100644 --- a/desktop-shared/src/main/kotlin/io/askimo/ui/chat/ChatViewModel.kt +++ b/desktop-shared/src/main/kotlin/io/askimo/ui/chat/ChatViewModel.kt @@ -1247,6 +1247,13 @@ class ChatViewModel( // Reset directive to null for new chat session selectedDirective = null + + // Clear the active session in the manager so that when the first message of the + // new chat is sent (and SessionCreatedEvent fires), the manager correctly adopts + // the newly created session as the active one. Without this, activeSessionId + // would still point to the previously selected session and the sidebar would + // keep highlighting the old chat item instead of the new one. + sessionManager.markNewChatPending() } /** diff --git a/desktop-shared/src/main/kotlin/io/askimo/ui/session/SessionManager.kt b/desktop-shared/src/main/kotlin/io/askimo/ui/session/SessionManager.kt index 656c6651..89376b1d 100644 --- a/desktop-shared/src/main/kotlin/io/askimo/ui/session/SessionManager.kt +++ b/desktop-shared/src/main/kotlin/io/askimo/ui/session/SessionManager.kt @@ -87,6 +87,16 @@ class SessionManager( var activeSessionId by mutableStateOf(null) private set + /** + * True when the user has started a "New Chat" while an existing session was active. + * In this state the active ViewModel has been cleared (currentSessionId = null) but + * activeSessionId still points at the previous session so that chatViewModel stays + * non-null and the input field remains visible. + * When the first message is sent and a SessionCreatedEvent fires, this flag causes + * the new session to be adopted as the active one, updating the sidebar selection. + */ + private var isPendingNewChat = false + init { Runtime.getRuntime().addShutdownHook( Thread { @@ -104,7 +114,7 @@ class SessionManager( EventBus.internalEvents .filterIsInstance() .collect { event -> - if (activeSessionId == null && event.projectId == null) { + if ((activeSessionId == null || isPendingNewChat) && event.projectId == null) { log.debug("New session created: ${event.sessionId}, setting as active") setActiveSession(event.sessionId) } @@ -512,6 +522,22 @@ class SessionManager( * Used when a new session is created by sending a message in "New Chat" state. */ fun setActiveSession(sessionId: String) { + val wasPendingNewChat = isPendingNewChat + isPendingNewChat = false + + // When transitioning from a "pending new chat" state, the ViewModel that sent the + // first message is still stored under the *old* activeSessionId key. Move it to + // the new sessionId so that getOrCreateChatViewModel(sessionId) returns the + // already-streaming instance instead of creating a fresh empty one (which would + // cause ChatView to show an empty conversation while the response streams in the + // background). + val currentActiveId = activeSessionId + if (wasPendingNewChat && currentActiveId != null && currentActiveId != sessionId) { + chatViewModels.remove(currentActiveId)?.let { existingViewModel -> + chatViewModels[sessionId] = existingViewModel + } + } + activeSessionId = sessionId createdSessions.add(sessionId) } @@ -634,4 +660,13 @@ class SessionManager( activeSessionId = null } } + + /** + * Mark that the user has initiated a "New Chat" while an existing session was active. + * The next SessionCreatedEvent (triggered when the first message is sent) will update + * activeSessionId to the new session so the sidebar highlights it correctly. + */ + fun markNewChatPending() { + isPendingNewChat = true + } }