feat(desktop): observer-driven activity bar in the thread composer - #4663
Open
TolgaCinisli wants to merge 4 commits into
Open
feat(desktop): observer-driven activity bar in the thread composer#4663TolgaCinisli wants to merge 4 commits into
TolgaCinisli wants to merge 4 commits into
Conversation
The inline bot activity bar rotated through the last 5 distinct transcript headlines every 2.2s, which read as flicker during long agent turns. Replace the rotation with one line that updates in place: Assistant · Bash: npm test · 2m 10s · 12 tools · ctx 118K/1M Current activity (running tool + clamped preview, or phase), ticking elapsed anchored to the agent working signal, per-turn tool count, and the latest usage reading. Popover and session panel are untouched. Signed-off-by: Tolga Cinisli <tolgacinisli@gmail.com>
…line Shell rows rendered the raw command text, so the composer bar showed noise like `sed -n '420,432p' src/…` instead of what the agent was doing. Claude Code (and other harnesses) send a human-authored `description` argument with every shell call — prefer it when present, falling back to the descriptor preview otherwise. The session panel still shows the full command; the bar is a status line, not a terminal. Signed-off-by: Tolga Cinisli <tolgacinisli@gmail.com>
The thread composer's activity accessory was fed only by thread-scoped typing entries, so once observer frames became the primary working signal the thread bar stayed dark for the whole turn. Store the NIP-AO envelope sessionId (thread root shortened) on each active turn and scope working agents to the open thread by prefix match, folded with the existing typing fallback via useThreadComposerWorkingPubkeys. Signed-off-by: Tolga Cinisli <tolgacinisli@gmail.com>
…urns Two turns running in one channel interleaved in a single status line, so the bar flipped between unrelated work. Give each bar a scope instead: - `threadRootId` locks a thread composer's bar onto its own turn by matching the observer frame sessionId as a prefix of the thread root. - Past one live turn the channel bar aggregates to "N threads · elapsed" rather than rendering one turn's detail as if it were the whole channel. New `getActiveTurnCountForChannel` returns a primitive, so the store subscription stays reference-stable under `useSyncExternalStore`. Signed-off-by: Tolga Cinisli <tolgacinisli@gmail.com>
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
The thread composer's activity accessory was fed only by thread-scoped typing
entries. Once observer frames became the primary working signal, opening a
thread showed a dark bar for the entire turn even while the channel bar was
live.
sessionId(the thread root, shortened) on eachactive turn, and scope working agents to the open thread by prefix match —
folded with the existing typing fallback in a new
useThreadComposerWorkingPubkeys.(new
threadRootIdprop), so two threads in one channel no longer show eachother's tool rows.
2 threads · 1m 04sinstead of interleaving two turns' details in one line.Each thread's own bar still carries its own detail.
getActiveTurnCountForChannelreturns a primitive so theuseSyncExternalStoresubscription is reference-stable for free.
Related issue
None found — searched open issues and PRs for "thread composer" / "activity
bar" / "parallel turns".
Testing
activeAgentTurnsStore.test.mjs— new cases forgetWorkingAgentPubkeysForThread(prefix match, missing sessionId, turncompletion) and
getActiveTurnCountForChannel(per-agent/per-channelcounting, null inputs, completed turns).
botActivityStatus.test.mjs— new case forthreadRootIdlocking the statusonto its own turn.
pnpm -C desktop test— 4058 passingpnpm -C desktop typecheck— cleanbiome checkon the touched files — clean"2 threads · elapsed"; each open thread's composer bar shows that thread's own
tool and counters.