Skip to content

Fix/deduplicate tool names#2278

Open
Anubhav200311 wants to merge 3 commits intodocker:mainfrom
Anubhav200311:fix/deduplicate-tool-names
Open

Fix/deduplicate tool names#2278
Anubhav200311 wants to merge 3 commits intodocker:mainfrom
Anubhav200311:fix/deduplicate-tool-names

Conversation

@Anubhav200311
Copy link
Copy Markdown

@Anubhav200311 Anubhav200311 commented Mar 30, 2026

When multiple toolsets contain tools with the same name, the Agent's Tools() method returns duplicates. This causes Anthropic API 400 errors because the API rejects requests with duplicate tool names.

This fix adds deduplication logic to the Tools() method in pkg/agent/agent.go. After all toolsets are collected, it filters out duplicate tool names, keeping the first occurrence and logging a warning for
any that are skipped. A corresponding test case ("duplicate tool names are deduplicated") is added in pkg/agent/agent_test.go to verify the behavior.
Fixes #2251

@Anubhav200311 Anubhav200311 requested a review from a team as a code owner March 30, 2026 04:52
@aheritier
Copy link
Copy Markdown
Contributor

/review

Copy link
Copy Markdown

@docker-agent docker-agent Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟡 NEEDS ATTENTION

This PR successfully fixes the duplicate tool name issue that was causing Anthropic API 400 errors. The deduplication logic is sound and will prevent the reported bug.

Findings: 1 medium-severity issue regarding inconsistent warning handling.

The deduplication warnings use slog.Warn() directly instead of addToolWarning(), which means they won't be captured by DrainWarnings(). Consider aligning with the existing warning pattern for consistency.

Comment thread pkg/agent/agent.go
Comment thread pkg/agent/agent.go
@Anubhav200311
Copy link
Copy Markdown
Author

Anubhav200311 commented Mar 30, 2026

Addressed the bot's feedback in the latest commit --> added addToolWarning() for consistent warning handling.

@Anubhav200311 Anubhav200311 force-pushed the fix/deduplicate-tool-names branch from e0a5bdb to 1b8a6db Compare April 6, 2026 19:03
@Anubhav200311
Copy link
Copy Markdown
Author

Hi @aheritier , I've rebased onto main to clean up the commit history. Could you trigger a re-review when you get the time? Thanks!

@derekmisler
Copy link
Copy Markdown
Contributor

/review

@aheritier aheritier removed the kind/bug label May 5, 2026
@aheritier
Copy link
Copy Markdown
Contributor

/review

Copy link
Copy Markdown

@docker-agent docker-agent Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟡 NEEDS ATTENTION

The deduplication logic is functionally correct and addresses the reported Anthropic API 400 error. The approach (first-occurrence wins, O(n) scan with a map) is clean and idiomatic Go.

One medium-severity issue was found in the new code, plus two low-severity observations:

Findings summary:

Severity Finding
🟡 MEDIUM Pre-existing pendingWarnings race extended by new dedup addToolWarning calls (see inline comment)
🔵 LOW Empty-string tool names are silently deduplicated rather than flagged as invalid — minor edge case
🔵 LOW Test verifies tool count and warning count but not which occurrence is retained (first vs. last) — a regression blind spot

Low-severity details:

  • Empty tool name handling (pkg/agent/agent.go): If a tool has an empty Name, it will be treated as a duplicate of any other empty-named tool and silently discarded with a duplicate tool "": keeping first occurrence warning. This is likely a degenerate case, but a pre-check like if t.Name == "" { continue } with a distinct warning would surface configuration errors more clearly.

  • Test coverage gap (pkg/agent/agent_test.go, line ~90): The test case checks wantToolCount: 3 and wantWarnings: 1, which confirms the count is right. It does not assert the identity of the retained tools (e.g., ["read_file", "write_file", "shell"] in that order). If the dedup logic were accidentally changed to keep the last occurrence, the test would still pass. Consider adding an assertion on the resulting tool names.

Comment thread pkg/agent/agent.go
if _, exists := seen[t.Name]; exists {
slog.Warn("Duplicate tool name; keeping first occurrence",
"agent", a.Name(), "tool", t.Name)
a.addToolWarning(fmt.Sprintf("duplicate tool %q: keeping first occurrence", t.Name))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM/LIKELY] New addToolWarning call in dedup loop extends pre-existing unsynchronized access to pendingWarnings

a.addToolWarning(...) appends to a.pendingWarnings (a plain []string with no mutex). This pattern already existed in collectTools (line 235) and ensureToolSetsAreStarted (line 281) before this PR, but the new dedup block adds two additional unsynchronized append sites within the same hot path.

If two goroutines call Tools() or StartedTools() concurrently — which is plausible in a multi-agent or event-driven context — they both invoke collectTools, both reach this loop, and both call addToolWarning without synchronization, creating a data race on the backing array of the slice.

Impact: In practice the risk is low because agent methods are typically not called concurrently from different goroutines, and this is a pre-existing structural gap rather than a new one. However, the new dedup code is the first time duplicate-tool warnings can be generated during normal (non-error) operation, making this path more likely to be exercised.

Suggestion: Guard pendingWarnings with a sync.Mutex, or — if concurrent use is not a design goal — document that Tools() / StartedTools() must not be called concurrently.

@aheritier aheritier added kind/fix PR fixes a bug (maps to fix: commit prefix) area/tools For features/issues/fixes related to the usage of built-in and MCP tools area/providers/anthropic For features/issues/fixes related to the usage of Anthropic models priority:high Major impact, should be addressed within 2 days effort:small Isolated change, clear solution, single area go Pull requests that update go code and removed priority:high Major impact, should be addressed within 2 days labels May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/providers/anthropic For features/issues/fixes related to the usage of Anthropic models area/tools For features/issues/fixes related to the usage of built-in and MCP tools effort:small Isolated change, clear solution, single area go Pull requests that update go code kind/fix PR fixes a bug (maps to fix: commit prefix)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Duplicate tool names across toolsets cause Anthropic 400 errors

3 participants