Render whole-file patches from change metadata

This commit is contained in:
iris-ai committed 2026-09-15 16:18:18 -04:00
1 parent 06bf1c8f81
commit 3d1b1e304d
4 files changed
+57 -18

No files matched your search

+41 -4
View File
@@ -9,7 +9,7 @@ use std::sync::Arc;
use serde_json::{Value, json};
use super::super::driver::{Event, SessionStatus, patch_start};
use super::super::driver::{Event, SessionStatus, patch_start, prefixed_lines};
use super::super::subagent::Subagents;
#[derive(Default)]
@@ -741,12 +741,17 @@ fn file_change_diff(item: &Value) -> String {
Some(Value::Object(changes)) => changes
.iter()
.map(|(path, change)| {
let kind = change.get("type").and_then(Value::as_str);
render_file_diff(
path,
change.get("type").and_then(Value::as_str),
kind,
change.get("move_path").and_then(Value::as_str),
change
.get("unified_diff")
.get(if matches!(kind, Some("add" | "delete")) {
"content"
} else {
"unified_diff"
})
.and_then(Value::as_str)
.unwrap_or_default(),
)
@@ -759,7 +764,9 @@ fn file_change_diff(item: &Value) -> String {
fn render_file_diff(path: &str, kind: Option<&str>, moved: Option<&str>, body: &str) -> String {
// Some protocol revisions carry complete unified diffs and some carry only their hunks.
if body.starts_with("--- ") || body.starts_with("diff --git ") {
if !matches!(kind, Some("add" | "delete"))
&& (body.starts_with("--- ") || body.starts_with("diff --git "))
{
return body.to_string();
}
let from = if kind == Some("add") {
@@ -772,6 +779,14 @@ fn render_file_diff(path: &str, kind: Option<&str>, moved: Option<&str>, body: &
} else {
moved.unwrap_or(path)
};
let body = match kind {
// Add and delete carry file content, not a unified diff. Prefixing it here makes the
// protocol's change kind authoritative: a '-' that belongs to a Markdown bullet can never
// be mistaken for diff syntax.
Some("add") => prefixed_lines('+', body),
Some("delete") => prefixed_lines('-', body),
_ => body.to_string(),
};
format!("--- {from}\n+++ {to}\n{body}")
}
@@ -1069,6 +1084,28 @@ mod tests {
);
}
#[test]
fn whole_file_changes_get_markers_from_their_kind_not_their_content() {
let item = line(
r#"{"changes":[{"path":"added.md","kind":{"type":"add"},"diff":"--- a rule\n- a bullet\nplain\n"},{"path":"deleted.md","kind":{"type":"delete"},"diff":"- another bullet\nplain\n"}]}"#,
);
assert_eq!(
file_change_diff(&item),
"--- /dev/null\n+++ added.md\n+--- a rule\n+- a bullet\n+plain\n\n--- deleted.md\n+++ /dev/null\n-- another bullet\n-plain\n"
);
}
#[test]
fn legacy_whole_file_changes_show_the_content_they_changed() {
let item = line(
r#"{"changes":{"added.md":{"type":"add","content":"new\n"},"deleted.md":{"type":"delete","content":"old\n"}}}"#,
);
assert_eq!(
file_change_diff(&item),
"--- /dev/null\n+++ added.md\n+new\n\n--- deleted.md\n+++ /dev/null\n-old\n"
);
}
#[test]
fn native_app_server_completion_corrects_provisional_streaming() {
let mut translator = Translator::default();