feat(server,tui): session stats pane — metrics over the WS bus + Bubble Tea overlay

Surfaces the observability metrics (observability-spec §3-tier-2) in the Go TUI:
a session-summary pane showing duration, token throughput per provider, tool
time, approval latency per tier, failure counts, and the session wall-time
accounting split. Press `S` (or palette → "session stats").

Mirrors the artifacts/config fetch pattern exactly — a WS request/response, not a
new transport. Server-side reuses the already-tested MetricsInspectionService
(one MetricsReport definition, two wires: REST `correx stats` + WS).

Server:
- ClientMessage.GetSessionStats + ServerMessage.SessionStats(@SerialName
  session.stats), reusing MetricsReport as the nested payload.
- StreamQueries.sessionStats replays via MetricsInspectionService (pure read,
  replay-neutral); routed in GlobalStreamHandler.
- ServerMessageSerializationTest golden pins the session.stats wire format.

TUI (Go/Bubble Tea):
- protocol: TypeSessionStats + StatsDto/nested structs + GetSessionStats encoder
  + golden decode test (cross-language contract).
- OverlayStats pane (statsModal), `S` key + palette entry + footer hint,
  loading/cache-by-session state, bounded breakdown rows.
- demo `stats` preview case for serverless visual verification.
This commit is contained in:
2026-06-13 10:39:52 +04:00
parent fe941408a7
commit 4f6bfa85f7
14 changed files with 387 additions and 10 deletions
+5 -1
View File
@@ -304,6 +304,10 @@ func (m *Model) applyServer(msg protocol.ServerMessage) {
if m.artifactsIndex >= len(m.artifacts) {
m.artifactsIndex = 0
}
case protocol.TypeSessionStats:
m.stats = msg.Stats
m.statsFor = msg.SessionID
m.statsLoading = false
case protocol.TypeConfigSnapshot:
m.configFields = msg.ConfigFields
m.configRestart = msg.ConfigRestartRequired
@@ -332,7 +336,7 @@ func sessionIDOf(msg protocol.ServerMessage) string {
protocol.TypeProtocolError, protocol.TypeProviderStatus,
protocol.TypeWorkflowList, protocol.TypeRouterResponse,
protocol.TypeModelChanged, protocol.TypeModelList, protocol.TypeResourceStatus,
protocol.TypeArtifactList, protocol.TypeConfigSnapshot:
protocol.TypeArtifactList, protocol.TypeConfigSnapshot, protocol.TypeSessionStats:
return ""
default:
return msg.SessionID