Enha: address template issues
This commit is contained in:
87
bot.go
87
bot.go
@@ -67,6 +67,80 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// cleanNullMessages removes messages with null or empty content to prevent API issues
|
||||||
|
func cleanNullMessages(messages []models.RoleMsg) []models.RoleMsg {
|
||||||
|
cleaned := make([]models.RoleMsg, 0, len(messages))
|
||||||
|
for _, msg := range messages {
|
||||||
|
// Include message if it has content or if it's a tool response (which might have tool_call_id)
|
||||||
|
if msg.HasContent() || msg.ToolCallID != "" {
|
||||||
|
cleaned = append(cleaned, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consolidateConsecutiveAssistantMessages(cleaned)
|
||||||
|
}
|
||||||
|
|
||||||
|
// consolidateConsecutiveAssistantMessages merges consecutive assistant messages into a single message
|
||||||
|
func consolidateConsecutiveAssistantMessages(messages []models.RoleMsg) []models.RoleMsg {
|
||||||
|
if len(messages) == 0 {
|
||||||
|
return messages
|
||||||
|
}
|
||||||
|
|
||||||
|
consolidated := make([]models.RoleMsg, 0, len(messages))
|
||||||
|
currentAssistantMsg := models.RoleMsg{}
|
||||||
|
isBuildingAssistantMsg := false
|
||||||
|
|
||||||
|
for i := 0; i < len(messages); i++ {
|
||||||
|
msg := messages[i]
|
||||||
|
|
||||||
|
if msg.Role == cfg.AssistantRole || msg.Role == cfg.WriteNextMsgAsCompletionAgent {
|
||||||
|
// If this is an assistant message, start or continue building
|
||||||
|
if !isBuildingAssistantMsg {
|
||||||
|
// Start accumulating assistant message
|
||||||
|
currentAssistantMsg = msg.Copy()
|
||||||
|
isBuildingAssistantMsg = true
|
||||||
|
} else {
|
||||||
|
// Continue accumulating - append content to the current assistant message
|
||||||
|
if currentAssistantMsg.IsContentParts() || msg.IsContentParts() {
|
||||||
|
// Handle structured content
|
||||||
|
if !currentAssistantMsg.IsContentParts() {
|
||||||
|
// Convert existing content to content parts
|
||||||
|
currentAssistantMsg = models.NewMultimodalMsg(currentAssistantMsg.Role, []interface{}{models.TextContentPart{Type: "text", Text: currentAssistantMsg.Content}})
|
||||||
|
currentAssistantMsg.ToolCallID = msg.ToolCallID
|
||||||
|
}
|
||||||
|
if msg.IsContentParts() {
|
||||||
|
currentAssistantMsg.ContentParts = append(currentAssistantMsg.ContentParts, msg.GetContentParts()...)
|
||||||
|
} else if msg.Content != "" {
|
||||||
|
currentAssistantMsg.AddTextPart(msg.Content)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Simple string content
|
||||||
|
if currentAssistantMsg.Content != "" {
|
||||||
|
currentAssistantMsg.Content += "\n" + msg.Content
|
||||||
|
} else {
|
||||||
|
currentAssistantMsg.Content = msg.Content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This is not an assistant message
|
||||||
|
// If we were building an assistant message, add it to the result
|
||||||
|
if isBuildingAssistantMsg {
|
||||||
|
consolidated = append(consolidated, currentAssistantMsg)
|
||||||
|
isBuildingAssistantMsg = false
|
||||||
|
}
|
||||||
|
// Add the non-assistant message
|
||||||
|
consolidated = append(consolidated, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't forget the last assistant message if we were building one
|
||||||
|
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
|
||||||
func GetLogLevel() string {
|
func GetLogLevel() string {
|
||||||
level := logLevel.Level()
|
level := logLevel.Level()
|
||||||
@@ -481,6 +555,10 @@ out:
|
|||||||
Role: botPersona, Content: respText.String(),
|
Role: botPersona, Content: respText.String(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean null/empty messages to prevent API issues with endpoints like llama.cpp jinja template
|
||||||
|
cleanChatBody()
|
||||||
|
|
||||||
colorText()
|
colorText()
|
||||||
updateStatusLine()
|
updateStatusLine()
|
||||||
// bot msg is done;
|
// bot msg is done;
|
||||||
@@ -492,6 +570,15 @@ out:
|
|||||||
findCall(respText.String(), toolResp.String(), tv)
|
findCall(respText.String(), toolResp.String(), tv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cleanChatBody removes messages with null or empty content to prevent API issues
|
||||||
|
func cleanChatBody() {
|
||||||
|
if chatBody != nil && chatBody.Messages != nil {
|
||||||
|
originalLen := len(chatBody.Messages)
|
||||||
|
chatBody.Messages = cleanNullMessages(chatBody.Messages)
|
||||||
|
logger.Debug("cleaned chat body", "original_len", originalLen, "new_len", len(chatBody.Messages))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func findCall(msg, toolCall string, tv *tview.TextView) {
|
func findCall(msg, toolCall string, tv *tview.TextView) {
|
||||||
fc := &models.FuncCall{}
|
fc := &models.FuncCall{}
|
||||||
if toolCall != "" {
|
if toolCall != "" {
|
||||||
|
|||||||
4
llm.go
4
llm.go
@@ -236,6 +236,8 @@ func (op LCPChat) FormMsg(msg, role string, resume bool) (io.Reader, error) {
|
|||||||
bodyCopy.Messages[i] = msg
|
bodyCopy.Messages[i] = msg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Clean null/empty messages to prevent API issues
|
||||||
|
bodyCopy.Messages = cleanNullMessages(bodyCopy.Messages)
|
||||||
req := models.OpenAIReq{
|
req := models.OpenAIReq{
|
||||||
ChatBody: bodyCopy,
|
ChatBody: bodyCopy,
|
||||||
Tools: nil,
|
Tools: nil,
|
||||||
@@ -385,6 +387,8 @@ func (ds DeepSeekerChat) FormMsg(msg, role string, resume bool) (io.Reader, erro
|
|||||||
bodyCopy.Messages[i] = msg
|
bodyCopy.Messages[i] = msg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Clean null/empty messages to prevent API issues
|
||||||
|
bodyCopy.Messages = cleanNullMessages(bodyCopy.Messages)
|
||||||
dsBody := models.NewDSChatReq(*bodyCopy)
|
dsBody := models.NewDSChatReq(*bodyCopy)
|
||||||
data, err := json.Marshal(dsBody)
|
data, err := json.Marshal(dsBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -230,6 +230,38 @@ func NewMultimodalMsg(role string, contentParts []interface{}) RoleMsg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasContent returns true if the message has either string content or structured content parts
|
||||||
|
func (m RoleMsg) HasContent() bool {
|
||||||
|
if m.Content != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if m.hasContentParts && len(m.ContentParts) > 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsContentParts returns true if the message uses structured content parts
|
||||||
|
func (m RoleMsg) IsContentParts() bool {
|
||||||
|
return m.hasContentParts
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContentParts returns the content parts of the message
|
||||||
|
func (m RoleMsg) GetContentParts() []interface{} {
|
||||||
|
return m.ContentParts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy creates a copy of the RoleMsg with all fields
|
||||||
|
func (m RoleMsg) Copy() RoleMsg {
|
||||||
|
return RoleMsg{
|
||||||
|
Role: m.Role,
|
||||||
|
Content: m.Content,
|
||||||
|
ContentParts: m.ContentParts,
|
||||||
|
ToolCallID: m.ToolCallID,
|
||||||
|
hasContentParts: m.hasContentParts,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AddTextPart adds a text content part to the message
|
// AddTextPart adds a text content part to the message
|
||||||
func (m *RoleMsg) AddTextPart(text string) {
|
func (m *RoleMsg) AddTextPart(text string) {
|
||||||
if !m.hasContentParts {
|
if !m.hasContentParts {
|
||||||
|
|||||||
Reference in New Issue
Block a user