22
33将标准工具定义转换为 Google ADK 函数格式。"""
44
5- from typing import List , Optional
5+ from typing import Any , Dict , List , Optional
66
77from agentrun .integration .utils .adapter import ToolAdapter
88from agentrun .integration .utils .canonical import CanonicalTool
99
1010
11+ def _json_schema_to_google_schema (
12+ schema : Dict [str , Any ],
13+ root_schema : Optional [Dict [str , Any ]] = None ,
14+ ) -> Any :
15+ """将 JSON Schema 转换为 Google ADK Schema
16+
17+ Google ADK 不支持 $ref 和 $defs,所以需要内联所有引用。
18+
19+ Args:
20+ schema: JSON Schema 定义
21+ root_schema: 根 schema,用于解析 $ref 引用
22+
23+ Returns:
24+ Google ADK types.Schema 对象
25+ """
26+ from google .genai import types
27+
28+ if not schema or not isinstance (schema , dict ):
29+ return types .Schema (type = types .Type .OBJECT )
30+
31+ if root_schema is None :
32+ root_schema = schema
33+
34+ # 处理 $ref 引用
35+ if "$ref" in schema :
36+ ref = schema ["$ref" ]
37+ resolved = _resolve_schema_ref (ref , root_schema )
38+ if resolved :
39+ return _json_schema_to_google_schema (resolved , root_schema )
40+ return types .Schema (type = types .Type .OBJECT )
41+
42+ schema_type = schema .get ("type" )
43+ description = schema .get ("description" )
44+
45+ # 类型映射
46+ type_mapping = {
47+ "string" : types .Type .STRING ,
48+ "integer" : types .Type .INTEGER ,
49+ "number" : types .Type .NUMBER ,
50+ "boolean" : types .Type .BOOLEAN ,
51+ "array" : types .Type .ARRAY ,
52+ "object" : types .Type .OBJECT ,
53+ }
54+
55+ google_type = type_mapping .get (
56+ str (schema_type or "object" ), types .Type .OBJECT
57+ )
58+
59+ # 处理数组类型
60+ if schema_type == "array" :
61+ items_schema = schema .get ("items" )
62+ items = None
63+ if items_schema :
64+ items = _json_schema_to_google_schema (items_schema , root_schema )
65+ return types .Schema (
66+ type = google_type ,
67+ description = description ,
68+ items = items ,
69+ )
70+
71+ # 处理对象类型
72+ if schema_type == "object" :
73+ props = schema .get ("properties" , {})
74+ required = schema .get ("required" , [])
75+
76+ google_props = {}
77+ for prop_name , prop_schema in props .items ():
78+ google_props [prop_name ] = _json_schema_to_google_schema (
79+ prop_schema , root_schema
80+ )
81+
82+ return types .Schema (
83+ type = google_type ,
84+ description = description ,
85+ properties = google_props if google_props else None ,
86+ required = required if required else None ,
87+ )
88+
89+ # 基本类型
90+ return types .Schema (
91+ type = google_type ,
92+ description = description ,
93+ )
94+
95+
96+ def _resolve_schema_ref (
97+ ref : str , root_schema : Dict [str , Any ]
98+ ) -> Optional [Dict [str , Any ]]:
99+ """解析 JSON Schema $ref 引用
100+
101+ Args:
102+ ref: $ref 字符串,如 "#/$defs/MyType" 或 "#/definitions/MyType"
103+ root_schema: 根 schema,包含 $defs 或 definitions
104+
105+ Returns:
106+ 解析后的 schema,如果无法解析则返回 None
107+ """
108+ if not ref or not ref .startswith ("#/" ):
109+ return None
110+
111+ # 解析路径,如 "#/$defs/MyType" -> ["$defs", "MyType"]
112+ path_parts = ref [2 :].split ("/" )
113+ current = root_schema
114+
115+ for part in path_parts :
116+ if not isinstance (current , dict ) or part not in current :
117+ return None
118+ current = current [part ]
119+
120+ return current if isinstance (current , dict ) else None
121+
122+
123+ def _create_custom_function_tool_class ():
124+ """创建自定义 FunctionTool 类
125+
126+ 延迟创建以避免在模块导入时依赖 google.adk。
127+ """
128+ from google .adk .tools .base_tool import BaseTool
129+
130+ class CustomFunctionTool (BaseTool ):
131+ """自定义 Google ADK 工具类
132+
133+ 允许手动指定 FunctionDeclaration,避免 Pydantic 模型的 $ref 问题。
134+ 继承自 google.adk.tools.BaseTool 以确保与 ADK Agent 兼容。
135+ """
136+
137+ def __init__ (
138+ self ,
139+ func ,
140+ declaration ,
141+ ):
142+ # 调用父类 __init__,传递 name 和 description
143+ super ().__init__ (
144+ name = declaration .name ,
145+ description = declaration .description or "" ,
146+ )
147+ self ._func = func
148+ self ._declaration = declaration
149+
150+ def _get_declaration (self ):
151+ return self ._declaration
152+
153+ async def run_async (self , * , args : Dict [str , Any ], tool_context ):
154+ """异步执行工具函数"""
155+ return self ._func (** args )
156+
157+ return CustomFunctionTool
158+
159+
160+ # 缓存类,避免重复创建
161+ _CustomFunctionToolClass = None
162+
163+
164+ def _get_custom_function_tool_class ():
165+ """获取 CustomFunctionTool 类(延迟加载)"""
166+ global _CustomFunctionToolClass
167+ if _CustomFunctionToolClass is None :
168+ _CustomFunctionToolClass = _create_custom_function_tool_class ()
169+ return _CustomFunctionToolClass
170+
171+
11172class GoogleADKToolAdapter (ToolAdapter ):
12173 """Google ADK 工具适配器 / Google ADK Tool Adapter
13174
14175 实现 CanonicalTool → Google ADK 函数的转换。
15- Google ADK 直接使用 Python 函数作为工具。"""
176+ 由于 Google ADK 不支持复杂的 JSON Schema(包含 $ref 和 $defs),
177+ 此适配器会手动构建 FunctionDeclaration 并使用自定义工具类。
178+ """
16179
17180 def get_registered_tool (self , name : str ) -> Optional [CanonicalTool ]:
18181 """根据名称获取最近注册的工具定义 / Google ADK Tool Adapter"""
@@ -21,5 +184,51 @@ def get_registered_tool(self, name: str) -> Optional[CanonicalTool]:
21184 def from_canonical (self , tools : List [CanonicalTool ]):
22185 """将标准格式转换为 Google ADK 工具 / Google ADK Tool Adapter
23186
24- Google ADK 通过函数的类型注解推断参数,需要动态创建带注解的函数。"""
25- return self .function_tools (tools )
187+ 为每个工具创建自定义的 FunctionTool,手动指定参数 schema,
188+ 以避免 Pydantic 模型产生的 $ref 问题。
189+ """
190+ from google .genai import types
191+
192+ result = []
193+
194+ for tool in tools :
195+ # 记录工具定义
196+ self ._registered_tools [tool .name ] = tool
197+
198+ # 从 parameters schema 构建 Google ADK Schema
199+ parameters_schema = tool .parameters or {
200+ "type" : "object" ,
201+ "properties" : {},
202+ }
203+
204+ google_schema = _json_schema_to_google_schema (
205+ parameters_schema , parameters_schema
206+ )
207+
208+ # 创建 FunctionDeclaration
209+ declaration = types .FunctionDeclaration (
210+ name = tool .name ,
211+ description = tool .description or "" ,
212+ parameters = google_schema ,
213+ )
214+
215+ # 创建包装函数
216+ def make_wrapper (canonical_tool : CanonicalTool ):
217+ def wrapper (** kwargs ):
218+ if canonical_tool .func is None :
219+ raise NotImplementedError (
220+ f"Tool function for '{ canonical_tool .name } ' "
221+ "is not implemented."
222+ )
223+ return canonical_tool .func (** kwargs )
224+
225+ return wrapper
226+
227+ wrapper_func = make_wrapper (tool )
228+
229+ # 创建自定义工具
230+ CustomFunctionTool = _get_custom_function_tool_class ()
231+ custom_tool = CustomFunctionTool (wrapper_func , declaration )
232+ result .append (custom_tool )
233+
234+ return result
0 commit comments