Skip to content

fix(agent): occurrence-aware tool call id sanitization#1854

Open
badgerbees wants to merge 1 commit intosipeed:mainfrom
badgerbees:fix/occurrence-aware-tool-ids
Open

fix(agent): occurrence-aware tool call id sanitization#1854
badgerbees wants to merge 1 commit intosipeed:mainfrom
badgerbees:fix/occurrence-aware-tool-ids

Conversation

@badgerbees
Copy link
Contributor

📝 Description

Summary:
This PR implements occurrence-aware tool ID sanitization to resolve 400 Bad Request errors caused by duplicate tool_call_id values. This ensures that PicoClaw is fully compatible with strict LLM providers (especially Anthropic and Cerebras) that reject reused IDs, even when they appear across separate turns.

Key Features & Fixes:

  • Occurrence-Aware FIFO Resolver: Changes the 1-to-1 ID mapping to a FIFO queue system. The first occurrence of a raw ID is allocated normally; each subsequent occurrence is assigned a unique fallback ID (e.g., call_auto_N). Tool results then "pop" from the queue to match their respective rewritten IDs in the correct order.
  • Single-Message Safety: If an LLM repeats the same ID multiple times in a single response, we now catch this immediately and assign unique fallback IDs before tool execution begins.
  • Global Invariant Enforcement: Adds a final sanitization pass to the transcript builder to ensure every tool_call_id and its corresponding tool response are distinct and unique across the entire history.

Changes:

  • pkg/providers/toolcall_utils.go: Updated NormalizeToolCall to plural form with logic to ensure initial uniqueness within a single message.
  • pkg/agent/context.go: Implemented the FIFO-based resolver in sanitizeHistoryForProvider (Pass 3) for absolute history-wide uniqueness.
  • pkg/agent/loop.go & pkg/tools/toolloop.go: Switched to the new consolidated normalization helper.

🗣️ Type of Change

  • 🐞 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • ⚡ Code refactoring (no functional changes, no api changes)

🤖 AI Code Generation

  • 🤖 Fully AI-generated (100% AI, 0% Human)
  • 🛠️ Mostly AI-generated (AI draft, Human verified/modified)
  • 👨‍💻 Mostly Human-written (Human lead, AI assisted or none)

🔗 Related Issue

N/A

📚 Technical Context (Skip for Docs)

  • Problem Overview:
    Modern LLM APIs require every tool call ID to be unique across a session. If a provider repeats an ID in different turns (or even in one message), it results in an API error. A simple static map fails here because it doesn't account for how many times an ID has appeared.

  • Solution Implementation:
    By using an IDMap with slice values, we can handle multiple occurrences of the same raw ID by assigning a unique rewritten ID for each. This preserves the correct call-order pairing and makes the whole transcript "OpenAI-compatible" for strict providers.

🧪 Test Environment

  • Hardware: PC
  • OS: Windows
  • Providers: Tested with strict OpenAI-compatible providers.

📸 Evidence (Optional)

Click to view Logs/Test Results

Test Results:

  • Passed go build ./pkg/agent
  • Passed go build ./pkg/tools

☑️ Checklist

  • My code/docs follow the style of this project.
  • I have performed a self-review of my own changes.
  • I have updated the documentation accordingly.

@sipeed-bot sipeed-bot bot added type: bug Something isn't working domain: agent domain: provider go Pull requests that update go code labels Mar 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain: agent domain: provider go Pull requests that update go code type: bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant