Skip to content

Commit e337e06

Browse files
committed
fix: schema generation for simple workflows
1 parent 52ba44e commit e337e06

3 files changed

Lines changed: 56 additions & 36 deletions

File tree

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-llamaindex"
3-
version = "0.1.2"
3+
version = "0.1.3"
44
description = "UiPath LlamaIndex SDK"
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.11"

src/uipath_llamaindex/runtime/schema.py

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@
2121
InputRequiredEvent,
2222
StopEvent,
2323
)
24-
from workflows.utils import (
25-
get_steps_from_class,
26-
get_steps_from_instance,
27-
)
2824

2925

3026
def get_entrypoints_schema(workflow: Workflow) -> dict[str, Any]:
@@ -128,7 +124,6 @@ def get_workflow_schema(workflow: Workflow) -> UiPathRuntimeGraph:
128124
nodes: list[UiPathRuntimeNode] = []
129125
edges: list[UiPathRuntimeEdge] = []
130126

131-
# Add __start__ node
132127
nodes.append(
133128
UiPathRuntimeNode(
134129
id="__start__",
@@ -139,19 +134,15 @@ def get_workflow_schema(workflow: Workflow) -> UiPathRuntimeGraph:
139134
)
140135
)
141136

142-
# Get all steps from the workflow
143-
steps = get_steps_from_class(workflow)
144-
if not steps:
145-
# If no steps are defined in the class, try to get them from the instance
146-
steps = get_steps_from_instance(workflow)
137+
steps = workflow._get_steps()
147138

148139
# Track if we need external step for human interaction
149140
has_human_interaction = False
150141
current_stop_event: type | None = None
151142

152143
# First pass: find the StopEvent used in this workflow and check for human interaction
153-
for _, step_func in steps.items():
154-
step_config: StepConfig | None = getattr(step_func, "__step_config", None)
144+
for name, step_func in steps.items():
145+
step_config: StepConfig | None = _get_step_config(name, step_func)
155146
if step_config is None:
156147
continue
157148

@@ -167,7 +158,7 @@ def get_workflow_schema(workflow: Workflow) -> UiPathRuntimeGraph:
167158

168159
# Create step nodes (all steps are type "node")
169160
for step_name, step_func in steps.items():
170-
step_config = getattr(step_func, "__step_config", None)
161+
step_config: StepConfig | None = _get_step_config(step_name, step_func)
171162
if step_config is None:
172163
continue
173164

@@ -204,12 +195,22 @@ def get_workflow_schema(workflow: Workflow) -> UiPathRuntimeGraph:
204195
)
205196
)
206197

198+
nodes.append(
199+
UiPathRuntimeNode(
200+
id="__end__",
201+
name="__end__",
202+
type="__end__",
203+
metadata={},
204+
subgraph=None,
205+
)
206+
)
207+
207208
# Create edges based on event flow
208209
start_event_class = workflow._start_event_class
209210
first_step_found = False
210211

211212
for step_name, step_func in steps.items():
212-
step_config = getattr(step_func, "__step_config", None)
213+
step_config: StepConfig | None = _get_step_config(step_name, step_func)
213214
if step_config is None:
214215
continue
215216

@@ -230,33 +231,32 @@ def get_workflow_schema(workflow: Workflow) -> UiPathRuntimeGraph:
230231
if return_type is type(None):
231232
continue
232233

234+
# If this returns StopEvent, connect to __end__
235+
if issubclass(return_type, StopEvent):
236+
if current_stop_event and return_type == current_stop_event:
237+
edges.append(
238+
UiPathRuntimeEdge(
239+
source=step_name,
240+
target="__end__",
241+
label=return_type.__name__,
242+
)
243+
)
244+
continue # Don't look for steps that accept StopEvent
245+
233246
# Find steps that accept this return type
234247
for target_step_name, target_step_func in steps.items():
235-
target_config: StepConfig | None = getattr(
236-
target_step_func, "__step_config", None
237-
)
248+
target_config: StepConfig | None = _get_step_config(target_step_name, target_step_func)
238249
if target_config is None:
239250
continue
240251

241252
if return_type in target_config.accepted_events:
242-
# Special handling for StopEvent - only connect to the actual StopEvent being used
243-
if issubclass(return_type, StopEvent):
244-
if current_stop_event and return_type == current_stop_event:
245-
edges.append(
246-
UiPathRuntimeEdge(
247-
source=step_name,
248-
target=target_step_name,
249-
label=return_type.__name__,
250-
)
251-
)
252-
else:
253-
edges.append(
254-
UiPathRuntimeEdge(
255-
source=step_name,
256-
target=target_step_name,
257-
label=return_type.__name__,
258-
)
253+
edges.append(
254+
UiPathRuntimeEdge(
255+
source=step_name,
256+
target=target_step_name,
257+
label=return_type.__name__,
259258
)
259+
)
260260

261261
# If this returns InputRequiredEvent, add edge to external_step
262262
if issubclass(return_type, InputRequiredEvent):
@@ -281,6 +281,26 @@ def get_workflow_schema(workflow: Workflow) -> UiPathRuntimeGraph:
281281

282282
return UiPathRuntimeGraph(nodes=nodes, edges=edges)
283283

284+
def _get_step_config(step_name: str, step_func: Any) -> StepConfig | None:
285+
"""
286+
Get the step configuration from a step function.
287+
288+
Returns None if:
289+
- The step name starts with underscore (internal method)
290+
- No step config is found
291+
292+
Args:
293+
step_name: Name of the step
294+
step_func: The step function
295+
296+
Returns:
297+
StepConfig if found and valid, None otherwise
298+
"""
299+
# Skip internal methods
300+
if step_name.startswith('_'):
301+
return None
302+
303+
return getattr(step_func, '_step_config', None) or getattr(step_func, '__step_config', None)
284304

285305
def _resolve_refs(
286306
schema: dict[str, Any],

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)