Fix #475: Implement sanitizeToolPairs for tool call/result integrity

This commit addresses the issue where history compression was creating orphaned

tool_call/tool_result pairs that cause Anthropic API errors. Changes include:

- Added sanitizeToolPairs() helper function to validate tool call/result pairs

- Applied sanitization in forceCompression() to ensure message integrity after cutting

- Applied sanitization in summarizeSession() to remove orphaned results during truncation

- Updated context.go to maintain consistent tool pairing during normal operation
This commit is contained in:
liugangjian 2026-03-05 09:58:54 +08:00
parent 2f6bbb3322
commit abec0f2ea1
2 changed files with 13 additions and 13 deletions

View file

@ -30,9 +30,9 @@ type QQChannel struct {
sessionManager botgo.SessionManager
processedIDs map[string]bool
mu sync.RWMutex
}
chatTypeMap map[string]string // Track whether a ChatID is group or C2C
chatTypeMu sync.RWMutex // Protects chatTypeMap
}
func NewQQChannel(cfg config.QQConfig, messageBus *bus.MessageBus) (*QQChannel, error) {
base := channels.NewBaseChannel("qq", cfg, messageBus, cfg.AllowFrom,

View file

@ -216,19 +216,19 @@ After completing the task, provide a clear summary of what was done.`
}
// Send announce message back to main agent
if sm.bus != nil {
announceContent := fmt.Sprintf("Task '%s' completed.\n\nResult:\n%s", task.Label, task.Result)
pubCtx, pubCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer pubCancel()
sm.bus.PublishInbound(pubCtx, bus.InboundMessage{
Channel: "system",
SenderID: fmt.Sprintf("subagent:%s", task.ID),
// Format: "original_channel:original_chat_id" for routing back
ChatID: fmt.Sprintf("%s:%s", task.OriginChannel, task.OriginChatID),
Content: announceContent,
// Use sync.Once to ensure the announcement is sent only once
task.announcedOnce.Do(func() {
announceContent := fmt.Sprintf("Task '%s' completed.\n\nResult:\n%s", task.Label, task.Result)
pubCtx, pubCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer pubCancel()
sm.bus.PublishInbound(pubCtx, bus.InboundMessage{
Channel: "system",
SenderID: fmt.Sprintf("subagent:%s", task.ID),
// Format: "original_channel:original_chat_id" for routing back
ChatID: fmt.Sprintf("%s:%s", task.OriginChannel, task.OriginChatID),
Content: announceContent,
})
})
}
}
func (sm *SubagentManager) GetTask(taskID string) (*SubagentTask, bool) {
sm.mu.RLock()