Ignore replayed tool starts

This commit is contained in:
iris-ai committed 2026-09-15 23:14:11 -04:00
1 parent 9bcf0f1a48
commit f00a178cf0
2 files changed
+25

No files matched your search

@@ -433,6 +433,13 @@ fun foldEvent(items: List<TranscriptItem>, entry: SeqEvent): List<TranscriptItem
}
}
is SessionEvent.ToolStart ->
// A call id names one call for its whole lifetime. Codex can repeat the start while
// recovering an in-flight item; appending that replay made two rows with one key, and
// Compose aborts the entire LazyColumn when it encounters them. Ignoring the replay
// also repairs transcripts which already contain it when they are folded on reopen.
if (items.any { it is TranscriptItem.ToolRun && it.id == event.id }) {
items
} else {
items +
TranscriptItem.ToolRun(
entry.seq,
@@ -443,6 +450,7 @@ fun foldEvent(items: List<TranscriptItem>, entry: SeqEvent): List<TranscriptItem
"",
done = false,
)
}
is SessionEvent.ToolUpdate -> updateTool(items, event.id) { it.copy(output = event.output) }
is SessionEvent.ToolEnd ->
// Created when its start is not here, rather than dropped. A fold that only ever
@@ -142,6 +142,23 @@ class TranscriptItemsTest {
assertTrue(items.none { it is TranscriptItem.TurnBreak }, "$items")
}
@Test
fun a_repeated_tool_start_is_still_one_row() {
val start = SessionEvent.ToolStart("exec-1", "Bash", "{\"command\":\"cargo test\"}")
val items =
fold(
start,
SessionEvent.AssistantText("The test run is still going."),
start,
SessionEvent.ToolEnd("exec-1", "finished"),
)
val tools = items.filterIsInstance<TranscriptItem.ToolRun>()
assertEquals(1, tools.size, "$items")
assertEquals("finished", tools.single().output)
assertTrue(tools.single().done)
}
/**
* The page-join half of the same rule. A boundary that cuts one reply leaves an unfinished half
* to be rejoined; a boundary that lands between two turns must not join anything, or paging