Skip to content

Commit a60a0c8

Browse files
mjnoviceclaude
andauthored
feat: add simulation support for uipath debug command (#1117)
Co-authored-by: Claude Sonnet 4.5 <[email protected]>
1 parent fe95698 commit a60a0c8

File tree

4 files changed

+608
-2
lines changed

4 files changed

+608
-2
lines changed

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"
3-
version = "2.5.29"
3+
version = "2.5.30"
44
description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools."
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.11"

src/uipath/_cli/cli_debug.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import asyncio
2+
import json
3+
import uuid
4+
from pathlib import Path
25

36
import click
47
from uipath.core.tracing import UiPathTraceManager
@@ -14,6 +17,17 @@
1417

1518
from uipath._cli._chat._bridge import get_chat_bridge
1619
from uipath._cli._debug._bridge import get_debug_bridge
20+
from uipath._cli._evals._span_collection import ExecutionSpanCollector
21+
from uipath._cli._evals.mocks.mocks import (
22+
clear_execution_context,
23+
set_execution_context,
24+
)
25+
from uipath._cli._evals.mocks.types import (
26+
LLMMockingStrategy,
27+
MockingContext,
28+
MockingStrategyType,
29+
ToolSimulation,
30+
)
1731
from uipath._cli._utils._debug import setup_debugging
1832
from uipath._cli._utils._studio_project import StudioClient
1933
from uipath._utils._bindings import ResourceOverwritesContext
@@ -26,6 +40,57 @@
2640
console = ConsoleLogger()
2741

2842

43+
def load_simulation_config() -> MockingContext | None:
44+
"""Load simulation.json from current directory and convert to MockingContext.
45+
46+
Returns:
47+
MockingContext with LLM mocking strategy if simulation.json exists and is valid,
48+
None otherwise.
49+
"""
50+
simulation_path = Path.cwd() / "simulation.json"
51+
52+
if not simulation_path.exists():
53+
return None
54+
55+
try:
56+
with open(simulation_path, "r", encoding="utf-8") as f:
57+
simulation_data = json.load(f)
58+
59+
# Check if simulation is enabled
60+
if not simulation_data.get("enabled", True):
61+
return None
62+
63+
# Extract tools to simulate
64+
tools_to_simulate = [
65+
ToolSimulation(name=tool["name"])
66+
for tool in simulation_data.get("toolsToSimulate", [])
67+
]
68+
69+
if not tools_to_simulate:
70+
return None
71+
72+
# Create LLM mocking strategy
73+
mocking_strategy = LLMMockingStrategy(
74+
type=MockingStrategyType.LLM,
75+
prompt=simulation_data.get("instructions", ""),
76+
tools_to_simulate=tools_to_simulate,
77+
)
78+
79+
# Create MockingContext for debugging
80+
mocking_context = MockingContext(
81+
strategy=mocking_strategy,
82+
name="debug-simulation",
83+
inputs={},
84+
)
85+
86+
console.info(f"Loaded simulation config for {len(tools_to_simulate)} tool(s)")
87+
return mocking_context
88+
89+
except Exception as e:
90+
console.warning(f"Failed to load simulation.json: {e}")
91+
return None
92+
93+
2994
@click.command()
3095
@click.argument("entrypoint", required=False)
3196
@click.argument("input", required=False, default=None)
@@ -114,6 +179,17 @@ async def execute_debug_runtime():
114179
debug_runtime: UiPathRuntimeProtocol | None = None
115180
factory: UiPathRuntimeFactoryProtocol | None = None
116181

182+
# Load simulation config and set up execution context for tool mocking
183+
mocking_ctx = load_simulation_config()
184+
span_collector: ExecutionSpanCollector | None = None
185+
execution_id = str(uuid.uuid4())
186+
187+
if mocking_ctx:
188+
# Create span collector for trace access during mocking
189+
span_collector = ExecutionSpanCollector()
190+
# Set execution context to enable tool simulation
191+
set_execution_context(mocking_ctx, span_collector, execution_id)
192+
117193
try:
118194
trigger_poll_interval: float = 5.0
119195

@@ -163,6 +239,10 @@ async def execute_debug_runtime():
163239
)
164240

165241
finally:
242+
# Clear execution context after debugging completes
243+
if mocking_ctx:
244+
clear_execution_context()
245+
166246
if debug_runtime:
167247
await debug_runtime.dispose()
168248
if chat_runtime:

0 commit comments

Comments
 (0)