diff options
| -rw-r--r-- | config/config.go | 29 | ||||
| -rw-r--r-- | llm.go | 24 | ||||
| -rw-r--r-- | main.go | 1 | ||||
| -rw-r--r-- | tui.go | 24 |
4 files changed, 68 insertions, 10 deletions
diff --git a/config/config.go b/config/config.go index fab9259..681757d 100644 --- a/config/config.go +++ b/config/config.go @@ -84,10 +84,33 @@ func LoadConfig(fn string) (*Config, error) { config.OpenRouterCompletionAPI: config.OpenRouterChatAPI, config.OpenRouterChatAPI: config.ChatAPI, } - for _, el := range []string{config.ChatAPI, config.CompletionAPI, config.DeepSeekChatAPI, config.DeepSeekCompletionAPI} { - if el != "" { - config.ApiLinks = append(config.ApiLinks, el) + // Build ApiLinks slice with only non-empty API links + // Only include DeepSeek APIs if DeepSeekToken is provided + if config.DeepSeekToken != "" { + if config.DeepSeekChatAPI != "" { + config.ApiLinks = append(config.ApiLinks, config.DeepSeekChatAPI) } + if config.DeepSeekCompletionAPI != "" { + config.ApiLinks = append(config.ApiLinks, config.DeepSeekCompletionAPI) + } + } + + // Only include OpenRouter APIs if OpenRouterToken is provided + if config.OpenRouterToken != "" { + if config.OpenRouterChatAPI != "" { + config.ApiLinks = append(config.ApiLinks, config.OpenRouterChatAPI) + } + if config.OpenRouterCompletionAPI != "" { + config.ApiLinks = append(config.ApiLinks, config.OpenRouterCompletionAPI) + } + } + + // Always include basic APIs + if config.ChatAPI != "" { + config.ApiLinks = append(config.ApiLinks, config.ChatAPI) + } + if config.CompletionAPI != "" { + config.ApiLinks = append(config.ApiLinks, config.CompletionAPI) } // if any value is empty fill with default return config, nil @@ -205,7 +205,6 @@ func (op OpenAIer) FormMsg(msg, role string, resume bool) (io.Reader, error) { newMsg = models.NewRoleMsg(role, msg) } chatBody.Messages = append(chatBody.Messages, newMsg) - // if rag - add as system message to avoid conflicts with tool usage if cfg.RAGEnabled { ragResp, err := chatRagUse(newMsg.Content) @@ -485,7 +484,28 @@ func (or OpenRouterChat) FormMsg(msg, role string, resume bool) (io.Reader, erro chatBody.Messages = append(chatBody.Messages, models.RoleMsg{Role: cfg.ToolRole, Content: toolSysMsg}) } if msg != "" { // otherwise let the bot continue - newMsg := models.RoleMsg{Role: role, Content: msg} + var newMsg models.RoleMsg + // Check if we have an image to add to this message + if imageAttachmentPath != "" { + // Create a multimodal message with both text and image + newMsg = models.NewMultimodalMsg(role, []interface{}{}) + // Add the text content + newMsg.AddTextPart(msg) + // Add the image content + imageURL, err := models.CreateImageURLFromPath(imageAttachmentPath) + if err != nil { + logger.Error("failed to create image URL from path", "error", err, "path", imageAttachmentPath) + // If image processing fails, fall back to simple text message + newMsg = models.NewRoleMsg(role, msg) + imageAttachmentPath = "" // Clear the attachment + } else { + newMsg.AddImagePart(imageURL) + imageAttachmentPath = "" // Clear the attachment after use + } + } else { + // Create a simple text message + newMsg = models.NewRoleMsg(role, msg) + } chatBody.Messages = append(chatBody.Messages, newMsg) // if rag - add as system message to avoid conflicts with tool usage if cfg.RAGEnabled { @@ -13,6 +13,7 @@ var ( editMode = false injectRole = true selectedIndex = int(-1) + currentAPIIndex = 0 // Index to track current API in ApiLinks slice // indexLine = "F12 to show keys help | bot resp mode: [orange:-:b]%v[-:-:-] (F6) | card's char: [orange:-:b]%s[-:-:-] (ctrl+s) | chat: [orange:-:b]%s[-:-:-] (F1) | toolUseAdviced: [orange:-:b]%v[-:-:-] (ctrl+k) | model: [orange:-:b]%s[-:-:-] (ctrl+l) | skip LLM resp: [orange:-:b]%v[-:-:-] (F10)\nAPI_URL: [orange:-:b]%s[-:-:-] (ctrl+v) | ThinkUse: [orange:-:b]%v[-:-:-] (ctrl+p) | Log Level: [orange:-:b]%v[-:-:-] (ctrl+p) | Recording: [orange:-:b]%v[-:-:-] (ctrl+r) | Writing as: [orange:-:b]%s[-:-:-] (ctrl+q)" indexLineCompletion = "F12 to show keys help | bot resp mode: [orange:-:b]%v[-:-:-] (F6) | card's char: [orange:-:b]%s[-:-:-] (ctrl+s) | chat: [orange:-:b]%s[-:-:-] (F1) | toolUseAdviced: [orange:-:b]%v[-:-:-] (ctrl+k) | model: [orange:-:b]%s[-:-:-] (ctrl+l) | skip LLM resp: [orange:-:b]%v[-:-:-] (F10)\nAPI_URL: [orange:-:b]%s[-:-:-] (ctrl+v) | ThinkUse: [orange:-:b]%v[-:-:-] (ctrl+p) | Log Level: [orange:-:b]%v[-:-:-] (ctrl+p) | Recording: [orange:-:b]%v[-:-:-] (ctrl+r) | Writing as: [orange:-:b]%s[-:-:-] (ctrl+q) | Bot will write as [orange:-:b]%s[-:-:-] (ctrl+x) | role_inject [orange:-:b]%v[-:-:-]" focusSwitcher = map[tview.Primitive]tview.Primitive{} @@ -764,13 +764,27 @@ func init() { return nil } if event.Key() == tcell.KeyCtrlV { - // switch between /chat and /completion api - newAPI := cfg.APIMap[cfg.CurrentAPI] - if newAPI == "" { - // do not switch + // switch between API links using index-based rotation + if len(cfg.ApiLinks) == 0 { + // No API links to rotate through return nil } - cfg.CurrentAPI = newAPI + // Find current API in the list to get the current index + currentIndex := -1 + for i, api := range cfg.ApiLinks { + if api == cfg.CurrentAPI { + currentIndex = i + break + } + } + // If current API is not in the list, start from beginning + // Otherwise, advance to next API in the list (with wrap-around) + if currentIndex == -1 { + currentAPIIndex = 0 + } else { + currentAPIIndex = (currentIndex + 1) % len(cfg.ApiLinks) + } + cfg.CurrentAPI = cfg.ApiLinks[currentAPIIndex] choseChunkParser() updateStatusLine() return nil |
