Clear from the phone, and put the numbers where they are read
Four changes to the session screen, three of them Bryan's and one that
fell out of them.
**/clear is offered like any other session command.** It joins
SESSION_COMMANDS, so it suggests itself while being typed and goes out
through the command endpoint that /compact already uses -- no new path,
and the boundary pump holds it mid-turn exactly as it holds a compaction.
**A clear draws a divider, not a deletion.** `Event::Cleared` becomes a
ClearedNote row saying that everything above stays here and is no longer
sent. That sentence is the row's whole job: the reader can see the
conversation is still on screen, so without it the divider reads as
something having been thrown away, which is the one thing it is not. It
carries no counts, because nothing was measured -- a compaction's
numbers are real and there is no equivalent here to report.
Compaction and clear now share `TranscriptDivider`. They are the same
kind of mark to somebody scrolling back -- "the session no longer has
what is above this" -- and the difference belongs in the words rather
than in how they are drawn, so the styling is written once and cannot
drift.
**The five-hour usage bar sits under the session header.** It reports
the paid service's own metering for the machine this session runs on,
fetched from that machine, refreshed every minute off the backend's
cache. It is never derived from the transcript's token counts: those are
a different quantity measured differently, and a quota-shaped bar built
out of them would be a guess wearing a measurement's clothes. Not
knowing has its own appearance and its own words -- "unknown" and why --
because a bar resting at zero because a machine is unreachable reads as
plenty of headroom, which is the opposite of the truth. The window is
selected by the API's own `kind` ("session"), added to UsageWindow in
this change, rather than by matching the label a person reads.
**The token total moved from the header to the bottom right of the
transcript**, pinned above the input rather than scrolling with it. In
the header it was one item in a run of dot-separated facts about the
session and read as another of them, rather than as the running total it
is.
SessionSummary now carries the setup id, which it deliberately did not.
The stated reason was that nothing here addressed a setup and holding
both id and name invited showing the wrong one; the usage bar addresses
one, so the reason lapsed rather than being overruled, and the comment
now carries the rule that replaces it: never display it. The server has
always sent the field, so nothing changed on the wire.
ktfmt, compileDebugKotlin and lintDebug all clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VETa8afmpWaYezLCqJhDB8
This commit is contained in:
1 parent
1e3eec8cf0
commit
6680fbb987
8 files changed
+258
-14
No files matched your search
@@ -161,6 +161,13 @@ sealed class TranscriptItem {
|
||||
* it finishes and this is the part worth keeping: it is the explanation for a gap in the
|
||||
* conversation, and for a minute or two in which the session was busy with nothing to show.
|
||||
*/
|
||||
/**
|
||||
* A clear that happened: everything above it left the session's context and stayed on screen.
|
||||
*
|
||||
* Carries only its position, because that is all it means.
|
||||
*/
|
||||
data class ClearedNote(override val seq: Long) : TranscriptItem()
|
||||
|
||||
data class CompactedNote(
|
||||
override val seq: Long,
|
||||
val preTokens: Long?,
|
||||
@@ -277,6 +284,7 @@ fun foldEvent(items: List<TranscriptItem>, entry: SeqEvent): List<TranscriptItem
|
||||
} else {
|
||||
items + TranscriptItem.ImageItem(entry.seq, event.ref)
|
||||
}
|
||||
is SessionEvent.Cleared -> items + TranscriptItem.ClearedNote(entry.seq)
|
||||
is SessionEvent.Compacted ->
|
||||
items +
|
||||
TranscriptItem.CompactedNote(
|
||||
@@ -726,7 +734,6 @@ fun SessionScreen(
|
||||
// What the session says it is set to now, which is the same fact
|
||||
// the picker below shows and has to be the same answer.
|
||||
model?.let { modelLabel(it) },
|
||||
if (totalTokens > 0) "$totalTokens tok" else null,
|
||||
)
|
||||
.joinToString(" · "),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
@@ -753,6 +760,11 @@ fun SessionScreen(
|
||||
}
|
||||
}
|
||||
|
||||
// Under the header, above everything the session itself says: it is a fact about the
|
||||
// machine rather than a turn in the conversation, and it is the number that decides
|
||||
// whether to keep going -- which was a screen away from where that gets decided.
|
||||
SessionUsageBar(settings = settings, setup = summary.setup)
|
||||
|
||||
(streamError ?: actionError)?.let { message ->
|
||||
Text(
|
||||
message,
|
||||
@@ -917,6 +929,7 @@ fun SessionScreen(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
is TranscriptItem.CommandRow -> CommandBubble(item.text)
|
||||
is TranscriptItem.ClearedNote -> ClearedRow()
|
||||
is TranscriptItem.CompactedNote -> CompactedRow(item)
|
||||
is TranscriptItem.PeerNote ->
|
||||
PeerMessageRow(
|
||||
@@ -934,6 +947,23 @@ fun SessionScreen(
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom right of the transcript, pinned rather than scrolled: it reports on the
|
||||
// conversation as a whole, so it should not be a thing you scroll away from and then
|
||||
// wonder about. Sat in the header until 2026-08-29, where it was one item in a run of
|
||||
// dot-separated facts about the session and read as another of them, rather than as
|
||||
// the running total it is.
|
||||
//
|
||||
// BottomEnd, clear of the jump-to-latest chevron at BottomCentre.
|
||||
if (totalTokens > 0) {
|
||||
Text(
|
||||
"$totalTokens tok",
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier =
|
||||
Modifier.align(Alignment.BottomEnd).padding(end = 12.dp, bottom = 4.dp),
|
||||
)
|
||||
}
|
||||
|
||||
// Only while the newest message is off-screen. Reading back
|
||||
// through a conversation is a place to be, not a state to be
|
||||
// rescued from, so this waits to be wanted.
|
||||
|
||||
Reference in new issue
Block a user