@@ -85,23 +85,23 @@ def sanitize_messages_for_llm(msgs: List[Any]) -> List[Any]:
8585 for m in msgs :
8686 if isinstance (m , _AI ):
8787 try :
88- for tc in getattr ( m , " tool_calls" , []) or []:
88+ for tc in m . tool_calls or []:
8989 if isinstance (tc , dict ):
9090 tid = tc .get ("id" ) or tc .get ("tool_call_id" )
9191 if tid :
9292 seen_tool_ids .add (tid )
9393 except Exception :
9494 pass
9595 clean .append (m )
96- elif isinstance (m , _TM ) or getattr ( m , " type" , "" ) == "tool" :
97- tid = getattr ( m , " tool_call_id" , None )
96+ elif isinstance (m , _TM ) or m . type == "tool" :
97+ tid = m . tool_call_id
9898 if tid and tid in seen_tool_ids :
9999 clean .append (m )
100100 else :
101101 continue
102102 else :
103103 clean .append (m )
104- while clean and (isinstance (clean [0 ], _TM ) or getattr ( clean [0 ], " type" , "" ) == "tool" ):
104+ while clean and (isinstance (clean [0 ], _TM ) or clean [0 ]. type == "tool" ):
105105 clean = clean [1 :]
106106 return clean
107107
@@ -122,26 +122,26 @@ def _compact_messages_tail(msgs: List[Any], limit: int = 6) -> List[Dict[str, An
122122 tail = msgs [- limit :] if msgs else []
123123 compact : List [Dict [str , Any ]] = []
124124 for m in tail :
125- role = getattr ( m , " type" , m .__class__ .__name__ .lower () )
125+ role = m . type if m . type else m .__class__ .__name__ .lower ()
126126 row : Dict [str , Any ] = {"role" : role }
127127 try :
128- is_ai = (_AI is not None and isinstance (m , _AI )) or getattr ( m , " type" , "" ) in (
128+ is_ai = (_AI is not None and isinstance (m , _AI )) or m . type in (
129129 "ai" ,
130130 "assistant" ,
131131 )
132132 if is_ai :
133133 ids : List [str ] = []
134- for tc in getattr ( m , " tool_calls" , []) or []:
134+ for tc in m . tool_calls or []:
135135 if isinstance (tc , dict ):
136136 tid = tc .get ("id" ) or tc .get ("tool_call_id" )
137137 if tid :
138138 ids .append (tid )
139139 if ids :
140140 row ["tool_calls" ] = ids
141- is_tool = (_TM is not None and isinstance (m , _TM )) or getattr ( m , " type" , "" ) == "tool"
141+ is_tool = (_TM is not None and isinstance (m , _TM )) or m . type == "tool"
142142 if is_tool :
143- row ["tool_call_id" ] = getattr ( m , " tool_call_id" , None )
144- name = getattr ( m , " name" , None )
143+ row ["tool_call_id" ] = m . tool_call_id
144+ name = m . name
145145 if name :
146146 row ["name" ] = name
147147 except Exception :
@@ -193,7 +193,7 @@ def build_result_envelope(
193193
194194 from .models import ResultEnvelope
195195
196- content = getattr ( tool_message , " content" , None )
196+ content = tool_message . content
197197 data_obj = None
198198 if isinstance (content , str ) and content :
199199 try :
@@ -210,9 +210,8 @@ def _extract_operation_from_tool_name(full: str) -> str:
210210 parts = full .split ("." )
211211 return parts [- 1 ] if parts else full
212212
213- description = (
214- getattr (tooldefs_by_name .get (tool_name ), "description" , None ) if tool_name else None
215- )
213+ tdef = tooldefs_by_name .get (tool_name ) if tool_name else None
214+ description = tdef .description if tdef else None
216215 env = ResultEnvelope (
217216 tool_key = tool_name or "tool" ,
218217 name = _extract_operation_from_tool_name (tool_name or "tool" ),
@@ -224,13 +223,15 @@ def _extract_operation_from_tool_name(full: str) -> str:
224223 return env .model_dump ()
225224
226225
227- async def build_adapters_for_tooldefs (
228- tool_manager : Any , tooldefs : List [Any ]
229- ) -> tuple [list [dict ], list [Any ]]:
230- """Create OpenAI tool schemas and LangChain StructuredTool adapters for ToolDefinitions.
226+ async def build_adapters_for_tooldefs (tool_manager : Any , tooldefs : List [Any ]) -> list [Any ]:
227+ """Create LangChain StructuredTool adapters for ToolDefinitions.
231228
232- Returns (tool_schemas, adapters)
229+ Each adapter wraps :meth:`ToolManager.resolve_tool_call` so that tools can
230+ be executed either via LangGraph's :class:`ToolNode` or directly via the
231+ manager. The same adapters can also be passed to ``ChatOpenAI.bind_tools``
232+ so we do not need to maintain separate OpenAI-specific tool schemas.
233233 """
234+
234235 try :
235236 from typing import Any as _Any
236237
@@ -241,7 +242,7 @@ async def build_adapters_for_tooldefs(
241242 from pydantic import create_model as _create_model
242243 except Exception :
243244 # Best-effort fallback (should not happen in runtime)
244- return [], []
245+ return []
245246
246247 def _args_model_from_parameters (tool_name : str , params : dict ) -> type [_BaseModel ]:
247248 props = (params or {}).get ("properties" , {}) or {}
@@ -261,20 +262,19 @@ def _args_model_from_parameters(tool_name: str, params: dict) -> type[_BaseModel
261262 pass
262263 return args_model
263264
264- tool_schemas : list [dict ] = [t .to_openai_schema () for t in (tooldefs or [])]
265265 adapters : list [_StructuredTool ] = []
266266 for tdef in tooldefs or []:
267267
268268 async def _exec_fn (_name = tdef .name , ** kwargs ):
269269 return await tool_manager .resolve_tool_call (_name , kwargs or {})
270270
271- ArgsModel = _args_model_from_parameters (tdef .name , getattr ( tdef , " parameters" , {}) or {}) # noqa: N806
271+ args_model = _args_model_from_parameters (tdef .name , tdef . parameters or {})
272272 adapters .append (
273273 _StructuredTool .from_function (
274274 coroutine = _exec_fn ,
275275 name = tdef .name ,
276- description = getattr ( tdef , " description" , "" ) or "" ,
277- args_schema = ArgsModel ,
276+ description = tdef . description or "" ,
277+ args_schema = args_model ,
278278 )
279279 )
280- return tool_schemas , adapters
280+ return adapters
0 commit comments