diff --git a/src/google/adk/tools/openapi_tool/openapi_spec_parser/openapi_spec_parser.py b/src/google/adk/tools/openapi_tool/openapi_spec_parser/openapi_spec_parser.py index ac86cd05..64eb204f 100644 --- a/src/google/adk/tools/openapi_tool/openapi_spec_parser/openapi_spec_parser.py +++ b/src/google/adk/tools/openapi_tool/openapi_spec_parser/openapi_spec_parser.py @@ -111,6 +111,11 @@ class OpenApiSpecParser: if operation_dict is None: continue + # Append path-level parameters + operation_dict["parameters"] = operation_dict.get( + "parameters", [] + ) + path_item.get("parameters", []) + # If operation ID is missing, assign an operation id based on path # and method if "operationId" not in operation_dict: diff --git a/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_spec_parser.py b/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_spec_parser.py index 8fbee55f..053da759 100644 --- a/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_spec_parser.py +++ b/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_spec_parser.py @@ -624,3 +624,60 @@ def test_parse_spec_with_duplicate_parameter_names(openapi_spec_generator): assert body_param is not None assert body_param.original_name == "name" assert body_param.py_name == "name_0" + + +def test_parse_spec_with_path_level_parameters(openapi_spec_generator): + """Test that operation parameters are correctly combined with path-level parameters.""" + openapi_spec = { + "openapi": "3.1.0", + "info": {"title": "Combine Parameters API", "version": "1.0.0"}, + "paths": { + "/test": { + "parameters": [{ + "name": "global_param", + "in": "query", + "schema": {"type": "string"}, + }], + "get": { + "parameters": [{ + "name": "local_param", + "in": "header", + "schema": {"type": "integer"}, + }], + "operationId": "testGet", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": {"schema": {"type": "string"}} + }, + } + }, + }, + } + }, + } + + parsed_operations = openapi_spec_generator.parse(openapi_spec) + assert len(parsed_operations) == 1 + + operation = parsed_operations[0] + assert len(operation.parameters) == 2 + + # Verify the combined parameters + global_param = next( + (p for p in operation.parameters if p.original_name == "global_param"), + None, + ) + local_param = next( + (p for p in operation.parameters if p.original_name == "local_param"), + None, + ) + + assert global_param is not None + assert global_param.param_location == "query" + assert global_param.type_value is str + + assert local_param is not None + assert local_param.param_location == "header" + assert local_param.type_value is int diff --git a/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_toolset.py b/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_toolset.py index fdb6d201..2b95e461 100644 --- a/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_toolset.py +++ b/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_toolset.py @@ -95,7 +95,7 @@ def test_openapi_toolset_tool_existing(openapi_spec: Dict): assert tool.is_long_running is False assert tool.operation.operationId == "calendar.calendars.get" assert tool.operation.description == "Returns metadata for a calendar." - assert len(tool.operation.parameters) == 1 + assert len(tool.operation.parameters) == 8 assert tool.operation.parameters[0].name == "calendarId" assert tool.operation.parameters[0].in_ == ParameterInType.path assert tool.operation.parameters[0].required is True