From 290ccc81d2a8bdef2e70c9412ec7422651b6f7d4 Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Fri, 5 Dec 2025 12:07:33 -0500 Subject: [PATCH 1/2] fix(gemini): use skip_thought_signature_validator for Gemini 3 Pro compatibility Gemini 3 Pro requires thought_signature to be passed back during multi-turn function calling. As a temporary workaround, we use the skip_thought_signature_validator bypass to get the model working without modifying the SDK's core type system. This is a short-term fix. A proper implementation that preserves thought signatures through the message history will be addressed in a follow-up PR. Fixes #1199 --- src/strands/models/gemini.py | 4 ++++ tests/strands/models/test_gemini.py | 31 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/strands/models/gemini.py b/src/strands/models/gemini.py index c24d91a0d..df34c5849 100644 --- a/src/strands/models/gemini.py +++ b/src/strands/models/gemini.py @@ -141,12 +141,16 @@ def _format_request_content_part(self, content: ContentBlock) -> genai.types.Par ) if "toolUse" in content: + # Use skip_thought_signature_validator to bypass Gemini 3 Pro's strict validation + # This is a temporary workaround until we implement proper thought signature preservation + # See: https://ai.google.dev/gemini-api/docs/thought-signatures return genai.types.Part( function_call=genai.types.FunctionCall( args=content["toolUse"]["input"], id=content["toolUse"]["toolUseId"], name=content["toolUse"]["name"], ), + thought_signature=b"skip_thought_signature_validator", ) raise TypeError(f"content_type=<{next(iter(content))}> | unsupported type") diff --git a/tests/strands/models/test_gemini.py b/tests/strands/models/test_gemini.py index a8f5351cc..6999b652d 100644 --- a/tests/strands/models/test_gemini.py +++ b/tests/strands/models/test_gemini.py @@ -289,6 +289,8 @@ async def test_stream_request_with_tool_use(gemini_client, model, model_id): "id": "c1", "name": "calculator", }, + # Skip validator is used as a temporary workaround for Gemini 3 Pro + "thought_signature": "c2tpcF90aG91Z2h0X3NpZ25hdHVyZV92YWxpZGF0b3I=", }, ], "role": "model", @@ -299,6 +301,35 @@ async def test_stream_request_with_tool_use(gemini_client, model, model_id): gemini_client.aio.models.generate_content_stream.assert_called_with(**exp_request) +@pytest.mark.asyncio +async def test_stream_request_with_tool_use_includes_thought_signature_skip(gemini_client, model, model_id): + """Test that toolUse includes skip_thought_signature_validator for Gemini 3 Pro compatibility.""" + messages = [ + { + "role": "assistant", + "content": [ + { + "toolUse": { + "toolUseId": "tool1", + "name": "get_weather", + "input": {"city": "Seattle"}, + }, + }, + ], + }, + ] + await anext(model.stream(messages)) + + call_args = gemini_client.aio.models.generate_content_stream.call_args + contents = call_args.kwargs["contents"] + + # Verify the thought_signature is set to skip validator + part = contents[0]["parts"][0] + assert "thought_signature" in part + # Base64 encoded "skip_thought_signature_validator" + assert part["thought_signature"] == "c2tpcF90aG91Z2h0X3NpZ25hdHVyZV92YWxpZGF0b3I=" + + @pytest.mark.asyncio async def test_stream_request_with_tool_results(gemini_client, model, model_id): messages = [ From 9c9dc4cecd635b731a99184a230e275c7dff4f0d Mon Sep 17 00:00:00 2001 From: Murat Kaan Meral Date: Fri, 5 Dec 2025 12:26:52 -0500 Subject: [PATCH 2/2] test(gemini): add Gemini 3 Pro integration test for thought_signature fix --- tests_integ/models/test_model_gemini.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests_integ/models/test_model_gemini.py b/tests_integ/models/test_model_gemini.py index f9da8490c..0d623bd89 100644 --- a/tests_integ/models/test_model_gemini.py +++ b/tests_integ/models/test_model_gemini.py @@ -175,3 +175,28 @@ def test_agent_structured_output_image_input(assistant_agent, yellow_img, yellow tru_color = assistant_agent.structured_output(type(yellow_color), content) exp_color = yellow_color assert tru_color == exp_color + + +@pytest.mark.parametrize("model_id", ["gemini-2.5-flash", "gemini-3-pro-preview"]) +def test_agent_multiturn_tool_use(model_id, tools, system_prompt): + """Test multi-turn conversation with tool use. + + Gemini 3 Pro requires thought_signature in multi-turn function calling. + Without skip_thought_signature_validator, this fails with: + "Function call is missing a thought_signature in functionCall parts" + + Validates fix for issue #1199. + """ + model = GeminiModel( + client_args={"api_key": os.getenv("GOOGLE_API_KEY")}, + model_id=model_id, + params={"temperature": 0.15}, + ) + agent = Agent(model=model, tools=tools, system_prompt=system_prompt) + + result1 = agent("What is the current time in New York?") + assert "12:00" in result1.message["content"][0]["text"].lower() + + # Second turn with tool use history - this is where Gemini 3 Pro would fail + result2 = agent("And what is the weather there?") + assert "sunny" in result2.message["content"][0]["text"].lower()