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,277 +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
|
-
from typing import Dict
|
16
|
-
from typing import List
|
17
|
-
|
18
|
-
from google.adk.tools import _automatic_function_calling_util
|
19
|
-
from google.adk.tools.agent_tool import ToolContext
|
20
|
-
from google.adk.tools.langchain_tool import LangchainTool
|
21
|
-
# TODO: crewai requires python 3.10 as minimum
|
22
|
-
# from crewai_tools import FileReadTool
|
23
|
-
from langchain_community.tools import ShellTool
|
24
|
-
from pydantic import BaseModel
|
25
|
-
import pytest
|
26
|
-
|
27
|
-
|
28
|
-
def test_unsupported_variant():
|
29
|
-
def simple_function(input_str: str) -> str:
|
30
|
-
return {'result': input_str}
|
31
|
-
|
32
|
-
with pytest.raises(ValueError):
|
33
|
-
_automatic_function_calling_util.build_function_declaration(
|
34
|
-
func=simple_function, variant='Unsupported'
|
35
|
-
)
|
36
|
-
|
37
|
-
|
38
|
-
def test_string_input():
|
39
|
-
def simple_function(input_str: str) -> str:
|
40
|
-
return {'result': input_str}
|
41
|
-
|
42
|
-
function_decl = _automatic_function_calling_util.build_function_declaration(
|
43
|
-
func=simple_function
|
44
|
-
)
|
45
|
-
|
46
|
-
assert function_decl.name == 'simple_function'
|
47
|
-
assert function_decl.parameters.type == 'OBJECT'
|
48
|
-
assert function_decl.parameters.properties['input_str'].type == 'STRING'
|
49
|
-
|
50
|
-
|
51
|
-
def test_int_input():
|
52
|
-
def simple_function(input_str: int) -> str:
|
53
|
-
return {'result': input_str}
|
54
|
-
|
55
|
-
function_decl = _automatic_function_calling_util.build_function_declaration(
|
56
|
-
func=simple_function
|
57
|
-
)
|
58
|
-
|
59
|
-
assert function_decl.name == 'simple_function'
|
60
|
-
assert function_decl.parameters.type == 'OBJECT'
|
61
|
-
assert function_decl.parameters.properties['input_str'].type == 'INTEGER'
|
62
|
-
|
63
|
-
|
64
|
-
def test_float_input():
|
65
|
-
def simple_function(input_str: float) -> str:
|
66
|
-
return {'result': input_str}
|
67
|
-
|
68
|
-
function_decl = _automatic_function_calling_util.build_function_declaration(
|
69
|
-
func=simple_function
|
70
|
-
)
|
71
|
-
|
72
|
-
assert function_decl.name == 'simple_function'
|
73
|
-
assert function_decl.parameters.type == 'OBJECT'
|
74
|
-
assert function_decl.parameters.properties['input_str'].type == 'NUMBER'
|
75
|
-
|
76
|
-
|
77
|
-
def test_bool_input():
|
78
|
-
def simple_function(input_str: bool) -> str:
|
79
|
-
return {'result': input_str}
|
80
|
-
|
81
|
-
function_decl = _automatic_function_calling_util.build_function_declaration(
|
82
|
-
func=simple_function
|
83
|
-
)
|
84
|
-
|
85
|
-
assert function_decl.name == 'simple_function'
|
86
|
-
assert function_decl.parameters.type == 'OBJECT'
|
87
|
-
assert function_decl.parameters.properties['input_str'].type == 'BOOLEAN'
|
88
|
-
|
89
|
-
|
90
|
-
def test_array_input():
|
91
|
-
def simple_function(input_str: List[str]) -> str:
|
92
|
-
return {'result': input_str}
|
93
|
-
|
94
|
-
function_decl = _automatic_function_calling_util.build_function_declaration(
|
95
|
-
func=simple_function
|
96
|
-
)
|
97
|
-
|
98
|
-
assert function_decl.name == 'simple_function'
|
99
|
-
assert function_decl.parameters.type == 'OBJECT'
|
100
|
-
assert function_decl.parameters.properties['input_str'].type == 'ARRAY'
|
101
|
-
|
102
|
-
|
103
|
-
def test_dict_input():
|
104
|
-
def simple_function(input_str: Dict[str, str]) -> str:
|
105
|
-
return {'result': input_str}
|
106
|
-
|
107
|
-
function_decl = _automatic_function_calling_util.build_function_declaration(
|
108
|
-
func=simple_function
|
109
|
-
)
|
110
|
-
|
111
|
-
assert function_decl.name == 'simple_function'
|
112
|
-
assert function_decl.parameters.type == 'OBJECT'
|
113
|
-
assert function_decl.parameters.properties['input_str'].type == 'OBJECT'
|
114
|
-
|
115
|
-
|
116
|
-
def test_basemodel_input():
|
117
|
-
class CustomInput(BaseModel):
|
118
|
-
input_str: str
|
119
|
-
|
120
|
-
def simple_function(input: CustomInput) -> str:
|
121
|
-
return {'result': input}
|
122
|
-
|
123
|
-
function_decl = _automatic_function_calling_util.build_function_declaration(
|
124
|
-
func=simple_function
|
125
|
-
)
|
126
|
-
|
127
|
-
assert function_decl.name == 'simple_function'
|
128
|
-
assert function_decl.parameters.type == 'OBJECT'
|
129
|
-
assert function_decl.parameters.properties['input'].type == 'OBJECT'
|
130
|
-
assert (
|
131
|
-
function_decl.parameters.properties['input'].properties['input_str'].type
|
132
|
-
== 'STRING'
|
133
|
-
)
|
134
|
-
|
135
|
-
|
136
|
-
def test_toolcontext_ignored():
|
137
|
-
def simple_function(input_str: str, tool_context: ToolContext) -> str:
|
138
|
-
return {'result': input_str}
|
139
|
-
|
140
|
-
function_decl = _automatic_function_calling_util.build_function_declaration(
|
141
|
-
func=simple_function, ignore_params=['tool_context']
|
142
|
-
)
|
143
|
-
|
144
|
-
assert function_decl.name == 'simple_function'
|
145
|
-
assert function_decl.parameters.type == 'OBJECT'
|
146
|
-
assert function_decl.parameters.properties['input_str'].type == 'STRING'
|
147
|
-
assert 'tool_context' not in function_decl.parameters.properties
|
148
|
-
|
149
|
-
|
150
|
-
def test_basemodel():
|
151
|
-
class SimpleFunction(BaseModel):
|
152
|
-
input_str: str
|
153
|
-
custom_input: int
|
154
|
-
|
155
|
-
function_decl = _automatic_function_calling_util.build_function_declaration(
|
156
|
-
func=SimpleFunction, ignore_params=['custom_input']
|
157
|
-
)
|
158
|
-
|
159
|
-
assert function_decl.name == 'SimpleFunction'
|
160
|
-
assert function_decl.parameters.type == 'OBJECT'
|
161
|
-
assert function_decl.parameters.properties['input_str'].type == 'STRING'
|
162
|
-
assert 'custom_input' not in function_decl.parameters.properties
|
163
|
-
|
164
|
-
|
165
|
-
def test_nested_basemodel_input():
|
166
|
-
class ChildInput(BaseModel):
|
167
|
-
input_str: str
|
168
|
-
|
169
|
-
class CustomInput(BaseModel):
|
170
|
-
child: ChildInput
|
171
|
-
|
172
|
-
def simple_function(input: CustomInput) -> str:
|
173
|
-
return {'result': input}
|
174
|
-
|
175
|
-
function_decl = _automatic_function_calling_util.build_function_declaration(
|
176
|
-
func=simple_function
|
177
|
-
)
|
178
|
-
|
179
|
-
assert function_decl.name == 'simple_function'
|
180
|
-
assert function_decl.parameters.type == 'OBJECT'
|
181
|
-
assert function_decl.parameters.properties['input'].type == 'OBJECT'
|
182
|
-
assert (
|
183
|
-
function_decl.parameters.properties['input'].properties['child'].type
|
184
|
-
== 'OBJECT'
|
185
|
-
)
|
186
|
-
assert (
|
187
|
-
function_decl.parameters.properties['input']
|
188
|
-
.properties['child']
|
189
|
-
.properties['input_str']
|
190
|
-
.type
|
191
|
-
== 'STRING'
|
192
|
-
)
|
193
|
-
|
194
|
-
|
195
|
-
def test_basemodel_with_nested_basemodel():
|
196
|
-
class ChildInput(BaseModel):
|
197
|
-
input_str: str
|
198
|
-
|
199
|
-
class CustomInput(BaseModel):
|
200
|
-
child: ChildInput
|
201
|
-
|
202
|
-
function_decl = _automatic_function_calling_util.build_function_declaration(
|
203
|
-
func=CustomInput, ignore_params=['custom_input']
|
204
|
-
)
|
205
|
-
|
206
|
-
assert function_decl.name == 'CustomInput'
|
207
|
-
assert function_decl.parameters.type == 'OBJECT'
|
208
|
-
assert function_decl.parameters.properties['child'].type == 'OBJECT'
|
209
|
-
assert (
|
210
|
-
function_decl.parameters.properties['child'].properties['input_str'].type
|
211
|
-
== 'STRING'
|
212
|
-
)
|
213
|
-
assert 'custom_input' not in function_decl.parameters.properties
|
214
|
-
|
215
|
-
|
216
|
-
def test_list():
|
217
|
-
def simple_function(
|
218
|
-
input_str: List[str], input_dir: List[Dict[str, str]]
|
219
|
-
) -> str:
|
220
|
-
return {'result': input_str}
|
221
|
-
|
222
|
-
function_decl = _automatic_function_calling_util.build_function_declaration(
|
223
|
-
func=simple_function
|
224
|
-
)
|
225
|
-
|
226
|
-
assert function_decl.name == 'simple_function'
|
227
|
-
assert function_decl.parameters.type == 'OBJECT'
|
228
|
-
assert function_decl.parameters.properties['input_str'].type == 'ARRAY'
|
229
|
-
assert function_decl.parameters.properties['input_str'].items.type == 'STRING'
|
230
|
-
assert function_decl.parameters.properties['input_dir'].type == 'ARRAY'
|
231
|
-
assert function_decl.parameters.properties['input_dir'].items.type == 'OBJECT'
|
232
|
-
|
233
|
-
|
234
|
-
def test_basemodel_list():
|
235
|
-
class ChildInput(BaseModel):
|
236
|
-
input_str: str
|
237
|
-
|
238
|
-
class CustomInput(BaseModel):
|
239
|
-
child: ChildInput
|
240
|
-
|
241
|
-
def simple_function(input_str: List[CustomInput]) -> str:
|
242
|
-
return {'result': input_str}
|
243
|
-
|
244
|
-
function_decl = _automatic_function_calling_util.build_function_declaration(
|
245
|
-
func=simple_function
|
246
|
-
)
|
247
|
-
|
248
|
-
assert function_decl.name == 'simple_function'
|
249
|
-
assert function_decl.parameters.type == 'OBJECT'
|
250
|
-
assert function_decl.parameters.properties['input_str'].type == 'ARRAY'
|
251
|
-
assert function_decl.parameters.properties['input_str'].items.type == 'OBJECT'
|
252
|
-
assert (
|
253
|
-
function_decl.parameters.properties['input_str']
|
254
|
-
.items.properties['child']
|
255
|
-
.type
|
256
|
-
== 'OBJECT'
|
257
|
-
)
|
258
|
-
assert (
|
259
|
-
function_decl.parameters.properties['input_str']
|
260
|
-
.items.properties['child']
|
261
|
-
.properties['input_str']
|
262
|
-
.type
|
263
|
-
== 'STRING'
|
264
|
-
)
|
265
|
-
|
266
|
-
|
267
|
-
# TODO: comment out this test for now as crewai requires python 3.10 as minimum
|
268
|
-
# def test_crewai_tool():
|
269
|
-
# docs_tool = CrewaiTool(
|
270
|
-
# name='direcotry_read_tool',
|
271
|
-
# description='use this to find files for you.',
|
272
|
-
# tool=FileReadTool(),
|
273
|
-
# )
|
274
|
-
# function_decl = docs_tool.get_declaration()
|
275
|
-
# assert function_decl.name == 'direcotry_read_tool'
|
276
|
-
# assert function_decl.parameters.type == 'OBJECT'
|
277
|
-
# assert function_decl.parameters.properties['file_path'].type == 'STRING'
|
@@ -1,304 +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
|
-
import asyncio
|
16
|
-
import contextlib
|
17
|
-
from typing import AsyncGenerator
|
18
|
-
from typing import Generator
|
19
|
-
from typing import Union
|
20
|
-
|
21
|
-
from google.adk.agents.invocation_context import InvocationContext
|
22
|
-
from google.adk.agents.live_request_queue import LiveRequestQueue
|
23
|
-
from google.adk.agents.llm_agent import Agent
|
24
|
-
from google.adk.agents.llm_agent import LlmAgent
|
25
|
-
from google.adk.agents.run_config import RunConfig
|
26
|
-
from google.adk.artifacts import InMemoryArtifactService
|
27
|
-
from google.adk.events.event import Event
|
28
|
-
from google.adk.memory.in_memory_memory_service import InMemoryMemoryService
|
29
|
-
from google.adk.models.base_llm import BaseLlm
|
30
|
-
from google.adk.models.base_llm_connection import BaseLlmConnection
|
31
|
-
from google.adk.models.llm_request import LlmRequest
|
32
|
-
from google.adk.models.llm_response import LlmResponse
|
33
|
-
from google.adk.runners import InMemoryRunner as AfInMemoryRunner
|
34
|
-
from google.adk.runners import Runner
|
35
|
-
from google.adk.sessions.in_memory_session_service import InMemorySessionService
|
36
|
-
from google.adk.sessions.session import Session
|
37
|
-
from google.genai import types
|
38
|
-
from google.genai.types import Part
|
39
|
-
from typing_extensions import override
|
40
|
-
|
41
|
-
|
42
|
-
class UserContent(types.Content):
|
43
|
-
|
44
|
-
def __init__(self, text_or_part: str):
|
45
|
-
parts = [
|
46
|
-
types.Part.from_text(text=text_or_part)
|
47
|
-
if isinstance(text_or_part, str)
|
48
|
-
else text_or_part
|
49
|
-
]
|
50
|
-
super().__init__(role='user', parts=parts)
|
51
|
-
|
52
|
-
|
53
|
-
class ModelContent(types.Content):
|
54
|
-
|
55
|
-
def __init__(self, parts: list[types.Part]):
|
56
|
-
super().__init__(role='model', parts=parts)
|
57
|
-
|
58
|
-
|
59
|
-
def create_invocation_context(agent: Agent, user_content: str = ''):
|
60
|
-
invocation_id = 'test_id'
|
61
|
-
artifact_service = InMemoryArtifactService()
|
62
|
-
session_service = InMemorySessionService()
|
63
|
-
memory_service = InMemoryMemoryService()
|
64
|
-
invocation_context = InvocationContext(
|
65
|
-
artifact_service=artifact_service,
|
66
|
-
session_service=session_service,
|
67
|
-
memory_service=memory_service,
|
68
|
-
invocation_id=invocation_id,
|
69
|
-
agent=agent,
|
70
|
-
session=session_service.create_session(
|
71
|
-
app_name='test_app', user_id='test_user'
|
72
|
-
),
|
73
|
-
user_content=types.Content(
|
74
|
-
role='user', parts=[types.Part.from_text(text=user_content)]
|
75
|
-
),
|
76
|
-
run_config=RunConfig(),
|
77
|
-
)
|
78
|
-
if user_content:
|
79
|
-
append_user_content(
|
80
|
-
invocation_context, [types.Part.from_text(text=user_content)]
|
81
|
-
)
|
82
|
-
return invocation_context
|
83
|
-
|
84
|
-
|
85
|
-
def append_user_content(
|
86
|
-
invocation_context: InvocationContext, parts: list[types.Part]
|
87
|
-
) -> Event:
|
88
|
-
session = invocation_context.session
|
89
|
-
event = Event(
|
90
|
-
invocation_id=invocation_context.invocation_id,
|
91
|
-
author='user',
|
92
|
-
content=types.Content(role='user', parts=parts),
|
93
|
-
)
|
94
|
-
session.events.append(event)
|
95
|
-
return event
|
96
|
-
|
97
|
-
|
98
|
-
# Extracts the contents from the events and transform them into a list of
|
99
|
-
# (author, simplified_content) tuples.
|
100
|
-
def simplify_events(events: list[Event]) -> list[(str, types.Part)]:
|
101
|
-
return [(event.author, simplify_content(event.content)) for event in events]
|
102
|
-
|
103
|
-
|
104
|
-
# Simplifies the contents into a list of (author, simplified_content) tuples.
|
105
|
-
def simplify_contents(contents: list[types.Content]) -> list[(str, types.Part)]:
|
106
|
-
return [(content.role, simplify_content(content)) for content in contents]
|
107
|
-
|
108
|
-
|
109
|
-
# Simplifies the content so it's easier to assert.
|
110
|
-
# - If there is only one part, return part
|
111
|
-
# - If the only part is pure text, return stripped_text
|
112
|
-
# - If there are multiple parts, return parts
|
113
|
-
# - remove function_call_id if it exists
|
114
|
-
def simplify_content(
|
115
|
-
content: types.Content,
|
116
|
-
) -> Union[str, types.Part, list[types.Part]]:
|
117
|
-
for part in content.parts:
|
118
|
-
if part.function_call and part.function_call.id:
|
119
|
-
part.function_call.id = None
|
120
|
-
if part.function_response and part.function_response.id:
|
121
|
-
part.function_response.id = None
|
122
|
-
if len(content.parts) == 1:
|
123
|
-
if content.parts[0].text:
|
124
|
-
return content.parts[0].text.strip()
|
125
|
-
else:
|
126
|
-
return content.parts[0]
|
127
|
-
return content.parts
|
128
|
-
|
129
|
-
|
130
|
-
def get_user_content(message: types.ContentUnion) -> types.Content:
|
131
|
-
return message if isinstance(message, types.Content) else UserContent(message)
|
132
|
-
|
133
|
-
|
134
|
-
class TestInMemoryRunner(AfInMemoryRunner):
|
135
|
-
"""InMemoryRunner that is tailored for tests, features async run method.
|
136
|
-
|
137
|
-
app_name is hardcoded as InMemoryRunner in the parent class.
|
138
|
-
"""
|
139
|
-
|
140
|
-
async def run_async_with_new_session(
|
141
|
-
self, new_message: types.ContentUnion
|
142
|
-
) -> list[Event]:
|
143
|
-
|
144
|
-
session = self.session_service.create_session(
|
145
|
-
app_name='InMemoryRunner', user_id='test_user'
|
146
|
-
)
|
147
|
-
collected_events = []
|
148
|
-
|
149
|
-
async for event in self.run_async(
|
150
|
-
user_id=session.user_id,
|
151
|
-
session_id=session.id,
|
152
|
-
new_message=get_user_content(new_message),
|
153
|
-
):
|
154
|
-
collected_events.append(event)
|
155
|
-
|
156
|
-
return collected_events
|
157
|
-
|
158
|
-
|
159
|
-
class InMemoryRunner:
|
160
|
-
"""InMemoryRunner that is tailored for tests."""
|
161
|
-
|
162
|
-
def __init__(
|
163
|
-
self,
|
164
|
-
root_agent: Union[Agent, LlmAgent],
|
165
|
-
response_modalities: list[str] = None,
|
166
|
-
):
|
167
|
-
self.root_agent = root_agent
|
168
|
-
self.runner = Runner(
|
169
|
-
app_name='test_app',
|
170
|
-
agent=root_agent,
|
171
|
-
artifact_service=InMemoryArtifactService(),
|
172
|
-
session_service=InMemorySessionService(),
|
173
|
-
memory_service=InMemoryMemoryService(),
|
174
|
-
)
|
175
|
-
self.session_id = self.runner.session_service.create_session(
|
176
|
-
app_name='test_app', user_id='test_user'
|
177
|
-
).id
|
178
|
-
|
179
|
-
@property
|
180
|
-
def session(self) -> Session:
|
181
|
-
return self.runner.session_service.get_session(
|
182
|
-
app_name='test_app', user_id='test_user', session_id=self.session_id
|
183
|
-
)
|
184
|
-
|
185
|
-
def run(self, new_message: types.ContentUnion) -> list[Event]:
|
186
|
-
return list(
|
187
|
-
self.runner.run(
|
188
|
-
user_id=self.session.user_id,
|
189
|
-
session_id=self.session.id,
|
190
|
-
new_message=get_user_content(new_message),
|
191
|
-
)
|
192
|
-
)
|
193
|
-
|
194
|
-
def run_live(self, live_request_queue: LiveRequestQueue) -> list[Event]:
|
195
|
-
collected_responses = []
|
196
|
-
|
197
|
-
async def consume_responses():
|
198
|
-
run_res = self.runner.run_live(
|
199
|
-
session=self.session,
|
200
|
-
live_request_queue=live_request_queue,
|
201
|
-
)
|
202
|
-
|
203
|
-
async for response in run_res:
|
204
|
-
collected_responses.append(response)
|
205
|
-
# When we have enough response, we should return
|
206
|
-
if len(collected_responses) >= 1:
|
207
|
-
return
|
208
|
-
|
209
|
-
try:
|
210
|
-
asyncio.run(consume_responses())
|
211
|
-
except asyncio.TimeoutError:
|
212
|
-
print('Returning any partial results collected so far.')
|
213
|
-
|
214
|
-
return collected_responses
|
215
|
-
|
216
|
-
|
217
|
-
class MockModel(BaseLlm):
|
218
|
-
model: str = 'mock'
|
219
|
-
|
220
|
-
requests: list[LlmRequest] = []
|
221
|
-
responses: list[LlmResponse]
|
222
|
-
response_index: int = -1
|
223
|
-
|
224
|
-
@classmethod
|
225
|
-
def create(
|
226
|
-
cls,
|
227
|
-
responses: Union[
|
228
|
-
list[types.Part], list[LlmResponse], list[str], list[list[types.Part]]
|
229
|
-
],
|
230
|
-
):
|
231
|
-
if not responses:
|
232
|
-
return cls(responses=[])
|
233
|
-
elif isinstance(responses[0], LlmResponse):
|
234
|
-
# reponses is list[LlmResponse]
|
235
|
-
return cls(responses=responses)
|
236
|
-
else:
|
237
|
-
responses = [
|
238
|
-
LlmResponse(content=ModelContent(item))
|
239
|
-
if isinstance(item, list) and isinstance(item[0], types.Part)
|
240
|
-
# responses is list[list[Part]]
|
241
|
-
else LlmResponse(
|
242
|
-
content=ModelContent(
|
243
|
-
# responses is list[str] or list[Part]
|
244
|
-
[Part(text=item) if isinstance(item, str) else item]
|
245
|
-
)
|
246
|
-
)
|
247
|
-
for item in responses
|
248
|
-
if item
|
249
|
-
]
|
250
|
-
|
251
|
-
return cls(responses=responses)
|
252
|
-
|
253
|
-
@staticmethod
|
254
|
-
def supported_models() -> list[str]:
|
255
|
-
return ['mock']
|
256
|
-
|
257
|
-
def generate_content(
|
258
|
-
self, llm_request: LlmRequest, stream: bool = False
|
259
|
-
) -> Generator[LlmResponse, None, None]:
|
260
|
-
# Increasement of the index has to happen before the yield.
|
261
|
-
self.response_index += 1
|
262
|
-
self.requests.append(llm_request)
|
263
|
-
# yield LlmResponse(content=self.responses[self.response_index])
|
264
|
-
yield self.responses[self.response_index]
|
265
|
-
|
266
|
-
@override
|
267
|
-
async def generate_content_async(
|
268
|
-
self, llm_request: LlmRequest, stream: bool = False
|
269
|
-
) -> AsyncGenerator[LlmResponse, None]:
|
270
|
-
# Increasement of the index has to happen before the yield.
|
271
|
-
self.response_index += 1
|
272
|
-
self.requests.append(llm_request)
|
273
|
-
yield self.responses[self.response_index]
|
274
|
-
|
275
|
-
@contextlib.asynccontextmanager
|
276
|
-
async def connect(self, llm_request: LlmRequest) -> BaseLlmConnection:
|
277
|
-
"""Creates a live connection to the LLM."""
|
278
|
-
yield MockLlmConnection(self.responses)
|
279
|
-
|
280
|
-
|
281
|
-
class MockLlmConnection(BaseLlmConnection):
|
282
|
-
|
283
|
-
def __init__(self, llm_responses: list[LlmResponse]):
|
284
|
-
self.llm_responses = llm_responses
|
285
|
-
|
286
|
-
async def send_history(self, history: list[types.Content]):
|
287
|
-
pass
|
288
|
-
|
289
|
-
async def send_content(self, content: types.Content):
|
290
|
-
pass
|
291
|
-
|
292
|
-
async def send(self, data):
|
293
|
-
pass
|
294
|
-
|
295
|
-
async def send_realtime(self, blob: types.Blob):
|
296
|
-
pass
|
297
|
-
|
298
|
-
async def receive(self) -> AsyncGenerator[LlmResponse, None]:
|
299
|
-
"""Yield each of the pre-defined LlmResponses."""
|
300
|
-
for response in self.llm_responses:
|
301
|
-
yield response
|
302
|
-
|
303
|
-
async def close(self):
|
304
|
-
pass
|