Add reminder message about system prompt (#28344)

Trying out sending the model a reminder message about code blocks in the
system prompt. If this seems to work well, we can include more specific
reminder messages, e.g. tool-specific ones.

Release Notes:

- N/A
This commit is contained in:
Richard Feldman 2025-04-09 10:09:48 -04:00 committed by GitHub
parent 9d6d152918
commit 3a8fe4d973
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 73 additions and 28 deletions

View file

@ -0,0 +1 @@
In your response, make sure to remember and follow my instructions about how to format code blocks (and don't mention that you are remembering it, just follow the instructions).

View file

@ -997,6 +997,20 @@ impl Thread {
self.attached_tracked_files_state(&mut request.messages, cx); self.attached_tracked_files_state(&mut request.messages, cx);
// Add reminder to the last user message about code blocks
if let Some(last_user_message) = request
.messages
.iter_mut()
.rev()
.find(|msg| msg.role == Role::User)
{
last_user_message
.content
.push(MessageContent::Text(system_prompt_reminder(
&self.prompt_builder,
)));
}
request request
} }
@ -1810,6 +1824,12 @@ impl Thread {
} }
} }
pub fn system_prompt_reminder(prompt_builder: &prompt_store::PromptBuilder) -> String {
prompt_builder
.generate_assistant_system_prompt_reminder()
.unwrap_or_default()
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ThreadError { pub enum ThreadError {
PaymentRequired, PaymentRequired,
@ -1879,7 +1899,7 @@ mod tests {
) )
.await; .await;
let (_workspace, _thread_store, thread, context_store) = let (_workspace, _thread_store, thread, context_store, prompt_builder) =
setup_test_environment(cx, project.clone()).await; setup_test_environment(cx, project.clone()).await;
add_file_to_context(&project, &context_store, "test/code.rs", cx) add_file_to_context(&project, &context_store, "test/code.rs", cx)
@ -1933,8 +1953,14 @@ fn main() {{
}); });
assert_eq!(request.messages.len(), 1); assert_eq!(request.messages.len(), 1);
let expected_full_message = format!("{}Please explain this code", expected_context); let actual_message = request.messages[0].string_contents();
assert_eq!(request.messages[0].string_contents(), expected_full_message); let expected_content = format!(
"{}Please explain this code{}",
expected_context,
system_prompt_reminder(&prompt_builder)
);
assert_eq!(actual_message, expected_content);
} }
#[gpui::test] #[gpui::test]
@ -1951,7 +1977,7 @@ fn main() {{
) )
.await; .await;
let (_, _thread_store, thread, context_store) = let (_, _thread_store, thread, context_store, _prompt_builder) =
setup_test_environment(cx, project.clone()).await; setup_test_environment(cx, project.clone()).await;
// Open files individually // Open files individually
@ -2051,7 +2077,7 @@ fn main() {{
) )
.await; .await;
let (_, _thread_store, thread, _context_store) = let (_, _thread_store, thread, _context_store, prompt_builder) =
setup_test_environment(cx, project.clone()).await; setup_test_environment(cx, project.clone()).await;
// Insert user message without any context (empty context vector) // Insert user message without any context (empty context vector)
@ -2077,11 +2103,14 @@ fn main() {{
}); });
assert_eq!(request.messages.len(), 1); assert_eq!(request.messages.len(), 1);
assert_eq!( let actual_message = request.messages[0].string_contents();
request.messages[0].string_contents(), let expected_content = format!(
"What is the best way to learn Rust?" "What is the best way to learn Rust?{}",
system_prompt_reminder(&prompt_builder)
); );
assert_eq!(actual_message, expected_content);
// Add second message, also without context // Add second message, also without context
let message2_id = thread.update(cx, |thread, cx| { let message2_id = thread.update(cx, |thread, cx| {
thread.insert_user_message("Are there any good books?", vec![], None, cx) thread.insert_user_message("Are there any good books?", vec![], None, cx)
@ -2097,14 +2126,17 @@ fn main() {{
}); });
assert_eq!(request.messages.len(), 2); assert_eq!(request.messages.len(), 2);
assert_eq!( // First message should be the system prompt
request.messages[0].string_contents(), assert_eq!(request.messages[0].role, Role::User);
"What is the best way to learn Rust?"
); // Second message should be the user message with prompt reminder
assert_eq!( let actual_message = request.messages[1].string_contents();
request.messages[1].string_contents(), let expected_content = format!(
"Are there any good books?" "Are there any good books?{}",
system_prompt_reminder(&prompt_builder)
); );
assert_eq!(actual_message, expected_content);
} }
#[gpui::test] #[gpui::test]
@ -2117,7 +2149,7 @@ fn main() {{
) )
.await; .await;
let (_workspace, _thread_store, thread, context_store) = let (_workspace, _thread_store, thread, context_store, prompt_builder) =
setup_test_environment(cx, project.clone()).await; setup_test_environment(cx, project.clone()).await;
// Open buffer and add it to context // Open buffer and add it to context
@ -2177,11 +2209,14 @@ fn main() {{
// The last message should be the stale buffer notification // The last message should be the stale buffer notification
assert_eq!(last_message.role, Role::User); assert_eq!(last_message.role, Role::User);
// Check the exact content of the message let actual_message = last_message.string_contents();
let expected_content = "These files changed since last read:\n- code.rs\n"; let expected_content = format!(
"These files changed since last read:\n- code.rs\n{}",
system_prompt_reminder(&prompt_builder)
);
assert_eq!( assert_eq!(
last_message.string_contents(), actual_message, expected_content,
expected_content,
"Last message should be exactly the stale buffer notification" "Last message should be exactly the stale buffer notification"
); );
} }
@ -2219,24 +2254,27 @@ fn main() {{
Entity<ThreadStore>, Entity<ThreadStore>,
Entity<Thread>, Entity<Thread>,
Entity<ContextStore>, Entity<ContextStore>,
Arc<PromptBuilder>,
) { ) {
let (workspace, cx) = let (workspace, cx) =
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx)); cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
let thread_store = cx.update(|_, cx| { let thread_store = cx.update(|_, cx| {
ThreadStore::new( ThreadStore::new(project.clone(), Arc::default(), prompt_builder.clone(), cx).unwrap()
project.clone(),
Arc::default(),
Arc::new(PromptBuilder::new(None).unwrap()),
cx,
)
.unwrap()
}); });
let thread = thread_store.update(cx, |store, cx| store.create_thread(cx)); let thread = thread_store.update(cx, |store, cx| store.create_thread(cx));
let context_store = cx.new(|_cx| ContextStore::new(project.downgrade(), None)); let context_store = cx.new(|_cx| ContextStore::new(project.downgrade(), None));
(workspace, thread_store, thread, context_store) (
workspace,
thread_store,
thread,
context_store,
prompt_builder,
)
} }
async fn add_file_to_context( async fn add_file_to_context(

View file

@ -261,6 +261,12 @@ impl PromptBuilder {
.render("assistant_system_prompt", context) .render("assistant_system_prompt", context)
} }
pub fn generate_assistant_system_prompt_reminder(&self) -> Result<String, RenderError> {
self.handlebars
.lock()
.render("assistant_system_prompt_reminder", &())
}
pub fn generate_inline_transformation_prompt( pub fn generate_inline_transformation_prompt(
&self, &self,
user_prompt: String, user_prompt: String,