agent: Push diffs of user edits to the agent (#34487)

This change improves user/agent collaborative editing.

When the user edits files that are used by the agent, the
`project_notification` tool now pushes *diffs* of the changes, not just
file names. This helps the agent to stay up to date without needing to
re-read files.

Release Notes:

- Improved user/agent collaborative editing: agent now receives diffs of
user edits
This commit is contained in:
Oleksiy Syvokon 2025-07-16 17:38:58 +03:00 committed by GitHub
parent 257bedf09b
commit 406ffb1e20
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 274 additions and 77 deletions

View file

@ -1532,7 +1532,9 @@ impl Thread {
) -> Option<PendingToolUse> {
let action_log = self.action_log.read(cx);
action_log.unnotified_stale_buffers(cx).next()?;
if !action_log.has_unnotified_user_edits() {
return None;
}
// Represent notification as a simulated `project_notifications` tool call
let tool_name = Arc::from("project_notifications");
@ -3253,7 +3255,6 @@ mod tests {
use futures::stream::BoxStream;
use gpui::TestAppContext;
use http_client;
use indoc::indoc;
use language_model::fake_provider::{FakeLanguageModel, FakeLanguageModelProvider};
use language_model::{
LanguageModelCompletionError, LanguageModelName, LanguageModelProviderId,
@ -3614,6 +3615,7 @@ fn main() {{
cx,
);
});
cx.run_until_parked();
// We shouldn't have a stale buffer notification yet
let notifications = thread.read_with(cx, |thread, _| {
@ -3643,11 +3645,13 @@ fn main() {{
cx,
)
});
cx.run_until_parked();
// Check for the stale buffer warning
thread.update(cx, |thread, cx| {
thread.flush_notifications(model.clone(), CompletionIntent::UserPrompt, cx)
});
cx.run_until_parked();
let notifications = thread.read_with(cx, |thread, _cx| {
find_tool_uses(thread, "project_notifications")
@ -3661,12 +3665,8 @@ fn main() {{
panic!("`project_notifications` should return text");
};
let expected_content = indoc! {"[The following is an auto-generated notification; do not reply]
These files have changed since the last read:
- code.rs
"};
assert_eq!(notification_content, expected_content);
assert!(notification_content.contains("These files have changed since the last read:"));
assert!(notification_content.contains("code.rs"));
// Insert another user message and flush notifications again
thread.update(cx, |thread, cx| {
@ -3682,6 +3682,7 @@ fn main() {{
thread.update(cx, |thread, cx| {
thread.flush_notifications(model.clone(), CompletionIntent::UserPrompt, cx)
});
cx.run_until_parked();
// There should be no new notifications (we already flushed one)
let notifications = thread.read_with(cx, |thread, _cx| {