Skip to content

track chat activity and unread state per session#62

Merged
wesbillman merged 2 commits intomainfrom
feat/chat-session-runtime
Apr 1, 2026
Merged

track chat activity and unread state per session#62
wesbillman merged 2 commits intomainfrom
feat/chat-session-runtime

Conversation

@wesbillman
Copy link
Copy Markdown
Collaborator

Category: improvement
User Impact: Users can see which chats are still busy or have unread output, and session-specific status data now stays with the correct chat when they switch tabs.
Problem: Chat runtime state was effectively shared across sessions, which made per-tab status, unread tracking, and token/model display unreliable once multiple chats were open. The tool usage pill could also wrap awkwardly with long tool names, which made the inline transcript harder to scan.
Solution: Move streaming, token, error, and unread state into per-session runtime records, route ACP stream updates globally by sessionId, and surface running/unread indicators in tabs and sidebars with a shared accent-aware indicator component. Clamp long tool names to a single line with truncation and tooltip fallback, then add regression coverage around the multi-session behavior.

File changes

src/app/AppShell.tsx
Wires the app shell to the global ACP stream listener, derives tab activity from per-session runtime state, clears unread state when the active chat is viewed, and preserves the newer startup hook shape from main.

src/features/chat/hooks/tests/useAcpStream.test.ts
Reworks stream-hook coverage around session-targeted updates, background unread marking, and listener lifecycle after moving to a global listener.

src/features/chat/hooks/tests/useChat.test.ts
Adds coverage for persona-aware cancellation across remounts and for concurrent sends from different sessions.

src/features/chat/hooks/useAcpStream.ts
Removes the per-view session filter, updates session runtimes by sessionId, and marks background sessions unread on completion.

src/features/chat/hooks/useChat.ts
Switches chat operations to session-scoped runtime state and keeps cancellation tied to the active streaming persona for that session.

src/features/chat/lib/sessionActivity.ts
Adds a small helper to derive whether a chat should be treated as actively running.

src/features/chat/stores/tests/chatStore.test.ts
Refreshes store tests around per-session runtime records, unread state, streaming state, and cleanup behavior.

src/features/chat/stores/chatStore.ts
Replaces the old global runtime fields with per-session runtime storage for chat state, tokens, streaming message ids, errors, and unread flags.

src/features/chat/ui/ChatView.tsx
Consumes token state from the session-aware useChat hook and removes the old per-view ACP listener.

src/features/chat/ui/ToolCallCard.tsx
Keeps tool pills left-aligned, clamps long tool names to a single line, and preserves the full tool name in a tooltip.

src/features/chat/ui/tests/ToolCallCard.test.tsx
Adds regression coverage for long tool-name truncation.

src/features/sidebar/ui/Sidebar.tsx
Derives sidebar chat metadata from per-session runtime state so project and recent lists can show running and unread state accurately.

src/features/sidebar/ui/SidebarChatRow.tsx
Accepts running and unread props and renders the shared activity indicator.

src/features/sidebar/ui/SidebarProjectsSection.tsx
Passes activity state through both expanded and collapsed project chat rows and uses the shared overlay indicator in collapsed recents.

src/features/sidebar/ui/tests/SidebarChatRow.test.tsx
Adds coverage for running and unread indicators in sidebar rows.

src/features/tabs/types.ts
Extends tab metadata with running and unread state.

src/features/tabs/ui/TabBar.test.tsx
Adds tab-bar coverage for running and unread indicators.

src/features/tabs/ui/TabBar.tsx
Displays per-session running and unread state in tabs via the shared indicator.

src/shared/types/chat.ts
Introduces the shared SessionChatRuntime type used to model session-specific runtime state.

src/shared/ui/SessionActivityIndicator.test.tsx
Adds direct coverage for inline and overlay activity indicator variants.

src/shared/ui/SessionActivityIndicator.tsx
Introduces a shared accent-aware activity indicator used by the tab and sidebar surfaces.

Reproduction Steps

  1. Open the desktop app and create at least two chat sessions.
  2. Start a response in one chat, switch to a different tab or back to Home, and confirm the inactive chat shows a brand-colored running indicator.
  3. Let the background response finish and confirm the tab/sidebar state changes from running to unread until you reopen that chat.
  4. Trigger a tool call with a long tool name and confirm the tool pill stays on one line, remains left-aligned, and shows the full name on hover.
  5. Switch between sessions and confirm token/model status stays attached to the active session instead of leaking across chats.

@wesbillman wesbillman merged commit f5a5e65 into main Apr 1, 2026
7 checks passed
@wesbillman wesbillman deleted the feat/chat-session-runtime branch April 1, 2026 20:30
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f4f2da33b6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +109 to +110
store.setStreamingMessageId(event.payload.sessionId, null);
store.setChatState(event.payload.sessionId, "idle");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Ignore completion events for sessions already removed

Because this hook now listens globally, acp:done can fire after a session has been archived/removed from useChatSessionStore (for example, while a background run is finishing). Writing runtime state unconditionally here recreates sessionStateById[sessionId] for a session that no longer exists, which leaves orphan unread/runtime entries that are never surfaced or cleaned up. Add a getSession(sessionId) guard before mutating chat runtime in this handler.

Useful? React with 👍 / 👎.

if (event.payload.sessionId !== sessionIdRef.current) return;
const modelName =
event.payload.currentModelName ?? event.payload.currentModelId;
useChatSessionStore
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Skip metadata updates for unknown session IDs

With the per-app listener, acp:model_state events are now processed even when the session is not present locally (e.g., removed/archived session). Calling updateSession unconditionally triggers persistence in chatSessionStore.updateSession, so this path can emit backend update calls and error logs for non-existent sessions. Guard on getSession(event.payload.sessionId) before updating metadata.

Useful? React with 👍 / 👎.

tellaho added a commit to tellaho/goose2 that referenced this pull request Apr 2, 2026
Merges 7 commits from main into tho/boss-ui:
- Image paste support in chat input (block#68)
- Tab name text unselectable (block#67)
- Chat title immediate update on send (block#66)
- Artifact v1 file viewing (block#63)
- Cmd+W tab close (block#64)
- Chat activity/unread state tracking (block#62)
- Sidebar hierarchy polish + faster reloads (block#61)

Key conflict resolutions:
- Keep Tailwind v4 CSS-based config (delete tailwind.config.js)
- Keep boss-ui dialog.tsx, add showCloseButton prop from main
- Add text-foreground-subtle token to boss-ui theme system
- Keep ToolCallAdapter (boss-ui), adopt ToolChainCards pattern from main
- Delete MarkdownContent/ToolCallCard (replaced by boss-ui ai-elements)
- Adopt SessionActivityIndicator from main into sidebar
- Adopt ClickableImage/ImageLightbox from main
- Merge drag-and-drop image support into ChatInput
- Keep boss-ui hover:bg-accent/50 treatment throughout sidebar

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant