Skip to content

Commit b1b2a74

Browse files
authored
Merge pull request #143 from UiPath/fix/open_ai_samples
fix: multi layer agents schema
2 parents d0b408b + 3c544f0 commit b1b2a74

4 files changed

Lines changed: 487 additions & 62 deletions

File tree

packages/uipath-openai-agents/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uipath-openai-agents"
3-
version = "0.0.2"
3+
version = "0.0.3"
44
description = "UiPath OpenAI Agents SDK"
55
readme = "README.md"
66
requires-python = ">=3.11"

packages/uipath-openai-agents/src/uipath_openai_agents/runtime/schema.py

Lines changed: 113 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)