Fix Codex transcript convergence
This commit is contained in:
1 parent
f9c8f640ce
commit
3c19b5a9bb
9 files changed
+192
-48
No files matched your search
@@ -52,12 +52,11 @@ impl Translator {
|
||||
Some("item.started") | Some("item/started") => start_item(&body["item"]),
|
||||
Some("item.updated") => update_item(&line["item"]),
|
||||
// The old `codex exec --json` dialect reports only the completed message. App-server
|
||||
// reports every message through durable delta notifications and its completed copy
|
||||
// must always be skipped. That rule cannot live in an in-memory set: after a backend
|
||||
// restart the deltas are behind the persisted log cursor while the completion is not,
|
||||
// which used to append the whole message again after its already-recorded prefix.
|
||||
// also reports deltas, but they are provisional: safety buffering can revise their
|
||||
// text before completion. Keep its completed copy as an append-only correction rather
|
||||
// than guessing that the two representations concatenate to the same answer.
|
||||
Some("item.completed") => complete_item(&body["item"], true),
|
||||
Some("item/completed") => complete_item(&body["item"], false),
|
||||
Some("item/completed") => final_item(&body["item"]),
|
||||
Some("item/agentMessage/delta") => {
|
||||
let Some(delta) = body.get("delta").and_then(Value::as_str) else {
|
||||
return Vec::new();
|
||||
@@ -221,6 +220,21 @@ fn complete_item(item: &Value, include_agent_message: bool) -> Vec<Event> {
|
||||
}
|
||||
}
|
||||
|
||||
fn final_item(item: &Value) -> Vec<Event> {
|
||||
match item.get("type").and_then(Value::as_str) {
|
||||
Some("agentMessage") => item
|
||||
.get("text")
|
||||
.and_then(Value::as_str)
|
||||
.map(|text| {
|
||||
vec![Event::AssistantTextFinal {
|
||||
text: text.to_string(),
|
||||
}]
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
_ => complete_item(item, false),
|
||||
}
|
||||
}
|
||||
|
||||
fn tool(item: &Value) -> Option<(String, String, Value)> {
|
||||
let id = item.get("id")?.as_str()?.to_string();
|
||||
let kind = item.get("type")?.as_str()?;
|
||||
@@ -633,7 +647,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn translates_native_app_server_streaming_without_repeating_the_final_item() {
|
||||
fn native_app_server_completion_corrects_provisional_streaming() {
|
||||
let mut translator = Translator::default();
|
||||
assert_eq!(
|
||||
translator.translate(&line(
|
||||
@@ -651,12 +665,13 @@ mod tests {
|
||||
delta: "hello".to_string()
|
||||
}]
|
||||
);
|
||||
assert!(
|
||||
translator
|
||||
.translate(&line(
|
||||
r#"{"method":"item/completed","params":{"item":{"id":"message-1","type":"agentMessage","text":"hello"}}}"#
|
||||
))
|
||||
.is_empty()
|
||||
assert_eq!(
|
||||
translator.translate(&line(
|
||||
r#"{"method":"item/completed","params":{"item":{"id":"message-1","type":"agentMessage","text":"hello, revised"}}}"#
|
||||
)),
|
||||
vec![Event::AssistantTextFinal {
|
||||
text: "hello, revised".to_string()
|
||||
}]
|
||||
);
|
||||
assert!(
|
||||
translator
|
||||
@@ -702,16 +717,17 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_app_server_completion_never_repeats_streamed_text_after_adoption() {
|
||||
fn an_app_server_completion_corrects_streamed_text_after_adoption() {
|
||||
// A newly adopted translator has not seen the deltas already recorded by the previous
|
||||
// backend. The dialect, rather than process-local memory, decides that this is a copy.
|
||||
let mut adopted = Translator::default();
|
||||
assert!(
|
||||
adopted
|
||||
.translate(&line(
|
||||
r#"{"method":"item/completed","params":{"item":{"id":"message-1","type":"agentMessage","text":"the complete message"}}}"#
|
||||
))
|
||||
.is_empty()
|
||||
assert_eq!(
|
||||
adopted.translate(&line(
|
||||
r#"{"method":"item/completed","params":{"item":{"id":"message-1","type":"agentMessage","text":"the complete message"}}}"#
|
||||
)),
|
||||
vec![Event::AssistantTextFinal {
|
||||
text: "the complete message".to_string()
|
||||
}]
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user