77from pathlib import Path
88from typing import Any
99
10- from pydantic import BaseModel , ConfigDict
10+ from pydantic import BaseModel , ConfigDict , Field
1111from uipath .core .errors import UiPathFaultedTriggerError
1212from uipath .core .tracing import UiPathTraceManager
1313
@@ -31,26 +31,55 @@ class UiPathRuntimeContext(BaseModel):
3131 resume : bool = False
3232 command : str | None = None
3333 job_id : str | None = None
34- conversation_id : str | None = None
35- exchange_id : str | None = None
36- message_id : str | None = None
34+ conversation_id : str | None = Field (
35+ None , description = "Conversation identifier for CAS"
36+ )
37+ exchange_id : str | None = Field (None , description = "Exchange identifier for CAS" )
38+ message_id : str | None = Field (None , description = "Message identifier for CAS" )
3739 mcp_server_id : str | None = None
3840 mcp_server_slug : str | None = None
3941 tenant_id : str | None = None
4042 org_id : str | None = None
4143 folder_key : str | None = None
4244 process_key : str | None = None
4345 config_path : str = "uipath.json"
44- runtime_dir : str | None = "__uipath"
45- result_file : str = "output.json"
46- state_file : str = "state.db"
47- input_file : str | None = None
48- output_file : str | None = None
49- trace_file : str | None = None
50- logs_file : str | None = "execution.log"
51- logs_min_level : str | None = "INFO"
46+ runtime_dir : str | None = Field (
47+ "__uipath" , description = "Directory for runtime files"
48+ )
49+ result_file : str = Field (
50+ "output.json" , description = "Filename for the result output"
51+ )
52+ result_file_path : str | None = Field (
53+ None ,
54+ description = (
55+ "Full path override for the result file. "
56+ "When specified, takes priority over runtime_dir + result_file. "
57+ "If not specified, path is constructed from runtime_dir and result_file."
58+ ),
59+ )
60+ state_file : str = Field ("state.db" , description = "Filename for the state database" )
61+ state_file_path : str | None = Field (
62+ None ,
63+ description = (
64+ "Full path override for the state file. "
65+ "When specified, takes priority over runtime_dir + state_file. "
66+ "If not specified, path is constructed from runtime_dir and state_file."
67+ ),
68+ )
69+ input_file : str | None = Field (None , description = "Full path to the input JSON file" )
70+ output_file : str | None = Field (
71+ None , description = "Full path to the output JSON file"
72+ )
73+ trace_file : str | None = Field (None , description = "Full path to the trace file" )
74+ logs_file : str | None = Field (
75+ "execution.log" , description = "Filename for the logs file"
76+ )
77+ logs_min_level : str | None = Field ("INFO" , description = "Minimum log level" )
5278 result : UiPathRuntimeResult | None = None
5379 trace_manager : UiPathTraceManager | None = None
80+ keep_state_file : bool = Field (
81+ False , description = "Prevents deletion of state file before running."
82+ )
5483
5584 model_config = ConfigDict (arbitrary_types_allowed = True , extra = "allow" )
5685
@@ -197,7 +226,7 @@ def __exit__(self, exc_type, exc_val, exc_tb):
197226 # Always write output file at runtime, except for inner runtimes
198227 # Inner runtimes have execution_id
199228 if self .job_id :
200- with open (self .result_file_path , "w" ) as f :
229+ with open (self .resolved_result_file_path , "w" ) as f :
201230 json .dump (content , f , indent = 2 , default = str )
202231
203232 # Write the execution output to file if requested
@@ -230,7 +259,7 @@ def __exit__(self, exc_type, exc_val, exc_tb):
230259 )
231260 error_result_content = error_result .to_dict ()
232261 if self .job_id :
233- with open (self .result_file_path , "w" ) as f :
262+ with open (self .resolved_result_file_path , "w" ) as f :
234263 json .dump (error_result_content , f , indent = 2 , default = str )
235264 except Exception as write_error :
236265 logger .error (f"Failed to write error output file: { str (write_error )} " )
@@ -251,16 +280,24 @@ def __exit__(self, exc_type, exc_val, exc_tb):
251280 self .logs_interceptor .teardown ()
252281
253282 @cached_property
254- def result_file_path (self ) -> str :
283+ def resolved_result_file_path (self ) -> str :
255284 """Get the full path to the result file."""
285+ # If full path is explicitly specified, use that
286+ if self .result_file_path :
287+ return self .result_file_path
288+ # Otherwise, construct from runtime_dir and result_file
256289 if self .runtime_dir and self .result_file :
257290 os .makedirs (self .runtime_dir , exist_ok = True )
258291 return os .path .join (self .runtime_dir , self .result_file )
259292 return os .path .join ("__uipath" , "output.json" )
260293
261294 @cached_property
262- def state_file_path (self ) -> str :
295+ def resolved_state_file_path (self ) -> str :
263296 """Get the full path to the state file."""
297+ # If full path is explicitly specified, use that
298+ if self .state_file_path :
299+ return self .state_file_path
300+ # Otherwise, construct from runtime_dir and state_file
264301 if self .runtime_dir and self .state_file :
265302 os .makedirs (self .runtime_dir , exist_ok = True )
266303 return os .path .join (self .runtime_dir , self .state_file )
0 commit comments