fix(ui): show all configured chat picker sessions

Remove the chat picker recency/current-agent filters while preserving the bounded configured-agent refresh, and add the changelog credit for @amknight.
This commit is contained in:
Alex Knight
2026-05-22 15:14:55 +10:00
committed by GitHub
parent b7356e4e58
commit 8df350030d
8 changed files with 9 additions and 42 deletions

View File

@@ -26,6 +26,7 @@ Docs: https://docs.openclaw.ai
- Agents/Copilot: drop unsafe GitHub Copilot Responses reasoning replay items before send so Telegram direct sessions no longer fail on overlong replay IDs. Fixes #85197. (#85198) Thanks @galiniliev.
- fix: constrain Windows task script names [AI]. (#85064) Thanks @pgondhi987.
- Control UI: keep the chat session picker from hiding older or cross-agent configured conversations while preserving the bounded configured-agent refresh. (#85211) Thanks @amknight.
- Agents/Anthropic: preserve unsafe integer tool-call input values in streamed Anthropic tool-use JSON, preventing Discord-style IDs from being rounded before dispatch. Fixes #47229. (#83063) Thanks @leno23.
- Agents/hooks: wait for local one-shot CLI and Codex `agent_end` plugin hooks before process cleanup so terminal observability flushes reliably. (#85007)
- CLI/agents: allow `openclaw agent --session-key` to target explicit session keys, including agent-scoped legacy keys. (#85121) Thanks @Kaspre.

View File

@@ -229,9 +229,11 @@ describe("refreshChat", () => {
"sessions.list",
"sessions list payload",
);
expect(sessionsListPayload.agentId).toBe("main");
expect(sessionsListPayload).not.toHaveProperty("activeMinutes");
expect(sessionsListPayload).not.toHaveProperty("agentId");
expect(sessionsListPayload.includeGlobal).toBe(true);
expect(sessionsListPayload.includeUnknown).toBe(true);
expect(sessionsListPayload.limit).toBe(100);
expect(request).toHaveBeenCalledWith("commands.list", {
agentId: "main",
includeArgs: true,
@@ -578,8 +580,8 @@ describe("refreshChat", () => {
"sessions.list",
"sessions list payload",
);
expect(sessionsListPayload.activeMinutes).toBe(120);
expect(sessionsListPayload.agentId).toBe("main");
expect(sessionsListPayload).not.toHaveProperty("activeMinutes");
expect(sessionsListPayload).not.toHaveProperty("agentId");
expect(sessionsListPayload.includeGlobal).toBe(true);
expect(sessionsListPayload.includeUnknown).toBe(true);
expect(sessionsListPayload.limit).toBe(100);

View File

@@ -85,7 +85,8 @@ export type ChatAbortOptions = {
preserveDraft?: boolean;
};
export const CHAT_SESSIONS_ACTIVE_MINUTES = 120;
// Chat pickers need recency-free session rows so older channel chats remain selectable.
export const CHAT_SESSIONS_ACTIVE_MINUTES = 0;
export const CHAT_SESSIONS_REFRESH_LIMIT = 100;
export {
handleChatDraftChange,
@@ -784,7 +785,6 @@ export async function refreshChat(
limit: CHAT_SESSIONS_REFRESH_LIMIT,
includeGlobal: true,
includeUnknown: true,
agentId: resolveAgentIdForSession(host) ?? undefined,
}),
refreshChatAvatar(host),
refreshChatModels(host),

View File

@@ -141,7 +141,7 @@ describe("handleGatewayEvent sessions.changed", () => {
vi.useRealTimers();
});
it("scopes post-chat final session refreshes to the run's agent", () => {
it("refreshes the full chat session list after a completed chat run", () => {
loadSessionsMock.mockReset();
handleChatEventMock.mockReset().mockReturnValue("final");
const host = createHost();
@@ -157,7 +157,6 @@ describe("handleGatewayEvent sessions.changed", () => {
expect(loadSessionsMock).toHaveBeenCalledWith(host, {
activeMinutes: 10,
agentId: "ops",
limit: 25,
});
});
@@ -557,7 +556,6 @@ describe("handleGatewayEvent session.message", () => {
expect(loadChatHistoryMock).not.toHaveBeenCalled();
expect(loadSessionsMock).toHaveBeenCalledWith(host, {
activeMinutes: 10,
agentId: "qa",
limit: 25,
});
await Promise.resolve();

View File

@@ -690,7 +690,6 @@ function handleTerminalChatEvent(
if (state === "final") {
void loadSessions(host as unknown as SessionsState, {
activeMinutes: CHAT_SESSIONS_ACTIVE_MINUTES,
agentId: resolveChatEventSessionListAgentId(host, payload),
limit: CHAT_SESSIONS_REFRESH_LIMIT,
});
}
@@ -720,27 +719,6 @@ function isEventForDifferentActiveRun(
return Boolean(activeRunId && payload && payload.runId !== activeRunId);
}
function resolveChatEventSessionListAgentId(
host: GatewayHost,
payload: ChatEventPayload | undefined,
): string {
return resolveSessionListAgentIdForSessionKey(
host,
payload?.sessionKey?.trim() || host.sessionKey,
);
}
function resolveSessionListAgentIdForSessionKey(host: GatewayHost, sessionKey: string): string {
const parsed = parseAgentSessionKey(sessionKey);
if (parsed?.agentId) {
return parsed.agentId;
}
const snapshot = host.hello?.snapshot as
| { sessionDefaults?: SessionDefaultsSnapshot }
| undefined;
return normalizeAgentId(snapshot?.sessionDefaults?.defaultAgentId);
}
function handleChatGatewayEvent(host: GatewayHost, payload: ChatEventPayload | undefined) {
if (payload?.sessionKey) {
setLastActiveSessionKey(
@@ -861,7 +839,6 @@ function handleSessionMessageGatewayEvent(
const runIdBeforeRefresh = host.chatRunId;
void loadSessions(host as unknown as SessionsState, {
activeMinutes: CHAT_SESSIONS_ACTIVE_MINUTES,
agentId: resolveSessionListAgentIdForSessionKey(host, sessionKey),
limit: CHAT_SESSIONS_REFRESH_LIMIT,
}).finally(() =>
replayDeferredSessionMessageReloadAfterSessionsRefresh(

View File

@@ -775,7 +775,6 @@ describe("createChatSession", () => {
includeGlobal: true,
includeUnknown: true,
showArchived: false,
agentId: "ops",
},
);
expect(state.sessionKey).toBe("agent:ops:dashboard:new-chat");
@@ -977,7 +976,6 @@ describe("switchChatSession", () => {
includeGlobal: true,
includeUnknown: true,
showArchived: false,
agentId: "main",
});
expect(
(state as unknown as { announceSessionSwitch: ReturnType<typeof vi.fn> })

View File

@@ -705,7 +705,6 @@ export async function createChatSession(state: AppViewState): Promise<boolean> {
includeGlobal: true,
includeUnknown: true,
showArchived: state.sessionsShowArchived,
agentId: resolveAgentIdFromSessionKey(previousSessionKey),
},
);
if (
@@ -738,7 +737,6 @@ async function refreshSessionOptions(state: AppViewState) {
includeGlobal: true,
includeUnknown: true,
showArchived: state.sessionsShowArchived,
agentId: parseAgentSessionKey(state.sessionKey)?.agentId,
});
}

View File

@@ -202,16 +202,9 @@ async function refreshSessionOptions(state: AppViewState) {
includeGlobal: true,
includeUnknown: true,
showArchived: state.sessionsShowArchived,
agentId: resolveSessionOptionsAgentId(state),
});
}
function resolveSessionOptionsAgentId(state: AppViewState): string {
return (
parseAgentSessionKey(state.sessionKey)?.agentId ?? normalizeAgentId(state.agentsList?.defaultId)
);
}
async function refreshVisibleToolsEffectiveForCurrentSessionLazy(state: AppViewState) {
return refreshVisibleToolsEffectiveForCurrentSession(state);
}