fix: reset TUI footer activity on session switch (#63988) (thanks @neeravmakwana)

* TUI: reset activity to idle on session switch

* chore: remove redundant tui session comment

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
This commit is contained in:
Neerav Makwana
2026-04-10 04:02:01 -04:00
committed by GitHub
parent dfdc281f55
commit 0002982e52
3 changed files with 70 additions and 1 deletions

View File

@@ -70,6 +70,7 @@ Docs: https://docs.openclaw.ai
- Cron/tool schemas: keep cron tool schemas strict-model-friendly while still preserving `failureAlert=false`, nullable `agentId`/`sessionKey`, and flattened add/update recovery for the newly exposed cron job fields. (#55043) Thanks @brunolorente.
- Git metadata: read commit ids from packed refs as well as loose refs so version and status metadata stay accurate after repository maintenance. (#63943)
- Gateway: keep `commands.list` skill entries categorized under tools and include provider-aware plugin `nativeName` metadata even when `scope=text`, so remote clients can group skills correctly and map text-surface plugin commands back to native aliases.
- TUI: reset footer activity to idle when switching sessions so a stale streaming indicator cannot persist after the selection changes. (#63988) Thanks @neeravmakwana.
## 2026.4.9

View File

@@ -246,6 +246,7 @@ describe("tui session actions", () => {
lastCtrlCAt: 0,
};
const setActivityStatus = vi.fn();
const { setSession } = createSessionActions({
client: {
listSessions,
@@ -266,11 +267,12 @@ describe("tui session actions", () => {
updateHeader: vi.fn(),
updateFooter: vi.fn(),
updateAutocompleteProvider: vi.fn(),
setActivityStatus: vi.fn(),
setActivityStatus,
});
await setSession("agent:main:other");
expect(setActivityStatus).toHaveBeenCalledWith("idle");
expect(loadHistory).toHaveBeenCalledWith({
sessionKey: "agent:main:other",
limit: 200,
@@ -281,4 +283,69 @@ describe("tui session actions", () => {
expect(state.sessionInfo.updatedAt).toBe(50);
expect(btw.clear).toHaveBeenCalled();
});
it("resets activity status to idle when switching sessions after streaming", async () => {
const listSessions = vi.fn().mockResolvedValue({
ts: Date.now(),
path: "/tmp/sessions.json",
count: 0,
defaults: {},
sessions: [],
});
const loadHistory = vi.fn().mockResolvedValue({
sessionId: "session-b",
messages: [],
});
const setActivityStatus = vi.fn();
const state: TuiStateAccess = {
agentDefaultId: "main",
sessionMainKey: "agent:main:main",
sessionScope: "global",
agents: [],
currentAgentId: "main",
currentSessionKey: "agent:main:main",
currentSessionId: null,
activeChatRunId: "run-1",
historyLoaded: true,
sessionInfo: {},
initialSessionApplied: true,
isConnected: true,
autoMessageSent: false,
toolsExpanded: false,
showThinking: false,
connectionStatus: "connected",
activityStatus: "streaming",
statusTimeout: null,
lastCtrlCAt: 0,
};
const { setSession } = createSessionActions({
client: {
listSessions,
loadHistory,
} as unknown as GatewayChatClient,
chatLog: {
addSystem: vi.fn(),
clearAll: vi.fn(),
} as unknown as import("./components/chat-log.js").ChatLog,
btw: createBtwPresenter(),
tui: { requestRender: vi.fn() } as unknown as import("@mariozechner/pi-tui").TUI,
opts: {},
state,
agentNames: new Map(),
initialSessionInput: "",
initialSessionAgentId: null,
resolveSessionKey: vi.fn((raw?: string) => raw ?? "agent:main:main"),
updateHeader: vi.fn(),
updateFooter: vi.fn(),
updateAutocompleteProvider: vi.fn(),
setActivityStatus,
});
await setSession("agent:main:other");
expect(setActivityStatus).toHaveBeenCalledWith("idle");
expect(state.activeChatRunId).toBeNull();
});
});

View File

@@ -363,6 +363,7 @@ export function createSessionActions(context: SessionActionContext) {
updateAgentFromSessionKey(nextKey);
state.currentSessionKey = nextKey;
state.activeChatRunId = null;
setActivityStatus("idle");
state.currentSessionId = null;
// Session keys can move backwards in updatedAt ordering; drop previous session freshness
// so refresh data for the newly selected session isn't rejected as stale.