Skip to content

Commit 45c873e

Browse files
committed
fix(tools): send the body for oneOf/anyOf/allOf OpenAPI request schemas
OperationParser names a polymorphic or untyped request body parameter 'body' (instead of '' used for plain scalar bodies) to avoid emitting an empty-named property in the function declaration. RestApiTool's _prepare_request_params only recognized the '' sentinel, so it never matched the 'body'-named parameter and silently sent no body at all. Fixes #6991
1 parent d637d1b commit 45c873e

2 files changed

Lines changed: 51 additions & 2 deletions

File tree

src/google/adk/tools/openapi_tool/openapi_spec_parser/rest_api_tool.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,8 +460,14 @@ def _prepare_request_params(
460460
break
461461
else: # like string
462462
for param in parameters:
463-
# original_name = '' indicating this param applies to the full body.
464-
if param.param_location == "body" and not param.original_name:
463+
# original_name = '' indicates this param applies to the full
464+
# body. OperationParser also uses original_name = 'body' for the
465+
# same purpose when the schema is oneOf/anyOf/allOf or untyped,
466+
# to avoid an empty-named property in the function declaration.
467+
if param.param_location == "body" and param.original_name in (
468+
"",
469+
"body",
470+
):
465471
body_data = (
466472
kwargs.get(param.py_name) if param.py_name in kwargs else None
467473
)

tests/unittests/tools/openapi_tool/openapi_spec_parser/test_rest_api_tool.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,49 @@ def test_prepare_request_params_string(
647647
assert request_params["data"] == "test_value"
648648
assert request_params["headers"]["Content-Type"] == "text/plain"
649649

650+
def test_prepare_request_params_oneof_body(
651+
self, sample_endpoint, sample_auth_credential, sample_auth_scheme
652+
):
653+
"""A oneOf/anyOf/allOf body is named 'body' by the parser and must
654+
still be sent as the JSON payload, not silently dropped."""
655+
oneof_schema = OpenAPISchema(
656+
oneOf=[
657+
OpenAPISchema(
658+
type="object", properties={"card": OpenAPISchema(type="string")}
659+
),
660+
OpenAPISchema(
661+
type="object", properties={"iban": OpenAPISchema(type="string")}
662+
),
663+
]
664+
)
665+
mock_operation = Operation(
666+
operationId="test_op",
667+
requestBody=RequestBody(
668+
content={"application/json": MediaType(schema=oneof_schema)}
669+
),
670+
)
671+
tool = RestApiTool(
672+
name="test_tool",
673+
description="Test Tool",
674+
endpoint=sample_endpoint,
675+
operation=mock_operation,
676+
auth_credential=sample_auth_credential,
677+
auth_scheme=sample_auth_scheme,
678+
)
679+
params = [
680+
ApiParameter(
681+
original_name="body",
682+
py_name="body",
683+
param_location="body",
684+
param_schema=oneof_schema,
685+
)
686+
]
687+
kwargs = {"body": {"card": "4111-1111"}}
688+
689+
request_params = tool._prepare_request_params(params, kwargs)
690+
691+
assert request_params["json"] == {"card": "4111-1111"}
692+
650693
def test_prepare_request_params_form_data(
651694
self, sample_endpoint, sample_auth_scheme, sample_auth_credential
652695
):

0 commit comments

Comments
 (0)