Report the context a session holds, not what it has spent
The number on the status row was a running total of tokens spent, so it could only ever climb: a session compacted from 128k down to 10k, or cleared outright, went on reporting the larger figure, and disagreed with the divider directly above it saying what the compaction had recovered. It now reports what the model is holding -- prompt plus both cache figures -- folded through `driver::context_after`, which is the one rule the pump, the transcript and the phone all use: a turn sets it, a compaction replaces it with what the compaction measured, and a clear leaves it unmeasured. Unmeasured says so in words, because an empty context and one nobody has counted used to look identical. Taken from the turn's last assistant message rather than its `result`: measured against CLI 2.1.237, a two-message turn reported a cache read of 40,211, being 14,259 and 25,952 -- the same conversation counted twice, and no size the model ever held.
This commit is contained in:
1 parent
81c8a57181
commit
5e11b9da80
12 files changed
+442
-130
No files matched your search
@@ -457,10 +457,10 @@ fun SessionScreen(
|
||||
val scope = rememberCoroutineScope()
|
||||
var items by remember { mutableStateOf(listOf<TranscriptItem>()) }
|
||||
var status by remember { mutableStateOf(summary.status) }
|
||||
// Seeded from the row this screen was opened from, so a conversation that has spent
|
||||
// something says so before any turn happens here. Zero used to mean "nothing yet" and
|
||||
// "nothing in the page I loaded" at once, and the second one is most of the long sessions.
|
||||
var totalTokens by remember(summary.id) { mutableLongStateOf(summary.totalTokens) }
|
||||
// Seeded from the row this screen was opened from, so a conversation already under way says
|
||||
// how much it is holding before any turn happens here. Null is "nobody has measured it",
|
||||
// which is a different answer from an empty context and is drawn differently.
|
||||
var contextTokens by remember(summary.id) { mutableStateOf(summary.contextTokens) }
|
||||
// When this screen saw the current compaction start, on this device's own clock, and how long
|
||||
// ago that is. See `compactingLabel`: null is the honest answer whenever the start was not
|
||||
// witnessed here, which is what opening a session that is already compacting looks like.
|
||||
@@ -611,14 +611,14 @@ fun SessionScreen(
|
||||
*/
|
||||
fun apply(entry: SeqEvent) {
|
||||
lastSeq.set(entry.seq)
|
||||
// Before the rest, and for every event rather than only the usage ones: a compaction and
|
||||
// a clear move this as much as a turn does, which is the whole reason it is a fold and
|
||||
// not a running total. See `contextAfter`.
|
||||
contextTokens = contextAfter(contextTokens, entry.event)
|
||||
when (val event = entry.event) {
|
||||
// Taken, not accumulated: the server's running total is on the event, and adding
|
||||
// up the deltas this screen happened to receive counted one page of a conversation
|
||||
// and called it the whole. `max` because pages arrive in no guaranteed order and an
|
||||
// older event's total is a smaller true answer, never a correction downwards; it
|
||||
// also leaves the seeded figure alone for transcripts recorded before the backend
|
||||
// sent a total at all.
|
||||
is SessionEvent.UsageDelta -> totalTokens = maxOf(totalTokens, event.total)
|
||||
// Nothing further: what it carries was folded into the context above, and what a
|
||||
// turn cost is not something the transcript draws.
|
||||
is SessionEvent.UsageDelta -> {}
|
||||
else -> {
|
||||
// What the session says it is set to now, which is the only thing that
|
||||
// says it: picking from either menu asks, and the answer comes back here.
|
||||
@@ -1214,7 +1214,11 @@ fun SessionScreen(
|
||||
)
|
||||
}
|
||||
|
||||
SessionStatusRow(status = status, compactingFor = compactingFor, totalTokens = totalTokens)
|
||||
SessionStatusRow(
|
||||
status = status,
|
||||
compactingFor = compactingFor,
|
||||
contextTokens = contextTokens,
|
||||
)
|
||||
|
||||
// Between the transcript and the box: above what is being typed, so the list does not
|
||||
// cover the thing the command is about, and below everything that explains it.
|
||||
@@ -1468,7 +1472,8 @@ private fun SessionStatusRow(
|
||||
status: String,
|
||||
/** Seconds since this device saw the compaction start; null if it did not see it. */
|
||||
compactingFor: Long?,
|
||||
totalTokens: Long,
|
||||
/** Context the session is holding, or null where nothing has measured it. */
|
||||
contextTokens: Long?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
@@ -1538,15 +1543,19 @@ private fun SessionStatusRow(
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
}
|
||||
// Nothing rather than "0 tok" before anything has been spent: a total of zero is a fact
|
||||
// about a conversation that has not started, and it is the one reading nobody needs.
|
||||
if (totalTokens > 0) {
|
||||
Text(
|
||||
"$totalTokens tok",
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
// How full the session is, which is the number a reader is asking about -- how much room
|
||||
// is left before the next compaction -- rather than what has been spent getting here.
|
||||
//
|
||||
// "unknown" in words, and always drawn. A context nobody has measured is not an empty
|
||||
// one, and the two used to share an appearance: a session that had just been cleared, one
|
||||
// whose provider never reports usage, and one that has not run a turn all showed nothing
|
||||
// at all, which reads as a conversation with room to spare. It is the same reason the
|
||||
// status word beside it names the quiet state instead of leaving the row blank.
|
||||
Text(
|
||||
contextTokens?.let { "context ${tokens(it)}" } ?: "context unknown",
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user