Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/google/adk/models/apigee_llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -813,9 +813,18 @@ def _map_tools(
if tools:
payload['tools'] = tools
if config.tool_config and config.tool_config.function_calling_config:
mode = config.tool_config.function_calling_config.mode
function_calling_config = config.tool_config.function_calling_config
mode = function_calling_config.mode
allowed_names = function_calling_config.allowed_function_names or []
if mode == types.FunctionCallingConfigMode.ANY:
payload['tool_choice'] = 'required'
# One allowed name forces that function, as AnthropicLlm does.
if len(allowed_names) == 1:
payload['tool_choice'] = {
'type': 'function',
'function': {'name': allowed_names[0]},
}
else:
payload['tool_choice'] = 'required'
elif mode == types.FunctionCallingConfigMode.NONE:
payload['tool_choice'] = 'none'
elif mode == types.FunctionCallingConfigMode.AUTO:
Expand Down
40 changes: 40 additions & 0 deletions tests/unittests/models/test_apigee_llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -1229,6 +1229,46 @@ def unsupported_tool() -> None:
client._construct_payload(request, stream=False)


@pytest.mark.parametrize(
('allowed_names', 'expected_choice'),
[
(
['lookup_order'],
{'type': 'function', 'function': {'name': 'lookup_order'}},
),
(['lookup_order', 'issue_refund'], 'required'),
(None, 'required'),
],
)
def test_construct_payload_any_mode_with_allowed_function_names(
allowed_names: list[str] | None, expected_choice: object
) -> None:
request = LlmRequest(
model='apigee/openai/gpt-4o',
contents=[],
config=types.GenerateContentConfig(
tools=[
types.Tool(
function_declarations=[
types.FunctionDeclaration(name='lookup_order'),
types.FunctionDeclaration(name='issue_refund'),
]
)
],
tool_config=types.ToolConfig(
function_calling_config=types.FunctionCallingConfig(
mode=types.FunctionCallingConfigMode.ANY,
allowed_function_names=allowed_names,
)
),
),
)

client = CompletionsHTTPClient(base_url='http://test')
payload = client._construct_payload(request, stream=False)
assert payload['tool_choice'] == expected_choice


def test_content_conversion_rejects_unnamed_function_call() -> None:
content = types.Content(
role='model',
Expand Down
Loading