diff --git a/bot.go b/bot.go index 5d9cf03..5ae215f 100644 --- a/bot.go +++ b/bot.go @@ -63,7 +63,9 @@ var ( "google/gemma-3-27b-it:free", "meta-llama/llama-3.3-70b-instruct:free", } - LocalModels = []string{} + LocalModels = []string{} + localModelsData *models.LCPModels + orModelsData *models.ORModels ) var thinkBlockRE = regexp.MustCompile(`(?s).*?`) @@ -355,6 +357,7 @@ func fetchORModels(free bool) ([]string, error) { if err := json.NewDecoder(resp.Body).Decode(data); err != nil { return nil, err } + orModelsData = data freeModels := data.ListModels(free) return freeModels, nil } @@ -416,6 +419,7 @@ func fetchLCPModelsWithStatus() (*models.LCPModels, error) { if err := json.NewDecoder(resp.Body).Decode(data); err != nil { return nil, err } + localModelsData = data return data, nil } diff --git a/helpfuncs.go b/helpfuncs.go index b63995c..7d7b65b 100644 --- a/helpfuncs.go +++ b/helpfuncs.go @@ -11,6 +11,7 @@ import ( "path" "path/filepath" "slices" + "strconv" "strings" "time" "unicode" @@ -376,9 +377,83 @@ func makeStatusLine() string { roleInject := fmt.Sprintf(" | [%s:-:b]role injection[-:-:-] (alt+7)", boolColors[injectRole]) statusLine += roleInject } + // context tokens + contextTokens := getContextTokens() + maxCtx := getMaxContextTokens() + if maxCtx == 0 { + maxCtx = 16384 + } + if contextTokens > 0 { + contextInfo := fmt.Sprintf(" | context: [cyan:-:b]%d/%d[-:-:-]", contextTokens, maxCtx) + statusLine += contextInfo + } return statusLine + imageInfo + shellModeInfo } +func getContextTokens() int { + if chatBody == nil || chatBody.Messages == nil { + return 0 + } + total := 0 + for _, msg := range chatBody.Messages { + if msg.Stats != nil { + total += msg.Stats.Tokens + } + } + return total +} + +const deepseekContext = 128000 + +func getMaxContextTokens() int { + if chatBody == nil || chatBody.Model == "" { + return 0 + } + modelName := chatBody.Model + if strings.Contains(cfg.CurrentAPI, "openrouter") { + if orModelsData != nil { + for _, m := range orModelsData.Data { + if m.ID == modelName { + return m.ContextLength + } + } + } + } else if strings.Contains(cfg.CurrentAPI, "deepseek") { + return deepseekContext + } else { + if localModelsData != nil { + for _, m := range localModelsData.Data { + if m.ID == modelName { + for _, arg := range m.Status.Args { + if strings.HasPrefix(arg, "--ctx-size") { + if strings.Contains(arg, "=") { + val := strings.Split(arg, "=")[1] + if n, err := strconv.Atoi(val); err == nil { + return n + } + } else { + idx := -1 + for i, a := range m.Status.Args { + if a == "--ctx-size" && i+1 < len(m.Status.Args) { + idx = i + 1 + break + } + } + if idx != -1 { + if n, err := strconv.Atoi(m.Status.Args[idx]); err == nil { + return n + } + } + } + } + } + } + } + } + } + return 0 +} + // set of roles within card definition and mention in chat history func listChatRoles() []string { currentChat, ok := chatMap[activeChatName]