15
15
from __future__ import annotations
16
16
17
17
from abc import ABC
18
+ import inspect
19
+ import logging
18
20
from typing import Any
21
+ from typing import Callable
22
+ from typing import get_args
23
+ from typing import get_origin
24
+ from typing import get_type_hints
19
25
from typing import Optional
20
26
from typing import Type
21
27
from typing import TYPE_CHECKING
22
28
from typing import TypeVar
29
+ from typing import Union
23
30
24
31
from google .genai import types
25
32
from pydantic import BaseModel
29
36
from ..utils .variant_utils import GoogleLLMVariant
30
37
from .tool_context import ToolContext
31
38
39
+ logger = logging .getLogger ("google_adk." + __name__ )
40
+
32
41
if TYPE_CHECKING :
33
42
from ..models .llm_request import LlmRequest
34
43
@@ -134,8 +143,9 @@ def from_config(
134
143
) -> SelfTool :
135
144
"""Creates a tool instance from a config.
136
145
137
- Subclasses should override and implement this method to do custom
138
- initialization from a config.
146
+ This default implementation uses inspect to automatically map config values
147
+ to constructor arguments based on their type hints. Subclasses should
148
+ override this method for custom initialization logic.
139
149
140
150
Args:
141
151
config: The config for the tool.
@@ -145,7 +155,66 @@ def from_config(
145
155
Returns:
146
156
The tool instance.
147
157
"""
148
- raise NotImplementedError (f"from_config for { cls } not implemented." )
158
+ from ..agents import config_agent_utils
159
+
160
+ # Get the constructor signature and resolve type hints
161
+ sig = inspect .signature (cls .__init__ )
162
+ type_hints = get_type_hints (cls .__init__ )
163
+ config_dict = config .model_dump ()
164
+ kwargs = {}
165
+
166
+ # Iterate through constructor parameters (skip "self")
167
+ for param_name , _ in sig .parameters .items ():
168
+ if param_name == "self" :
169
+ continue
170
+ param_type = type_hints .get (param_name )
171
+
172
+ if param_name in config_dict :
173
+ value = config_dict [param_name ]
174
+
175
+ # Get the actual type T of the parameter if it's Optional[T]
176
+ if get_origin (param_type ) is Union :
177
+ # This is Optional[T] which is Union[T, None]
178
+ args = get_args (param_type )
179
+ if len (args ) == 2 and type (None ) in args :
180
+ # Get the non-None type
181
+ actual_type = args [0 ] if args [1 ] is type (None ) else args [1 ]
182
+ param_type = actual_type
183
+
184
+ if param_type in (int , str , bool , float ):
185
+ kwargs [param_name ] = value
186
+ elif (
187
+ inspect .isclass (param_type )
188
+ and issubclass (param_type , BaseModel )
189
+ and value is not None
190
+ ):
191
+ kwargs [param_name ] = param_type .model_validate (value )
192
+ elif param_type is Callable or get_origin (param_type ) is Callable :
193
+ kwargs [param_name ] = config_agent_utils .resolve_fully_qualified_name (
194
+ value
195
+ )
196
+ elif param_type in (list , set , dict ):
197
+ kwargs [param_name ] = param_type (value )
198
+ elif get_origin (param_type ) is list :
199
+ list_args = get_args (param_type )
200
+ if issubclass (list_args [0 ], BaseModel ):
201
+ kwargs [param_name ] = [
202
+ list_args [0 ].model_validate (item ) for item in value
203
+ ]
204
+ elif list_args [0 ] in (int , str , bool , float ):
205
+ kwargs [param_name ] = value
206
+ elif list_args [0 ] is Callable or get_origin (list_args [0 ]) is Callable :
207
+ kwargs [param_name ] = [
208
+ config_agent_utils .resolve_fully_qualified_name (item )
209
+ for item in value
210
+ ]
211
+ else :
212
+ logger .warning (
213
+ "Unsupported parsing for list argument: %s." , param_name
214
+ )
215
+ else :
216
+ logger .warning ("Unsupported parsing for argument: %s." , param_name )
217
+ return cls (** kwargs )
149
218
150
219
151
220
def _find_tool_with_function_declarations (
@@ -218,9 +287,9 @@ class ToolConfig(BaseModel):
218
287
my_tool_arg2: value2
219
288
```
220
289
221
- 4. For user-defined functions that generate tool instances, the `name` is the
222
- fully qualified path to the function and `config` is passed to the function
223
- as arguments.
290
+ 4. For user-defined functions that generate tool instances, the `name` is
291
+ the fully qualified path to the function and `config` is passed to the
292
+ function as arguments.
224
293
225
294
```
226
295
tools:
0 commit comments