zeta2: Include a single unified diff for the edit history (#40400)
Instead of producing multiple code blocks for each edit history event, we now produce a continuous unified diff. Release Notes: - N/A --------- Co-authored-by: Oleksiy Syvokon <oleksiy.syvokon@gmail.com>
This commit is contained in:
co-authored by
Oleksiy Syvokon
parent
923e880150
commit
23a0b6503c
Generated
+1
@@ -3384,6 +3384,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"indoc",
|
||||
"pretty_assertions",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
@@ -25,3 +25,4 @@ workspace-hack.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions.workspace = true
|
||||
indoc.workspace = true
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use chrono::Duration;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
fmt::Display,
|
||||
ops::{Add, Range, Sub},
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
@@ -91,6 +92,38 @@ pub enum Event {
|
||||
},
|
||||
}
|
||||
|
||||
impl Display for Event {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Event::BufferChange {
|
||||
path,
|
||||
old_path,
|
||||
diff,
|
||||
predicted,
|
||||
} => {
|
||||
let new_path = path.as_deref().unwrap_or(Path::new("untitled"));
|
||||
let old_path = old_path.as_deref().unwrap_or(new_path);
|
||||
|
||||
if *predicted {
|
||||
write!(
|
||||
f,
|
||||
"// User accepted prediction:\n--- a/{}\n+++ b/{}\n{diff}",
|
||||
old_path.display(),
|
||||
new_path.display()
|
||||
)
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
"--- a/{}\n+++ b/{}\n{diff}",
|
||||
old_path.display(),
|
||||
new_path.display()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Signature {
|
||||
pub text: String,
|
||||
@@ -204,3 +237,82 @@ impl Sub for Line {
|
||||
Self(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use indoc::indoc;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn test_event_display() {
|
||||
let ev = Event::BufferChange {
|
||||
path: None,
|
||||
old_path: None,
|
||||
diff: "@@ -1,2 +1,2 @@\n-a\n-b\n".into(),
|
||||
predicted: false,
|
||||
};
|
||||
assert_eq!(
|
||||
ev.to_string(),
|
||||
indoc! {"
|
||||
--- a/untitled
|
||||
+++ b/untitled
|
||||
@@ -1,2 +1,2 @@
|
||||
-a
|
||||
-b
|
||||
"}
|
||||
);
|
||||
|
||||
let ev = Event::BufferChange {
|
||||
path: Some(PathBuf::from("foo/bar.txt")),
|
||||
old_path: Some(PathBuf::from("foo/bar.txt")),
|
||||
diff: "@@ -1,2 +1,2 @@\n-a\n-b\n".into(),
|
||||
predicted: false,
|
||||
};
|
||||
assert_eq!(
|
||||
ev.to_string(),
|
||||
indoc! {"
|
||||
--- a/foo/bar.txt
|
||||
+++ b/foo/bar.txt
|
||||
@@ -1,2 +1,2 @@
|
||||
-a
|
||||
-b
|
||||
"}
|
||||
);
|
||||
|
||||
let ev = Event::BufferChange {
|
||||
path: Some(PathBuf::from("abc.txt")),
|
||||
old_path: Some(PathBuf::from("123.txt")),
|
||||
diff: "@@ -1,2 +1,2 @@\n-a\n-b\n".into(),
|
||||
predicted: false,
|
||||
};
|
||||
assert_eq!(
|
||||
ev.to_string(),
|
||||
indoc! {"
|
||||
--- a/123.txt
|
||||
+++ b/abc.txt
|
||||
@@ -1,2 +1,2 @@
|
||||
-a
|
||||
-b
|
||||
"}
|
||||
);
|
||||
|
||||
let ev = Event::BufferChange {
|
||||
path: Some(PathBuf::from("abc.txt")),
|
||||
old_path: Some(PathBuf::from("123.txt")),
|
||||
diff: "@@ -1,2 +1,2 @@\n-a\n-b\n".into(),
|
||||
predicted: true,
|
||||
};
|
||||
assert_eq!(
|
||||
ev.to_string(),
|
||||
indoc! {"
|
||||
// User accepted prediction:
|
||||
--- a/123.txt
|
||||
+++ b/abc.txt
|
||||
@@ -1,2 +1,2 @@
|
||||
-a
|
||||
-b
|
||||
"}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
//! Zeta2 prompt planning and generation code shared with cloud.
|
||||
|
||||
use anyhow::{Context as _, Result, anyhow};
|
||||
use cloud_llm_client::predict_edits_v3::{
|
||||
self, Event, Line, Point, PromptFormat, ReferencedDeclaration,
|
||||
};
|
||||
use cloud_llm_client::predict_edits_v3::{self, Line, Point, PromptFormat, ReferencedDeclaration};
|
||||
use indoc::indoc;
|
||||
use ordered_float::OrderedFloat;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
@@ -419,7 +417,7 @@ impl<'a> PlannedPrompt<'a> {
|
||||
};
|
||||
|
||||
if self.request.events.is_empty() {
|
||||
prompt.push_str("No edits yet.\n\n");
|
||||
prompt.push_str("(No edit history)\n\n");
|
||||
} else {
|
||||
prompt.push_str(
|
||||
"The following are the latest edits made by the user, from earlier to later.\n\n",
|
||||
@@ -465,50 +463,15 @@ impl<'a> PlannedPrompt<'a> {
|
||||
}
|
||||
|
||||
fn push_events(output: &mut String, events: &[predict_edits_v3::Event]) {
|
||||
if events.is_empty() {
|
||||
return;
|
||||
};
|
||||
|
||||
writeln!(output, "`````diff").unwrap();
|
||||
for event in events {
|
||||
match event {
|
||||
Event::BufferChange {
|
||||
path,
|
||||
old_path,
|
||||
diff,
|
||||
predicted,
|
||||
} => {
|
||||
if let Some(old_path) = &old_path
|
||||
&& let Some(new_path) = &path
|
||||
{
|
||||
if old_path != new_path {
|
||||
writeln!(
|
||||
output,
|
||||
"User renamed {} to {}\n\n",
|
||||
old_path.display(),
|
||||
new_path.display()
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
let path = path
|
||||
.as_ref()
|
||||
.map_or_else(|| "untitled".to_string(), |path| path.display().to_string());
|
||||
|
||||
if *predicted {
|
||||
writeln!(
|
||||
output,
|
||||
"User accepted prediction {:?}:\n`````diff\n{}\n`````\n",
|
||||
path, diff
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
writeln!(
|
||||
output,
|
||||
"User edited {:?}:\n`````diff\n{}\n`````\n",
|
||||
path, diff
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
writeln!(output, "{}", event).unwrap();
|
||||
}
|
||||
writeln!(output, "`````\n").unwrap();
|
||||
}
|
||||
|
||||
fn push_file_snippets(
|
||||
|
||||
Reference in New Issue
Block a user