Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
694535badc
3 files changed
+182
-3
No files matched your search
@@ -177,6 +177,52 @@ sealed class TranscriptItem {
|
||||
) : TranscriptItem()
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a page of older items in front of the ones already loaded, healing any tool call the page
|
||||
* boundary cut in two.
|
||||
*
|
||||
* A boundary lands wherever it lands, and roughly half the time that is between a call and its
|
||||
* result. The newer page then holds a `ToolEnd` whose start it never saw, which [foldEvent] draws
|
||||
* as a row of its own -- correctly, because a call that renders as nothing is indistinguishable
|
||||
* from one that never happened. When the older page arrives it brings the real `ToolStart`, and
|
||||
* concatenating the two lists left *both*: the same call twice, once as a proper card and once as a
|
||||
* nameless placeholder. Visible as a run of four calls reporting "Called 5 tools", and worse than
|
||||
* the miscount -- the extra row is at the join, so it also moves everything the reader was looking
|
||||
* at.
|
||||
*
|
||||
* Merged by the call's own id rather than by position, because position is exactly what a page
|
||||
* boundary destroys. The older row wins on what a start knows (the tool's name, its input) and the
|
||||
* newer on what an end knows (the output, and whether it finished), which is the only way round
|
||||
* that loses nothing.
|
||||
*/
|
||||
fun joinPages(earlier: List<TranscriptItem>, later: List<TranscriptItem>): List<TranscriptItem> {
|
||||
val startedEarlier =
|
||||
earlier.filterIsInstance<TranscriptItem.ToolRun>().mapTo(mutableSetOf()) { it.id }
|
||||
if (startedEarlier.isEmpty()) return earlier + later
|
||||
val endedLater =
|
||||
later
|
||||
.filterIsInstance<TranscriptItem.ToolRun>()
|
||||
.associateBy { it.id }
|
||||
.filterKeys { it in startedEarlier }
|
||||
if (endedLater.isEmpty()) return earlier + later
|
||||
val healed = earlier.map { row ->
|
||||
val half = (row as? TranscriptItem.ToolRun)?.let { endedLater[it.id] }
|
||||
if (row is TranscriptItem.ToolRun && half != null) {
|
||||
row.copy(
|
||||
output = half.output,
|
||||
done = half.done,
|
||||
// Kept from both halves: a question or an image can be attached to either,
|
||||
// depending on which side of the boundary its event fell.
|
||||
asks = row.asks + half.asks,
|
||||
images = row.images + half.images,
|
||||
)
|
||||
} else {
|
||||
row
|
||||
}
|
||||
}
|
||||
return healed + later.filterNot { it is TranscriptItem.ToolRun && it.id in endedLater }
|
||||
}
|
||||
|
||||
fun foldEvent(items: List<TranscriptItem>, entry: SeqEvent): List<TranscriptItem> =
|
||||
when (val event = entry.event) {
|
||||
is SessionEvent.UserMessage -> items + TranscriptItem.UserMsg(entry.seq, event.text)
|
||||
@@ -636,7 +682,7 @@ fun SessionScreen(
|
||||
earlier = foldEvent(earlier, entry)
|
||||
}
|
||||
}
|
||||
items = earlier + items
|
||||
items = joinPages(earlier, items)
|
||||
}
|
||||
} catch (_: ApiException) {
|
||||
// Leave `moreHistory` alone: the next scroll asks again.
|
||||
|
||||
Reference in new issue
Block a user