Strip other agents' tool calls from conversation history#1677
Strip other agents' tool calls from conversation history#1677trungutt wants to merge 2 commits intodocker:mainfrom
Conversation
Prevent agent hallucination by removing tool call patterns from other agents when building the message history for the current agent.
There was a problem hiding this comment.
Review Summary
Found 1 potential issue in the changed code related to tool call ID collision handling. The overall approach of stripping other agents' tool calls looks good, but there's a potential edge case that should be considered.
The shallow copy approach used at line 667 (cleaned := msg) is correct and idiomatic Go - it properly strips the ToolCalls from the returned messages.
| // Skip tool responses that belong to another agent's tool calls | ||
| if msg.Role == chat.MessageRoleTool && otherAgentToolCallIDs[msg.ToolCallID] { | ||
| continue | ||
| } |
There was a problem hiding this comment.
Potential issue: Tool call ID collision could filter legitimate responses
The code collects tool call IDs from other agents (lines 634-647) and then filters out any tool responses matching those IDs. However, if two agents generate the same tool call ID (e.g., OpenAI's short ID format could theoretically produce duplicate IDs across different API calls), this could incorrectly filter out legitimate tool responses from the current agent's previous turns.
Scenario:
- Agent A creates tool call with ID "call_abc123" and receives response
- Later, Agent B creates a tool call that also gets ID "call_abc123" (collision)
- When preparing messages for Agent A again, the tool response from step 1 would be incorrectly filtered out
Suggested fix:
Consider tracking tool call ownership with tuples like map[string]string mapping toolCallID -> agentName, or storing (agentName, toolCallID) pairs in a struct set. This would ensure that only tool responses actually belonging to other agents are filtered.
While ID collisions are rare in practice, this could cause confusing behavior in long-running multi-agent conversations.
pkg/session/session.go
Outdated
| startIndex := lastSummaryIndex + 1 | ||
|
|
||
| // Collect tool call IDs from other agents' assistant messages so we can | ||
| // strip both the calls and their corresponding tool-role responses. |
There was a problem hiding this comment.
We should NOT do this, instead we should do something like what ADK does, IIRC ADK converts tool calls to simple "FYI, agent did this and that" user messages
…pping them Instead of removing other agents' tool calls and responses from history (losing information), convert them to user-role narrative messages with attribution, following the ADK approach. This preserves context while preventing hallucination of tool calls the agent doesn't have.
Problem
In conversation where we have multiple agents coordinating with each other by handoff/delegation mechanism (given that each of these agents has different set of tools), this history can contain tool calls from other agents. In subsequent conversation, this causes the agent to hallucinate tool calls for tools it doesn't have access to, because it sees the tool calls in the history and tries to use them again, but with the incorrect agent.
Attempt to fix
When building the message history for an agent inGetMessages(), strip tool calls and their corresponding tool responses from other agents' messages. The text content is still preserved so the agent retains conversational context, but the tool usage patterns that trigger hallucination are removed.Instead of stripping other agents' tool calls from conversation history (which loses useful context), convert them into plain-text narrative messages with agent attribution, similar to Google ADK's approach.