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 sessionManager botgo.SessionManager
processedIDs map[string]bool processedIDs map[string]bool
mu sync.RWMutex mu sync.RWMutex
}
chatTypeMap map[string]string // Track whether a ChatID is group or C2C chatTypeMap map[string]string // Track whether a ChatID is group or C2C
chatTypeMu sync.RWMutex // Protects chatTypeMap chatTypeMu sync.RWMutex // Protects chatTypeMap
}
func NewQQChannel(cfg config.QQConfig, messageBus *bus.MessageBus) (*QQChannel, error) { func NewQQChannel(cfg config.QQConfig, messageBus *bus.MessageBus) (*QQChannel, error) {
base := channels.NewBaseChannel("qq", cfg, messageBus, cfg.AllowFrom, base := channels.NewBaseChannel("qq", cfg, messageBus, cfg.AllowFrom,

View file

@ -216,7 +216,8 @@ After completing the task, provide a clear summary of what was done.`
} }
// Send announce message back to main agent // Send announce message back to main agent
if sm.bus != nil { // 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) announceContent := fmt.Sprintf("Task '%s' completed.\n\nResult:\n%s", task.Label, task.Result)
pubCtx, pubCancel := context.WithTimeout(context.Background(), 5*time.Second) pubCtx, pubCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer pubCancel() defer pubCancel()
@ -227,8 +228,7 @@ After completing the task, provide a clear summary of what was done.`
ChatID: fmt.Sprintf("%s:%s", task.OriginChannel, task.OriginChatID), ChatID: fmt.Sprintf("%s:%s", task.OriginChannel, task.OriginChatID),
Content: announceContent, Content: announceContent,
}) })
} })
}
func (sm *SubagentManager) GetTask(taskID string) (*SubagentTask, bool) { func (sm *SubagentManager) GetTask(taskID string) (*SubagentTask, bool) {
sm.mu.RLock() sm.mu.RLock()