fix(chat_completions): strip internal tool_name from messages for strict providers#29126
Merged
Conversation
…ders The 'tool_name' key on role=tool messages is an internal Hermes field (stored in the messages.tool_name SQLite column for FTS indexing) that is not part of the OpenAI Chat Completions schema. Strict OpenAI-compatible providers — notably Moonshot AI (Kimi) — reject it with HTTP 400: Error from provider: Extra inputs are not permitted, field: 'messages[N].tool_name', value: 'execute_code' Add 'tool_name' to the sanitize block in ChatCompletionsTransport.convert_messages alongside the existing Codex Responses API fields (codex_reasoning_items, codex_message_items) so it is popped before the request is sent. Reproducer: hermes chat --model kimi-k2.6 > list the top 5 Hacker News stories -> assistant emits tool_call(execute_code) -> tool result message gets tool_name='execute_code' -> next turn's payload includes messages[N].tool_name -> 400 Permissive backends (MiniMax, OpenRouter on most routes) ignore the extra field and were masking the bug.
Salvage follow-up to PR #28958 (savanne-kham): - convert_messages() docstring now explicitly documents the tool_name strip alongside Codex fields, names which providers reject it (Fireworks, Moonshot/Kimi), and why permissive providers (OpenRouter, MiniMax) masked the bug. - AUTHOR_MAP entry for savanne.kham@protonmail.com -> savanne-kham.
Contributor
🔎 Lint report:
|
19 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Salvages #28958 by @savanne-kham onto current main, with a broader docstring describing the bigger user impact than the original PR captured.
What this fixes
Community report (porkmagus, May 19): every API call after the first tool-call dies with HTTP 400 on Fireworks/Firepass, Moonshot/Kimi, and other strict OpenAI-compatible providers:
Repros from a fresh session — the first turn that triggers any tool kills the conversation; user has to restart hermes.
Root cause
agent/tool_dispatch_helpers.pymake_tool_result_message()deliberately attachestool_nameto every tool-result dict sorun_agent._flush_messages_to_session_db()can persist it for SQLite FTS indexing. That field is not part of the OpenAI Chat Completions schema and rides into the next-turn wire payload.Permissive providers (OpenRouter, MiniMax) silently dropped the extra field, masking the bug. Strict providers (Fireworks, Moonshot/Kimi) reject the entire request.
Changes
agent/transports/chat_completions.py— extend the existingneeds_sanitizedetection and per-messagepopstep to covertool_name, same pattern already used forcodex_reasoning_items/codex_message_items. Broadened the docstring to explicitly name which providers reject it and why permissive providers masked the bug.tests/agent/transports/test_chat_completions.py— newtest_convert_messages_strips_tool_namecovers strip + deepcopy-on-demand contract (FTS-sidetool_namemust survive on the original message).scripts/release.py— AUTHOR_MAP entry for savanne.kham@protonmail.com.Validation
tool_name not permittedtool_nameE2E verified via direct
convert_messages()call on a realistic tool-result message:tool_nameis absent from the serialized payload, but the original message dict retains it.Closes #28958.
Co-authored-by: Savanne Kham savanne.kham@protonmail.com