feat(server): persist and display assistant message token usage #334
No reviewers
Labels
No labels
Epic 5
MCP
P1
PR-0
PR-1
api
api-layer
architecture
area:backend
area:frontend
arrow
authentication
backend
bug
chat
client
clipboard
common-module
compose
cross-cutting
cross-cutting-requirement
data-layer
data-models
database
desktop-client
documentation
duplicate
enhancement
epic
epic-1
epic-2
epic-3
epic-4
epic-5
epic-6
epic-7
epic-llm-config
error-handling
feature
frontend
good first issue
help wanted
implementation
infrastructure
installer
invalid
kotlin
ktor
llm
medium-priority
message
multiplatform
needs-review
needs-triage
packaging
performance
phase-1
phase-2
phase-3
phase-4
phase-5
phase3
phase:3
priority: high
question
refactor
refactoring
resource-sharing
security
server
server-module
services
session
session-management
settings
setup
shutdown
state
storage
streaming
sub-issue
tests
tooling
type:task
ui
ui/ux
user-accounts
user-management
ux
viewmodel
websocket
windows
windows-integration
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Torvian.eu/chatbot!334
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/assistant-message-usage-stats"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Persists the token usage a provider reports for an assistant generation and surfaces it to the user from the message header, so token consumption is auditable per message instead of being discarded after each stream.
Changes
UsageStatsand an optionalusageStatsfield onChatMessage.AssistantMessage, withnullmeaning "no usage reported" rather than zero tokens.inputTokens/outputTokensand replaced the nestedLLMCompletionResult.UsageStatswith the shared model.LLMStreamChunk.FinalUsageStats, emitted by the OpenAI, Responses and Ollama dialects immediately before their terminal chunk, so usage is recorded from one authoritative signal.V33__assistant_message_usage.sqlmigration, the Exposed column, a tolerant mapper decode, DAO insert/update plumbing, turn persistence and the session clone copy.<model>:header on finalized assistant messages, with English and Spanish strings.formatInstanthelper now used by both the usage dialog and the file reference dialog.Implementation notes
UsageChunkobservation path is retained but is no longer emitted by any dialect;FinalUsageStatsis the single terminal source of truth.V33is used becauseV32is already taken by a KotlinBaseJavaMigration; the migration is additive and nullable, so no data backfill is required.updateMessageContentwrites usage unconditionally, which matches its only two callers (turn finalization and the public edit path).Validation
./gradlew :server:classes./gradlew :server:testClasses./gradlew :server:test./gradlew :app:desktopMainClasses./gradlew :app:desktopTestClasses./gradlew :app:desktopTest./gradlew :common:desktopTestThe implementer ran all of the above with
BUILD SUCCESSFUL; the independent review re-ran:server:testand:app:desktopTest(2164 / 945 tests, 0 failures)../gradlew buildwas intentionally not run.Risks and follow-up
AssistantMessagenow emitsusageStats: nullon the wire for messages without usage, so older strict clients must tolerate the extra property.