Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
`sessions read` showed one entry with its tool output cut at 2,000
characters, not at 40,000 as with `--count 1`. `read_session` now takes a
`count` of 0 as 1.
- **Handoff:** "Where it stopped" says which entries after the agent's
last message it had no room for when none of them fit. It said nothing
of them. The entries it says it left out for room no longer start or
end with a system note, which a handoff always leaves out, so a note
alone is no longer said to be left out for room.
- **`status`, `check_limits` and `doctor`** say why an account can't be
read in the same words. `check_limits`' verdict on the first account
says how to fix it, as the others do, not only that its limits can't be
Expand Down
65 changes: 59 additions & 6 deletions src/sessions/handoff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ fn stopped(entries: &[Entry], stop: usize, quoted: &[usize], share: usize, now:
..SAID
};
let first = render(stop, last, &opening, now);
let (after, _) = fit(
let (after, full) = fit(
stop + 1..entries.len(),
share.saturating_sub(first.len()),
|at| {
Expand All @@ -483,11 +483,13 @@ fn stopped(entries: &[Entry], stop: usize, quoted: &[usize], share: usize, now:
})
},
);
let from = after.first().map_or(entries.len(), |(at, _)| *at);
let gap = match from > stop + 1 && from < entries.len() {
true => format!("\n\n{}", left_out(stop + 1, from - 1)),
false => String::new(),
};
// A system note is left out wherever it falls, not for room.
let gap = full
.and_then(|at| {
let from = (stop + 1..=at).find(|&next| entries[next].kind != Kind::System)?;
Some(format!("\n\n{}", left_out(from, at)))
})
.unwrap_or_default();
let what = match (last.kind, entries.len() - stop - 1) {
(Kind::Assistant, 0) => "Its last message, the session's last entry.".to_owned(),
(Kind::Assistant, count) => format!(
Expand Down Expand Up @@ -995,6 +997,57 @@ mod tests {
);
}

/// Where it stopped says which entries after the last message it had no
/// room for: from the first after it that isn't a system note to the one
/// that didn't fit.
#[test]
fn where_it_stopped_says_just_what_it_left_out_for_room() {
let failed = "test quoted_commas ... FAILED\n";
let tests = |output: &str| {
call(
"Bash",
r#"{"command": "cargo test"}"#,
output,
true,
Role::Work,
)
};
let stop = |after: Vec<Entry>| {
let mut entries = vec![
said(Kind::User, 0, "Fix the CSV parser."),
said(Kind::Assistant, 1, "Running the tests."),
];
entries.extend(after);
stopped(&entries, 1, &[], 1000, 10 * MINUTE)
};
// A system note is left out wherever it falls, not for room.
let noted = stop(vec![said(Kind::System, 2, "A reminder."), tests(failed)]);
assert!(!noted.contains("left out for room"), "{noted}");
// Room ran out at #2; the note after it doesn't count with it.
let cut = stop(vec![
tests(&failed.repeat(60)),
said(Kind::System, 3, "A reminder."),
tests(failed),
]);
assert!(cut.contains("\nEntry #2 is left out for room.\n"), "{cut}");
// Nor does the note before it.
let noted_first = stop(vec![
said(Kind::System, 2, "A reminder."),
tests(&failed.repeat(60)),
tests(failed),
]);
assert!(
noted_first.contains("\nEntry #3 is left out for room.\n"),
"{noted_first}"
);
// With room for none of the entries after the last message.
let none = stop(vec![tests(&failed.repeat(60))]);
assert!(
none.contains("\nEntry #2 is left out for room.\n"),
"{none}"
);
}

#[test]
fn a_request_answered_is_kept_though_the_next_starts_the_same() {
let first = "Run the tests and fix the failures in the parser crate.";
Expand Down
Loading