Fix: do not delete tool calls or lose them on copy
This commit is contained in:
109
bot.go
109
bot.go
@@ -136,6 +136,9 @@ func processMessageTag(msg *models.RoleMsg) *models.RoleMsg {
|
|||||||
// filterMessagesForCharacter returns messages visible to the specified character.
|
// filterMessagesForCharacter returns messages visible to the specified character.
|
||||||
// If CharSpecificContextEnabled is false, returns all messages.
|
// If CharSpecificContextEnabled is false, returns all messages.
|
||||||
func filterMessagesForCharacter(messages []models.RoleMsg, character string) []models.RoleMsg {
|
func filterMessagesForCharacter(messages []models.RoleMsg, character string) []models.RoleMsg {
|
||||||
|
if strings.Contains(cfg.CurrentAPI, "chat") {
|
||||||
|
return messages
|
||||||
|
}
|
||||||
if cfg == nil || !cfg.CharSpecificContextEnabled || character == "" {
|
if cfg == nil || !cfg.CharSpecificContextEnabled || character == "" {
|
||||||
return messages
|
return messages
|
||||||
}
|
}
|
||||||
@@ -158,82 +161,52 @@ func filterMessagesForCharacter(messages []models.RoleMsg, character string) []m
|
|||||||
return filtered
|
return filtered
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanToolCalls(messages []models.RoleMsg) []models.RoleMsg {
|
|
||||||
// If AutoCleanToolCallsFromCtx is false, keep tool call messages in context
|
|
||||||
if cfg != nil && !cfg.AutoCleanToolCallsFromCtx {
|
|
||||||
return consolidateAssistantMessages(messages)
|
|
||||||
}
|
|
||||||
cleaned := make([]models.RoleMsg, 0, len(messages))
|
|
||||||
for i := range messages {
|
|
||||||
// recognize the message as the tool call and remove it
|
|
||||||
// tool call in last msg should stay
|
|
||||||
if messages[i].ToolCallID == "" || i == len(messages)-1 {
|
|
||||||
cleaned = append(cleaned, messages[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return consolidateAssistantMessages(cleaned)
|
|
||||||
}
|
|
||||||
|
|
||||||
// consolidateAssistantMessages merges consecutive assistant messages into a single message
|
|
||||||
func consolidateAssistantMessages(messages []models.RoleMsg) []models.RoleMsg {
|
func consolidateAssistantMessages(messages []models.RoleMsg) []models.RoleMsg {
|
||||||
if len(messages) == 0 {
|
if len(messages) == 0 {
|
||||||
return messages
|
return messages
|
||||||
}
|
}
|
||||||
consolidated := make([]models.RoleMsg, 0, len(messages))
|
result := make([]models.RoleMsg, 0, len(messages))
|
||||||
currentAssistantMsg := models.RoleMsg{}
|
for i := range messages {
|
||||||
isBuildingAssistantMsg := false
|
// Non-assistant messages are appended as-is
|
||||||
for i := 0; i < len(messages); i++ {
|
if messages[i].Role != cfg.AssistantRole {
|
||||||
msg := messages[i]
|
result = append(result, messages[i])
|
||||||
// assistant role only
|
continue
|
||||||
if msg.Role == cfg.AssistantRole {
|
}
|
||||||
// If this is an assistant message, start or continue building
|
// Assistant message: start a new block or merge with the last one
|
||||||
if !isBuildingAssistantMsg {
|
if len(result) == 0 || result[len(result)-1].Role != cfg.AssistantRole {
|
||||||
// Start accumulating assistant message
|
// First assistant in a block: append a copy (avoid mutating input)
|
||||||
currentAssistantMsg = msg.Copy()
|
result = append(result, messages[i].Copy())
|
||||||
isBuildingAssistantMsg = true
|
continue
|
||||||
} else {
|
}
|
||||||
// Continue accumulating - append content to the current assistant message
|
// Merge with the last assistant message
|
||||||
if currentAssistantMsg.IsContentParts() || msg.IsContentParts() {
|
last := &result[len(result)-1]
|
||||||
// Handle structured content
|
// If either message has structured content, unify to ContentParts
|
||||||
if !currentAssistantMsg.IsContentParts() {
|
if last.IsContentParts() || messages[i].IsContentParts() {
|
||||||
// Preserve the original ToolCallID before conversion
|
// Convert last to ContentParts if needed, preserving ToolCallID
|
||||||
originalToolCallID := currentAssistantMsg.ToolCallID
|
if !last.IsContentParts() {
|
||||||
// Convert existing content to content parts
|
toolCallID := last.ToolCallID
|
||||||
currentAssistantMsg = models.NewMultimodalMsg(currentAssistantMsg.Role, []interface{}{models.TextContentPart{Type: "text", Text: currentAssistantMsg.Content}})
|
*last = models.NewMultimodalMsg(last.Role, []interface{}{
|
||||||
// Restore the original ToolCallID to preserve tool call linking
|
models.TextContentPart{Type: "text", Text: last.Content},
|
||||||
currentAssistantMsg.ToolCallID = originalToolCallID
|
})
|
||||||
}
|
last.ToolCallID = toolCallID
|
||||||
if msg.IsContentParts() {
|
}
|
||||||
currentAssistantMsg.ContentParts = append(currentAssistantMsg.ContentParts, msg.GetContentParts()...)
|
// Add current message's content to last
|
||||||
} else if msg.Content != "" {
|
if messages[i].IsContentParts() {
|
||||||
currentAssistantMsg.AddTextPart(msg.Content)
|
last.ContentParts = append(last.ContentParts, messages[i].GetContentParts()...)
|
||||||
}
|
} else if messages[i].Content != "" {
|
||||||
} else {
|
last.AddTextPart(messages[i].Content)
|
||||||
// Simple string content
|
|
||||||
if currentAssistantMsg.Content != "" {
|
|
||||||
currentAssistantMsg.Content += "\n" + msg.Content
|
|
||||||
} else {
|
|
||||||
currentAssistantMsg.Content = msg.Content
|
|
||||||
}
|
|
||||||
// ToolCallID is already preserved since we're not creating a new message object when just concatenating content
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This is not an assistant message
|
// Both simple strings: concatenate with newline
|
||||||
// If we were building an assistant message, add it to the result
|
if last.Content != "" && messages[i].Content != "" {
|
||||||
if isBuildingAssistantMsg {
|
last.Content += "\n" + messages[i].Content
|
||||||
consolidated = append(consolidated, currentAssistantMsg)
|
} else if messages[i].Content != "" {
|
||||||
isBuildingAssistantMsg = false
|
last.Content = messages[i].Content
|
||||||
}
|
}
|
||||||
// Add the non-assistant message
|
// ToolCallID is already preserved in last
|
||||||
consolidated = append(consolidated, msg)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Don't forget the last assistant message if we were building one
|
return result
|
||||||
if isBuildingAssistantMsg {
|
|
||||||
consolidated = append(consolidated, currentAssistantMsg)
|
|
||||||
}
|
|
||||||
return consolidated
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLogLevel returns the current log level as a string
|
// GetLogLevel returns the current log level as a string
|
||||||
@@ -982,7 +955,7 @@ func cleanChatBody() {
|
|||||||
}
|
}
|
||||||
// Tool request cleaning is now configurable via AutoCleanToolCallsFromCtx (default false)
|
// Tool request cleaning is now configurable via AutoCleanToolCallsFromCtx (default false)
|
||||||
// /completion msg where part meant for user and other part tool call
|
// /completion msg where part meant for user and other part tool call
|
||||||
chatBody.Messages = cleanToolCalls(chatBody.Messages)
|
// chatBody.Messages = cleanToolCalls(chatBody.Messages)
|
||||||
chatBody.Messages = consolidateAssistantMessages(chatBody.Messages)
|
chatBody.Messages = consolidateAssistantMessages(chatBody.Messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
main.go
2
main.go
@@ -16,7 +16,7 @@ var (
|
|||||||
shellHistory []string
|
shellHistory []string
|
||||||
shellHistoryPos int = -1
|
shellHistoryPos int = -1
|
||||||
thinkingCollapsed = false
|
thinkingCollapsed = false
|
||||||
toolCollapsed = false
|
toolCollapsed = true
|
||||||
statusLineTempl = "help (F12) | chat: [orange:-:b]%s[-:-:-] (F1) | [%s:-:b]tool use[-:-:-] (ctrl+k) | model: [%s:-:b]%s[-:-:-] (ctrl+l) | [%s:-:b]skip LLM resp[-:-:-] (F10)\nAPI: [orange:-:b]%s[-:-:-] (ctrl+v) | writing as: [orange:-:b]%s[-:-:-] (ctrl+q) | bot will write as [orange:-:b]%s[-:-:-] (ctrl+x)"
|
statusLineTempl = "help (F12) | chat: [orange:-:b]%s[-:-:-] (F1) | [%s:-:b]tool use[-:-:-] (ctrl+k) | model: [%s:-:b]%s[-:-:-] (ctrl+l) | [%s:-:b]skip LLM resp[-:-:-] (F10)\nAPI: [orange:-:b]%s[-:-:-] (ctrl+v) | writing as: [orange:-:b]%s[-:-:-] (ctrl+q) | bot will write as [orange:-:b]%s[-:-:-] (ctrl+x)"
|
||||||
focusSwitcher = map[tview.Primitive]tview.Primitive{}
|
focusSwitcher = map[tview.Primitive]tview.Primitive{}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -283,6 +283,8 @@ func (m *RoleMsg) Copy() RoleMsg {
|
|||||||
KnownTo: m.KnownTo,
|
KnownTo: m.KnownTo,
|
||||||
Stats: m.Stats,
|
Stats: m.Stats,
|
||||||
HasContentParts: m.HasContentParts,
|
HasContentParts: m.HasContentParts,
|
||||||
|
ToolCall: m.ToolCall,
|
||||||
|
IsShellCommand: m.IsShellCommand,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user