fix: gate TUI lifecycle updates to active run (#1567) (thanks @vignesh07)

This commit is contained in:
Peter Steinberger
2026-01-24 07:23:25 +00:00
parent 8f4426052c
commit ad7fc4964a
3 changed files with 33 additions and 1 deletions

View File

@@ -58,6 +58,7 @@ Docs: https://docs.clawd.bot
- MS Teams (plugin): remove `.default` suffix from Graph scopes to avoid double-appending. (#1507) Thanks @Evizero.
- Browser: keep extension relay tabs controllable when the extension reuses a session id after switching tabs. (#1160)
- TUI: track active run ids from chat events so tool/lifecycle updates show for non-TUI runs. (#1567) Thanks @vignesh07.
- TUI: ignore lifecycle updates from non-active runs to keep status accurate. (#1567) Thanks @vignesh07.
## 2026.1.22

View File

@@ -184,4 +184,33 @@ describe("tui-event-handlers: handleAgentEvent", () => {
expect(chatLog.startTool).not.toHaveBeenCalled();
expect(tui.requestRender).not.toHaveBeenCalled();
});
it("ignores lifecycle updates for non-active runs in the same session", () => {
const state = makeState({ activeChatRunId: "run-active" });
const { chatLog, tui, setActivityStatus } = makeContext(state);
const { handleChatEvent, handleAgentEvent } = createEventHandlers({
chatLog: chatLog as any,
tui: tui as any,
state,
setActivityStatus,
});
handleChatEvent({
runId: "run-other",
sessionKey: state.currentSessionKey,
state: "delta",
message: { content: "hello" },
});
setActivityStatus.mockClear();
tui.requestRender.mockClear();
handleAgentEvent({
runId: "run-other",
stream: "lifecycle",
data: { phase: "end" },
});
expect(setActivityStatus).not.toHaveBeenCalled();
expect(tui.requestRender).not.toHaveBeenCalled();
});
});

View File

@@ -125,7 +125,8 @@ export function createEventHandlers(context: EventHandlerContext) {
syncSessionKey();
// Agent events (tool streaming, lifecycle) are emitted per-run. Filter against the
// active chat run id, not the session id.
if (evt.runId !== state.activeChatRunId && !sessionRuns.has(evt.runId)) return;
const isActiveRun = evt.runId === state.activeChatRunId;
if (!isActiveRun && !sessionRuns.has(evt.runId)) return;
if (evt.stream === "tool") {
const data = evt.data ?? {};
const phase = asString(data.phase, "");
@@ -147,6 +148,7 @@ export function createEventHandlers(context: EventHandlerContext) {
return;
}
if (evt.stream === "lifecycle") {
if (!isActiveRun) return;
const phase = typeof evt.data?.phase === "string" ? evt.data.phase : "";
if (phase === "start") setActivityStatus("running");
if (phase === "end") setActivityStatus("idle");