diff --git a/src/google/adk/flows/llm_flows/functions.py b/src/google/adk/flows/llm_flows/functions.py index 259d40b6b6..7bf597d29a 100644 --- a/src/google/adk/flows/llm_flows/functions.py +++ b/src/google/adk/flows/llm_flows/functions.py @@ -302,7 +302,7 @@ def build_auth_request_event( args=AuthToolArguments( function_call_id=function_call_id, auth_config=auth_config, - ).model_dump(exclude_none=True, by_alias=True), + ).model_dump(mode='json', exclude_none=True, by_alias=True), ) long_running_tool_ids.add(request_euc_function_call.id) parts.append(types.Part(function_call=request_euc_function_call)) diff --git a/tests/unittests/flows/llm_flows/test_functions_request_euc.py b/tests/unittests/flows/llm_flows/test_functions_request_euc.py index f1e1d1f610..2ab97af07c 100644 --- a/tests/unittests/flows/llm_flows/test_functions_request_euc.py +++ b/tests/unittests/flows/llm_flows/test_functions_request_euc.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import json from typing import Any from typing import Optional @@ -153,6 +154,68 @@ def call_external_api2(tool_context: ToolContext) -> Optional[int]: ) +def test_function_request_euc_args_are_json_serializable(): + responses = [ + [ + types.Part.from_function_call(name='call_external_api', args={}), + ], + [ + types.Part.from_text(text='response1'), + ], + ] + + auth_config = AuthConfig( + auth_scheme=OAuth2( + flows=OAuthFlows( + authorizationCode=OAuthFlowAuthorizationCode( + authorizationUrl='https://accounts.google.com/o/oauth2/auth', + tokenUrl='https://oauth2.googleapis.com/token', + scopes={ + 'https://www.googleapis.com/auth/calendar': ( + 'See, edit, share, and permanently delete all the' + ' calendars you can access using Google Calendar' + ) + }, + ) + ) + ), + raw_auth_credential=AuthCredential( + auth_type=AuthCredentialTypes.OAUTH2, + oauth2=OAuth2Auth( + client_id='oauth_client_id', + client_secret='oauth_client_secret', + ), + ), + ) + + mock_model = testing_utils.MockModel.create(responses=responses) + + def call_external_api(tool_context: ToolContext) -> Optional[int]: + tool_context.request_credential(auth_config) + + agent = Agent( + name='root_agent', + model=mock_model, + tools=[call_external_api], + ) + runner = testing_utils.InMemoryRunner(agent) + events = runner.run('test') + + request_euc_function_call = events[1].content.parts[0].function_call + assert ( + request_euc_function_call.name == functions.REQUEST_EUC_FUNCTION_CALL_NAME + ) + + # The in-memory event args must be JSON-serializable. A python-mode dump + # leaves auth_scheme.type as a live SecuritySchemeType enum, which breaks any + # consumer that json.dumps the event before it round-trips the session DB. + json.dumps(request_euc_function_call.args) + assert ( + request_euc_function_call.args['authConfig']['authScheme']['type'] + == 'oauth2' + ) + + def test_function_get_auth_response(): id_1 = 'id_1' id_2 = 'id_2'