Skip to content

fix(bridge): sanitize orphaned tool results in v2 adapter - #1975

Merged
ilblackdragon merged 2 commits into
stagingfrom
firat/feat-toolresult-v2-adapter-9n8
Apr 6, 2026
Merged

ilblackdragon merged 2 commits into
stagingfrom
firat/feat-toolresult-v2-adapter-9n8

Conversation

@serrrfirat

Copy link
Copy Markdown
Collaborator

Summary

  • sanitize V2 bridge chat history before sending it to LLM providers
  • reuse the shared sanitize_tool_messages helper from the LLM module
  • add regression tests covering both orphaned and valid action-result sequences in the bridge adapter

Root cause

The V2 LlmBridgeAdapter converted ThreadMessage values directly into ChatMessage values and forwarded them to the provider without calling sanitize_tool_messages(). When thread history contained an orphaned action result, Anthropic rejected the request with error 2013 because the tool_result no longer had a matching preceding tool call.

Impact

  • orphaned tool results are rewritten into normal user-visible messages before provider submission
  • valid tool call / tool result pairs are preserved unchanged
  • V2 Anthropic threads can recover from compaction, checkpoint restore, or pause/resume histories that would previously get stuck

Validation

  • cargo fmt --all --check
  • cargo test bridge::llm_adapter::tests --lib

Closes #1950

@github-actions github-actions Bot added scope: llm LLM integration size: M 50-199 changed lines risk: low Changes to docs, tests, or low-risk modules contributor: experienced 6-19 merged PRs labels Apr 3, 2026
@serrrfirat
serrrfirat marked this pull request as ready for review April 3, 2026 15:29

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a sanitization step for tool messages within the LlmBridgeAdapter by calling sanitize_tool_messages before provider execution. This ensures that orphaned action results are appropriately handled. Additionally, new unit tests have been added to verify the correct processing of both orphaned and matched action results. There are no review comments to address, and I have no further feedback to provide.

@github-actions github-actions Bot added size: L 200-499 changed lines and removed size: M 50-199 changed lines labels Apr 3, 2026
@serrrfirat serrrfirat changed the title [codex] fix(bridge): sanitize orphaned tool results in v2 adapter fix(bridge): sanitize orphaned tool results in v2 adapter Apr 3, 2026

@ilblackdragon ilblackdragon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Automated review — LGTM with minor notes

TL;DR: Well-scoped bug fix. Correctly isolates orphaned tool results at the adapter boundary using the existing sanitize_tool_messages helper. Good test coverage. Ready to merge after addressing the visibility nit below.

Findings

# Severity File:Line Issue Suggestion
1 Low src/llm/mod.rs:59 pub(crate) use sanitize_tool_messages re-export — per CLAUDE.md "No pub use re-exports unless exposing to downstream consumers" Use the direct path use crate::llm::provider::sanitize_tool_messages at the sole call site in llm_adapter.rs
2 Low src/bridge/llm_adapter.rs:51 let mut chat_messages but only mutated once via sanitize Either document the in-place rationale or accept &[ChatMessage] and return a new vec
3 Low Test structure All three new async tests use CapturingProvider that always returns Ok(...); no negative path Add a test where the provider returns an error after sanitize, to verify error propagation is intact

Strengths

  • Root cause clearly identified (missing sanitize_tool_messages call in adapter path → Anthropic error 2013)
  • Smart reuse of existing helper (DRY)
  • Uses tracing::debug!() — respects the TUI logging convention
  • Tests cover both complete() and complete_with_tools() paths

Open questions

  1. Is the pub(crate) re-export intentional for future callers, or can it stay private to the provider module?
  2. Are there other adapter paths (streaming, retries, failover) that could also receive corrupted message sequences and should call sanitize?

@ilblackdragon
ilblackdragon merged commit 98f4471 into staging Apr 6, 2026
14 checks passed
@ilblackdragon
ilblackdragon deleted the firat/feat-toolresult-v2-adapter-9n8 branch April 6, 2026 06:38
drchirag1991 pushed a commit to drchirag1991/ironclaw that referenced this pull request Apr 8, 2026
* fix(bridge): sanitize orphaned tool results in v2 adapter

* test(bridge): cover no-tool sanitizer path
@ironclaw-ci ironclaw-ci Bot mentioned this pull request Apr 10, 2026
@ironclaw-ci ironclaw-ci Bot mentioned this pull request Apr 18, 2026
theredspoon pushed a commit to theredspoon/ironclaw that referenced this pull request Jun 21, 2026
* fix(bridge): sanitize orphaned tool results in v2 adapter

* test(bridge): cover no-tool sanitizer path
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: experienced 6-19 merged PRs risk: low Changes to docs, tests, or low-risk modules scope: llm LLM integration size: L 200-499 changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(bridge): orphaned tool_result messages in v2 LLM adapter cause Anthropic API error 2013

2 participants