Keep open tool cards out of groups

This commit is contained in:
iris-ai committed 2026-09-15 22:43:45 -04:00
1 parent 33b130b6bb
commit 9bcf0f1a48
4 files changed
+55 -48

No files matched your search

@@ -307,8 +307,6 @@ fun SessionScreen(
// Which runs of adjacent tool calls are open, by the group row's own key, so a group survives
// more calls arriving after it.
var expandedGroups by remember { mutableStateOf(setOf<String>()) }
// Calls already drawn inside a group, so being folded into one is noticed exactly once each.
var everGrouped by remember { mutableStateOf(setOf<String>()) }
// Which messages from other agents are open, by the seq that identifies their row. Closed by
// default, which is the rule for anything new in this transcript.
var expandedNotes by remember { mutableStateOf(setOf<Long>()) }
@@ -412,7 +410,7 @@ fun SessionScreen(
// arrived, waiting for them to return to the newest end. See [record].
var held by remember { mutableStateOf(listOf<SeqEvent>()) }
// What is actually drawn: the transcript with runs of adjacent tool calls folded into one row.
val rows = remember(items) { groupToolRuns(items) }
val rows = remember(items, expandedTools) { groupToolRuns(items, expandedTools) }
// Bumped when a cold reply's parses become ready, so the flatten runs again and can split it.
var warmedTick by remember { mutableIntStateOf(0) }
val units =
@@ -609,7 +607,7 @@ fun SessionScreen(
* Computed from `items` rather than `rows` for the reason [loadOlderPage] gives.
*/
fun anchorRow(seq: Long): Long? {
val ordered = groupToolRuns(items)
val ordered = groupToolRuns(items, expandedTools)
val at = ordered.indexOfLast { it.startSeq <= seq }
// Zero is the oldest loaded row, which is the half-row above; not found is -1.
return if (at > 0) ordered[at].startSeq else null
@@ -702,25 +700,6 @@ fun SessionScreen(
}
}
// A call opened on its own stays open when it is folded into a group -- either because a second
// call in the same run arrived, or because something landed behind the last call and it
// rejoined the run it was standing outside of. Until this, watching a Bash call and having the
// session make another one shut the one being read and folded it behind "Called 2 tools".
//
// Per call rather than per group, because a group outlives the calls joining it: considered at
// the moment each call first lands inside one, and never again, so the reader who then shuts
// the group has shut it.
LaunchedEffect(rows) {
val fresh =
rows.filterIsInstance<TranscriptRow.Tools>().flatMap { group ->
group.calls.filter { it.id !in everGrouped }.map { group.key to it.id }
}
if (fresh.isEmpty()) return@LaunchedEffect
expandedGroups =
expandedGroups + fresh.filter { it.second in expandedTools }.map { it.first }
everGrouped = everGrouped + fresh.map { it.second }
}
// A compaction reports nothing about its own progress -- measured against the CLI, which says
// it has started and then nothing at all until it is done. So what this counts is the one thing
// anybody here can measure: how long it has been going. A bar filling up would be this screen