Suggest conversation-based thread titles in /rename (#40495)

## What changed

- Generate a title suggestion from the latest substantive user and assistant messages when the TUI `/rename` prompt opens.
- Prefill the prompt with the result while keeping it editable and preserving any text the user enters before generation finishes.
- Bound and escape the conversation context, omit commentary and IDE context, and correlate responses with the active thread and prompt so stale suggestions are ignored.

## Testing

- Cover conversation selection and prompt construction, generated-title delivery through the embedded app server, loading and prefilled prompt states, stale responses, and preservation of manual edits.

GitOrigin-RevId: 1e7f1d5d4f6503ff9da0548388f610c446c130ca
This commit is contained in:
Felipe Coury authored and copyberry committed 2026-08-24 23:15:04 +00:00
1 parent 0c992c305d
commit 5a51caf04d
13 files changed
+877 -2

No files matched your search

@@ -1621,6 +1621,37 @@ async fn live_app_server_manual_thread_name_is_visible_before_notification() {
assert_eq!(drain_insert_history(&mut rx).len(), 1);
}
#[tokio::test]
async fn thread_name_suggestion_requires_matching_thread_and_request() {
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
let thread_id = ThreadId::new();
let request_id = uuid::Uuid::new_v4();
chat.thread_id = Some(thread_id);
let view = CustomPromptView::new(
"Rename thread".to_string(),
"Type a name and press Enter".to_string(),
/*initial_text*/ String::new(),
/*context_label*/ None,
Box::new(|_| {}),
)
.with_text_suggestion(request_id, "Loading".into(), "Ready".into());
chat.bottom_pane.show_text_prompt(view);
chat.apply_thread_name_suggestion(ThreadId::new(), request_id, Some("Wrong thread"));
chat.apply_thread_name_suggestion(thread_id, uuid::Uuid::new_v4(), Some("Wrong request"));
let popup = render_bottom_popup(&chat, /*width*/ 80);
assert!(popup.contains("Loading"));
assert!(!popup.contains("Wrong"));
chat.apply_thread_name_suggestion(thread_id, request_id, Some("Suggested title"));
let popup = render_bottom_popup(&chat, /*width*/ 80);
assert!(popup.contains("Ready"));
assert!(popup.contains("Suggested title"));
}
#[tokio::test]
async fn live_app_server_thread_closed_requests_immediate_exit() {
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;