@@ -231,3 +231,70 @@ def test_invoke_snake_case_key_ignored(self) -> None:
231231 """Converse handler must not react to stop_reason (snake_case)."""
232232 msg = AIMessage (content = "" , response_metadata = {"stop_reason" : "max_tokens" })
233233 self .handler .check_stop_reason (msg ) # should not raise
234+
235+
236+ # ---------------------------------------------------------------------------
237+ # Null-safety: thinking_enabled detection
238+ # ---------------------------------------------------------------------------
239+
240+
241+ class TestBedrockInvokeThinkingNullSafety :
242+ """model_kwargs or its nested values may be None — must not raise."""
243+
244+ def test_model_kwargs_is_none (self ) -> None :
245+ model = type ("FakeChatBedrock" , (), {})()
246+ model .model_kwargs = None
247+ handler = BedrockInvokePayloadHandler (model )
248+ result = handler .get_tool_binding_kwargs ([], "any" )
249+ assert result ["tool_choice" ] == "any"
250+
251+ def test_thinking_value_is_none (self ) -> None :
252+ model = type ("FakeChatBedrock" , (), {})()
253+ model .model_kwargs = {"thinking" : None }
254+ handler = BedrockInvokePayloadHandler (model )
255+ result = handler .get_tool_binding_kwargs ([], "any" )
256+ assert result ["tool_choice" ] == "any"
257+
258+ def test_model_kwargs_attribute_missing (self ) -> None :
259+ model = type ("FakeChatBedrock" , (), {})()
260+ handler = BedrockInvokePayloadHandler (model )
261+ result = handler .get_tool_binding_kwargs ([], "any" )
262+ assert result ["tool_choice" ] == "any"
263+
264+ def test_thinking_value_is_non_dict_truthy (self ) -> None :
265+ model = type ("FakeChatBedrock" , (), {})()
266+ model .model_kwargs = {"thinking" : "enabled" }
267+ handler = BedrockInvokePayloadHandler (model )
268+ result = handler .get_tool_binding_kwargs ([], "any" )
269+ assert result ["tool_choice" ] == "any"
270+
271+
272+ class TestBedrockConverseThinkingNullSafety :
273+ """additional_model_request_fields or its nested values may be None — must not raise."""
274+
275+ def test_additional_fields_is_none (self ) -> None :
276+ model = type ("FakeChatBedrockConverse" , (), {})()
277+ model .additional_model_request_fields = None
278+ handler = BedrockConversePayloadHandler (model )
279+ result = handler .get_tool_binding_kwargs ([], "any" )
280+ assert result ["tool_choice" ] == "any"
281+
282+ def test_thinking_value_is_none (self ) -> None :
283+ model = type ("FakeChatBedrockConverse" , (), {})()
284+ model .additional_model_request_fields = {"thinking" : None }
285+ handler = BedrockConversePayloadHandler (model )
286+ result = handler .get_tool_binding_kwargs ([], "any" )
287+ assert result ["tool_choice" ] == "any"
288+
289+ def test_thinking_value_is_non_dict_truthy (self ) -> None :
290+ model = type ("FakeChatBedrockConverse" , (), {})()
291+ model .additional_model_request_fields = {"thinking" : "enabled" }
292+ handler = BedrockConversePayloadHandler (model )
293+ result = handler .get_tool_binding_kwargs ([], "any" )
294+ assert result ["tool_choice" ] == "any"
295+
296+ def test_additional_fields_attribute_missing (self ) -> None :
297+ model = type ("FakeChatBedrockConverse" , (), {})()
298+ handler = BedrockConversePayloadHandler (model )
299+ result = handler .get_tool_binding_kwargs ([], "any" )
300+ assert result ["tool_choice" ] == "any"
0 commit comments