Summary
Pressing Escape in TUI to abort a running agent shows "no active run" even though the agent is actively executing commands (browser clicks, tool calls, etc.).
Root Cause
Race condition in src/tui/tui-session-actions.ts:
const abortActive = async () => {
if (!state.activeChatRunId) {
chatLog.addSystem("no active run"); // ← exits early!
tui.requestRender();
return;
}
// abort code never runs...
};
The activeChatRunId is set AFTER sendChat returns:
// tui-command-handlers.ts:412-419
const { runId } = await client.sendChat({...}); // agent starts running
state.activeChatRunId = runId; // set AFTER response
If user presses Escape between the request being sent and the runId being returned, abort fails silently.
However, the server (chat.abort) supports aborting by sessionKey alone without runId:
// server-methods/chat.ts:121-127
if (!runId) {
const res = abortChatRunsForSessionKey(ops, { sessionKey, stopReason: "rpc" });
respond(true, { ok: true, aborted: res.aborted, runIds: res.runIds });
return;
}
Suggested Fix
- Update
gateway-chat.ts to accept optional runId:
async abortChat(opts: { sessionKey: string; runId?: string }) {
return await this.client.request<{ ok: boolean; aborted: boolean; runIds?: string[] }>(
"chat.abort",
{
sessionKey: opts.sessionKey,
...(opts.runId ? { runId: opts.runId } : {}),
},
);
}
- Update
tui-session-actions.ts to always send abort:
const abortActive = async () => {
try {
const res = await client.abortChat({
sessionKey: state.currentSessionKey,
runId: state.activeChatRunId ?? undefined,
});
if (res.aborted) {
setActivityStatus("aborted");
} else {
chatLog.addSystem("no active run");
}
} catch (err) {
chatLog.addSystem(`abort failed: ${String(err)}`);
setActivityStatus("abort failed");
}
tui.requestRender();
};
Impact
Environment
- Version: 2026.1.16-2
- Surface: TUI (terminal)
Summary
Pressing Escape in TUI to abort a running agent shows "no active run" even though the agent is actively executing commands (browser clicks, tool calls, etc.).
Root Cause
Race condition in
src/tui/tui-session-actions.ts:The
activeChatRunIdis set AFTERsendChatreturns:If user presses Escape between the request being sent and the
runIdbeing returned, abort fails silently.However, the server (
chat.abort) supports aborting bysessionKeyalone withoutrunId:Suggested Fix
gateway-chat.tsto accept optionalrunId:tui-session-actions.tsto always send abort:Impact
/stopand/aborttext commands in TUIEnvironment