feat(chat): add the raw llm request viewer #342
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!342
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/raw-llm-request-viewer"
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
Lets the owner of a chat session inspect the exact provider request the server prepared for the latest assistant step, so a surprising reply can be traced back to what was actually sent.
Changes
Added a provider-neutral
RawLlmRequestPayload(method, url) and araw_llm_requestinformational event on both the non-streaming and streaming chat surfaces. A step that issues several requests emits one event per request, and the latest one wins.Captured the prepared request in the LLM client path through an
onRequestPreparedobserver, forwarded through the retrying decorator, the turn runners and the transport mappers; the streaming client is now suspending so the observer runs in the turn's own coroutine before dispatch.Masked the credential before any event exists: the URL and every header value get the same
min(8, length/2)-prefix masking, a short key becomes****, and noAuthorizationheader is synthesized for a keyless provider.Added an app-side capture slot with overwrite semantics, cleared by a state reset and by an accepted send, plus a read-only dialog with an explicit empty state, a Copy action and a top-bar menu entry.
Copied document contains only the four wire fields; the body size shown in the dialog is computed client-side from the body.
Implementation notes
The new payload and the new event subtypes are an additive wire change that requires a lock-step server and client upgrade: an older client cannot decode the new event subtypes.
A capture never affects the transcript: the repository treats both new events as diagnostic no-ops that leave the cached session untouched.
The capture must never break the completion it describes, so a non-cancellation failure inside the observer is logged and swallowed while cancellation is rethrown.
The body is forwarded verbatim and is not masked; all current strategies send a pre-serialized body that contains no credential.
Validation
./gradlew :server:testClasses :server:test./gradlew :app:desktopMainClasses :app:desktopTestClasses :app:desktopTestRisks and follow-up
Android and WebAssembly targets were not compiled in the validation environment; no exhaustive
whenover the touched sealed types exists inandroidMainorwasmJsMain.Follow-up candidates deliberately left out of this change: the mapper KDoc overstates body masking, the accepted/refused-send and tool-loop paths have no dedicated tests, and the copied body relies on
Any.toString()for non-string bodies.