Skip to content

Commit 891e42b

Browse files
loong0306Nova
andauthored
fix(ui): preserve user-selected session on reconnect and tab switch (openclaw#59611) thanks @loong0306
Fixes openclaw#57072 — chat UI state desync after route navigation. - applySessionDefaults() now detects user-selected sessions and preserves them on reconnect - Chat tab session switching consolidated to use switchChatSession() helper - Overview session-key handler uses shared resetChatStateForSessionSwitch to prevent stale state leaks - Session select dropdowns now set ?selected to reflect actual state Co-authored-by: loong0306 <loong0306@gmail.com> Co-authored-by: Nova <nova@openknot.ai>
1 parent 10a92e2 commit 891e42b

3 files changed

Lines changed: 44 additions & 5 deletions

File tree

ui/src/ui/app-gateway.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,27 @@ function applySessionDefaults(host: GatewayHost, defaults?: SessionDefaultsSnaps
177177
if (!defaults?.mainSessionKey) {
178178
return;
179179
}
180+
181+
// Detect if user has already selected a specific session (not an alias like "main").
182+
// If normalization doesn't change the value, it's a user-selected session.
183+
const normalizedSessionKey = normalizeSessionKeyForDefaults(host.sessionKey, defaults);
184+
const isUserSelectedSession = normalizedSessionKey === host.sessionKey;
185+
186+
if (isUserSelectedSession) {
187+
// User has selected a specific session; preserve their choice
188+
// Only normalize lastActiveSessionKey, don't override current sessionKey
189+
const resolvedLastActiveSessionKey = normalizeSessionKeyForDefaults(
190+
host.settings.lastActiveSessionKey,
191+
defaults,
192+
);
193+
if (resolvedLastActiveSessionKey !== host.settings.lastActiveSessionKey) {
194+
applySettings(host as unknown as Parameters<typeof applySettings>[0], {
195+
...host.settings,
196+
lastActiveSessionKey: resolvedLastActiveSessionKey,
197+
});
198+
}
199+
return; // Keep user's session selection
200+
}
180201
const resolvedSessionKey = normalizeSessionKeyForDefaults(host.sessionKey, defaults);
181202
const resolvedSettingsSessionKey = normalizeSessionKeyForDefaults(
182203
host.settings.sessionKey,

ui/src/ui/app-render.helpers.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,11 @@ export function renderTab(state: AppViewState, tab: Tab, opts?: { collapsed?: bo
117117
}
118118
event.preventDefault();
119119
if (tab === "chat") {
120-
const mainSessionKey = resolveSidebarChatSessionKey(state);
121-
if (state.sessionKey !== mainSessionKey) {
120+
if (!state.sessionKey) {
121+
const mainSessionKey = resolveSidebarChatSessionKey(state);
122122
resetChatStateForSessionSwitch(state, mainSessionKey);
123+
}
124+
if (state.tab !== "chat") {
123125
void state.loadAssistantIdentity();
124126
}
125127
}
@@ -202,7 +204,13 @@ export function renderChatSessionSelect(state: AppViewState) {
202204
group.options,
203205
(entry) => entry.key,
204206
(entry) =>
205-
html`<option value=${entry.key} title=${entry.title}>${entry.label}</option>`,
207+
html`<option
208+
value=${entry.key}
209+
title=${entry.title}
210+
?selected=${entry.key === state.sessionKey}
211+
>
212+
${entry.label}
213+
</option>`,
206214
)}
207215
</optgroup>`,
208216
)}
@@ -474,7 +482,13 @@ export function renderChatMobileToggle(state: AppViewState) {
474482
<optgroup label=${group.label}>
475483
${group.options.map(
476484
(opt) => html`
477-
<option value=${opt.key} title=${opt.title}>${opt.label}</option>
485+
<option
486+
value=${opt.key}
487+
title=${opt.title}
488+
?selected=${opt.key === state.sessionKey}
489+
>
490+
${opt.label}
491+
</option>
478492
`,
479493
)}
480494
</optgroup>

ui/src/ui/app-render.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1113,13 +1113,17 @@ export function renderApp(state: AppViewState) {
11131113
onSessionKeyChange: (next) => {
11141114
state.sessionKey = next;
11151115
state.chatMessage = "";
1116+
state.chatMessages = [];
1117+
state.chatToolMessages = [];
1118+
state.chatStream = null;
1119+
state.chatRunId = null;
1120+
state.chatQueue = [];
11161121
state.resetToolStream();
11171122
state.applySettings({
11181123
...state.settings,
11191124
sessionKey: next,
11201125
lastActiveSessionKey: next,
11211126
});
1122-
void state.loadAssistantIdentity();
11231127
},
11241128
onToggleGatewayTokenVisibility: () => {
11251129
state.overviewShowGatewayToken = !state.overviewShowGatewayToken;

0 commit comments

Comments
 (0)