This commit is contained in:
Umesh Yadav 2025-07-16 15:27:56 +00:00 committed by GitHub
parent 406ffb1e20
commit a787992431
286 changed files with 3675 additions and 16480 deletions

View file

@ -6,6 +6,7 @@ use language_model::{LanguageModel, LanguageModelRequest, LanguageModelToolSchem
use project::Project;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::fmt::Write as _;
use std::sync::Arc;
use ui::IconName;
@ -30,7 +31,7 @@ impl Tool for ProjectNotificationsTool {
}
fn icon(&self) -> IconName {
IconName::ToolNotification
IconName::Envelope
}
fn input_schema(&self, format: LanguageModelToolSchemaFormat) -> Result<serde_json::Value> {
@ -51,22 +52,34 @@ impl Tool for ProjectNotificationsTool {
_window: Option<AnyWindowHandle>,
cx: &mut App,
) -> ToolResult {
let Some(user_edits_diff) =
action_log.update(cx, |log, cx| log.flush_unnotified_user_edits(cx))
else {
return result("No new notifications");
let mut stale_files = String::new();
let mut notified_buffers = Vec::new();
for stale_file in action_log.read(cx).unnotified_stale_buffers(cx) {
if let Some(file) = stale_file.read(cx).file() {
writeln!(&mut stale_files, "- {}", file.path().display()).ok();
notified_buffers.push(stale_file.clone());
}
}
if !notified_buffers.is_empty() {
action_log.update(cx, |log, cx| {
log.mark_buffers_as_notified(notified_buffers, cx);
});
}
let response = if stale_files.is_empty() {
"No new notifications".to_string()
} else {
// NOTE: Changes to this prompt require a symmetric update in the LLM Worker
const HEADER: &str = include_str!("./project_notifications_tool/prompt_header.txt");
format!("{HEADER}{stale_files}").replace("\r\n", "\n")
};
// NOTE: Changes to this prompt require a symmetric update in the LLM Worker
const HEADER: &str = include_str!("./project_notifications_tool/prompt_header.txt");
result(&format!("{HEADER}\n\n```diff\n{user_edits_diff}\n```\n").replace("\r\n", "\n"))
Task::ready(Ok(response.into())).into()
}
}
fn result(response: &str) -> ToolResult {
Task::ready(Ok(response.to_string().into())).into()
}
#[cfg(test)]
mod tests {
use super::*;
@ -110,7 +123,6 @@ mod tests {
action_log.update(cx, |log, cx| {
log.buffer_read(buffer.clone(), cx);
});
cx.run_until_parked();
// Run the tool before any changes
let tool = Arc::new(ProjectNotificationsTool);
@ -130,7 +142,6 @@ mod tests {
cx,
)
});
cx.run_until_parked();
let response = result.output.await.unwrap();
let response_text = match &response.content {
@ -147,7 +158,6 @@ mod tests {
buffer.update(cx, |buffer, cx| {
buffer.edit([(1..1, "\nChange!\n")], None, cx);
});
cx.run_until_parked();
// Run the tool again
let result = cx.update(|cx| {
@ -161,7 +171,6 @@ mod tests {
cx,
)
});
cx.run_until_parked();
// This time the buffer is stale, so the tool should return a notification
let response = result.output.await.unwrap();
@ -170,12 +179,10 @@ mod tests {
_ => panic!("Expected text response"),
};
assert!(
response_text.contains("These files have changed"),
"Tool should return the stale buffer notification"
);
assert!(
response_text.contains("test/code.rs"),
let expected_content = "[The following is an auto-generated notification; do not reply]\n\nThese files have changed since the last read:\n- code.rs\n";
assert_eq!(
response_text.as_str(),
expected_content,
"Tool should return the stale buffer notification"
);
@ -191,7 +198,6 @@ mod tests {
cx,
)
});
cx.run_until_parked();
let response = result.output.await.unwrap();
let response_text = match &response.content {