@@ -143,8 +143,9 @@ def get_agent_schema(agent: Agent) -> UiPathRuntimeGraph:
143143 """
144144 Extract graph structure from an OpenAI Agent.
145145
146- OpenAI Agents can delegate to other agents through handoffs,
147- creating a hierarchical agent structure.
146+ OpenAI Agents are represented as simple nodes. Regular tools are aggregated
147+ into a single tools node per agent with metadata. Agent-tools and handoff
148+ agents are represented as separate agent nodes.
148149
149150 Args:
150151 agent: An OpenAI Agent instance
@@ -154,109 +155,161 @@ def get_agent_schema(agent: Agent) -> UiPathRuntimeGraph:
154155 """
155156 nodes : list [UiPathRuntimeNode ] = []
156157 edges : list [UiPathRuntimeEdge ] = []
157-
158- # Start node
159- nodes .append (
160- UiPathRuntimeNode (
161- id = "__start__" ,
162- name = "__start__" ,
163- type = "__start__" ,
164- subgraph = None ,
165- )
166- )
167-
168- # Main agent node (always type "model" since it's an LLM)
169- agent_name = getattr (agent , "name" , "agent" )
170- nodes .append (
171- UiPathRuntimeNode (
172- id = agent_name ,
173- name = agent_name ,
174- type = "model" ,
175- subgraph = None ,
158+ visited : set [str ] = set () # Track visited agents to avoid circular references
159+
160+ def _add_agent_and_tools (current_agent : Agent ) -> None :
161+ """Recursively add agent, its tools, and nested agents to the graph."""
162+ agent_name = getattr (current_agent , "name" , "agent" )
163+
164+ # Prevent circular references using agent name
165+ if agent_name in visited :
166+ return
167+ visited .add (agent_name )
168+
169+ # Add agent node (first visit always adds the node)
170+ nodes .append (
171+ UiPathRuntimeNode (
172+ id = agent_name ,
173+ name = agent_name ,
174+ type = "node" ,
175+ subgraph = None ,
176+ metadata = None ,
177+ )
176178 )
177- )
178179
179- # Connect start to main agent
180- edges .append (
181- UiPathRuntimeEdge (
182- source = "__start__" ,
183- target = agent_name ,
184- label = "input" ,
185- )
186- )
180+ # Process tools - separate agent-tools from regular tools
181+ tools = getattr (current_agent , "tools" , None ) or []
182+ agent_tools : list [Agent ] = []
183+ regular_tools : list [Any ] = []
187184
188- # Add tool nodes if tools are available
189- tools = getattr (agent , "tools" , None ) or []
190- if tools :
191185 for tool in tools :
192- # Extract tool name - handle various tool types
193- tool_name = _get_tool_name (tool )
194- if tool_name :
186+ if isinstance (tool , Agent ):
187+ agent_tools .append (tool )
188+ else :
189+ regular_tools .append (tool )
190+
191+ # Process agent-tools (agents used as tools)
192+ for tool_agent in agent_tools :
193+ tool_agent_name = getattr (tool_agent , "name" , _get_tool_name (tool_agent ))
194+ if tool_agent_name and tool_agent_name not in visited :
195+ # Recursively process agent-tool
196+ _add_agent_and_tools (tool_agent )
197+
198+ # Add edges for agent-tool
199+ edges .append (
200+ UiPathRuntimeEdge (
201+ source = agent_name ,
202+ target = tool_agent_name ,
203+ label = "tool_call" ,
204+ )
205+ )
206+ edges .append (
207+ UiPathRuntimeEdge (
208+ source = tool_agent_name ,
209+ target = agent_name ,
210+ label = "tool_result" ,
211+ )
212+ )
213+
214+ # Process regular tools - aggregate into single tools node
215+ if regular_tools :
216+ tool_names = [_get_tool_name (tool ) for tool in regular_tools ]
217+ tool_names = [name for name in tool_names if name ] # Filter out None values
218+
219+ if tool_names :
220+ # Create a single tools node for this agent
221+ tools_node_id = f"{ agent_name } _tools"
195222 nodes .append (
196223 UiPathRuntimeNode (
197- id = tool_name ,
198- name = tool_name ,
224+ id = tools_node_id ,
225+ name = "tools" ,
199226 type = "tool" ,
200227 subgraph = None ,
228+ metadata = {
229+ "tool_names" : tool_names ,
230+ "tool_count" : len (tool_names ),
231+ },
201232 )
202233 )
203- # Bidirectional edges: agent calls tool, tool returns to agent
234+
235+ # Add bidirectional edges for tools node
204236 edges .append (
205237 UiPathRuntimeEdge (
206238 source = agent_name ,
207- target = tool_name ,
208- label = "tool_call" ,
239+ target = tools_node_id ,
240+ label = None ,
209241 )
210242 )
211243 edges .append (
212244 UiPathRuntimeEdge (
213- source = tool_name ,
245+ source = tools_node_id ,
214246 target = agent_name ,
215- label = "tool_result" ,
247+ label = None ,
216248 )
217249 )
218250
219- # Add handoff agents as nodes
220- handoffs = getattr (agent , "handoffs" , None ) or []
221- if handoffs :
251+ # Process handoff agents
252+ handoffs = getattr (current_agent , "handoffs" , None ) or []
222253 for handoff_agent in handoffs :
223254 handoff_name = getattr (handoff_agent , "name" , None )
224- if handoff_name :
225- nodes .append (
226- UiPathRuntimeNode (
227- id = handoff_name ,
228- name = handoff_name ,
229- type = "model" ,
230- subgraph = None , # Handoff agents are peers, not subgraphs
231- )
232- )
233- # Handoff edges
255+ if handoff_name and handoff_name not in visited :
256+ # Recursively process handoff agent
257+ _add_agent_and_tools (handoff_agent )
258+
259+ # Add handoff edges without labels
234260 edges .append (
235261 UiPathRuntimeEdge (
236262 source = agent_name ,
237263 target = handoff_name ,
238- label = "handoff" ,
264+ label = None ,
239265 )
240266 )
241267 edges .append (
242268 UiPathRuntimeEdge (
243269 source = handoff_name ,
244270 target = agent_name ,
245- label = "handoff_complete" ,
271+ label = None ,
246272 )
247273 )
248274
249- # End node
275+ # Add __start__ node
276+ nodes .append (
277+ UiPathRuntimeNode (
278+ id = "__start__" ,
279+ name = "__start__" ,
280+ type = "__start__" ,
281+ subgraph = None ,
282+ metadata = None ,
283+ )
284+ )
285+
286+ # Recursively build graph starting from main agent
287+ _add_agent_and_tools (agent )
288+
289+ # Get the main agent name
290+ agent_name = getattr (agent , "name" , "agent" )
291+
292+ # Add __end__ node
250293 nodes .append (
251294 UiPathRuntimeNode (
252295 id = "__end__" ,
253296 name = "__end__" ,
254297 type = "__end__" ,
255298 subgraph = None ,
299+ metadata = None ,
300+ )
301+ )
302+
303+ # Connect start to main agent
304+ edges .append (
305+ UiPathRuntimeEdge (
306+ source = "__start__" ,
307+ target = agent_name ,
308+ label = "input" ,
256309 )
257310 )
258311
259- # Connect agent to end
312+ # Connect main agent to end
260313 edges .append (
261314 UiPathRuntimeEdge (
262315 source = agent_name ,
0 commit comments