use tempfile::tempdir;
use super::{AGENT, write_file};
use crate::git_tree::{AgentState, Framing};
use crate::steps_view::{OUTPUT_LIMIT, Wound, build_aged, latest_wound};
const THINKING_ONLY_LENGTH: &[u8] = br#"{"type":"message_start","v":1,"role":"assistant"}
{"type":"content_delta","index":0,"delta":{"thinking_delta":"weighing it up"}}
{"type":"usage","input_tokens":900,"output_tokens":4096}
{"type":"finish","reason":"length"}
{"type":"end"}
"#;
#[test]
fn an_output_limited_step_is_a_wound_though_its_framing_is_complete() {
let dir = tempdir().unwrap();
let ws = dir.path();
write_file(ws, "001", "response.json", THINKING_ONLY_LENGTH);
write_file(ws, "001", "meta.json", br#"{"commit":"abc"}"#);
let view = build_aged(ws, AGENT, AgentState::Stopped);
let step = &view.steps[0];
assert_eq!(step.wound, Wound::OutputLimit);
assert_eq!(
step.framing,
Framing::Complete,
"the transport reading is untouched — the sealed entry really is there"
);
assert_eq!(step.attempts, 1);
assert_eq!(step.tokens.total_tokens(), 4_996);
assert!(latest_wound(&view).wounded());
}
#[test]
fn a_partial_text_turn_keeps_its_text_and_is_still_marked_truncated() {
let dir = tempdir().unwrap();
let ws = dir.path();
write_file(
ws,
"001",
"response.json",
br#"{"type":"content_delta","index":0,"delta":{"text_delta":"the answer is 4"}}
{"type":"finish","reason":"length"}
{"type":"end"}
"#,
);
assert_eq!(
build_aged(ws, AGENT, AgentState::Stopped).steps[0].wound,
Wound::OutputLimit
);
assert_eq!(
crate::git_tree::stream_from_disk(ws, AGENT).text.as_deref(),
Some("the answer is 4"),
"the §5.1 #10 fold is untouched — the fragment still reaches the glass"
);
}
#[test]
fn no_other_settled_shape_becomes_the_output_limit_wound() {
let dir = tempdir().unwrap();
let ws = dir.path();
for (seq, reason) in [("001", "stop"), ("002", "tool_use"), ("003", "refusal")] {
write_file(
ws,
seq,
"response.json",
format!("{{\"type\":\"finish\",\"reason\":\"{reason}\"}}\n{{\"type\":\"end\"}}\n")
.as_bytes(),
);
}
write_file(
ws,
"004",
"response.json",
b"{\"type\":\"error\",\"kind\":\"http\"}\n{\"type\":\"end\"}\n",
);
write_file(
ws,
"005",
"response.json",
b"{\"type\":\"content_delta\"}\n",
);
let view = build_aged(ws, AGENT, AgentState::Stopped);
for step in &view.steps {
assert_eq!(step.wound, Wound::None, "step {}", step.seq);
}
assert_eq!(view.steps[3].framing, Framing::Failed);
assert_eq!(view.steps[4].framing, Framing::Killed);
}
#[test]
fn the_output_limit_wound_says_what_ended_the_turn_and_how_to_carry_on() {
let dir = tempdir().unwrap();
let ws = dir.path();
write_file(ws, "001", "response.json", THINKING_ONLY_LENGTH);
let sentence = latest_wound(&build_aged(ws, AGENT, AgentState::Stopped)).banner();
assert!(sentence.contains(OUTPUT_LIMIT), "the class: {sentence}");
assert!(
sentence.contains("output budget ran out"),
"what happened, in words: {sentence}"
);
assert!(
sentence.contains("send a message"),
"the recovery is the gesture that exists: {sentence}"
);
assert!(
sentence.contains("Nudge cannot"),
"and the control that vanished says why: {sentence}"
);
assert!(
sentence.contains("nothing was committed"),
"a truncation is not a short answer: {sentence}"
);
assert!(
sentence.contains("max_output_tokens"),
"the remedy is config, not a retry: {sentence}"
);
assert!(
!sentence.contains(" "),
"one sentence, not a source continuation leaking its indent: {sentence}"
);
let answered = crate::steps_view::wire::steps(&build_aged(ws, AGENT, AgentState::Stopped));
let row = &answered["rows"][0];
assert_eq!(row["wound"], "output_limit", "got:\n{answered:#}");
assert_eq!(row["framing"], "complete", "got:\n{answered:#}");
}
#[test]
fn a_driver_at_work_excuses_the_newest_output_limited_step_only() {
let dir = tempdir().unwrap();
let ws = dir.path();
write_file(ws, "001", "response.json", THINKING_ONLY_LENGTH);
write_file(ws, "002", "response.json", THINKING_ONLY_LENGTH);
let view = build_aged(ws, AGENT, AgentState::InFlight);
assert_eq!(view.steps[0].wound, Wound::OutputLimit);
assert_eq!(view.steps[1].wound, Wound::None);
}