mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
feat: rename info to status, add /status slash command
Rename session info endpoint from /sessions/:id/info to /sessions/:id/status and update frontend tab label accordingly. Add /status slash command that displays current session metrics (message count, context usage, cache hit rate, used skills) as formatted text in any channel.
This commit is contained in:
@@ -15,5 +15,6 @@ func (h *Handler) buildRegistry() *Registry {
|
||||
r.RegisterGroup(h.buildHeartbeatGroup())
|
||||
r.RegisterGroup(h.buildSkillGroup())
|
||||
r.RegisterGroup(h.buildFSGroup())
|
||||
r.RegisterGroup(h.buildStatusGroup())
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
func (h *Handler) buildStatusGroup() *CommandGroup {
|
||||
g := newCommandGroup("status", "View current session status")
|
||||
g.DefaultAction = "show"
|
||||
g.Register(SubCommand{
|
||||
Name: "show",
|
||||
Usage: "show - Show current session status",
|
||||
Handler: func(cc CommandContext) (string, error) {
|
||||
botUUID, err := parseBotUUID(cc.BotID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
sessionID, err := h.queries.GetLatestSessionIDByBot(cc.Ctx, botUUID)
|
||||
if err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return "No active session found.", nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
msgCount, err := h.queries.CountMessagesBySession(cc.Ctx, sessionID)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("count messages: %w", err)
|
||||
}
|
||||
|
||||
var usedTokens int64
|
||||
latestUsage, err := h.queries.GetLatestAssistantUsage(cc.Ctx, sessionID)
|
||||
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
|
||||
return "", fmt.Errorf("get usage: %w", err)
|
||||
}
|
||||
if err == nil {
|
||||
usedTokens = latestUsage
|
||||
}
|
||||
|
||||
cacheRow, err := h.queries.GetSessionCacheStats(cc.Ctx, sessionID)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("get cache: %w", err)
|
||||
}
|
||||
|
||||
var contextWindowStr string
|
||||
if h.settingsService != nil {
|
||||
s, sErr := h.settingsService.GetBot(cc.Ctx, cc.BotID)
|
||||
if sErr == nil && s.ChatModelID != "" && h.modelsService != nil {
|
||||
m, mErr := h.modelsService.GetByID(cc.Ctx, s.ChatModelID)
|
||||
if mErr == nil && m.Config.ContextWindow != nil {
|
||||
contextWindowStr = formatTokens(int64(*m.Config.ContextWindow))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cacheHitRate float64
|
||||
if cacheRow.TotalInputTokens > 0 {
|
||||
cacheHitRate = float64(cacheRow.CacheReadTokens) / float64(cacheRow.TotalInputTokens) * 100
|
||||
}
|
||||
|
||||
skills, _ := h.queries.GetSessionUsedSkills(cc.Ctx, sessionID)
|
||||
|
||||
var b strings.Builder
|
||||
b.WriteString("Session Status:\n\n")
|
||||
fmt.Fprintf(&b, "- Messages: %d\n", msgCount)
|
||||
if contextWindowStr != "" {
|
||||
fmt.Fprintf(&b, "- Context: %s / %s\n", formatTokens(usedTokens), contextWindowStr)
|
||||
} else {
|
||||
fmt.Fprintf(&b, "- Context: %s\n", formatTokens(usedTokens))
|
||||
}
|
||||
fmt.Fprintf(&b, "- Cache Hit Rate: %.1f%%\n", cacheHitRate)
|
||||
fmt.Fprintf(&b, "- Cache Read: %s\n", formatTokens(cacheRow.CacheReadTokens))
|
||||
fmt.Fprintf(&b, "- Cache Write: %s\n", formatTokens(cacheRow.CacheWriteTokens))
|
||||
|
||||
if len(skills) > 0 {
|
||||
fmt.Fprintf(&b, "- Skills: %s\n", strings.Join(skills, ", "))
|
||||
}
|
||||
|
||||
return strings.TrimRight(b.String(), "\n"), nil
|
||||
},
|
||||
})
|
||||
return g
|
||||
}
|
||||
|
||||
func formatTokens(n int64) string {
|
||||
if n >= 1_000_000 {
|
||||
return fmt.Sprintf("%.1fM", float64(n)/1_000_000)
|
||||
}
|
||||
if n >= 1_000 {
|
||||
return fmt.Sprintf("%.1fK", float64(n)/1_000)
|
||||
}
|
||||
return strconv.FormatInt(n, 10)
|
||||
}
|
||||
Reference in New Issue
Block a user