Cargo.lock 🔗
@@ -3384,6 +3384,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"chrono",
+ "indoc",
"pretty_assertions",
"serde",
"serde_json",
Agus Zubiaga and Oleksiy Syvokon created
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>
Cargo.lock | 1
crates/cloud_llm_client/Cargo.toml | 1
crates/cloud_llm_client/src/predict_edits_v3.rs | 112 +++++++++++++++
crates/cloud_zeta2_prompt/src/cloud_zeta2_prompt.rs | 55 +------
4 files changed, 123 insertions(+), 46 deletions(-)
@@ -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]) {
- 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();
- }
- }
+ if events.is_empty() {
+ return;
+ };
- 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, "`````diff").unwrap();
+ for event in events {
+ writeln!(output, "{}", event).unwrap();
}
+ writeln!(output, "`````\n").unwrap();
}
fn push_file_snippets(