diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cb9a37f8..55eee5bd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - Tools: add tmux-style `process send-keys` and bracketed paste helpers for PTY sessions. - Tools: add `process submit` helper to send CR for PTY sessions. - Tools: respond to PTY cursor position queries to unblock interactive TUIs. +- TUI: refresh session token counts after runs complete or fail. (#1079) — thanks @d-ploutarchos. - Status: trim `/status` to current-provider usage only and drop the OAuth/token block. - Directory: unify `clawdbot directory` across channels and plugin channels. - UI: allow deleting sessions from the Control UI. diff --git a/src/tui/tui-event-handlers.ts b/src/tui/tui-event-handlers.ts index 72b6e648c..045c7f940 100644 --- a/src/tui/tui-event-handlers.ts +++ b/src/tui/tui-event-handlers.ts @@ -72,11 +72,13 @@ export function createEventHandlers(context: EventHandlerContext) { chatLog.addSystem("run aborted"); state.activeChatRunId = null; setActivityStatus("aborted"); + void refreshSessionInfo?.(); } if (evt.state === "error") { chatLog.addSystem(`run error: ${evt.errorMessage ?? "unknown"}`); state.activeChatRunId = null; setActivityStatus("error"); + void refreshSessionInfo?.(); } tui.requestRender(); }; diff --git a/src/tui/tui-session-actions.ts b/src/tui/tui-session-actions.ts index f394c522c..327363653 100644 --- a/src/tui/tui-session-actions.ts +++ b/src/tui/tui-session-actions.ts @@ -41,6 +41,7 @@ export function createSessionActions(context: SessionActionContext) { updateAutocompleteProvider, setActivityStatus, } = context; + let refreshSessionInfoPromise: Promise | null = null; const applyAgentsResult = (result: GatewayAgentsList) => { state.agentDefaultId = normalizeAgentId(result.defaultId); @@ -95,43 +96,51 @@ export function createSessionActions(context: SessionActionContext) { }; const refreshSessionInfo = async () => { + if (refreshSessionInfoPromise) return refreshSessionInfoPromise; + refreshSessionInfoPromise = (async () => { + try { + const listAgentId = + state.currentSessionKey === "global" || state.currentSessionKey === "unknown" + ? undefined + : state.currentAgentId; + const result = await client.listSessions({ + includeGlobal: false, + includeUnknown: false, + agentId: listAgentId, + }); + const entry = result.sessions.find((row) => { + // Exact match + if (row.key === state.currentSessionKey) return true; + // Also match canonical keys like "agent:default:main" against "main" + const parsed = parseAgentSessionKey(row.key); + return parsed?.rest === state.currentSessionKey; + }); + state.sessionInfo = { + thinkingLevel: entry?.thinkingLevel, + verboseLevel: entry?.verboseLevel, + reasoningLevel: entry?.reasoningLevel, + model: entry?.model ?? result.defaults?.model ?? undefined, + modelProvider: entry?.modelProvider ?? result.defaults?.modelProvider ?? undefined, + contextTokens: entry?.contextTokens ?? result.defaults?.contextTokens, + inputTokens: entry?.inputTokens ?? null, + outputTokens: entry?.outputTokens ?? null, + totalTokens: entry?.totalTokens ?? null, + responseUsage: entry?.responseUsage, + updatedAt: entry?.updatedAt ?? null, + displayName: entry?.displayName, + }; + } catch (err) { + chatLog.addSystem(`sessions list failed: ${String(err)}`); + } + updateAutocompleteProvider(); + updateFooter(); + tui.requestRender(); + })(); try { - const listAgentId = - state.currentSessionKey === "global" || state.currentSessionKey === "unknown" - ? undefined - : state.currentAgentId; - const result = await client.listSessions({ - includeGlobal: false, - includeUnknown: false, - agentId: listAgentId, - }); - const entry = result.sessions.find((row) => { - // Exact match - if (row.key === state.currentSessionKey) return true; - // Also match canonical keys like "agent:default:main" against "main" - const parsed = parseAgentSessionKey(row.key); - return parsed?.rest === state.currentSessionKey; - }); - state.sessionInfo = { - thinkingLevel: entry?.thinkingLevel, - verboseLevel: entry?.verboseLevel, - reasoningLevel: entry?.reasoningLevel, - model: entry?.model ?? result.defaults?.model ?? undefined, - modelProvider: entry?.modelProvider ?? result.defaults?.modelProvider ?? undefined, - contextTokens: entry?.contextTokens ?? result.defaults?.contextTokens, - inputTokens: entry?.inputTokens ?? null, - outputTokens: entry?.outputTokens ?? null, - totalTokens: entry?.totalTokens ?? null, - responseUsage: entry?.responseUsage, - updatedAt: entry?.updatedAt ?? null, - displayName: entry?.displayName, - }; - } catch (err) { - chatLog.addSystem(`sessions list failed: ${String(err)}`); + await refreshSessionInfoPromise; + } finally { + refreshSessionInfoPromise = null; } - updateAutocompleteProvider(); - updateFooter(); - tui.requestRender(); }; const loadHistory = async () => {