Add AgentConversationEntry and friends.#10167
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
|
I'm starting a first review of this pull request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR introduces the AgentConversationEntry projection and supporting tests/specs for a staged migration away from ConversationOrTask. The schema is directionally aligned with the stated goal, but the builder currently preserves two of the gaps it is intended to remove.
Concerns
- Task-backed entries compute
capabilities.can_openthrough the legacy task-only action path, so entries that successfully attach a local conversation or server token can still be marked unopenable. - The metadata-only pass uses a helper that filters out ambient-agent metadata, so cloud ambient conversations without a current task row are omitted from the new projection.
Found: 0 critical, 2 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
| has_ambient_run: true, | ||
| }, | ||
| capabilities: AgentConversationCapabilities { | ||
| can_open: item.get_open_action(None, app).is_some(), |
There was a problem hiding this comment.
local_conversation_id by run id but lacks a task conversation_id/session is still marked unopenable; compute this from the entry identity instead.
There was a problem hiding this comment.
This gets changed in a later PR in the stack.
| entries.push(entry); | ||
| } | ||
|
|
||
| for metadata in history_model.get_local_conversations_metadata() { |
There was a problem hiding this comment.
get_local_conversations_metadata() excludes metadata with ambient_agent_task_id, so cloud ambient conversations without a current task row are dropped from get_entries; add an ambient-metadata pass or iterate all metadata and only skip child conversations explicitly.
There was a problem hiding this comment.
I think this is intended for this increment.
harryalbert
left a comment
There was a problem hiding this comment.
awesome. Had some small comments and questions but overally LGTM
| `AgentConversationsModel` currently exposes `ConversationOrTask`, a wrapper over either `AmbientAgentTask` or `ConversationMetadata`, to list, details, filtering, and navigation surfaces in `app/src/ai/agent_conversations_model.rs (399-813)`. The wrapper centralizes several display helpers, but still encodes important behavior as “task vs conversation” decisions. The most problematic example is `link_preference()` and `get_open_action()` in `app/src/ai/agent_conversations_model.rs (624-813)`: task rows choose between session, conversation transcript, or no action from cached task fields, while local conversation rows restore/navigate from `ConversationNavigationData`. | ||
| The model also intentionally hides local conversation rows when a task appears to represent the same logical run in `app/src/ai/agent_conversations_model.rs (1382-1497)`. That shadowing is useful for preserving cloud-run affordances, but it means the visible task row can discard better local-conversation navigation data. A task row with a stale or incomplete `session_id`, `session_link`, `conversation_id`, or `is_sandbox_running` can therefore be unopenable even when the hidden conversation representation is restorable. | ||
| The underlying sources are already separate. `BlocklistAIHistoryModel` owns loaded `AIConversation` contents in `conversations_by_id` and lightweight historical/cloud metadata in `all_conversations_metadata` in `app/src/ai/blocklist/history_model.rs (49-214)`. Cloud metadata can exist without a loaded conversation via `AIConversationMetadata` and `merge_cloud_conversation_metadata` in `app/src/ai/blocklist/history_model/conversation_loader.rs (334-453)`, while `load_conversation_data` loads content only on demand in `app/src/ai/blocklist/history_model/conversation_loader.rs (145-236)`. `ActiveAgentViewsModel` separately tracks which local conversations and ambient sessions are currently open in `app/src/ai/active_agent_views_model.rs (45-531)`. | ||
| This migration introduces a projection-layer `AgentConversationEntry` for list/navigation/detail surfaces. It should not replace `AIConversation`, `BlocklistAIHistoryModel`, or transcript content APIs. Its job is to merge provenance and lightweight display data into one logical row so UI surfaces no longer choose between task and conversation representations. |
| pub ambient_run_id: Option<AmbientAgentTaskId>, | ||
| pub server_conversation_token: Option<ServerConversationToken>, | ||
| pub parent_conversation_id: Option<AIConversationId>, | ||
| pub parent_run_id: Option<AmbientAgentTaskId>, |
There was a problem hiding this comment.
is this for orchestration purposes?
|
|
||
| /// Availability flags for the source data that contributed to an entry. | ||
| #[derive(Clone, Debug, PartialEq, Eq)] | ||
| pub struct AgentConversationBacking { |
There was a problem hiding this comment.
nit, but I don't think this struct naming is super clear
There was a problem hiding this comment.
Renamed to AgentConversationBackingData.
There was a problem hiding this comment.
should. these increments maybe be added with their respective branches? I'm skipping reviewing increments 2 through 4 just because they're not implemented yet (but I can review if you think it makes more sense to cover it all up-front)
| - `AgentConversationProvenance` | ||
| - `AgentConversationBacking` | ||
| - `AgentConversationCapabilities` | ||
| Add an internal builder that consumes current model state and `AppContext`. The builder should: |
There was a problem hiding this comment.
do you have an intuition for how intensive this operation is/how often it'll happen? I think keeping this function pure would be really nice, but wondering if we should do some caching in case it's called very frequently and is expensive
There was a problem hiding this comment.
Shall be addressed in follow ups
aad9222 to
bc6b7ef
Compare
e048029 to
b6a5b47
Compare
b6a5b47 to
ab1fa14
Compare

Adds a new AgentConversationEntry abstraction designed to replace ConversationOrTask.
ConversationOrTask requires a bifurcation between local and cloud conversations that is prone to skew. Downstream of ConversationOrTask, navigation policy (e.g. should clicking this item open a cloud mode pane? or open a cloud transcript view?) and other behaviors are computed and cached. With cloud conversation continuation and local->cloud handoff, it makes less sense to do this bifurcation up front, and instead introduce a unified abstraction that broadly represents an AI conversation, whether its a local conversation started by the user, a cloud ambient agent conversation, or a conversation for which we only currently have server metadata (e.g. have not actually fetched transcript contents from storage).
This refactor will make it easier to implement correct behavior for UI that depends on a conversation's provenance.
This is the first PR in a 4 pr stack, introducing the abstraction itself - but does not hook it into anythinganything. There is 1 master tech spec and 4 more granular specs for each incremental PR.