diff --git a/google/genai/_extra_utils.py b/google/genai/_extra_utils.py index 98a75748e..2d807aefe 100644 --- a/google/genai/_extra_utils.py +++ b/google/genai/_extra_utils.py @@ -530,10 +530,23 @@ def raise_error_for_afc_incompatible_config(config: Optional[types.GenerateConte return afc_config = config.automatic_function_calling disable_afc_config = afc_config.disable if afc_config else False + function_calling_config = config.tool_config.function_calling_config stream_function_call = ( - config.tool_config.function_calling_config.stream_function_call_arguments + function_calling_config.stream_function_call_arguments ) + if ( + function_calling_config.mode == types.FunctionCallingConfigMode.ANY + and not disable_afc_config + ): + logger.warning( + 'tool_config.function_calling_config.mode is set to ANY while' + ' automatic function calling (AFC) is enabled. AFC will continue' + ' calling functions until max_remote_calls is reached, so the model' + ' may not return a natural language response. Set mode to AUTO or' + ' disable automatic function calling if this is intentional.' + ) + if stream_function_call and not disable_afc_config: raise ValueError( 'Running in streaming mode with stream_function_call_arguments' diff --git a/google/genai/tests/afc/test_raise_error_for_afc_incompatible_config.py b/google/genai/tests/afc/test_raise_error_for_afc_incompatible_config.py index eadadb2b6..3453bd7f3 100644 --- a/google/genai/tests/afc/test_raise_error_for_afc_incompatible_config.py +++ b/google/genai/tests/afc/test_raise_error_for_afc_incompatible_config.py @@ -16,6 +16,8 @@ """Tests for raise_error_for_afc_incompatible_config.""" +import logging + import pytest from ... import types from ..._extra_utils import raise_error_for_afc_incompatible_config @@ -157,3 +159,50 @@ def test_incompatible_config_stream_function_call_arguments_set_no_disable_afc() ), ) ) + + +@pytest.mark.parametrize( + ('mode', 'disable_afc', 'should_warn'), + [ + (types.FunctionCallingConfigMode.ANY, False, True), + (types.FunctionCallingConfigMode.ANY, True, False), + (types.FunctionCallingConfigMode.AUTO, False, False), + ], +) +def test_function_calling_mode_warns_when_afc_is_enabled( + caplog, mode, disable_afc, should_warn +): + caplog.set_level(logging.WARNING, logger='google_genai.models') + + raise_error_for_afc_incompatible_config( + types.GenerateContentConfig( + automatic_function_calling=types.AutomaticFunctionCallingConfig( + disable=disable_afc, + ), + tool_config=types.ToolConfig( + function_calling_config=types.FunctionCallingConfig(mode=mode), + ), + ) + ) + + if should_warn: + assert 'mode is set to ANY' in caplog.text + assert 'automatic function calling' in caplog.text + else: + assert not caplog.records + + +def test_any_function_calling_mode_warns_when_afc_config_is_unset(caplog): + caplog.set_level(logging.WARNING, logger='google_genai.models') + + raise_error_for_afc_incompatible_config( + types.GenerateContentConfig( + tool_config=types.ToolConfig( + function_calling_config=types.FunctionCallingConfig( + mode=types.FunctionCallingConfigMode.ANY, + ), + ), + ) + ) + + assert 'mode is set to ANY' in caplog.text