5.3 KiB
Inline conversation and history navigation via agent entries
Context
APP-4313 makes inline conversation surfaces use AgentConversationsModel entries instead of local-only ConversationNavigationData.
The old source, ConversationNavigationData, is local-conversation-centric. It is built from open terminal views, cleared/live local conversations, and local metadata in app/src/ai/conversation_navigation/mod.rs (18-348). It has pane/window navigation fields, but no ambient task identity.
The new source, AgentConversationsModel, exposes one normalized projection for local conversations and ambient runs:
get_entriesmerges task rows, loaded conversation rows, and historical metadata rows inapp/src/ai/agent_conversations_model.rs (1032-1081).- When a task shadows a local conversation, the task keeps row ownership.
AgentConversationEntryIdidentifies either anAmbientRunorConversationinapp/src/ai/agent_conversations_model/entry.rs (29-38). The same model owns open-action policy.resolve_open_actionre-reads current state at accept time, then prefers:- already-open ambient sessions
- already-open local conversations
- joinable ambient sessions
- restorable local conversations
- transcript viewer fallback
See
app/src/ai/agent_conversations_model.rs (1117-1239).ActiveAgentViewsModeltracks open/focused local conversations and ambient sessions throughConversationOrTaskIdinapp/src/ai/active_agent_views_model.rs (25-66). Its focused/open terminal view lookup APIs feed inline menu labels and suffixes inapp/src/ai/active_agent_views_model.rs (297-515). Before this change, inline conversation menu rows carriedConversationNavigationData, and inline history rows carriedAIConversationId. That excluded task-backed cloud agent rows and duplicated navigation rules in input handlers.
Proposed changes
Shared row identity
Use AgentConversationEntryId as the row action payload.
AcceptConversation now stores item_id. The message bar maps that id to ConversationOrTaskId to choose “go to conversation” vs “continue in this pane” in app/src/terminal/input/conversations/mod.rs (29-72).
Inline history mirrors that shape. AcceptHistoryItem, MenuItem, row identity restoration, and accepted events now preserve AgentConversationEntryId in app/src/terminal/input/inline_history/data_source.rs (33-219) and app/src/terminal/input/inline_history/view.rs (34-87).
Inline conversation menu
ConversationMenuDataSource now starts from AgentConversationsModel::get_entries(...), then keeps only rows where resolve_open_action(..., ActivePane, ...) returns an action. This hides unopenable rows and centralizes navigation policy in app/src/terminal/input/conversations/data_source.rs (32-50).
Search behavior stays the same:
- empty query shows up to 50 recent entries
- non-empty query fuzzy-matches title
- Current Directory compares
entry.display.working_directory - the currently active local conversation is hidden
See
app/src/terminal/input/conversations/data_source.rs (57-156). Rendering uses entry display data: - status icon from
entry.display.status - timestamp from
entry.display.last_updated - title/accessibility text from
entry.display.titleSeeapp/src/terminal/input/conversations/search_item.rs (24-196). Open-state rendering asksActiveAgentViewsModel::get_terminal_view_id_for_entry(...)for the open terminal view, using task id first and local conversation id as fallback. It compares that terminal view withget_focused_terminal_view_id(...)to decide whether to show “open in different pane” inapp/src/terminal/input/conversations/search_item.rs (99-113)andapp/src/ai/active_agent_views_model.rs (297-515).
Testing and validation
Preserve:
- inline conversation menu hides the currently active local conversation
- Current Directory filter still works Verify:
- task-backed
AgentConversationEntryId::AmbientRunsurvives inline-history interleaving - accepting a task-backed row opens or focuses the ambient session when possible
- accepting a local conversation row still restores/navigates into the active pane
- labels and suffixes are correct for open local conversations, open ambient sessions, and task-backed rows with local ids Manual checks:
- Open inline conversation menu, search a local conversation, accept it, confirm it opens in active pane.
- Open inline history, search a cloud/ambient run, accept it, confirm it focuses or opens through the shared resolver.
- Toggle Current Directory filter and confirm only matching
entry.display.working_directoryrows appear.
Risks and mitigations
Stale action payloads
Risk: rows carry a stale WorkspaceAction or old ConversationNavigationData.
Mitigation: rows carry only AgentConversationEntryId; actions resolve at accept time.
Hidden task-backed rows
Risk: menus only show local conversations.
Mitigation: data sources start from AgentConversationsModel::get_entries(...) and only drop rows without an open action.
Local/task alias mismatch
Risk: a task-backed row with a local conversation id renders wrong open/focused state. Mitigation: rendering uses the same task-first/local-fallback terminal view lookup shape as open-action resolution.
Over-broad history rows
Risk: display-only metadata creates unopenable history rows.
Mitigation: both menu data sources filter through resolve_open_action.