package engine // norm_orphan_tool_result.go -- 移除孤立的 tool_result 块. // // 来源:早期方案第 1 步(collectToolUseIDs + removeOrphanedToolResults). // 场景:压缩,消息合并后可能产生孤立的 tool_result. // API 遇到无对应 tool_use 的 tool_result 会返回 400. // 跨场景通用:任何使用工具调用的场景都可能遇到. import ( "git.flytoex.net/yuanwei/flyto-agent/pkg/query" ) // OrphanToolResultRemover 移除没有对应 tool_use 的 tool_result 块. // // 精妙之处(CLEVER): 先收集所有 tool_use ID 再过滤,保证即使 tool_use // 出现在 tool_result 之后(理论上不该发生,但压缩可能打乱顺序)也能正确匹配. type OrphanToolResultRemover struct{} func (r *OrphanToolResultRemover) Name() string { return "orphan_tool_result" } func (r *OrphanToolResultRemover) Priority() int { return 10 } func (r *OrphanToolResultRemover) Normalize(messages []query.Message) []query.Message { if len(messages) == 0 { return messages } // 收集所有 tool_use ID(公共工具函数,避免与 ToolResultPairingNormalizer 重复实现) toolUseIDs := collectToolUseIDs(messages) // 过滤孤立的 tool_result result := make([]query.Message, 0, len(messages)) for _, msg := range messages { var filteredContent []query.Content for _, c := range msg.Content { if c.Type == query.ContentToolResult { if c.ToolUseID == "" || !toolUseIDs[c.ToolUseID] { // 孤立的 tool_result,跳过 continue } } filteredContent = append(filteredContent, c) } if len(filteredContent) > 0 { result = append(result, query.Message{ Role: msg.Role, Content: filteredContent, Time: msg.Time, Metadata: msg.Metadata, }) } } return result }