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,24 +31,50 @@ 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
5480
@@ -197,7 +223,7 @@ def __exit__(self, exc_type, exc_val, exc_tb):
197223 # Always write output file at runtime, except for inner runtimes
198224 # Inner runtimes have execution_id
199225 if self .job_id :
200- with open (self .result_file_path , "w" ) as f :
226+ with open (self .resolved_result_file_path , "w" ) as f :
201227 json .dump (content , f , indent = 2 , default = str )
202228
203229 # Write the execution output to file if requested
@@ -230,7 +256,7 @@ def __exit__(self, exc_type, exc_val, exc_tb):
230256 )
231257 error_result_content = error_result .to_dict ()
232258 if self .job_id :
233- with open (self .result_file_path , "w" ) as f :
259+ with open (self .resolved_result_file_path , "w" ) as f :
234260 json .dump (error_result_content , f , indent = 2 , default = str )
235261 except Exception as write_error :
236262 logger .error (f"Failed to write error output file: { str (write_error )} " )
@@ -251,16 +277,24 @@ def __exit__(self, exc_type, exc_val, exc_tb):
251277 self .logs_interceptor .teardown ()
252278
253279 @cached_property
254- def result_file_path (self ) -> str :
280+ def resolved_result_file_path (self ) -> str :
255281 """Get the full path to the result file."""
282+ # If full path is explicitly specified, use that
283+ if self .result_file_path :
284+ return self .result_file_path
285+ # Otherwise, construct from runtime_dir and result_file
256286 if self .runtime_dir and self .result_file :
257287 os .makedirs (self .runtime_dir , exist_ok = True )
258288 return os .path .join (self .runtime_dir , self .result_file )
259289 return os .path .join ("__uipath" , "output.json" )
260290
261291 @cached_property
262- def state_file_path (self ) -> str :
292+ def resolved_state_file_path (self ) -> str :
263293 """Get the full path to the state file."""
294+ # If full path is explicitly specified, use that
295+ if self .state_file_path :
296+ return self .state_file_path
297+ # Otherwise, construct from runtime_dir and state_file
264298 if self .runtime_dir and self .state_file :
265299 os .makedirs (self .runtime_dir , exist_ok = True )
266300 return os .path .join (self .runtime_dir , self .state_file )
0 commit comments