Repository navigation
Conversation
Gemini 3 returns each tool call's thought signature as extra_content.google.thought_signature on its OpenAI-compatible endpoint and answers 400 when the next request replays the call without it. Keep the field through both OpenAI-compatible parsers and stream merging, and send it back in Message.to_dict_clean only when the provider returned it. fix modelscope#1040
This branch has not been deployed
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.
Change Summary
Gemini 3 tool loops stop after the first tool result with
400 Function call is missing a thought_signature. On Gemini's OpenAI-compatible endpoint the signature comes back on each tool call asextra_content.google.thought_signature. Google requires it to be sent back, and ms-agent dropped it.This PR keeps
extra_contentonToolCall:transport/openai_compat.pyand the legacyopenai_llm.py, read it in the streaming and non-streaming parsers.Message.to_dict_cleanputs it back on the wire tool call.The field is written only when the provider returned it, so requests to other OpenAI-compatible providers are unchanged. Session logs already keep it, because
ToolCallis a plain dict.Known limits, left out to keep this focused:
extra_content.ResponseAdapter.to_messagedoes not carry the field. It has no caller in the repo, and the agent loop does not use it.The
reasoning_contentpoint in the issue comments is a separate change and is not included here.Related issue number
fix #1040
Checklist
pre-commit installandpre-commit run --all-filesbefore git commit, and passed lint check.Tests
New
tests/llm/test_tool_call_extra_content.pyuses realopenaiChatCompletionandChatCompletionChunkobjects withextra_content. It covers both clients for:Without the fix, 3 of the 4 tests fail with
KeyError: 'extra_content'. The test that checks no field is added passes either way.tests/llm/test_message_text.py,test_continuation_guard.pyandtest_thinking_fallback.pyalso pass.pre-commit run --fileswas run on the changed files. yapf also wanted to reformat three unrelated existing lines in the touched files, and I left those out of the diff. I tested against the parsing code only, not against the live Gemini API.