From 3021e4b2b4bef7d55356bc42237a6923a668f8a9 Mon Sep 17 00:00:00 2001 From: hobokenchicken Date: Thu, 7 May 2026 11:16:36 -0400 Subject: [PATCH] fix: log resolved model name instead of group name in Recent Activity When using model groups (e.g. 'deepseek-auto'), the dashboard logged the group name instead of the concrete resolved model (e.g. 'deepseek-reasoner'). Now: - logRequest passes the resolved modelID (concrete) + modelGroup (group name) - RequestLog struct has a new ModelGroup field (omitempty) - Dashboard displays resolved model (via group) when a group was used Files changed: internal/server/logging.go - add ModelGroup field internal/server/server.go - pass resolved modelID, capture modelGroup static/js/websocket.js - show group annotation in Recent Activity static/js/pages/overview.js - show group annotation in overview table static/js/pages/monitoring.js - show group annotation in stream --- internal/server/logging.go | 1 + internal/server/server.go | 31 +++++++++++++++++-------------- static/js/pages/monitoring.js | 2 +- static/js/pages/overview.js | 4 ++-- static/js/websocket.js | 4 ++-- 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/internal/server/logging.go b/internal/server/logging.go index f9fc8ba1..8b448175 100644 --- a/internal/server/logging.go +++ b/internal/server/logging.go @@ -12,6 +12,7 @@ type RequestLog struct { ClientID string `json:"client_id"` Provider string `json:"provider"` Model string `json:"model"` + ModelGroup string `json:"model_group,omitempty"` PromptTokens uint32 `json:"prompt_tokens"` CompletionTokens uint32 `json:"completion_tokens"` ReasoningTokens uint32 `json:"reasoning_tokens"` diff --git a/internal/server/server.go b/internal/server/server.go index 2e69a18e..bf8845e7 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -362,7 +362,7 @@ func (s *Server) handleResponses(c *gin.Context) { if stream { ch, err := provider.ResponsesStream(c.Request.Context(), &req) if err != nil { - s.logRequest(startTime, clientID, providerName, req.Model, nil, err, false) + s.logRequest(startTime, clientID, providerName, req.Model, "", nil, err, false) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } @@ -377,9 +377,9 @@ func (s *Server) handleResponses(c *gin.Context) { if !ok { fmt.Fprintf(w, "data: [DONE]\n\n") if lastUsage != nil { - s.logRequest(startTime, clientID, providerName, req.Model, lastUsage.ToUsage(), nil, false) + s.logRequest(startTime, clientID, providerName, req.Model, "", lastUsage.ToUsage(), nil, false) } else { - s.logRequest(startTime, clientID, providerName, req.Model, nil, nil, false) + s.logRequest(startTime, clientID, providerName, req.Model, "", nil, nil, false) } return false } @@ -399,15 +399,15 @@ func (s *Server) handleResponses(c *gin.Context) { resp, err := provider.Responses(c.Request.Context(), &req) if err != nil { - s.logRequest(startTime, clientID, providerName, req.Model, nil, err, false) + s.logRequest(startTime, clientID, providerName, req.Model, "", nil, err, false) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } if resp.Usage != nil { - s.logRequest(startTime, clientID, providerName, req.Model, resp.Usage.ToUsage(), nil, false) + s.logRequest(startTime, clientID, providerName, req.Model, "", resp.Usage.ToUsage(), nil, false) } else { - s.logRequest(startTime, clientID, providerName, req.Model, nil, nil, false) + s.logRequest(startTime, clientID, providerName, req.Model, "", nil, nil, false) } c.JSON(http.StatusOK, resp) } @@ -528,7 +528,9 @@ func (s *Server) handleChatCompletions(c *gin.Context) { } // Check if model is a group and route to a concrete model + modelGroup := "" if s.modelRouter != nil && s.modelRouter.IsGroup(modelID) { + modelGroup = modelID userMessage := extractUserMessage(req.Messages) decision, err := s.modelRouter.Route(c.Request.Context(), modelID, userMessage) if err != nil { @@ -536,7 +538,7 @@ func (s *Server) handleChatCompletions(c *gin.Context) { return } modelID = decision.SelectedModel - log.Printf("[ROUTER] %s -> %s (%s: %s)", req.Model, modelID, decision.Strategy, decision.Reason) + log.Printf("[ROUTER] %s -> %s (%s: %s)", modelGroup, modelID, decision.Strategy, decision.Reason) } // Convert ChatCompletionRequest to UnifiedRequest @@ -657,7 +659,7 @@ if unifiedReq.MaxTokens == nil { if unifiedReq.Stream { ch, err := provider.ChatCompletionStream(c.Request.Context(), unifiedReq) if err != nil { - s.logRequest(startTime, clientID, providerName, req.Model, nil, err, unifiedReq.HasImages) + s.logRequest(startTime, clientID, providerName, modelID, modelGroup, nil, err, unifiedReq.HasImages) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } @@ -671,7 +673,7 @@ if unifiedReq.MaxTokens == nil { chunk, ok := <-ch if !ok { fmt.Fprintf(w, "data: [DONE]\n\n") - s.logRequest(startTime, clientID, providerName, req.Model, lastUsage, nil, unifiedReq.HasImages) + s.logRequest(startTime, clientID, providerName, modelID, modelGroup, lastUsage, nil, unifiedReq.HasImages) return false } if chunk.Usage != nil { @@ -689,12 +691,12 @@ if unifiedReq.MaxTokens == nil { resp, err := provider.ChatCompletion(c.Request.Context(), unifiedReq) if err != nil { - s.logRequest(startTime, clientID, providerName, req.Model, nil, err, unifiedReq.HasImages) + s.logRequest(startTime, clientID, providerName, modelID, modelGroup, nil, err, unifiedReq.HasImages) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } - s.logRequest(startTime, clientID, providerName, req.Model, resp.Usage, nil, unifiedReq.HasImages) + s.logRequest(startTime, clientID, providerName, modelID, modelGroup, resp.Usage, nil, unifiedReq.HasImages) c.JSON(http.StatusOK, resp) } @@ -763,7 +765,7 @@ func (s *Server) handleImageGenerations(c *gin.Context) { resp, err := provider.ImageGeneration(c.Request.Context(), &req) if err != nil { - s.logRequest(startTime, clientID, providerName, req.Model, nil, err, false) + s.logRequest(startTime, clientID, providerName, req.Model, "", nil, err, false) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } @@ -777,7 +779,7 @@ func (s *Server) handleImageGenerations(c *gin.Context) { // Calculate per-image cost (not per-token like chat) cost := imageGenCost(providerName, req.Model, req.Size, uint32(len(resp.Data))) - s.logRequest(startTime, clientID, providerName, req.Model, &models.Usage{ + s.logRequest(startTime, clientID, providerName, req.Model, "", &models.Usage{ PromptTokens: promptTokens, CompletionTokens: uint32(len(resp.Data)), TotalTokens: promptTokens + uint32(len(resp.Data)), @@ -819,12 +821,13 @@ func imageGenCost(provider, model string, size *string, n uint32) float64 { return perImage * float64(n) } -func (s *Server) logRequest(start time.Time, clientID, provider, model string, usage *models.Usage, err error, hasImages bool) { +func (s *Server) logRequest(start time.Time, clientID, provider, model, modelGroup string, usage *models.Usage, err error, hasImages bool) { entry := RequestLog{ Timestamp: start, ClientID: clientID, Provider: provider, Model: model, + ModelGroup: modelGroup, Status: "success", DurationMS: time.Since(start).Milliseconds(), HasImages: hasImages, diff --git a/static/js/pages/monitoring.js b/static/js/pages/monitoring.js index bbf308d8..83c9edc6 100644 --- a/static/js/pages/monitoring.js +++ b/static/js/pages/monitoring.js @@ -392,7 +392,7 @@ class MonitoringPage {
${request.client_id || 'Unknown'} → - ${request.provider || 'Unknown'} (${request.model || 'Unknown'}) + ${request.provider || 'Unknown'} (${request.model || 'Unknown'}${request.model_group ? ` via ${request.model_group}` : ''})
${request.total_tokens || request.tokens || 0} tokens • ${request.duration_ms || request.duration || 0}ms
diff --git a/static/js/pages/overview.js b/static/js/pages/overview.js index d992570f..7baa51be 100644 --- a/static/js/pages/overview.js +++ b/static/js/pages/overview.js @@ -252,7 +252,7 @@ class OverviewPage { ${time} ${request.client_id} ${request.provider} - ${request.model} + ${request.model}${request.model_group ? ` (via ${request.model_group})` : ''} ${request.tokens.toLocaleString()} @@ -313,7 +313,7 @@ class OverviewPage { ${time} ${request.client_id} ${request.provider} - ${request.model} + ${request.model}${request.model_group ? ` (via ${request.model_group})` : ''} ${(request.total_tokens || request.tokens || 0).toLocaleString()} diff --git a/static/js/websocket.js b/static/js/websocket.js index 983bcbdf..019554c7 100644 --- a/static/js/websocket.js +++ b/static/js/websocket.js @@ -309,7 +309,7 @@ class WebSocketManager { ${time} ${request.client_id || 'Unknown'} ${request.provider || 'Unknown'} - ${request.model || 'Unknown'} + ${request.model || 'Unknown'}${request.model_group ? ` (via ${request.model_group})` : ''} ${(request.total_tokens || request.tokens || 0)} @@ -358,7 +358,7 @@ class WebSocketManager {
${request.client_id || 'Unknown'} → - ${request.provider || 'Unknown'} (${request.model || 'Unknown'}) + ${request.provider || 'Unknown'} (${request.model || 'Unknown'}${request.model_group ? ` via ${request.model_group}` : ''})
${(request.total_tokens || request.tokens || 0)} tokens • ${(request.duration_ms || request.duration || 0)}ms