feat: simplify the text editor to be more like pi (#7426)

This commit is contained in:
Michael Neale
2026-02-24 11:47:41 +11:00
committed by GitHub
parent 6f2a9d63da
commit edede637d7
2 changed files with 42 additions and 52 deletions
@@ -1835,10 +1835,9 @@ mod tests {
.as_text() .as_text()
.unwrap(); .unwrap();
assert!( assert!(assistant_content
assistant_content.text.contains("The file") .text
&& assistant_content.text.contains("has been edited") .contains("Successfully replaced text in"));
);
// Verify the file contents changed // Verify the file contents changed
let content = fs::read_to_string(&file_path).unwrap(); let content = fs::read_to_string(&file_path).unwrap();
@@ -2308,7 +2307,7 @@ mod tests {
.as_text() .as_text()
.unwrap(); .unwrap();
assert!(text.text.contains("Text has been inserted at line 1")); assert!(text.text.contains("Successfully inserted") && text.text.contains("at line 1"));
// Verify the file content by reading it directly // Verify the file content by reading it directly
let file_content = fs::read_to_string(&file_path).unwrap(); let file_content = fs::read_to_string(&file_path).unwrap();
@@ -2365,7 +2364,7 @@ mod tests {
.as_text() .as_text()
.unwrap(); .unwrap();
assert!(text.text.contains("Text has been inserted at line 3")); assert!(text.text.contains("Successfully inserted") && text.text.contains("at line 3"));
// Verify the file content by reading it directly // Verify the file content by reading it directly
let file_content = fs::read_to_string(&file_path).unwrap(); let file_content = fs::read_to_string(&file_path).unwrap();
@@ -2427,7 +2426,7 @@ mod tests {
.as_text() .as_text()
.unwrap(); .unwrap();
assert!(text.text.contains("Text has been inserted at line 4")); assert!(text.text.contains("Successfully inserted") && text.text.contains("at line 4"));
// Verify the file content by reading it directly // Verify the file content by reading it directly
let file_content = fs::read_to_string(&file_path).unwrap(); let file_content = fs::read_to_string(&file_path).unwrap();
@@ -2484,7 +2483,7 @@ mod tests {
.as_text() .as_text()
.unwrap(); .unwrap();
assert!(text.text.contains("Text has been inserted at line 4")); assert!(text.text.contains("Successfully inserted") && text.text.contains("at line 4"));
// Verify the file content by reading it directly // Verify the file content by reading it directly
let file_content = fs::read_to_string(&file_path).unwrap(); let file_content = fs::read_to_string(&file_path).unwrap();
+35 -44
View File
@@ -799,9 +799,9 @@ pub async fn text_editor_replace(
// Simple success message for Editor API // Simple success message for Editor API
return Ok(vec![ return Ok(vec![
Content::text(format!("Successfully edited {}", path.display())) Content::text(format!("Successfully replaced text in {}.", path.display()))
.with_audience(vec![Role::Assistant]), .with_audience(vec![Role::Assistant]),
Content::text(format!("File {} has been edited", path.display())) Content::text(format!("Successfully replaced text in {}.", path.display()))
.with_audience(vec![Role::User]) .with_audience(vec![Role::User])
.with_priority(0.2), .with_priority(0.2),
]); ]);
@@ -848,11 +848,7 @@ pub async fn text_editor_replace(
) )
})?; })?;
// Try to detect the language from the file extension let new_line_count = new_str.lines().count();
let language = lang::get_language_identifier(path);
// Show a snippet of the changed content with context
const SNIPPET_LINES: usize = 4;
// Count newlines before the replacement to find the line number // Count newlines before the replacement to find the line number
let replacement_line = content let replacement_line = content
@@ -860,13 +856,18 @@ pub async fn text_editor_replace(
.next() .next()
.expect("should split on already matched content") .expect("should split on already matched content")
.matches('\n') .matches('\n')
.count(); .count()
+ 1; // 1-indexed
// Calculate start and end lines for the snippet let summary = format!("Successfully replaced text in {}.", path.display());
let start_line = replacement_line.saturating_sub(SNIPPET_LINES);
let end_line = replacement_line + SNIPPET_LINES + new_content.matches('\n').count();
// Get the relevant lines for our snippet // Try to detect the language from the file extension
let language = lang::get_language_identifier(path);
// Show a snippet of the changed content with context for the user only
const SNIPPET_LINES: usize = 4;
let start_line = replacement_line.saturating_sub(SNIPPET_LINES + 1);
let end_line = replacement_line + SNIPPET_LINES + new_line_count;
let lines: Vec<&str> = new_content.lines().collect(); let lines: Vec<&str> = new_content.lines().collect();
let snippet = lines let snippet = lines
.iter() .iter()
@@ -876,27 +877,21 @@ pub async fn text_editor_replace(
.collect::<Vec<&str>>() .collect::<Vec<&str>>()
.join("\n"); .join("\n");
let output = formatdoc! {r#" let user_output = formatdoc! {r#"
Successfully replaced text in {path} at line {line}.
```{language} ```{language}
{snippet} {snippet}
``` ```
"#, "#,
path=path.display(),
line=replacement_line,
language=language, language=language,
snippet=snippet snippet=snippet
}; };
let success_message = formatdoc! {r#"
The file {} has been edited, and the section now reads:
{}
Review the changes above for errors. Undo and edit the file again if necessary!
"#,
path.display(),
output
};
Ok(vec![ Ok(vec![
Content::text(success_message).with_audience(vec![Role::Assistant]), Content::text(summary).with_audience(vec![Role::Assistant]),
Content::text(output) Content::text(user_output)
.with_audience(vec![Role::User]) .with_audience(vec![Role::User])
.with_priority(0.2), .with_priority(0.2),
]) ])
@@ -988,48 +983,44 @@ pub async fn text_editor_insert(
) )
})?; })?;
let insertion_line = insert_line + 1; // Convert to 1-indexed for display
let inserted_line_count = new_str.lines().count();
let summary = format!(
"Successfully inserted {} lines at line {} in {}",
inserted_line_count,
insertion_line,
path.display()
);
// Try to detect the language from the file extension // Try to detect the language from the file extension
let language = lang::get_language_identifier(path); let language = lang::get_language_identifier(path);
// Show a snippet of the inserted content with context // Show a snippet of the inserted content with context for the user only
const SNIPPET_LINES: usize = 4; const SNIPPET_LINES: usize = 4;
let insertion_line = insert_line + 1; // Convert to 1-indexed for display
// Calculate start and end lines for the snippet
let start_line = insertion_line.saturating_sub(SNIPPET_LINES); let start_line = insertion_line.saturating_sub(SNIPPET_LINES);
let end_line = std::cmp::min(insertion_line + SNIPPET_LINES, new_lines.len()); let end_line = std::cmp::min(insertion_line + SNIPPET_LINES, new_lines.len());
// Get the relevant lines for our snippet with line numbers
let snippet_lines: Vec<String> = new_lines[start_line.saturating_sub(1)..end_line] let snippet_lines: Vec<String> = new_lines[start_line.saturating_sub(1)..end_line]
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, line)| format!("{}: {}", start_line + i, line)) .map(|(i, line)| format!("{}: {}", start_line + i, line))
.collect(); .collect();
let snippet = snippet_lines.join("\n"); let snippet = snippet_lines.join("\n");
let output = formatdoc! {r#" let user_output = formatdoc! {r#"
{summary}
```{language} ```{language}
{snippet} {snippet}
``` ```
"#, "#,
summary=summary,
language=language, language=language,
snippet=snippet snippet=snippet
}; };
let success_message = formatdoc! {r#"
Text has been inserted at line {} in {}. The section now reads:
{}
Review the changes above for errors. Undo and edit the file again if necessary!
"#,
insertion_line,
path.display(),
output
};
Ok(vec![ Ok(vec![
Content::text(success_message).with_audience(vec![Role::Assistant]), Content::text(summary).with_audience(vec![Role::Assistant]),
Content::text(output) Content::text(user_output)
.with_audience(vec![Role::User]) .with_audience(vec![Role::User])
.with_priority(0.2), .with_priority(0.2),
]) ])