Files

66 lines
5.3 KiB
Markdown

# 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_entries` merges task rows, loaded conversation rows, and historical metadata rows in `app/src/ai/agent_conversations_model.rs (1032-1081)`.
- When a task shadows a local conversation, the task keeps row ownership.
- `AgentConversationEntryId` identifies either an `AmbientRun` or `Conversation` in `app/src/ai/agent_conversations_model/entry.rs (29-38)`.
The same model owns open-action policy. `resolve_open_action` re-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)`.
`ActiveAgentViewsModel` tracks open/focused local conversations and ambient sessions through `ConversationOrTaskId` in `app/src/ai/active_agent_views_model.rs (25-66)`. Its focused/open terminal view lookup APIs feed inline menu labels and suffixes in `app/src/ai/active_agent_views_model.rs (297-515)`.
Before this change, inline conversation menu rows carried `ConversationNavigationData`, and inline history rows carried `AIConversationId`. 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.title`
See `app/src/terminal/input/conversations/search_item.rs (24-196)`.
Open-state rendering asks `ActiveAgentViewsModel::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 with `get_focused_terminal_view_id(...)` to decide whether to show “open in different pane” in `app/src/terminal/input/conversations/search_item.rs (99-113)` and `app/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::AmbientRun` survives 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_directory` rows 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`.