google-adk 0.0.3__py3-none-any.whl → 0.0.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- google/adk/agents/run_config.py +4 -0
- google/adk/auth/auth_preprocessor.py +19 -16
- google/adk/cli/browser/index.html +1 -1
- google/adk/cli/browser/{main-SY2WYYGV.js → main-CU22TRPI.js} +30 -30
- google/adk/cli/cli.py +8 -8
- google/adk/cli/cli_deploy.py +2 -4
- google/adk/cli/cli_tools_click.py +6 -6
- google/adk/flows/llm_flows/contents.py +21 -1
- google/adk/flows/llm_flows/functions.py +3 -1
- google/adk/models/google_llm.py +0 -1
- google/adk/runners.py +13 -2
- google/adk/version.py +1 -1
- {google_adk-0.0.3.dist-info → google_adk-0.0.4.dist-info}/METADATA +4 -2
- google_adk-0.0.4.dist-info/RECORD +175 -0
- {google_adk-0.0.3.dist-info → google_adk-0.0.4.dist-info}/WHEEL +1 -1
- google_adk-0.0.4.dist-info/licenses/LICENSE +202 -0
- google/adk/._version.py +0 -0
- google/adk/docs/Makefile +0 -20
- google/adk/docs/build/doctrees/google-adk.doctree +0 -0
- google/adk/docs/build/html/_sources/google-adk.rst.txt +0 -98
- google/adk/docs/build/html/_sources/index.rst.txt +0 -7
- google/adk/docs/build/html/_static/autodoc_pydantic.css +0 -27
- google/adk/docs/build/html/_static/basic.css +0 -925
- google/adk/docs/build/html/_static/debug.css +0 -85
- google/adk/docs/build/html/_static/doctools.js +0 -156
- google/adk/docs/build/html/_static/documentation_options.js +0 -29
- google/adk/docs/build/html/_static/file.png +0 -0
- google/adk/docs/build/html/_static/language_data.js +0 -199
- google/adk/docs/build/html/_static/minus.png +0 -0
- google/adk/docs/build/html/_static/plus.png +0 -0
- google/adk/docs/build/html/_static/pygments.css +0 -274
- google/adk/docs/build/html/_static/scripts/furo-extensions.js +0 -16
- google/adk/docs/build/html/_static/scripts/furo.js +0 -19
- google/adk/docs/build/html/_static/scripts/furo.js.LICENSE.txt +0 -7
- google/adk/docs/build/html/_static/scripts/furo.js.map +0 -1
- google/adk/docs/build/html/_static/searchtools.js +0 -620
- google/adk/docs/build/html/_static/skeleton.css +0 -312
- google/adk/docs/build/html/_static/sphinx_highlight.js +0 -170
- google/adk/docs/build/html/_static/styles/furo-extensions.css +0 -18
- google/adk/docs/build/html/_static/styles/furo-extensions.css.map +0 -1
- google/adk/docs/build/html/_static/styles/furo.css +0 -18
- google/adk/docs/build/html/_static/styles/furo.css.map +0 -1
- google/adk/docs/build/html/genindex.html +0 -861
- google/adk/docs/build/html/google-adk.html +0 -5461
- google/adk/docs/build/html/index.html +0 -567
- google/adk/docs/build/html/objects.inv +0 -0
- google/adk/docs/build/html/py-modindex.html +0 -373
- google/adk/docs/build/html/search.html +0 -333
- google/adk/docs/build/html/searchindex.js +0 -17
- google/adk/docs/source/conf.py +0 -133
- google/adk/docs/source/google-adk.rst +0 -98
- google/adk/docs/source/index.rst +0 -7
- google/adk/tests/__init__.py +0 -14
- google/adk/tests/integration/.env.example +0 -10
- google/adk/tests/integration/__init__.py +0 -18
- google/adk/tests/integration/conftest.py +0 -119
- google/adk/tests/integration/fixture/__init__.py +0 -14
- google/adk/tests/integration/fixture/agent_with_config/__init__.py +0 -15
- google/adk/tests/integration/fixture/agent_with_config/agent.py +0 -88
- google/adk/tests/integration/fixture/callback_agent/__init__.py +0 -15
- google/adk/tests/integration/fixture/callback_agent/agent.py +0 -105
- google/adk/tests/integration/fixture/context_update_test/OWNERS +0 -1
- google/adk/tests/integration/fixture/context_update_test/__init__.py +0 -15
- google/adk/tests/integration/fixture/context_update_test/agent.py +0 -43
- google/adk/tests/integration/fixture/context_update_test/successful_test.session.json +0 -582
- google/adk/tests/integration/fixture/context_variable_agent/__init__.py +0 -15
- google/adk/tests/integration/fixture/context_variable_agent/agent.py +0 -115
- google/adk/tests/integration/fixture/customer_support_ma/__init__.py +0 -15
- google/adk/tests/integration/fixture/customer_support_ma/agent.py +0 -172
- google/adk/tests/integration/fixture/ecommerce_customer_service_agent/__init__.py +0 -15
- google/adk/tests/integration/fixture/ecommerce_customer_service_agent/agent.py +0 -338
- google/adk/tests/integration/fixture/ecommerce_customer_service_agent/order_query.test.json +0 -69
- google/adk/tests/integration/fixture/ecommerce_customer_service_agent/test_config.json +0 -6
- google/adk/tests/integration/fixture/flow_complex_spark/__init__.py +0 -15
- google/adk/tests/integration/fixture/flow_complex_spark/agent.py +0 -182
- google/adk/tests/integration/fixture/flow_complex_spark/sample.session.json +0 -190
- google/adk/tests/integration/fixture/hello_world_agent/__init__.py +0 -15
- google/adk/tests/integration/fixture/hello_world_agent/agent.py +0 -95
- google/adk/tests/integration/fixture/hello_world_agent/roll_die.test.json +0 -24
- google/adk/tests/integration/fixture/hello_world_agent/test_config.json +0 -6
- google/adk/tests/integration/fixture/home_automation_agent/__init__.py +0 -15
- google/adk/tests/integration/fixture/home_automation_agent/agent.py +0 -304
- google/adk/tests/integration/fixture/home_automation_agent/simple_test.test.json +0 -5
- google/adk/tests/integration/fixture/home_automation_agent/simple_test2.test.json +0 -5
- google/adk/tests/integration/fixture/home_automation_agent/test_config.json +0 -5
- google/adk/tests/integration/fixture/home_automation_agent/test_files/dependent_tool_calls.test.json +0 -18
- google/adk/tests/integration/fixture/home_automation_agent/test_files/memorizing_past_events/eval_data.test.json +0 -17
- google/adk/tests/integration/fixture/home_automation_agent/test_files/memorizing_past_events/test_config.json +0 -6
- google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_multi_turn_conversation.test.json +0 -18
- google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_test.test.json +0 -17
- google/adk/tests/integration/fixture/home_automation_agent/test_files/simple_test2.test.json +0 -5
- google/adk/tests/integration/fixture/home_automation_agent/test_files/test_config.json +0 -5
- google/adk/tests/integration/fixture/tool_agent/__init__.py +0 -15
- google/adk/tests/integration/fixture/tool_agent/agent.py +0 -218
- google/adk/tests/integration/fixture/tool_agent/files/Agent_test_plan.pdf +0 -0
- google/adk/tests/integration/fixture/trip_planner_agent/__init__.py +0 -15
- google/adk/tests/integration/fixture/trip_planner_agent/agent.py +0 -110
- google/adk/tests/integration/fixture/trip_planner_agent/initial.session.json +0 -13
- google/adk/tests/integration/fixture/trip_planner_agent/test_config.json +0 -5
- google/adk/tests/integration/fixture/trip_planner_agent/test_files/initial.session.json +0 -13
- google/adk/tests/integration/fixture/trip_planner_agent/test_files/test_config.json +0 -5
- google/adk/tests/integration/fixture/trip_planner_agent/test_files/trip_inquiry_sub_agent.test.json +0 -7
- google/adk/tests/integration/fixture/trip_planner_agent/trip_inquiry.test.json +0 -19
- google/adk/tests/integration/models/__init__.py +0 -14
- google/adk/tests/integration/models/test_google_llm.py +0 -65
- google/adk/tests/integration/test_callback.py +0 -70
- google/adk/tests/integration/test_context_variable.py +0 -67
- google/adk/tests/integration/test_evalute_agent_in_fixture.py +0 -76
- google/adk/tests/integration/test_multi_agent.py +0 -28
- google/adk/tests/integration/test_multi_turn.py +0 -42
- google/adk/tests/integration/test_single_agent.py +0 -23
- google/adk/tests/integration/test_sub_agent.py +0 -26
- google/adk/tests/integration/test_system_instruction.py +0 -177
- google/adk/tests/integration/test_tools.py +0 -287
- google/adk/tests/integration/test_with_test_file.py +0 -34
- google/adk/tests/integration/tools/__init__.py +0 -14
- google/adk/tests/integration/utils/__init__.py +0 -16
- google/adk/tests/integration/utils/asserts.py +0 -75
- google/adk/tests/integration/utils/test_runner.py +0 -97
- google/adk/tests/unittests/__init__.py +0 -14
- google/adk/tests/unittests/agents/__init__.py +0 -14
- google/adk/tests/unittests/agents/test_base_agent.py +0 -407
- google/adk/tests/unittests/agents/test_langgraph_agent.py +0 -191
- google/adk/tests/unittests/agents/test_llm_agent_callbacks.py +0 -138
- google/adk/tests/unittests/agents/test_llm_agent_fields.py +0 -231
- google/adk/tests/unittests/agents/test_loop_agent.py +0 -136
- google/adk/tests/unittests/agents/test_parallel_agent.py +0 -92
- google/adk/tests/unittests/agents/test_sequential_agent.py +0 -114
- google/adk/tests/unittests/artifacts/__init__.py +0 -14
- google/adk/tests/unittests/artifacts/test_artifact_service.py +0 -276
- google/adk/tests/unittests/auth/test_auth_handler.py +0 -575
- google/adk/tests/unittests/conftest.py +0 -73
- google/adk/tests/unittests/fast_api/__init__.py +0 -14
- google/adk/tests/unittests/fast_api/test_fast_api.py +0 -269
- google/adk/tests/unittests/flows/__init__.py +0 -14
- google/adk/tests/unittests/flows/llm_flows/__init__.py +0 -14
- google/adk/tests/unittests/flows/llm_flows/_test_examples.py +0 -142
- google/adk/tests/unittests/flows/llm_flows/test_agent_transfer.py +0 -311
- google/adk/tests/unittests/flows/llm_flows/test_functions_long_running.py +0 -244
- google/adk/tests/unittests/flows/llm_flows/test_functions_request_euc.py +0 -346
- google/adk/tests/unittests/flows/llm_flows/test_functions_sequential.py +0 -93
- google/adk/tests/unittests/flows/llm_flows/test_functions_simple.py +0 -258
- google/adk/tests/unittests/flows/llm_flows/test_identity.py +0 -66
- google/adk/tests/unittests/flows/llm_flows/test_instructions.py +0 -164
- google/adk/tests/unittests/flows/llm_flows/test_model_callbacks.py +0 -142
- google/adk/tests/unittests/flows/llm_flows/test_other_configs.py +0 -46
- google/adk/tests/unittests/flows/llm_flows/test_tool_callbacks.py +0 -269
- google/adk/tests/unittests/models/__init__.py +0 -14
- google/adk/tests/unittests/models/test_google_llm.py +0 -224
- google/adk/tests/unittests/models/test_litellm.py +0 -804
- google/adk/tests/unittests/models/test_models.py +0 -60
- google/adk/tests/unittests/sessions/__init__.py +0 -14
- google/adk/tests/unittests/sessions/test_session_service.py +0 -227
- google/adk/tests/unittests/sessions/test_vertex_ai_session_service.py +0 -246
- google/adk/tests/unittests/streaming/__init__.py +0 -14
- google/adk/tests/unittests/streaming/test_streaming.py +0 -50
- google/adk/tests/unittests/tools/__init__.py +0 -14
- google/adk/tests/unittests/tools/apihub_tool/clients/test_apihub_client.py +0 -499
- google/adk/tests/unittests/tools/apihub_tool/test_apihub_toolset.py +0 -204
- google/adk/tests/unittests/tools/application_integration_tool/clients/test_connections_client.py +0 -600
- google/adk/tests/unittests/tools/application_integration_tool/clients/test_integration_client.py +0 -630
- google/adk/tests/unittests/tools/application_integration_tool/test_application_integration_toolset.py +0 -345
- google/adk/tests/unittests/tools/google_api_tool/__init__.py +0 -13
- google/adk/tests/unittests/tools/google_api_tool/test_googleapi_to_openapi_converter.py +0 -657
- google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_auto_auth_credential_exchanger.py +0 -145
- google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_base_auth_credential_exchanger.py +0 -68
- google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_oauth2_exchanger.py +0 -153
- google/adk/tests/unittests/tools/openapi_tool/auth/credential_exchangers/test_service_account_exchanger.py +0 -196
- google/adk/tests/unittests/tools/openapi_tool/auth/test_auth_helper.py +0 -573
- google/adk/tests/unittests/tools/openapi_tool/common/test_common.py +0 -436
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test.yaml +0 -1367
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_spec_parser.py +0 -628
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_openapi_toolset.py +0 -139
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_operation_parser.py +0 -406
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_rest_api_tool.py +0 -966
- google/adk/tests/unittests/tools/openapi_tool/openapi_spec_parser/test_tool_auth_handler.py +0 -201
- google/adk/tests/unittests/tools/retrieval/__init__.py +0 -14
- google/adk/tests/unittests/tools/retrieval/test_vertex_ai_rag_retrieval.py +0 -147
- google/adk/tests/unittests/tools/test_agent_tool.py +0 -167
- google/adk/tests/unittests/tools/test_base_tool.py +0 -141
- google/adk/tests/unittests/tools/test_build_function_declaration.py +0 -277
- google/adk/tests/unittests/utils.py +0 -304
- google_adk-0.0.3.dist-info/RECORD +0 -340
- {google_adk-0.0.3.dist-info → google_adk-0.0.4.dist-info}/entry_points.txt +0 -0
@@ -1,966 +0,0 @@
|
|
1
|
-
# Copyright 2025 Google LLC
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
|
-
|
15
|
-
|
16
|
-
import json
|
17
|
-
from unittest.mock import MagicMock
|
18
|
-
from unittest.mock import patch
|
19
|
-
|
20
|
-
from fastapi.openapi.models import MediaType
|
21
|
-
from fastapi.openapi.models import Operation
|
22
|
-
from fastapi.openapi.models import Parameter as OpenAPIParameter
|
23
|
-
from fastapi.openapi.models import RequestBody
|
24
|
-
from fastapi.openapi.models import Schema as OpenAPISchema
|
25
|
-
from google.adk.sessions.state import State
|
26
|
-
from google.adk.tools.openapi_tool.auth.auth_helpers import token_to_scheme_credential
|
27
|
-
from google.adk.tools.openapi_tool.common.common import ApiParameter
|
28
|
-
from google.adk.tools.openapi_tool.openapi_spec_parser.openapi_spec_parser import OperationEndpoint
|
29
|
-
from google.adk.tools.openapi_tool.openapi_spec_parser.operation_parser import OperationParser
|
30
|
-
from google.adk.tools.openapi_tool.openapi_spec_parser.rest_api_tool import RestApiTool
|
31
|
-
from google.adk.tools.openapi_tool.openapi_spec_parser.rest_api_tool import snake_to_lower_camel
|
32
|
-
from google.adk.tools.openapi_tool.openapi_spec_parser.rest_api_tool import to_gemini_schema
|
33
|
-
from google.adk.tools.tool_context import ToolContext
|
34
|
-
from google.genai.types import FunctionDeclaration
|
35
|
-
from google.genai.types import Schema
|
36
|
-
from google.genai.types import Type
|
37
|
-
import pytest
|
38
|
-
|
39
|
-
|
40
|
-
class TestRestApiTool:
|
41
|
-
|
42
|
-
@pytest.fixture
|
43
|
-
def mock_tool_context(self):
|
44
|
-
"""Fixture for a mock OperationParser."""
|
45
|
-
mock_context = MagicMock(spec=ToolContext)
|
46
|
-
mock_context.state = State({}, {})
|
47
|
-
mock_context.get_auth_response.return_value = {}
|
48
|
-
mock_context.request_credential.return_value = {}
|
49
|
-
return mock_context
|
50
|
-
|
51
|
-
@pytest.fixture
|
52
|
-
def mock_operation_parser(self):
|
53
|
-
"""Fixture for a mock OperationParser."""
|
54
|
-
mock_parser = MagicMock(spec=OperationParser)
|
55
|
-
mock_parser.get_function_name.return_value = "mock_function_name"
|
56
|
-
mock_parser.get_json_schema.return_value = {}
|
57
|
-
mock_parser.get_parameters.return_value = []
|
58
|
-
mock_parser.get_return_type_hint.return_value = "str"
|
59
|
-
mock_parser.get_pydoc_string.return_value = "Mock docstring"
|
60
|
-
mock_parser.get_signature_parameters.return_value = []
|
61
|
-
mock_parser.get_return_type_value.return_value = str
|
62
|
-
mock_parser.get_annotations.return_value = {}
|
63
|
-
return mock_parser
|
64
|
-
|
65
|
-
@pytest.fixture
|
66
|
-
def sample_endpiont(self):
|
67
|
-
return OperationEndpoint(
|
68
|
-
base_url="https://example.com", path="/test", method="GET"
|
69
|
-
)
|
70
|
-
|
71
|
-
@pytest.fixture
|
72
|
-
def sample_operation(self):
|
73
|
-
return Operation(
|
74
|
-
operationId="testOperation",
|
75
|
-
description="Test operation",
|
76
|
-
parameters=[],
|
77
|
-
requestBody=RequestBody(
|
78
|
-
content={
|
79
|
-
"application/json": MediaType(
|
80
|
-
schema=OpenAPISchema(
|
81
|
-
type="object",
|
82
|
-
properties={
|
83
|
-
"testBodyParam": OpenAPISchema(type="string")
|
84
|
-
},
|
85
|
-
)
|
86
|
-
)
|
87
|
-
}
|
88
|
-
),
|
89
|
-
)
|
90
|
-
|
91
|
-
@pytest.fixture
|
92
|
-
def sample_api_parameters(self):
|
93
|
-
return [
|
94
|
-
ApiParameter(
|
95
|
-
original_name="test_param",
|
96
|
-
py_name="test_param",
|
97
|
-
param_location="query",
|
98
|
-
param_schema=OpenAPISchema(type="string"),
|
99
|
-
is_required=True,
|
100
|
-
),
|
101
|
-
ApiParameter(
|
102
|
-
original_name="",
|
103
|
-
py_name="test_body_param",
|
104
|
-
param_location="body",
|
105
|
-
param_schema=OpenAPISchema(type="string"),
|
106
|
-
is_required=True,
|
107
|
-
),
|
108
|
-
]
|
109
|
-
|
110
|
-
@pytest.fixture
|
111
|
-
def sample_return_parameter(self):
|
112
|
-
return ApiParameter(
|
113
|
-
original_name="test_param",
|
114
|
-
py_name="test_param",
|
115
|
-
param_location="query",
|
116
|
-
param_schema=OpenAPISchema(type="string"),
|
117
|
-
is_required=True,
|
118
|
-
)
|
119
|
-
|
120
|
-
@pytest.fixture
|
121
|
-
def sample_auth_scheme(self):
|
122
|
-
scheme, _ = token_to_scheme_credential(
|
123
|
-
"apikey", "header", "", "sample_auth_credential_internal_test"
|
124
|
-
)
|
125
|
-
return scheme
|
126
|
-
|
127
|
-
@pytest.fixture
|
128
|
-
def sample_auth_credential(self):
|
129
|
-
_, credential = token_to_scheme_credential(
|
130
|
-
"apikey", "header", "", "sample_auth_credential_internal_test"
|
131
|
-
)
|
132
|
-
return credential
|
133
|
-
|
134
|
-
def test_init(
|
135
|
-
self,
|
136
|
-
sample_endpiont,
|
137
|
-
sample_operation,
|
138
|
-
sample_auth_scheme,
|
139
|
-
sample_auth_credential,
|
140
|
-
):
|
141
|
-
tool = RestApiTool(
|
142
|
-
name="test_tool",
|
143
|
-
description="Test Tool",
|
144
|
-
endpoint=sample_endpiont,
|
145
|
-
operation=sample_operation,
|
146
|
-
auth_scheme=sample_auth_scheme,
|
147
|
-
auth_credential=sample_auth_credential,
|
148
|
-
)
|
149
|
-
assert tool.name == "test_tool"
|
150
|
-
assert tool.description == "Test Tool"
|
151
|
-
assert tool.endpoint == sample_endpiont
|
152
|
-
assert tool.operation == sample_operation
|
153
|
-
assert tool.auth_credential == sample_auth_credential
|
154
|
-
assert tool.auth_scheme == sample_auth_scheme
|
155
|
-
assert tool.credential_exchanger is not None
|
156
|
-
|
157
|
-
def test_from_parsed_operation_str(
|
158
|
-
self,
|
159
|
-
sample_endpiont,
|
160
|
-
sample_api_parameters,
|
161
|
-
sample_return_parameter,
|
162
|
-
sample_operation,
|
163
|
-
):
|
164
|
-
parsed_operation_str = json.dumps({
|
165
|
-
"name": "test_operation",
|
166
|
-
"description": "Test Description",
|
167
|
-
"endpoint": sample_endpiont.model_dump(),
|
168
|
-
"operation": sample_operation.model_dump(),
|
169
|
-
"auth_scheme": None,
|
170
|
-
"auth_credential": None,
|
171
|
-
"parameters": [p.model_dump() for p in sample_api_parameters],
|
172
|
-
"return_value": sample_return_parameter.model_dump(),
|
173
|
-
})
|
174
|
-
|
175
|
-
tool = RestApiTool.from_parsed_operation_str(parsed_operation_str)
|
176
|
-
assert tool.name == "test_operation"
|
177
|
-
|
178
|
-
def test_get_declaration(
|
179
|
-
self, sample_endpiont, sample_operation, mock_operation_parser
|
180
|
-
):
|
181
|
-
tool = RestApiTool(
|
182
|
-
name="test_tool",
|
183
|
-
description="Test description",
|
184
|
-
endpoint=sample_endpiont,
|
185
|
-
operation=sample_operation,
|
186
|
-
should_parse_operation=False,
|
187
|
-
)
|
188
|
-
tool._operation_parser = mock_operation_parser
|
189
|
-
|
190
|
-
declaration = tool._get_declaration()
|
191
|
-
assert isinstance(declaration, FunctionDeclaration)
|
192
|
-
assert declaration.name == "test_tool"
|
193
|
-
assert declaration.description == "Test description"
|
194
|
-
assert isinstance(declaration.parameters, Schema)
|
195
|
-
|
196
|
-
@patch(
|
197
|
-
"google.adk.tools.openapi_tool.openapi_spec_parser.rest_api_tool.requests.request"
|
198
|
-
)
|
199
|
-
def test_call_success(
|
200
|
-
self,
|
201
|
-
mock_request,
|
202
|
-
mock_tool_context,
|
203
|
-
sample_endpiont,
|
204
|
-
sample_operation,
|
205
|
-
sample_auth_scheme,
|
206
|
-
sample_auth_credential,
|
207
|
-
):
|
208
|
-
mock_response = MagicMock()
|
209
|
-
mock_response.json.return_value = {"result": "success"}
|
210
|
-
mock_request.return_value = mock_response
|
211
|
-
|
212
|
-
tool = RestApiTool(
|
213
|
-
name="test_tool",
|
214
|
-
description="Test Tool",
|
215
|
-
endpoint=sample_endpiont,
|
216
|
-
operation=sample_operation,
|
217
|
-
auth_scheme=sample_auth_scheme,
|
218
|
-
auth_credential=sample_auth_credential,
|
219
|
-
)
|
220
|
-
|
221
|
-
# Call the method
|
222
|
-
result = tool.call(args={}, tool_context=mock_tool_context)
|
223
|
-
|
224
|
-
# Check the result
|
225
|
-
assert result == {"result": "success"}
|
226
|
-
|
227
|
-
@patch(
|
228
|
-
"google.adk.tools.openapi_tool.openapi_spec_parser.rest_api_tool.requests.request"
|
229
|
-
)
|
230
|
-
def test_call_auth_pending(
|
231
|
-
self,
|
232
|
-
mock_request,
|
233
|
-
sample_endpiont,
|
234
|
-
sample_operation,
|
235
|
-
sample_auth_scheme,
|
236
|
-
sample_auth_credential,
|
237
|
-
):
|
238
|
-
|
239
|
-
tool = RestApiTool(
|
240
|
-
name="test_tool",
|
241
|
-
description="Test Tool",
|
242
|
-
endpoint=sample_endpiont,
|
243
|
-
operation=sample_operation,
|
244
|
-
auth_scheme=sample_auth_scheme,
|
245
|
-
auth_credential=sample_auth_credential,
|
246
|
-
)
|
247
|
-
with patch(
|
248
|
-
"google.adk.tools.openapi_tool.openapi_spec_parser.rest_api_tool.ToolAuthHandler.from_tool_context"
|
249
|
-
) as mock_from_tool_context:
|
250
|
-
mock_tool_auth_handler_instance = MagicMock()
|
251
|
-
mock_tool_auth_handler_instance.prepare_auth_credentials.return_value.state = (
|
252
|
-
"pending"
|
253
|
-
)
|
254
|
-
mock_from_tool_context.return_value = mock_tool_auth_handler_instance
|
255
|
-
|
256
|
-
response = tool.call(args={}, tool_context=None)
|
257
|
-
assert response == {
|
258
|
-
"pending": True,
|
259
|
-
"message": "Needs your authorization to access your data.",
|
260
|
-
}
|
261
|
-
|
262
|
-
def test_prepare_request_params_query_body(
|
263
|
-
self, sample_endpiont, sample_auth_credential, sample_auth_scheme
|
264
|
-
):
|
265
|
-
# Create a mock Operation object
|
266
|
-
mock_operation = Operation(
|
267
|
-
operationId="test_op",
|
268
|
-
parameters=[
|
269
|
-
OpenAPIParameter(**{
|
270
|
-
"name": "testQueryParam",
|
271
|
-
"in": "query",
|
272
|
-
"schema": OpenAPISchema(type="string"),
|
273
|
-
})
|
274
|
-
],
|
275
|
-
requestBody=RequestBody(
|
276
|
-
content={
|
277
|
-
"application/json": MediaType(
|
278
|
-
schema=OpenAPISchema(
|
279
|
-
type="object",
|
280
|
-
properties={
|
281
|
-
"param1": OpenAPISchema(type="string"),
|
282
|
-
"param2": OpenAPISchema(type="integer"),
|
283
|
-
},
|
284
|
-
)
|
285
|
-
)
|
286
|
-
}
|
287
|
-
),
|
288
|
-
)
|
289
|
-
|
290
|
-
tool = RestApiTool(
|
291
|
-
name="test_tool",
|
292
|
-
description="test",
|
293
|
-
endpoint=sample_endpiont,
|
294
|
-
operation=mock_operation,
|
295
|
-
auth_credential=sample_auth_credential,
|
296
|
-
auth_scheme=sample_auth_scheme,
|
297
|
-
)
|
298
|
-
|
299
|
-
params = [
|
300
|
-
ApiParameter(
|
301
|
-
original_name="param1",
|
302
|
-
py_name="param1",
|
303
|
-
param_location="body",
|
304
|
-
param_schema=OpenAPISchema(type="string"),
|
305
|
-
),
|
306
|
-
ApiParameter(
|
307
|
-
original_name="param2",
|
308
|
-
py_name="param2",
|
309
|
-
param_location="body",
|
310
|
-
param_schema=OpenAPISchema(type="integer"),
|
311
|
-
),
|
312
|
-
ApiParameter(
|
313
|
-
original_name="testQueryParam",
|
314
|
-
py_name="test_query_param",
|
315
|
-
param_location="query",
|
316
|
-
param_schema=OpenAPISchema(type="string"),
|
317
|
-
),
|
318
|
-
]
|
319
|
-
kwargs = {
|
320
|
-
"param1": "value1",
|
321
|
-
"param2": 123,
|
322
|
-
"test_query_param": "query_value",
|
323
|
-
}
|
324
|
-
|
325
|
-
request_params = tool._prepare_request_params(params, kwargs)
|
326
|
-
assert request_params["method"] == "get"
|
327
|
-
assert request_params["url"] == "https://example.com/test"
|
328
|
-
assert request_params["json"] == {"param1": "value1", "param2": 123}
|
329
|
-
assert request_params["params"] == {"testQueryParam": "query_value"}
|
330
|
-
|
331
|
-
def test_prepare_request_params_array(
|
332
|
-
self, sample_endpiont, sample_auth_scheme, sample_auth_credential
|
333
|
-
):
|
334
|
-
mock_operation = Operation(
|
335
|
-
operationId="test_op",
|
336
|
-
requestBody=RequestBody(
|
337
|
-
content={
|
338
|
-
"application/json": MediaType(
|
339
|
-
schema=OpenAPISchema(
|
340
|
-
type="array", items=OpenAPISchema(type="string")
|
341
|
-
)
|
342
|
-
)
|
343
|
-
}
|
344
|
-
),
|
345
|
-
)
|
346
|
-
|
347
|
-
tool = RestApiTool(
|
348
|
-
name="test_tool",
|
349
|
-
description="test",
|
350
|
-
endpoint=sample_endpiont,
|
351
|
-
operation=mock_operation,
|
352
|
-
auth_credential=sample_auth_credential,
|
353
|
-
auth_scheme=sample_auth_scheme,
|
354
|
-
)
|
355
|
-
params = [
|
356
|
-
ApiParameter(
|
357
|
-
original_name="array", # Match the parameter name
|
358
|
-
py_name="array",
|
359
|
-
param_location="body",
|
360
|
-
param_schema=OpenAPISchema(
|
361
|
-
type="array", items=OpenAPISchema(type="string")
|
362
|
-
),
|
363
|
-
)
|
364
|
-
]
|
365
|
-
kwargs = {"array": ["item1", "item2"]}
|
366
|
-
|
367
|
-
request_params = tool._prepare_request_params(params, kwargs)
|
368
|
-
|
369
|
-
assert request_params["json"] == ["item1", "item2"]
|
370
|
-
|
371
|
-
def test_prepare_request_params_string(
|
372
|
-
self, sample_endpiont, sample_auth_credential, sample_auth_scheme
|
373
|
-
):
|
374
|
-
mock_operation = Operation(
|
375
|
-
operationId="test_op",
|
376
|
-
requestBody=RequestBody(
|
377
|
-
content={
|
378
|
-
"text/plain": MediaType(schema=OpenAPISchema(type="string"))
|
379
|
-
}
|
380
|
-
),
|
381
|
-
)
|
382
|
-
tool = RestApiTool(
|
383
|
-
name="test_tool",
|
384
|
-
description="Test Tool",
|
385
|
-
endpoint=sample_endpiont,
|
386
|
-
operation=mock_operation,
|
387
|
-
auth_credential=sample_auth_credential,
|
388
|
-
auth_scheme=sample_auth_scheme,
|
389
|
-
)
|
390
|
-
params = [
|
391
|
-
ApiParameter(
|
392
|
-
original_name="",
|
393
|
-
py_name="input_string",
|
394
|
-
param_location="body",
|
395
|
-
param_schema=OpenAPISchema(type="string"),
|
396
|
-
)
|
397
|
-
]
|
398
|
-
kwargs = {"input_string": "test_value"}
|
399
|
-
|
400
|
-
request_params = tool._prepare_request_params(params, kwargs)
|
401
|
-
|
402
|
-
assert request_params["data"] == "test_value"
|
403
|
-
assert request_params["headers"]["Content-Type"] == "text/plain"
|
404
|
-
|
405
|
-
def test_prepare_request_params_form_data(
|
406
|
-
self, sample_endpiont, sample_auth_scheme, sample_auth_credential
|
407
|
-
):
|
408
|
-
mock_operation = Operation(
|
409
|
-
operationId="test_op",
|
410
|
-
requestBody=RequestBody(
|
411
|
-
content={
|
412
|
-
"application/x-www-form-urlencoded": MediaType(
|
413
|
-
schema=OpenAPISchema(
|
414
|
-
type="object",
|
415
|
-
properties={"key1": OpenAPISchema(type="string")},
|
416
|
-
)
|
417
|
-
)
|
418
|
-
}
|
419
|
-
),
|
420
|
-
)
|
421
|
-
tool = RestApiTool(
|
422
|
-
name="test_tool",
|
423
|
-
description="test",
|
424
|
-
endpoint=sample_endpiont,
|
425
|
-
operation=mock_operation,
|
426
|
-
auth_credential=sample_auth_credential,
|
427
|
-
auth_scheme=sample_auth_scheme,
|
428
|
-
)
|
429
|
-
params = [
|
430
|
-
ApiParameter(
|
431
|
-
original_name="key1",
|
432
|
-
py_name="key1",
|
433
|
-
param_location="body",
|
434
|
-
param_schema=OpenAPISchema(type="string"),
|
435
|
-
)
|
436
|
-
]
|
437
|
-
kwargs = {"key1": "value1"}
|
438
|
-
|
439
|
-
request_params = tool._prepare_request_params(params, kwargs)
|
440
|
-
|
441
|
-
assert request_params["data"] == {"key1": "value1"}
|
442
|
-
assert (
|
443
|
-
request_params["headers"]["Content-Type"]
|
444
|
-
== "application/x-www-form-urlencoded"
|
445
|
-
)
|
446
|
-
|
447
|
-
def test_prepare_request_params_multipart(
|
448
|
-
self, sample_endpiont, sample_auth_credential, sample_auth_scheme
|
449
|
-
):
|
450
|
-
mock_operation = Operation(
|
451
|
-
operationId="test_op",
|
452
|
-
requestBody=RequestBody(
|
453
|
-
content={
|
454
|
-
"multipart/form-data": MediaType(
|
455
|
-
schema=OpenAPISchema(
|
456
|
-
type="object",
|
457
|
-
properties={
|
458
|
-
"file1": OpenAPISchema(
|
459
|
-
type="string", format="binary"
|
460
|
-
)
|
461
|
-
},
|
462
|
-
)
|
463
|
-
)
|
464
|
-
}
|
465
|
-
),
|
466
|
-
)
|
467
|
-
tool = RestApiTool(
|
468
|
-
name="test_tool",
|
469
|
-
description="test",
|
470
|
-
endpoint=sample_endpiont,
|
471
|
-
operation=mock_operation,
|
472
|
-
auth_credential=sample_auth_credential,
|
473
|
-
auth_scheme=sample_auth_scheme,
|
474
|
-
)
|
475
|
-
params = [
|
476
|
-
ApiParameter(
|
477
|
-
original_name="file1",
|
478
|
-
py_name="file1",
|
479
|
-
param_location="body",
|
480
|
-
param_schema=OpenAPISchema(type="string", format="binary"),
|
481
|
-
)
|
482
|
-
]
|
483
|
-
kwargs = {"file1": b"file_content"}
|
484
|
-
|
485
|
-
request_params = tool._prepare_request_params(params, kwargs)
|
486
|
-
|
487
|
-
assert request_params["files"] == {"file1": b"file_content"}
|
488
|
-
assert request_params["headers"]["Content-Type"] == "multipart/form-data"
|
489
|
-
|
490
|
-
def test_prepare_request_params_octet_stream(
|
491
|
-
self, sample_endpiont, sample_auth_scheme, sample_auth_credential
|
492
|
-
):
|
493
|
-
mock_operation = Operation(
|
494
|
-
operationId="test_op",
|
495
|
-
requestBody=RequestBody(
|
496
|
-
content={
|
497
|
-
"application/octet-stream": MediaType(
|
498
|
-
schema=OpenAPISchema(type="string", format="binary")
|
499
|
-
)
|
500
|
-
}
|
501
|
-
),
|
502
|
-
)
|
503
|
-
tool = RestApiTool(
|
504
|
-
name="test_tool",
|
505
|
-
description="test",
|
506
|
-
endpoint=sample_endpiont,
|
507
|
-
operation=mock_operation,
|
508
|
-
auth_credential=sample_auth_credential,
|
509
|
-
auth_scheme=sample_auth_scheme,
|
510
|
-
)
|
511
|
-
params = [
|
512
|
-
ApiParameter(
|
513
|
-
original_name="",
|
514
|
-
py_name="data",
|
515
|
-
param_location="body",
|
516
|
-
param_schema=OpenAPISchema(type="string", format="binary"),
|
517
|
-
)
|
518
|
-
]
|
519
|
-
kwargs = {"data": b"binary_data"}
|
520
|
-
|
521
|
-
request_params = tool._prepare_request_params(params, kwargs)
|
522
|
-
|
523
|
-
assert request_params["data"] == b"binary_data"
|
524
|
-
assert (
|
525
|
-
request_params["headers"]["Content-Type"] == "application/octet-stream"
|
526
|
-
)
|
527
|
-
|
528
|
-
def test_prepare_request_params_path_param(
|
529
|
-
self, sample_endpiont, sample_auth_credential, sample_auth_scheme
|
530
|
-
):
|
531
|
-
mock_operation = Operation(operationId="test_op")
|
532
|
-
tool = RestApiTool(
|
533
|
-
name="test_tool",
|
534
|
-
description="Test Tool",
|
535
|
-
endpoint=sample_endpiont,
|
536
|
-
operation=mock_operation,
|
537
|
-
auth_credential=sample_auth_credential,
|
538
|
-
auth_scheme=sample_auth_scheme,
|
539
|
-
)
|
540
|
-
params = [
|
541
|
-
ApiParameter(
|
542
|
-
original_name="user_id",
|
543
|
-
py_name="user_id",
|
544
|
-
param_location="path",
|
545
|
-
param_schema=OpenAPISchema(type="string"),
|
546
|
-
)
|
547
|
-
]
|
548
|
-
kwargs = {"user_id": "123"}
|
549
|
-
endpoint_with_path = OperationEndpoint(
|
550
|
-
base_url="https://example.com", path="/test/{user_id}", method="get"
|
551
|
-
)
|
552
|
-
tool.endpoint = endpoint_with_path
|
553
|
-
|
554
|
-
request_params = tool._prepare_request_params(params, kwargs)
|
555
|
-
|
556
|
-
assert (
|
557
|
-
request_params["url"] == "https://example.com/test/123"
|
558
|
-
) # Path param replaced
|
559
|
-
|
560
|
-
def test_prepare_request_params_header_param(
|
561
|
-
self,
|
562
|
-
sample_endpiont,
|
563
|
-
sample_auth_credential,
|
564
|
-
sample_auth_scheme,
|
565
|
-
sample_operation,
|
566
|
-
):
|
567
|
-
tool = RestApiTool(
|
568
|
-
name="test_tool",
|
569
|
-
description="Test Tool",
|
570
|
-
endpoint=sample_endpiont,
|
571
|
-
operation=sample_operation,
|
572
|
-
auth_credential=sample_auth_credential,
|
573
|
-
auth_scheme=sample_auth_scheme,
|
574
|
-
)
|
575
|
-
params = [
|
576
|
-
ApiParameter(
|
577
|
-
original_name="X-Custom-Header",
|
578
|
-
py_name="x_custom_header",
|
579
|
-
param_location="header",
|
580
|
-
param_schema=OpenAPISchema(type="string"),
|
581
|
-
)
|
582
|
-
]
|
583
|
-
kwargs = {"x_custom_header": "header_value"}
|
584
|
-
|
585
|
-
request_params = tool._prepare_request_params(params, kwargs)
|
586
|
-
|
587
|
-
assert request_params["headers"]["X-Custom-Header"] == "header_value"
|
588
|
-
|
589
|
-
def test_prepare_request_params_cookie_param(
|
590
|
-
self,
|
591
|
-
sample_endpiont,
|
592
|
-
sample_auth_credential,
|
593
|
-
sample_auth_scheme,
|
594
|
-
sample_operation,
|
595
|
-
):
|
596
|
-
tool = RestApiTool(
|
597
|
-
name="test_tool",
|
598
|
-
description="Test Tool",
|
599
|
-
endpoint=sample_endpiont,
|
600
|
-
operation=sample_operation,
|
601
|
-
auth_credential=sample_auth_credential,
|
602
|
-
auth_scheme=sample_auth_scheme,
|
603
|
-
)
|
604
|
-
params = [
|
605
|
-
ApiParameter(
|
606
|
-
original_name="session_id",
|
607
|
-
py_name="session_id",
|
608
|
-
param_location="cookie",
|
609
|
-
param_schema=OpenAPISchema(type="string"),
|
610
|
-
)
|
611
|
-
]
|
612
|
-
kwargs = {"session_id": "cookie_value"}
|
613
|
-
|
614
|
-
request_params = tool._prepare_request_params(params, kwargs)
|
615
|
-
|
616
|
-
assert request_params["cookies"]["session_id"] == "cookie_value"
|
617
|
-
|
618
|
-
def test_prepare_request_params_multiple_mime_types(
|
619
|
-
self, sample_endpiont, sample_auth_credential, sample_auth_scheme
|
620
|
-
):
|
621
|
-
# Test what happens when multiple mime types are specified. It should take
|
622
|
-
# the first one.
|
623
|
-
mock_operation = Operation(
|
624
|
-
operationId="test_op",
|
625
|
-
requestBody=RequestBody(
|
626
|
-
content={
|
627
|
-
"application/json": MediaType(
|
628
|
-
schema=OpenAPISchema(type="string")
|
629
|
-
),
|
630
|
-
"text/plain": MediaType(schema=OpenAPISchema(type="string")),
|
631
|
-
}
|
632
|
-
),
|
633
|
-
)
|
634
|
-
tool = RestApiTool(
|
635
|
-
name="test_tool",
|
636
|
-
description="Test Tool",
|
637
|
-
endpoint=sample_endpiont,
|
638
|
-
operation=mock_operation,
|
639
|
-
auth_credential=sample_auth_credential,
|
640
|
-
auth_scheme=sample_auth_scheme,
|
641
|
-
)
|
642
|
-
params = [
|
643
|
-
ApiParameter(
|
644
|
-
original_name="",
|
645
|
-
py_name="input",
|
646
|
-
param_location="body",
|
647
|
-
param_schema=OpenAPISchema(type="string"),
|
648
|
-
)
|
649
|
-
]
|
650
|
-
kwargs = {"input": "some_value"}
|
651
|
-
|
652
|
-
request_params = tool._prepare_request_params(params, kwargs)
|
653
|
-
|
654
|
-
assert request_params["headers"]["Content-Type"] == "application/json"
|
655
|
-
|
656
|
-
def test_prepare_request_params_unknown_parameter(
|
657
|
-
self,
|
658
|
-
sample_endpiont,
|
659
|
-
sample_auth_credential,
|
660
|
-
sample_auth_scheme,
|
661
|
-
sample_operation,
|
662
|
-
):
|
663
|
-
tool = RestApiTool(
|
664
|
-
name="test_tool",
|
665
|
-
description="Test Tool",
|
666
|
-
endpoint=sample_endpiont,
|
667
|
-
operation=sample_operation,
|
668
|
-
auth_credential=sample_auth_credential,
|
669
|
-
auth_scheme=sample_auth_scheme,
|
670
|
-
)
|
671
|
-
params = [
|
672
|
-
ApiParameter(
|
673
|
-
original_name="known_param",
|
674
|
-
py_name="known_param",
|
675
|
-
param_location="query",
|
676
|
-
param_schema=OpenAPISchema(type="string"),
|
677
|
-
)
|
678
|
-
]
|
679
|
-
kwargs = {"known_param": "value", "unknown_param": "unknown"}
|
680
|
-
|
681
|
-
request_params = tool._prepare_request_params(params, kwargs)
|
682
|
-
|
683
|
-
# Make sure unknown parameters are ignored and do not raise errors.
|
684
|
-
assert "unknown_param" not in request_params["params"]
|
685
|
-
|
686
|
-
def test_prepare_request_params_base_url_handling(
|
687
|
-
self, sample_auth_credential, sample_auth_scheme, sample_operation
|
688
|
-
):
|
689
|
-
# No base_url provided, should use path as is
|
690
|
-
tool_no_base = RestApiTool(
|
691
|
-
name="test_tool_no_base",
|
692
|
-
description="Test Tool",
|
693
|
-
endpoint=OperationEndpoint(base_url="", path="/no_base", method="get"),
|
694
|
-
operation=sample_operation,
|
695
|
-
auth_credential=sample_auth_credential,
|
696
|
-
auth_scheme=sample_auth_scheme,
|
697
|
-
)
|
698
|
-
params = []
|
699
|
-
kwargs = {}
|
700
|
-
|
701
|
-
request_params_no_base = tool_no_base._prepare_request_params(
|
702
|
-
params, kwargs
|
703
|
-
)
|
704
|
-
assert request_params_no_base["url"] == "/no_base"
|
705
|
-
|
706
|
-
tool_trailing_slash = RestApiTool(
|
707
|
-
name="test_tool",
|
708
|
-
description="Test Tool",
|
709
|
-
endpoint=OperationEndpoint(
|
710
|
-
base_url="https://example.com/", path="/trailing", method="get"
|
711
|
-
),
|
712
|
-
operation=sample_operation,
|
713
|
-
auth_credential=sample_auth_credential,
|
714
|
-
auth_scheme=sample_auth_scheme,
|
715
|
-
)
|
716
|
-
|
717
|
-
request_params_trailing = tool_trailing_slash._prepare_request_params(
|
718
|
-
params, kwargs
|
719
|
-
)
|
720
|
-
assert request_params_trailing["url"] == "https://example.com/trailing"
|
721
|
-
|
722
|
-
def test_prepare_request_params_no_unrecognized_query_parameter(
|
723
|
-
self,
|
724
|
-
sample_endpiont,
|
725
|
-
sample_auth_credential,
|
726
|
-
sample_auth_scheme,
|
727
|
-
sample_operation,
|
728
|
-
):
|
729
|
-
tool = RestApiTool(
|
730
|
-
name="test_tool",
|
731
|
-
description="Test Tool",
|
732
|
-
endpoint=sample_endpiont,
|
733
|
-
operation=sample_operation,
|
734
|
-
auth_credential=sample_auth_credential,
|
735
|
-
auth_scheme=sample_auth_scheme,
|
736
|
-
)
|
737
|
-
params = [
|
738
|
-
ApiParameter(
|
739
|
-
original_name="unrecognized_param",
|
740
|
-
py_name="unrecognized_param",
|
741
|
-
param_location="query",
|
742
|
-
param_schema=OpenAPISchema(type="string"),
|
743
|
-
)
|
744
|
-
]
|
745
|
-
kwargs = {"unrecognized_param": None} # Explicitly passing None
|
746
|
-
request_params = tool._prepare_request_params(params, kwargs)
|
747
|
-
|
748
|
-
# Query param not in sample_operation. It should be ignored.
|
749
|
-
assert "unrecognized_param" not in request_params["params"]
|
750
|
-
|
751
|
-
def test_prepare_request_params_no_credential(
|
752
|
-
self,
|
753
|
-
sample_endpiont,
|
754
|
-
sample_operation,
|
755
|
-
):
|
756
|
-
tool = RestApiTool(
|
757
|
-
name="test_tool",
|
758
|
-
description="Test Tool",
|
759
|
-
endpoint=sample_endpiont,
|
760
|
-
operation=sample_operation,
|
761
|
-
auth_credential=None,
|
762
|
-
auth_scheme=None,
|
763
|
-
)
|
764
|
-
params = [
|
765
|
-
ApiParameter(
|
766
|
-
original_name="param_name",
|
767
|
-
py_name="param_name",
|
768
|
-
param_location="query",
|
769
|
-
param_schema=OpenAPISchema(type="string"),
|
770
|
-
)
|
771
|
-
]
|
772
|
-
kwargs = {"param_name": "aaa", "empty_param": ""}
|
773
|
-
|
774
|
-
request_params = tool._prepare_request_params(params, kwargs)
|
775
|
-
|
776
|
-
assert "param_name" in request_params["params"]
|
777
|
-
assert "empty_param" not in request_params["params"]
|
778
|
-
|
779
|
-
|
780
|
-
class TestToGeminiSchema:
|
781
|
-
|
782
|
-
def test_to_gemini_schema_none(self):
|
783
|
-
assert to_gemini_schema(None) is None
|
784
|
-
|
785
|
-
def test_to_gemini_schema_not_dict(self):
|
786
|
-
with pytest.raises(TypeError, match="openapi_schema must be a dictionary"):
|
787
|
-
to_gemini_schema("not a dict")
|
788
|
-
|
789
|
-
def test_to_gemini_schema_empty_dict(self):
|
790
|
-
result = to_gemini_schema({})
|
791
|
-
assert isinstance(result, Schema)
|
792
|
-
assert result.type == Type.OBJECT
|
793
|
-
assert result.properties == {"dummy_DO_NOT_GENERATE": Schema(type="string")}
|
794
|
-
|
795
|
-
def test_to_gemini_schema_dict_with_only_object_type(self):
|
796
|
-
result = to_gemini_schema({"type": "object"})
|
797
|
-
assert isinstance(result, Schema)
|
798
|
-
assert result.type == Type.OBJECT
|
799
|
-
assert result.properties == {"dummy_DO_NOT_GENERATE": Schema(type="string")}
|
800
|
-
|
801
|
-
def test_to_gemini_schema_basic_types(self):
|
802
|
-
openapi_schema = {
|
803
|
-
"type": "object",
|
804
|
-
"properties": {
|
805
|
-
"name": {"type": "string"},
|
806
|
-
"age": {"type": "integer"},
|
807
|
-
"is_active": {"type": "boolean"},
|
808
|
-
},
|
809
|
-
}
|
810
|
-
gemini_schema = to_gemini_schema(openapi_schema)
|
811
|
-
assert isinstance(gemini_schema, Schema)
|
812
|
-
assert gemini_schema.type == Type.OBJECT
|
813
|
-
assert gemini_schema.properties["name"].type == Type.STRING
|
814
|
-
assert gemini_schema.properties["age"].type == Type.INTEGER
|
815
|
-
assert gemini_schema.properties["is_active"].type == Type.BOOLEAN
|
816
|
-
|
817
|
-
def test_to_gemini_schema_nested_objects(self):
|
818
|
-
openapi_schema = {
|
819
|
-
"type": "object",
|
820
|
-
"properties": {
|
821
|
-
"address": {
|
822
|
-
"type": "object",
|
823
|
-
"properties": {
|
824
|
-
"street": {"type": "string"},
|
825
|
-
"city": {"type": "string"},
|
826
|
-
},
|
827
|
-
}
|
828
|
-
},
|
829
|
-
}
|
830
|
-
gemini_schema = to_gemini_schema(openapi_schema)
|
831
|
-
assert gemini_schema.properties["address"].type == Type.OBJECT
|
832
|
-
assert (
|
833
|
-
gemini_schema.properties["address"].properties["street"].type
|
834
|
-
== Type.STRING
|
835
|
-
)
|
836
|
-
assert (
|
837
|
-
gemini_schema.properties["address"].properties["city"].type
|
838
|
-
== Type.STRING
|
839
|
-
)
|
840
|
-
|
841
|
-
def test_to_gemini_schema_array(self):
|
842
|
-
openapi_schema = {
|
843
|
-
"type": "array",
|
844
|
-
"items": {"type": "string"},
|
845
|
-
}
|
846
|
-
gemini_schema = to_gemini_schema(openapi_schema)
|
847
|
-
assert gemini_schema.type == Type.ARRAY
|
848
|
-
assert gemini_schema.items.type == Type.STRING
|
849
|
-
|
850
|
-
def test_to_gemini_schema_nested_array(self):
|
851
|
-
openapi_schema = {
|
852
|
-
"type": "array",
|
853
|
-
"items": {
|
854
|
-
"type": "object",
|
855
|
-
"properties": {"name": {"type": "string"}},
|
856
|
-
},
|
857
|
-
}
|
858
|
-
gemini_schema = to_gemini_schema(openapi_schema)
|
859
|
-
assert gemini_schema.items.properties["name"].type == Type.STRING
|
860
|
-
|
861
|
-
def test_to_gemini_schema_any_of(self):
|
862
|
-
openapi_schema = {
|
863
|
-
"anyOf": [{"type": "string"}, {"type": "integer"}],
|
864
|
-
}
|
865
|
-
gemini_schema = to_gemini_schema(openapi_schema)
|
866
|
-
assert len(gemini_schema.any_of) == 2
|
867
|
-
assert gemini_schema.any_of[0].type == Type.STRING
|
868
|
-
assert gemini_schema.any_of[1].type == Type.INTEGER
|
869
|
-
|
870
|
-
def test_to_gemini_schema_general_list(self):
|
871
|
-
openapi_schema = {
|
872
|
-
"type": "array",
|
873
|
-
"properties": {
|
874
|
-
"list_field": {"type": "array", "items": {"type": "string"}},
|
875
|
-
},
|
876
|
-
}
|
877
|
-
gemini_schema = to_gemini_schema(openapi_schema)
|
878
|
-
assert gemini_schema.properties["list_field"].type == Type.ARRAY
|
879
|
-
assert gemini_schema.properties["list_field"].items.type == Type.STRING
|
880
|
-
|
881
|
-
def test_to_gemini_schema_enum(self):
|
882
|
-
openapi_schema = {"type": "string", "enum": ["a", "b", "c"]}
|
883
|
-
gemini_schema = to_gemini_schema(openapi_schema)
|
884
|
-
assert gemini_schema.enum == ["a", "b", "c"]
|
885
|
-
|
886
|
-
def test_to_gemini_schema_required(self):
|
887
|
-
openapi_schema = {
|
888
|
-
"type": "object",
|
889
|
-
"required": ["name"],
|
890
|
-
"properties": {"name": {"type": "string"}},
|
891
|
-
}
|
892
|
-
gemini_schema = to_gemini_schema(openapi_schema)
|
893
|
-
assert gemini_schema.required == ["name"]
|
894
|
-
|
895
|
-
def test_to_gemini_schema_nested_dict(self):
|
896
|
-
openapi_schema = {
|
897
|
-
"type": "object",
|
898
|
-
"properties": {"metadata": {"key1": "value1", "key2": 123}},
|
899
|
-
}
|
900
|
-
gemini_schema = to_gemini_schema(openapi_schema)
|
901
|
-
# Since metadata is not properties nor item, it will call to_gemini_schema recursively.
|
902
|
-
assert isinstance(gemini_schema.properties["metadata"], Schema)
|
903
|
-
assert (
|
904
|
-
gemini_schema.properties["metadata"].type == Type.OBJECT
|
905
|
-
) # add object type by default
|
906
|
-
assert gemini_schema.properties["metadata"].properties == {
|
907
|
-
"dummy_DO_NOT_GENERATE": Schema(type="string")
|
908
|
-
}
|
909
|
-
|
910
|
-
def test_to_gemini_schema_ignore_title_default_format(self):
|
911
|
-
openapi_schema = {
|
912
|
-
"type": "string",
|
913
|
-
"title": "Test Title",
|
914
|
-
"default": "default_value",
|
915
|
-
"format": "date",
|
916
|
-
}
|
917
|
-
gemini_schema = to_gemini_schema(openapi_schema)
|
918
|
-
|
919
|
-
assert gemini_schema.title is None
|
920
|
-
assert gemini_schema.default is None
|
921
|
-
assert gemini_schema.format is None
|
922
|
-
|
923
|
-
def test_to_gemini_schema_property_ordering(self):
|
924
|
-
openapi_schema = {
|
925
|
-
"type": "object",
|
926
|
-
"propertyOrdering": ["name", "age"],
|
927
|
-
"properties": {
|
928
|
-
"name": {"type": "string"},
|
929
|
-
"age": {"type": "integer"},
|
930
|
-
},
|
931
|
-
}
|
932
|
-
|
933
|
-
gemini_schema = to_gemini_schema(openapi_schema)
|
934
|
-
assert gemini_schema.property_ordering == ["name", "age"]
|
935
|
-
|
936
|
-
def test_to_gemini_schema_converts_property_dict(self):
|
937
|
-
openapi_schema = {
|
938
|
-
"properties": {
|
939
|
-
"name": {"type": "string", "description": "The property key"},
|
940
|
-
"value": {"type": "string", "description": "The property value"},
|
941
|
-
},
|
942
|
-
"type": "object",
|
943
|
-
"description": "A single property entry in the Properties message.",
|
944
|
-
}
|
945
|
-
gemini_schema = to_gemini_schema(openapi_schema)
|
946
|
-
assert gemini_schema.type == Type.OBJECT
|
947
|
-
assert gemini_schema.properties["name"].type == Type.STRING
|
948
|
-
assert gemini_schema.properties["value"].type == Type.STRING
|
949
|
-
|
950
|
-
def test_to_gemini_schema_remove_unrecognized_fields(self):
|
951
|
-
openapi_schema = {
|
952
|
-
"type": "string",
|
953
|
-
"description": "A single date string.",
|
954
|
-
"format": "date",
|
955
|
-
}
|
956
|
-
gemini_schema = to_gemini_schema(openapi_schema)
|
957
|
-
assert gemini_schema.type == Type.STRING
|
958
|
-
assert not gemini_schema.format
|
959
|
-
|
960
|
-
|
961
|
-
def test_snake_to_lower_camel():
|
962
|
-
assert snake_to_lower_camel("single") == "single"
|
963
|
-
assert snake_to_lower_camel("two_words") == "twoWords"
|
964
|
-
assert snake_to_lower_camel("three_word_example") == "threeWordExample"
|
965
|
-
assert not snake_to_lower_camel("")
|
966
|
-
assert snake_to_lower_camel("alreadyCamelCase") == "alreadyCamelCase"
|