package com.example.aiapp import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier /** * The mark a compaction leaves in the transcript. * * A divider rather than something anybody said: everything above it is out of the session's context * now, and that is a fact about the conversation, not a turn in it. Drawn by [TranscriptDivider], * which a clear also uses, so the two marks cannot drift apart. * * Blue is [commandColor]: the session acting on itself rather than working on what was asked of it. */ @Composable fun CompactedRow(item: TranscriptItem.CompactedNote, modifier: Modifier = Modifier) { TranscriptDivider(compactionSummary(item), commandColor, modifier) } /** * What to say about a compaction: the two sizes, and nothing else. * * The counts are the whole point -- "a million tokens became ten thousand" is the reader's answer * to why the wait was worth it. When they were not reported this says only that a compaction * happened, rather than filling in a plausible number. */ fun compactionSummary(item: TranscriptItem.CompactedNote): String { val pre = item.preTokens val post = item.postTokens return if (pre != null && post != null) { "Compacted • ${tokens(pre)} → ${tokens(post)} tok" } else { "Compacted" } } /** * A token count as a reader reads one. * * Shared with the status row rather than formatted at each: the divider and the row report the same * quantity about the same moment, and one grouping its thousands while the other did not read as * two different measurements. */ fun tokens(count: Long): String = "%,d".format(count) /** * What the working indicator says while a compaction is running. * * Elapsed time and nothing else, because elapsed time is all there is: the CLI announces that a * compaction has begun and then says nothing until it has finished, so any bar or estimate here * would be this screen's guess wearing a measurement's clothes. * * [seconds] is null when this device did not see the compaction start, which is what opening a * session that is already compacting looks like. That case says only "compacting": a number counted * from the moment the screen opened would be wrong in the direction that matters. */ fun compactingLabel(seconds: Long?): String = when { seconds == null -> "compacting" seconds < 60 -> "compacting ${seconds}s" else -> "compacting ${seconds / 60}m ${seconds % 60}s" }