From c9e49cdf4a79e691dfa9e3f71333a2285025219a Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Tue, 3 Jun 2025 14:56:18 -0600 Subject: [PATCH] Fix panic when re-editing old message with creases (#32017) Co-authored-by: Cole Miller Release Notes: - agent: Fixed a panic when re-editing old messages --------- Co-authored-by: Cole Miller Co-authored-by: Cole Miller --- crates/agent/src/active_thread.rs | 93 ++++++++++++++++++++++++++++++- crates/agent/src/thread.rs | 2 + docs/src/debugger.md | 4 +- 3 files changed, 95 insertions(+), 4 deletions(-) diff --git a/crates/agent/src/active_thread.rs b/crates/agent/src/active_thread.rs index c14320a6247263b494b982e8064b32d2c242f884..136b29a23a8faac05689de7be768c78a6c68c1aa 100644 --- a/crates/agent/src/active_thread.rs +++ b/crates/agent/src/active_thread.rs @@ -3,7 +3,7 @@ use crate::context::{AgentContextHandle, RULES_ICON}; use crate::context_picker::{ContextPicker, MentionLink}; use crate::context_store::ContextStore; use crate::context_strip::{ContextStrip, ContextStripEvent, SuggestContextKind}; -use crate::message_editor::insert_message_creases; +use crate::message_editor::{extract_message_creases, insert_message_creases}; use crate::thread::{ LastRestoreCheckpoint, MessageCrease, MessageId, MessageSegment, Thread, ThreadError, ThreadEvent, ThreadFeedback, ThreadSummary, @@ -1564,6 +1564,8 @@ impl ActiveThread { let edited_text = state.editor.read(cx).text(cx); + let creases = state.editor.update(cx, extract_message_creases); + let new_context = self .context_store .read(cx) @@ -1588,6 +1590,7 @@ impl ActiveThread { message_id, Role::User, vec![MessageSegment::Text(edited_text)], + creases, Some(context.loaded_context), checkpoint.ok(), cx, @@ -3657,10 +3660,13 @@ fn open_editor_at_position( #[cfg(test)] mod tests { use assistant_tool::{ToolRegistry, ToolWorkingSet}; - use editor::EditorSettings; + use editor::{EditorSettings, display_map::CreaseMetadata}; use fs::FakeFs; use gpui::{AppContext, TestAppContext, VisualTestContext}; - use language_model::{LanguageModel, fake_provider::FakeLanguageModel}; + use language_model::{ + ConfiguredModel, LanguageModel, LanguageModelRegistry, + fake_provider::{FakeLanguageModel, FakeLanguageModelProvider}, + }; use project::Project; use prompt_store::PromptBuilder; use serde_json::json; @@ -3721,6 +3727,87 @@ mod tests { assert!(!cx.read(|cx| workspace.read(cx).is_being_followed(CollaboratorId::Agent))); } + #[gpui::test] + async fn test_reinserting_creases_for_edited_message(cx: &mut TestAppContext) { + init_test_settings(cx); + + let project = create_test_project(cx, json!({})).await; + + let (cx, active_thread, _, thread, model) = + setup_test_environment(cx, project.clone()).await; + cx.update(|_, cx| { + LanguageModelRegistry::global(cx).update(cx, |registry, cx| { + registry.set_default_model( + Some(ConfiguredModel { + provider: Arc::new(FakeLanguageModelProvider), + model, + }), + cx, + ); + }); + }); + + let creases = vec![MessageCrease { + range: 14..22, + metadata: CreaseMetadata { + icon_path: "icon".into(), + label: "foo.txt".into(), + }, + context: None, + }]; + + let message = thread.update(cx, |thread, cx| { + let message_id = thread.insert_user_message( + "Tell me about @foo.txt", + ContextLoadResult::default(), + None, + creases, + cx, + ); + thread.message(message_id).cloned().unwrap() + }); + + active_thread.update_in(cx, |active_thread, window, cx| { + active_thread.start_editing_message( + message.id, + message.segments.as_slice(), + message.creases.as_slice(), + window, + cx, + ); + let editor = active_thread + .editing_message + .as_ref() + .unwrap() + .1 + .editor + .clone(); + editor.update(cx, |editor, cx| editor.edit([(0..13, "modified")], cx)); + active_thread.confirm_editing_message(&Default::default(), window, cx); + }); + cx.run_until_parked(); + + let message = thread.update(cx, |thread, _| thread.message(message.id).cloned().unwrap()); + active_thread.update_in(cx, |active_thread, window, cx| { + active_thread.start_editing_message( + message.id, + message.segments.as_slice(), + message.creases.as_slice(), + window, + cx, + ); + let editor = active_thread + .editing_message + .as_ref() + .unwrap() + .1 + .editor + .clone(); + let text = editor.update(cx, |editor, cx| editor.text(cx)); + assert_eq!(text, "modified @foo.txt"); + }); + } + fn init_test_settings(cx: &mut TestAppContext) { cx.update(|cx| { let settings_store = SettingsStore::test(cx); diff --git a/crates/agent/src/thread.rs b/crates/agent/src/thread.rs index cd1a62e57076340dfd9e7bee7ae087d107601e62..0fa7ed98fe85f005d710eb29d8ee01336917733e 100644 --- a/crates/agent/src/thread.rs +++ b/crates/agent/src/thread.rs @@ -1026,6 +1026,7 @@ impl Thread { id: MessageId, new_role: Role, new_segments: Vec, + creases: Vec, loaded_context: Option, checkpoint: Option, cx: &mut Context, @@ -1035,6 +1036,7 @@ impl Thread { }; message.role = new_role; message.segments = new_segments; + message.creases = creases; if let Some(context) = loaded_context { message.loaded_context = context; } diff --git a/docs/src/debugger.md b/docs/src/debugger.md index d23de9542cc80ae6ab129ac3456bcc867fb51108..4d21fb55634efade6678950eebd2837031329675 100644 --- a/docs/src/debugger.md +++ b/docs/src/debugger.md @@ -156,7 +156,9 @@ For a common Flask Application with a file structure similar to the following: ## Breakpoints -Zed currently supports these types of breakpoints: +To set a breakpoint, simply click next to the line number in the editor gutter. +Breakpoints can be tweaked depending on your needs; to access additional options of a given breakpoint, right-click on the breakpoint icon in the gutter and select the desired option. +At present, you can: - Standard Breakpoints: Stop at the breakpoint when it's hit - Log Breakpoints: Output a log message instead of stopping at the breakpoint when it's hit