Fix: apilinks rotation

This commit is contained in:
Grail Finder
2025-11-24 12:00:46 +03:00
parent 504af1a213
commit 8a62e98789
4 changed files with 68 additions and 10 deletions

View File

@@ -84,10 +84,33 @@ func LoadConfig(fn string) (*Config, error) {
config.OpenRouterCompletionAPI: config.OpenRouterChatAPI, config.OpenRouterCompletionAPI: config.OpenRouterChatAPI,
config.OpenRouterChatAPI: config.ChatAPI, config.OpenRouterChatAPI: config.ChatAPI,
} }
for _, el := range []string{config.ChatAPI, config.CompletionAPI, config.DeepSeekChatAPI, config.DeepSeekCompletionAPI} { // Build ApiLinks slice with only non-empty API links
if el != "" { // Only include DeepSeek APIs if DeepSeekToken is provided
config.ApiLinks = append(config.ApiLinks, el) 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 // if any value is empty fill with default
return config, nil return config, nil

24
llm.go
View File

@@ -205,7 +205,6 @@ func (op OpenAIer) FormMsg(msg, role string, resume bool) (io.Reader, error) {
newMsg = models.NewRoleMsg(role, msg) newMsg = models.NewRoleMsg(role, msg)
} }
chatBody.Messages = append(chatBody.Messages, newMsg) chatBody.Messages = append(chatBody.Messages, newMsg)
// if rag - add as system message to avoid conflicts with tool usage // if rag - add as system message to avoid conflicts with tool usage
if cfg.RAGEnabled { if cfg.RAGEnabled {
ragResp, err := chatRagUse(newMsg.Content) 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}) chatBody.Messages = append(chatBody.Messages, models.RoleMsg{Role: cfg.ToolRole, Content: toolSysMsg})
} }
if msg != "" { // otherwise let the bot continue 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) chatBody.Messages = append(chatBody.Messages, newMsg)
// if rag - add as system message to avoid conflicts with tool usage // if rag - add as system message to avoid conflicts with tool usage
if cfg.RAGEnabled { if cfg.RAGEnabled {

View File

@@ -13,6 +13,7 @@ var (
editMode = false editMode = false
injectRole = true injectRole = true
selectedIndex = int(-1) 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)" // 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[-:-:-]" 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{} focusSwitcher = map[tview.Primitive]tview.Primitive{}

24
tui.go
View File

@@ -764,13 +764,27 @@ func init() {
return nil return nil
} }
if event.Key() == tcell.KeyCtrlV { if event.Key() == tcell.KeyCtrlV {
// switch between /chat and /completion api // switch between API links using index-based rotation
newAPI := cfg.APIMap[cfg.CurrentAPI] if len(cfg.ApiLinks) == 0 {
if newAPI == "" { // No API links to rotate through
// do not switch
return nil 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() choseChunkParser()
updateStatusLine() updateStatusLine()
return nil return nil