Skip to content

GH8642: rename agent conversations (custom title on agent-panel cards)#10553

Open
joeyfrasier wants to merge 1 commit into
warpdotdev:masterfrom
joeyfrasier:joeyfrasier/gh8642-implementation
Open

GH8642: rename agent conversations (custom title on agent-panel cards)#10553
joeyfrasier wants to merge 1 commit into
warpdotdev:masterfrom
joeyfrasier:joeyfrasier/gh8642-implementation

Conversation

@joeyfrasier
Copy link
Copy Markdown

Description

Implements GH-8642: allow users to rename an agent conversation (custom title on agent-panel cards). Adds an end-to-end "user-set conversation title" feature that propagates from the data model through persistence, the conversation list, and the vertical-tabs panel.

User-visible surfaces:

  • Conversation list (left panel): inline rename editor with overflow-menu items "Rename conversation" and "Reset conversation name" (Reset shows only when a user-set title exists). Double-click the row title to start a rename. Enter / blur commits, Escape cancels.
  • Vertical tabs: double-clicking the title region of a pane that hosts a chrome conversation now starts a workspace-level inline rename for that conversation; the inline editor renders in the same title slot the existing tab/pane editors use. The pane right-click context menu offers "Rename conversation" / "Reset conversation name" alongside the existing pane-name items.
  • Title preference: a user-set title always wins over the use_latest_user_prompt_as_conversation_title_in_tab_names setting — we never silently overwrite a user's rename when they toggle the setting or ship a new exchange.

Implementation outline (commit-by-commit):

  • 29d4694user_set_title: Option<String> on AIConversation and AgentConversationData; new BlocklistAIHistoryEvent::UpdatedConversationTitle variant. Persisted via existing conversation save path.
  • 722337a — exhaustive-match cleanup for the new event variant across the codebase.
  • 9a04857BlocklistAIHistoryModel::set_conversation_user_title returning Result<bool, RenameConversationError> with shared-session-viewer guard, metadata mirroring, and a has_user_set_title flag on ConversationNavigationData. Conversation loader parses user_set_title from the persisted JSON.
  • 94b17c1 — three new WorkspaceAction variants: RenameConversation, ResetConversationName, SetConversationUserTitle; all participate in app-state save.
  • 90d8647 — conversation-list rename UX (editor, menu items, double-click handler, ItemProps swap).
  • 3a9ab80 — title-preference safety net: TerminalAgentText::has_user_set_title short-circuits preferred_agent_tab_titles so the user-set title can't be overridden by the latest-prompt setting.
  • 505a96e — workspace-level conversation_rename_editor, WorkspaceState::conversation_being_renamed (mutually exclusive with tab/pane rename), real Workspace::rename_conversation / finish_conversation_rename / cancel_conversation_rename.
  • f09ccf8 — vertical-tabs UX wiring: PaneProps extended with conversation_id / is_conversation_being_renamed / conversation_rename_editor; render_title_override adds a third branch; render_pane_title_slot flips its double-click target; new pane_conversation_rename_props helper resolves the triple per pane row with the shared-session-viewer guard. tab.rs gains PaneConversationMenuTarget + pane_conversation_menu_items + menu_items_with_pane_targets; the workspace's pane context menu builder resolves the target from the right-clicked pane's terminal view.
  • 13cf01f — sibling tests for the rename state machine and clippy cleanup.

Linked Issue

Closes #8642.

  • The linked issue is labeled ready-to-spec or ready-to-implement.
  • Where appropriate, screenshots or a short video of the implementation are included below.

Screenshots / Videos

No screenshots attached in this PR yet — the surfaces are functional and styled to match the existing tab/pane rename editors (12pt single-line UI font, same inline mount point). Happy to capture a short video of the conversation-list and vertical-tabs flows on request.

Testing

Automated:

  • New unit tests in app/src/workspace/util_tests.rs (4 tests) exercise the WorkspaceState rename state machine: starts empty, mutual exclusivity between tab / pane / conversation rename, idempotent clear, identity check on is_conversation_being_renamed.
  • New regression test in app/src/workspace/view/vertical_tabs_tests.rs: preferred_agent_tab_titles_user_set_title_beats_latest_prompt_preference ensures the user-set title beats the latest-prompt setting (the spec PR spec: Renaming Conversations #9746 "risks" mitigation).
  • app/src/ai/agent/conversation_tests.rs covers restored_conversation_picks_up_persisted_user_set_title, title_prefers_user_set_title_over_auto_description, normalize_user_title_* (trimming, empty-as-None, char-cap, multi-byte char counting).

Local validations:

  • cargo check -p warp --lib clean at every step of the staged commits.
  • cargo clippy -p warp --lib --tests --all-features -- -D warnings clean.
  • All new tests pass; the broader warp lib suite has only pre-existing unrelated flakiness (terminal/server/codex tests that pass in isolation on master too).

Agent Mode

  • Warp Agent Mode - This PR was created via Warp's AI Agent Mode

Generated with Warp Agent Mode.

Co-Authored-By: Oz oz-agent@warp.dev

@cla-bot cla-bot Bot added the cla-signed label May 9, 2026
@github-actions github-actions Bot added the external-contributor Indicates that a PR has been opened by someone outside the Warp team. label May 9, 2026
@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 9, 2026

@joeyfrasier

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 /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

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

Overview

This PR adds local user-set titles for agent conversations across persistence, conversation-list rows, and vertical-tabs pane chrome.

Concerns

  • Metadata-only local conversations can enter the rename flow, but the model returns NotLoaded and the UI only logs the failure, so the change is lost after commit.
  • Resetting a title clears user_set_title but leaves cached metadata with the old custom title, so metadata-backed surfaces keep showing the reset name until restart.

Verdict

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

Comment thread app/src/ai/blocklist/history_model.rs Outdated
// `convert_persisted_conversation_to_ai_conversation_with_metadata`,
// insert into `conversations_by_id`, then re-dispatch this method.
// The load is async, so the API will need a callback or a future.
Err(RenameConversationError::NotLoaded(conversation_id))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ [IMPORTANT] Conversation-list rows can be metadata-only, so this NotLoaded branch makes the advertised rename flow fail after blur/Enter while the workspace only logs the error. Implement the load-and-mutate path before exposing rename for historical rows, or gate the UI to loaded conversations.

Comment thread app/src/ai/blocklist/history_model.rs Outdated
if let Some(t) = new_user_title {
metadata.title = t;
}
// Note: when clearing the override (Reset), `metadata.title` retains the last
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ [IMPORTANT] Resetting clears user_set_title but leaves metadata.title as the old custom value, so cached historical/command-palette surfaces keep showing the reset title until restart. Recompute or store the derived title when clearing the override before shipping Reset.

@joeyfrasier joeyfrasier force-pushed the joeyfrasier/gh8642-implementation branch from 9650d0c to 0e4cace Compare May 11, 2026 22:49
Adds the ability to set, reset, and persist a user-supplied display title on an
`AIConversation`, separate from the auto-generated title chain. The new title
is local-only (not synced to the server) and surfaces in the conversation list,
command palette, vertical tabs, pane headers, and conversation details panel.

Spec: specs/GH8642/ (PR warpdotdev#9746)

- 2a model layer: `BlocklistAIHistoryModel::set_conversation_user_title` with
  idempotent writes, metadata mirror, and `RenameConversationError` variants
  (NotFound, NoLocalData, NotLoaded, SharedSessionViewer).
  - Reset path recomputes `metadata.title` from `AIConversation::auto_generated_title_for_display`
    so cached historical surfaces revert immediately on reset.
- 2b SQLite persistence: `user_set_title: Option<String>` field on
  `AgentConversationData`, serialized with `skip_serializing_if = "Option::is_none"`
  for backward compatibility.
- 2c event plumbing: `BlocklistAIHistoryEvent::UpdatedConversationTitle`
  emitted on changes; consumed by terminal view (refresh pane header),
  conversation list (re-render), and ignored by orchestration/SDK paths
  with explicit comments.
- 2d UI workspace wiring: `WorkspaceAction::RenameConversation`,
  `ResetConversationName`, `SetConversationUserTitle`; workspace-level
  conversation rename editor and `WorkspaceState::conversation_being_renamed`
  (mutually exclusive with tab/pane rename).
- 3a vertical-tabs surface: double-click title region or right-click menu
  begins inline rename for the chrome conversation; reset entry conditional
  on `has_user_set_title`.
- 3b conversation list surface: title slot renders the shared rename editor
  while renaming; `Reset conversation name` entry in overflow menu.
- 3c title preference: a user-set title overrides the
  `use_latest_user_prompt_as_conversation_title_in_tab_names` setting in
  vertical tabs (`has_user_set_title` short-circuits the title preference
  resolver).
- 3d `ConversationNavigationData.has_user_set_title` populated from
  `AIConversation::user_set_title().is_some()` (live) and
  `AIConversationMetadata.user_set_title.is_some()` (historical).

- `history_model.rs:1901` NotLoaded path now performs a synchronous SQLite
  load via the existing `load_conversation_from_db` helper before falling
  back to NotLoaded, so metadata-only rows with local data succeed instead
  of dropping the rename on the floor.
- `history_model.rs:1952` reset now recomputes `metadata.title` from
  the derived chain instead of leaving the stale custom value.
- Regression tests for both:
  - `test_set_conversation_user_title_returns_not_loaded_only_when_db_load_fails`
  - `test_set_conversation_user_title_reset_recomputes_metadata_title_from_derived_chain`

Added `test_pane_title_is_pane_scoped_while_conversation_title_is_conversation_scoped`
(history_model_tests.rs) to demonstrate that "Rename pane" and
"Rename conversation" write to different layers with different lifetimes:
pane title lives on `PaneConfiguration.custom_vertical_tabs_title` (dies with
the pane), conversation title lives on the `AIConversation` itself plus the
`AIConversationMetadata` mirror (survives pane lifecycle).

- 9 new tests in `history_model_tests.rs` for `set_conversation_user_title`
  (rename, idempotency, metadata mirror, reset chain, NotFound, NoLocalData,
  NotLoaded, SharedSessionViewer, and the persistence-divergence test).
- Existing test files updated with `user_set_title: None` on
  `AgentConversationData` literals and `has_user_set_title: false` on
  `ConversationNavigationData` literals.
- Test files renamed: `history_model_test.rs` -> `history_model_tests.rs`
  and `search_test.rs` -> `search_tests.rs` (master rename absorbed).

Tested with cargo test (89 passed across history_model, agent_conversations_model,
conversation_navigation, conversation_details_panel, orchestration_event_streamer,
workspace::util, and search_tests modules) and cargo clippy --tests --all-features
-- -D warnings.

Co-Authored-By: Oz <oz-agent@warp.dev>
@joeyfrasier joeyfrasier force-pushed the joeyfrasier/gh8642-implementation branch from 0e4cace to 351e179 Compare May 11, 2026 23:09
@joeyfrasier
Copy link
Copy Markdown
Author

/oz-review

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 11, 2026

@joeyfrasier

This PR is not linked to an issue that is marked with ready-to-implement.

Issue-state enforcement details:

Readiness check:

To continue, link this PR to a same-repo issue such as Closes #123 in the PR description, and make sure that issue has ready-to-implement.

Powered by Oz

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

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

@joeyfrasier

This PR is not linked to an issue that is marked with ready-to-implement.

Issue-state enforcement details:

  • Associated same-repo issues checked: #8642

  • Required readiness label: ready-to-implement

Readiness check:

  • #8642: missing ready-to-implement; readiness labels present: ready-to-spec

To continue, link this PR to a same-repo issue such as Closes #123 in the PR description, and make sure that issue has ready-to-implement.

Powered by Oz

@joeyfrasier joeyfrasier mentioned this pull request May 12, 2026
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed external-contributor Indicates that a PR has been opened by someone outside the Warp team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Renaming Conversations

1 participant