From 2580360f919c234deba0756f99d25f44046bf667 Mon Sep 17 00:00:00 2001 From: Grail Finder Date: Sat, 28 Feb 2026 09:13:05 +0300 Subject: Fix: removed code that deletes tool calls --- bot.go | 20 +++++++++----------- llm.go | 52 +++++++++++++--------------------------------------- models/models.go | 18 +++++++++--------- 3 files changed, 31 insertions(+), 59 deletions(-) diff --git a/bot.go b/bot.go index 86b602c..20ff813 100644 --- a/bot.go +++ b/bot.go @@ -1144,12 +1144,10 @@ func findCall(msg, toolCall string) bool { // Store tool call info in the assistant message // Convert Args map to JSON string for storage argsJSON, _ := json.Marshal(lastToolCall.Args) - chatBody.Messages[lastMsgIdx].ToolCalls = []models.ToolCall{ - { - ID: lastToolCall.ID, - Name: lastToolCall.Name, - Args: string(argsJSON), - }, + chatBody.Messages[lastMsgIdx].ToolCall = &models.ToolCall{ + ID: lastToolCall.ID, + Name: lastToolCall.Name, + Args: string(argsJSON), } // call a func _, ok := fnMap[fc.Name] @@ -1210,15 +1208,15 @@ func chatToTextSlice(messages []models.RoleMsg, showSys bool) []string { for i := range messages { icon := fmt.Sprintf("[-:-:b](%d) <%s>:[-:-:-]", i, messages[i].Role) // Handle tool call indicators (assistant messages with tool call but empty content) - if messages[i].Role == cfg.AssistantRole && len(messages[i].ToolCalls) > 0 { + if messages[i].Role == cfg.AssistantRole && messages[i].ToolCall != nil && messages[i].ToolCall.ID != "" { // This is a tool call indicator - show collapsed if toolCollapsed { - toolName := messages[i].ToolCalls[0].Name - resp[i] = fmt.Sprintf("%s\n[yellow::i][tool call: %s (press Ctrl+T to expand)][-:-:-]", icon, toolName) + toolName := messages[i].ToolCall.Name + resp[i] = fmt.Sprintf("%s\n[yellow::i][tool call: %s (press Ctrl+T to expand)][-:-:-]\n", icon, toolName) } else { // Show full tool call info - toolName := messages[i].ToolCalls[0].Name - resp[i] = fmt.Sprintf("%s\n[yellow::i][tool call: %s][-:-:-]\nargs: %s", icon, toolName, messages[i].ToolCalls[0].Args) + toolName := messages[i].ToolCall.Name + resp[i] = fmt.Sprintf("%s\n%s\n[yellow::i][tool call: %s][-:-:-]\nargs: %s\nid: %s\n", icon, messages[i].GetText(), toolName, messages[i].ToolCall.Args, messages[i].ToolCall.ID) } continue } diff --git a/llm.go b/llm.go index e9a3b0e..e4c8471 100644 --- a/llm.go +++ b/llm.go @@ -282,24 +282,15 @@ func (op LCPChat) FormMsg(msg, role string, resume bool) (io.Reader, error) { "content_len", len(newMsg.Content), "message_count_after_add", len(chatBody.Messages)) } filteredMessages, _ := filterMessagesForCurrentCharacter(chatBody.Messages) - // Filter out tool call indicators (assistant messages with ToolCallID but empty content) - var filteredForLLM []models.RoleMsg - for i := range filteredMessages { - isToolCallIndicator := filteredMessages[i].Role != "system" && filteredMessages[i].ToolCallID != "" && filteredMessages[i].Content == "" && len(filteredMessages[i].ToolCalls) > 0 - if isToolCallIndicator { - continue - } - filteredForLLM = append(filteredForLLM, filteredMessages[i]) - } // openai /v1/chat does not support custom roles; needs to be user, assistant, system // Add persona suffix to the last user message to indicate who the assistant should reply as bodyCopy := &models.ChatBody{ - Messages: make([]models.RoleMsg, len(filteredForLLM)), + Messages: make([]models.RoleMsg, len(filteredMessages)), Model: chatBody.Model, Stream: chatBody.Stream, } - for i := range filteredForLLM { - strippedMsg := *stripThinkingFromMsg(&filteredForLLM[i]) + for i := range filteredMessages { + strippedMsg := *stripThinkingFromMsg(&filteredMessages[i]) switch strippedMsg.Role { case cfg.UserRole: bodyCopy.Messages[i] = strippedMsg @@ -314,7 +305,7 @@ func (op LCPChat) FormMsg(msg, role string, resume bool) (io.Reader, error) { bodyCopy.Messages[i] = strippedMsg } // Clear ToolCalls - they're stored in chat history for display but not sent to LLM - bodyCopy.Messages[i].ToolCalls = nil + // bodyCopy.Messages[i].ToolCall = nil } // Clean null/empty messages to prevent API issues bodyCopy.Messages = consolidateAssistantMessages(bodyCopy.Messages) @@ -441,23 +432,14 @@ func (ds DeepSeekerChat) FormMsg(msg, role string, resume bool) (io.Reader, erro } // Create copy of chat body with standardized user role filteredMessages, _ := filterMessagesForCurrentCharacter(chatBody.Messages) - // Filter out tool call indicators (assistant messages with ToolCallID but empty content) - var filteredForLLM []models.RoleMsg - for i := range filteredMessages { - isToolCallIndicator := filteredMessages[i].Role != "system" && filteredMessages[i].ToolCallID != "" && filteredMessages[i].Content == "" && len(filteredMessages[i].ToolCalls) > 0 - if isToolCallIndicator { - continue - } - filteredForLLM = append(filteredForLLM, filteredMessages[i]) - } // Add persona suffix to the last user message to indicate who the assistant should reply as bodyCopy := &models.ChatBody{ - Messages: make([]models.RoleMsg, len(filteredForLLM)), + Messages: make([]models.RoleMsg, len(filteredMessages)), Model: chatBody.Model, Stream: chatBody.Stream, } - for i := range filteredForLLM { - strippedMsg := *stripThinkingFromMsg(&filteredForLLM[i]) + for i := range filteredMessages { + strippedMsg := *stripThinkingFromMsg(&filteredMessages[i]) switch strippedMsg.Role { case cfg.UserRole: if i == 1 { @@ -476,7 +458,7 @@ func (ds DeepSeekerChat) FormMsg(msg, role string, resume bool) (io.Reader, erro bodyCopy.Messages[i] = strippedMsg } // Clear ToolCalls - they're stored in chat history for display but not sent to LLM - bodyCopy.Messages[i].ToolCalls = nil + // bodyCopy.Messages[i].ToolCall = nil } // Clean null/empty messages to prevent API issues bodyCopy.Messages = consolidateAssistantMessages(bodyCopy.Messages) @@ -627,23 +609,14 @@ func (or OpenRouterChat) FormMsg(msg, role string, resume bool) (io.Reader, erro } // Create copy of chat body with standardized user role filteredMessages, _ := filterMessagesForCurrentCharacter(chatBody.Messages) - // Filter out tool call indicators (assistant messages with ToolCallID but empty content) - var filteredForLLM []models.RoleMsg - for i := range filteredMessages { - isToolCallIndicator := filteredMessages[i].Role != "system" && filteredMessages[i].ToolCallID != "" && filteredMessages[i].Content == "" && len(filteredMessages[i].ToolCalls) > 0 - if isToolCallIndicator { - continue - } - filteredForLLM = append(filteredForLLM, filteredMessages[i]) - } // Add persona suffix to the last user message to indicate who the assistant should reply as bodyCopy := &models.ChatBody{ - Messages: make([]models.RoleMsg, len(filteredForLLM)), + Messages: make([]models.RoleMsg, len(filteredMessages)), Model: chatBody.Model, Stream: chatBody.Stream, } - for i := range filteredForLLM { - strippedMsg := *stripThinkingFromMsg(&filteredForLLM[i]) + for i := range filteredMessages { + strippedMsg := *stripThinkingFromMsg(&filteredMessages[i]) switch strippedMsg.Role { case cfg.UserRole: bodyCopy.Messages[i] = strippedMsg @@ -658,7 +631,8 @@ func (or OpenRouterChat) FormMsg(msg, role string, resume bool) (io.Reader, erro bodyCopy.Messages[i] = strippedMsg } // Clear ToolCalls - they're stored in chat history for display but not sent to LLM - bodyCopy.Messages[i].ToolCalls = nil + // literally deletes data that we need + // bodyCopy.Messages[i].ToolCall = nil } // Clean null/empty messages to prevent API issues bodyCopy.Messages = consolidateAssistantMessages(bodyCopy.Messages) diff --git a/models/models.go b/models/models.go index 200d898..b9e9fad 100644 --- a/models/models.go +++ b/models/models.go @@ -102,7 +102,7 @@ type RoleMsg struct { Content string `json:"-"` ContentParts []any `json:"-"` ToolCallID string `json:"tool_call_id,omitempty"` // For tool response messages - ToolCalls []ToolCall `json:"tool_calls,omitempty"` // For assistant messages with tool calls + ToolCall *ToolCall `json:"tool_call,omitempty"` // For assistant messages with tool calls IsShellCommand bool `json:"is_shell_command,omitempty"` // True for shell command outputs (always shown) KnownTo []string `json:"known_to,omitempty"` Stats *ResponseStats `json:"stats"` @@ -119,7 +119,7 @@ func (m RoleMsg) MarshalJSON() ([]byte, error) { Role string `json:"role"` Content []any `json:"content"` ToolCallID string `json:"tool_call_id,omitempty"` - ToolCalls []ToolCall `json:"tool_calls,omitempty"` + ToolCall *ToolCall `json:"tool_call,omitempty"` IsShellCommand bool `json:"is_shell_command,omitempty"` KnownTo []string `json:"known_to,omitempty"` Stats *ResponseStats `json:"stats,omitempty"` @@ -127,7 +127,7 @@ func (m RoleMsg) MarshalJSON() ([]byte, error) { Role: m.Role, Content: m.ContentParts, ToolCallID: m.ToolCallID, - ToolCalls: m.ToolCalls, + ToolCall: m.ToolCall, IsShellCommand: m.IsShellCommand, KnownTo: m.KnownTo, Stats: m.Stats, @@ -139,7 +139,7 @@ func (m RoleMsg) MarshalJSON() ([]byte, error) { Role string `json:"role"` Content string `json:"content"` ToolCallID string `json:"tool_call_id,omitempty"` - ToolCalls []ToolCall `json:"tool_calls,omitempty"` + ToolCall *ToolCall `json:"tool_call,omitempty"` IsShellCommand bool `json:"is_shell_command,omitempty"` KnownTo []string `json:"known_to,omitempty"` Stats *ResponseStats `json:"stats,omitempty"` @@ -147,7 +147,7 @@ func (m RoleMsg) MarshalJSON() ([]byte, error) { Role: m.Role, Content: m.Content, ToolCallID: m.ToolCallID, - ToolCalls: m.ToolCalls, + ToolCall: m.ToolCall, IsShellCommand: m.IsShellCommand, KnownTo: m.KnownTo, Stats: m.Stats, @@ -163,7 +163,7 @@ func (m *RoleMsg) UnmarshalJSON(data []byte) error { Role string `json:"role"` Content []any `json:"content"` ToolCallID string `json:"tool_call_id,omitempty"` - ToolCalls []ToolCall `json:"tool_calls,omitempty"` + ToolCall *ToolCall `json:"tool_call,omitempty"` IsShellCommand bool `json:"is_shell_command,omitempty"` KnownTo []string `json:"known_to,omitempty"` Stats *ResponseStats `json:"stats,omitempty"` @@ -172,7 +172,7 @@ func (m *RoleMsg) UnmarshalJSON(data []byte) error { m.Role = structured.Role m.ContentParts = structured.Content m.ToolCallID = structured.ToolCallID - m.ToolCalls = structured.ToolCalls + m.ToolCall = structured.ToolCall m.IsShellCommand = structured.IsShellCommand m.KnownTo = structured.KnownTo m.Stats = structured.Stats @@ -185,7 +185,7 @@ func (m *RoleMsg) UnmarshalJSON(data []byte) error { Role string `json:"role"` Content string `json:"content"` ToolCallID string `json:"tool_call_id,omitempty"` - ToolCalls []ToolCall `json:"tool_calls,omitempty"` + ToolCall *ToolCall `json:"tool_call,omitempty"` IsShellCommand bool `json:"is_shell_command,omitempty"` KnownTo []string `json:"known_to,omitempty"` Stats *ResponseStats `json:"stats,omitempty"` @@ -196,7 +196,7 @@ func (m *RoleMsg) UnmarshalJSON(data []byte) error { m.Role = simple.Role m.Content = simple.Content m.ToolCallID = simple.ToolCallID - m.ToolCalls = simple.ToolCalls + m.ToolCall = simple.ToolCall m.IsShellCommand = simple.IsShellCommand m.KnownTo = simple.KnownTo m.Stats = simple.Stats -- cgit v1.2.3