fix(status-bar): keep spinner/timer alive across turn boundaries#122
Merged
yishuiliunian merged 1 commit intomainfrom Apr 19, 2026
Merged
fix(status-bar): keep spinner/timer alive across turn boundaries#122yishuiliunian merged 1 commit intomainfrom
yishuiliunian merged 1 commit intomainfrom
Conversation
The status bar would flicker to Idle mid-execution while the agent was still actively processing. Users saw the spinner animation stop, the turn timer freeze, and yet the content area kept streaming new output. It resolved itself after a short moment. Root cause: AwaitingInput (end of turn N) and Running (start of turn N+1) are two separate events that hop agent-proc -> stdio -> hub broadcast -> mpsc bridge -> TUI. Between their arrivals the session state has status = WaitingForInput, turn_start = None, and all six "active" branches in status_icon_and_label miss, so the status bar renders Idle. ToolResult / TokenUsage events continue to arrive in the same window, which is why the content area keeps updating. The same transition happens mid-turn on retry / context-overflow / stream-error paths, amplifying the visibility. Fix: decouple status-bar liveness from any specific event's observable status. Every agent activity event now stamps last_active_at on the conversation; the TUI treats anything within a 750ms grace window as "working", keeps the spinner rotating via a global monotonic animation clock, and only falls back to Idle once activity has genuinely stopped. - session: AgentConversation.mark_active / is_recently_active, stamped from Stream, ThinkingStream, ThinkingComplete, ToolCall, ToolResult, ToolBatchStart, ToolProgress, RetryError, Started, Running, ServerToolUse, ServerToolResult. - tui: is_agent_active consumes the grace window; spinner uses a process-wide clock so frame progression is independent of turn_elapsed freezing; displayed turn duration is unchanged. Tests: 6 new session tests cover stamping on each event type, the grace-window bridging of AwaitingInput -> Running, and reset_timer clearing the stamp.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
turn_elapsed冻结,但内容区仍在流式更新,一段时间后自愈。AwaitingInput与Running是两条独立事件,中间存在 ms~数百 ms 的时序窗口;该窗口内status_icon_and_label所有 active 分支全部 miss,状态栏渲染成 Idle。retry / context-overflow / stream-error 路径会放大这个抖动。last_active_at,TUI 在 750ms grace 窗内仍视为活跃;spinner 动画改用全局单调时钟,独立于turn_elapsed。Changes
session (
crates/loopal-session)agent_conversation.rs: 新增last_active_at字段 +mark_active()/is_recently_active(grace)API,reset_timer()同步清戳agent_handler.rs: Stream / ThinkingStream / ThinkingComplete / ToolCall / ToolResult / ToolBatchStart / ToolProgress / RetryError / Started / Running / ServerToolUse / ServerToolResult 在处理时都conv.mark_active()tests/suite/activity_grace_test.rs(新): 6 条单测覆盖各事件打戳、grace 窗口跨AwaitingInput→Running保留、reset_timer清戳、零-grace 即过期tui (
crates/loopal-tui/src/views/unified_status.rs)is_agent_active新增is_recently_active(ACTIVITY_GRACE=750ms)分支status_icon_and_label新增 grace 分支 → 保持 "Working" 而非 "Idle"animation_clock();显示的 turn 时长仍沿用turn_elapsed,不改语义Test plan
bazel build //... --config=clippy通过bazel build //... --config=rustfmt通过bazel test //...52/52 全过(含 6 条新 session 测试)参考:上一个相关修复 #121 (emit explicit Running agent event on turn start)。本 PR 是该修复的补充——即使 Running 事件按预期发出,跨进程/跨 channel 的时序抖动仍会被用户察觉,此处从显示层兜底。