feat(chat): add token & cost estimator badges (M9.6)

Per-message token count badge (e.g. "125 tok", "1.2k tok") next to
timestamp. ContextBar tooltip shows running total and estimated cost
based on model pricing table. Pricing for Claude Haiku/Sonnet/Opus.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-03 23:36:31 +00:00
co-authored by Claude Opus 4.6
parent 210fa7d3c6
commit 55faf5043a
3 changed files with 36 additions and 3 deletions
@@ -205,6 +205,8 @@
<div v-if="!isEditing" class="flex items-center gap-2 mt-1.5">
<span class="text-[10px] select-none text-white/30">{{ formattedTime }}</span>
<span v-if="message.editedAt" class="text-[10px] text-white/25 select-none">(edited)</span>
<span v-if="showTokenCount" class="text-[10px] text-white/20 select-none" :title="`~${estimatedTokens} tokens`">{{ tokenLabel }}</span>
<span v-if="message.feedback" class="text-[10px] select-none">{{ message.feedback === 'up' ? '👍' : '👎' }}</span>
<button
v-if="inlineFilms.length > 1"
class="text-[10px] text-accent/70 hover:text-accent transition-colors"
@@ -457,6 +459,15 @@ const formattedTime = computed(() => {
return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
})
// Token estimate (~4 chars per token)
const estimatedTokens = computed(() => Math.ceil(props.message.content.length / 4))
const showTokenCount = computed(() => props.message.content.length > 20)
const tokenLabel = computed(() => {
const t = estimatedTokens.value
if (t >= 1000) return `${(t / 1000).toFixed(1)}k tok`
return `${t} tok`
})
function openPanelWithContext() {
updatePanelFromText(props.message.content, props.triggeringQuery, props.message.webResults ?? [])
}