Skip to content

fix: strip call_id/response_item_id from tool_calls for Mistral compatibility#1058

Merged
teknium1 merged 1 commit intomainfrom
hermes/hermes-465f3702
Mar 12, 2026
Merged

fix: strip call_id/response_item_id from tool_calls for Mistral compatibility#1058
teknium1 merged 1 commit intomainfrom
hermes/hermes-465f3702

Conversation

@teknium1
Copy link
Contributor

Summary

Mistral's API strictly validates the Chat Completions schema and rejects unknown fields (call_id, response_item_id) with 422 "Extra inputs are not permitted". These fields are added by _build_assistant_message() for Codex Responses API support but are not part of the Chat Completions spec.

Approach

Unlike PR #864 which stripped these fields unconditionally (and mutated originals via shallow copy), this fix:

  1. Only strips when targeting Mistral — checks for api.mistral.ai in self.base_url
  2. Creates new tool_call dicts via dict comprehension instead of tc.pop() — avoids mutating the shared objects from msg.copy() (shallow copy)
  3. Preserves fields in internal message history — so _chat_messages_to_responses_input() can still read call_id/response_item_id if the session falls back to a Codex provider mid-conversation

Changes

  • Added _sanitize_tool_calls_for_strict_api() static method that builds new tool_call dicts without the Codex-specific fields
  • Applied in all 3 API message building locations:
    • Main conversation loop (run_conversation)
    • _handle_max_iterations()
    • flush_memories()

Why not merge PR #864

PR #864 had several issues:

  • Ran an autoformatter on the entire 5000-line run_agent.py (+1526/-758 lines of noise)
  • Reverted the centralized provider router from PR feat: centralized provider router, call_llm API, unified /model command #1003 (merge conflict resolution against stale branch)
  • Stripped call_id/response_item_id unconditionally for ALL providers, not just Mistral
  • Used tc.pop() on shallow-copied dicts, permanently destroying the fields from internal message history

This PR cherry-picks the valid fix idea with proper scoping.

Related

Co-authored-by: unmodeled-tyler unmodeled.tyler@proton.me

…tibility

Mistral's API strictly validates the Chat Completions schema and rejects
unknown fields (call_id, response_item_id) with 422. These fields are
added by _build_assistant_message() for Codex Responses API support.

This fix:
- Only strips when targeting Mistral (api.mistral.ai in base_url)
- Creates new tool_call dicts instead of mutating originals (shallow
  copy safety — msg.copy() shares the tool_calls list)
- Preserves call_id/response_item_id in the internal message history
  so _chat_messages_to_responses_input() can still read them if the
  session falls back to a Codex provider mid-conversation

Applied in all 3 API message building locations:
- Main conversation loop (run_conversation)
- _handle_max_iterations()
- flush_memories()

Inspired by PR #864 (unmodeled-tyler) which identified the issue but
applied the fix unconditionally and mutated originals via shallow copy.

Co-authored-by: unmodeled-tyler <unmodeled.tyler@proton.me>
@teknium1 teknium1 merged commit 73ea510 into main Mar 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant