Skip to content

fix(desktop): stop spinning animation on archived in_progress todo items - #42666

Closed
liuhao1024 wants to merge 1 commit into
NousResearch:mainfrom
liuhao1024:fix/desktop-archived-todo-spinning
Closed

fix(desktop): stop spinning animation on archived in_progress todo items#42666
liuhao1024 wants to merge 1 commit into
NousResearch:mainfrom
liuhao1024:fix/desktop-archived-todo-spinning

Conversation

@liuhao1024

Copy link
Copy Markdown
Contributor

Problem

After an assistant turn completes in Desktop, the hoisted todo card still renders archived in_progress items with a spinning Loader2Icon, making the completed session appear stuck.

The backend correctly preserves the final todo snapshot (including unfinished items), but the Desktop renderer treats all in_progress items as if they were actively streaming.

Fixes #42662

Solution

Add an isLive prop to HoistedTodoPanel (and its internal Checkmark component) that distinguishes between live streaming and archived states:

  • Live (isLive=true, message is running): in_progress items render with animate-spin Loader2Icon at full opacity — unchanged behavior
  • Archived (isLive=false, message completed): in_progress items render with a static dot at 70% opacity — clearly shows incomplete but not "running"

thread.tsx passes isLive={messageStatus === 'running'} to HoistedTodoPanel.

Files Changed

File Change
apps/desktop/src/components/assistant-ui/todo-tool.tsx Add isLive prop to Checkmark and HoistedTodoPanel; render static dot when archived
apps/desktop/src/components/assistant-ui/thread.tsx Pass isLive={messageStatus === 'running'} to HoistedTodoPanel
apps/desktop/src/components/assistant-ui/streaming.test.tsx Add 2 tests: archived in_progress shows static dot, live shows spinner

Testing

✓ renders live todo rows during a running turn
✓ renders archived todos after turn completion regardless of pending state
✓ hoists todo outside the thinking disclosure when reasoning is present
✓ shows static dot for archived in_progress items after turn completes  ← NEW
✓ shows spinning icon for in_progress items during live streaming       ← NEW

All existing todo tests continue to pass. No type errors in modified files.

Screenshots

Before (spinning on completed turn) After (static dot)
in_progress row spins indefinitely after turn ends in_progress row shows muted static dot

When an assistant turn completes, the hoisted todo panel could still
show a spinning Loader2Icon for archived in_progress items, making
the completed session appear stuck.

Add an isLive prop to HoistedTodoPanel that controls whether
in_progress items render with animate-spin (live) or a static dot
(archived). Thread passes messageStatus === 'running' so the panel
distinguishes streaming from completed state.

Fixes NousResearch#42662
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have labels Jun 9, 2026
Phantomthedog added a commit to Phantomthedog/hermes-agent that referenced this pull request Jun 17, 2026
The composer status stack rendered in_progress todo items with a live
spinner regardless of whether the owning assistant turn was still
running. After turn completion, archived in_progress rows looked like
active execution — the root cause of NousResearch#42662.

Changes:
- Add isLive flag to ComposerStatusItem, derived from $workingSessionIds
- When isLive=false and todoStatus=in_progress: static dot instead of
  animated spinner, dimmer opacity (70% vs 100%)
- When isLive=true: spinner as before
- Non-todo items (background, subagent) unaffected

Ported semantics from PR NousResearch#42666 (todo-tool.tsx HoistedTodoPanel) to the
current status-stack architecture where todo rendering moved in NousResearch#44630.

Tests: 4 new tests for isLive transitions (live→archived, non-todo unset).
All 12 composer-status tests pass. All 9 todo store/lib tests pass.
TypeScript clean compile.
@DavidMetcalfe

Copy link
Copy Markdown
Contributor

The single CI failure on this PR (test (6)) is unrelated to the changes here. It is a pre-existing flaky race-condition test in tests/test_tui_gateway_server.py::test_session_create_no_race_keeps_worker_alive:

FAILED tests/test_tui_gateway_server.py::test_session_create_no_race_keeps_worker_alive
AssertionError: build thread unregistered its own notify despite no race

The test acknowledges sibling-shard leakage in its own comments (lines 5176-5183) — a prior session.create test in the same shard leaves a registration behind that triggers a spurious assertion. It has no @pytest.mark.flaky marker, and the workaround (clearing server._sessions at test start) is insufficient when a sibling thread fires before the snapshot.

247 other tests in that slice passed. The PR only touches 3 files in apps/desktop/src/components/assistant-ui/ — no amount of Desktop todo-panel changes could cause a TUI gateway server race.

A maintainer can unblock this by:

  1. Re-triggering the failed CI slice (may pass on a cold shard)
  2. Adding @pytest.mark.flaky(reruns=1) to the test
  3. Re-sharding the test suite so this test runs in isolation
  4. Merging as-is if the CI gate allows admin override for unrelated failures

cc @teknium1 @brooklyn @kshitijk4poor — this is a small Desktop-only fix for #42662 that has been sitting unreviewed for 2 weeks. The only red check is a pre-existing flaky test. Would one of you be able to take a look?

@liuhao1024

Copy link
Copy Markdown
Contributor Author

Closing — code refactored

The files touched by this PR have been significantly refactored:

  • todo-tool.tsx — deleted in d62979a6f (feat(desktop): composer status stack, live subagent windows, editable prompts). The HoistedTodoPanel component no longer exists.
  • thread.tsx — the inline {hoistedTodos.length > 0 && <HoistedTodoPanel .../>} line was replaced with a comment: {/* Todos render in the composer status stack now, not inline. */}
  • streaming.test.tsx — the test harness references old HoistedTodoPanel types that are no longer present.

New architecture

Todos now render through the composer status stack (apps/desktop/src/app/chat/composer/status-stack/):

  • store/composer-status.tstodoToItem() maps in_progressstate: 'running'
  • status-stack/status-row.tsxleadingGlyph() shows a GlyphSpinner when item.state === 'running'

Bug may persist in new code

The underlying issue (spinning animation on in_progress todos after turn completion) may still exist in the new implementation, since todoToItem() unconditionally maps in_progress to running regardless of whether the turn is actually live. A new fix would need to:

  1. Thread isLive/messageStatus context through to todoToItem()
  2. Distinguish in_progress during live streaming vs. after turn completion
  3. Show a static indicator (e.g., filled dot) for archived in_progress items

Closing this PR as the original changes are no longer applicable to the current codebase.

@liuhao1024 liuhao1024 closed this Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Low — cosmetic, nice to have type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Desktop todo panel shows archived in_progress items as still running after the assistant turn has completed

3 participants