Skip to content

Repository files navigation

UiPath Runtime

PyPI downloadsPyPI - VersionPython versions

Runtime abstractions and contracts for the UiPath Python SDK.

Overview

uipath-runtime provides the foundational interfaces and base contracts for building agent runtimes in the UiPath ecosystem. It defines the protocols that all runtime implementations must follow and provides utilities for execution context, event streaming, tracing, structured error handling, durable execution, and human-in-the-loop interactions.

This package is typically used as a dependency by higher-level SDKs such as:

PackageDownloadsVersion
uipathDownloadsPyPI
uipath-langchainDownloadsPyPI
uipath-llamaindexDownloadsPyPI
uipath-google-adkDownloadsPyPI
uipath-openai-agentsDownloadsPyPI
uipath-agent-frameworkDownloadsPyPI
uipath-mcpDownloadsPyPI

You would use this directly only if you're building custom runtime implementations.

Installation

uv add uipath-runtime

Developer Tools

Check out uipath-dev - an interactive application for building, testing, and debugging UiPath Python runtimes, agents, and automation scripts.

Runtime Protocols

All runtimes implement the UiPathRuntimeProtocol (or one of its sub-protocols):

  • get_schema() — defines input and output JSON schemas.
  • execute(input, options) — executes the runtime logic and returns a UiPathRuntimeResult.
  • stream(input, options) — optionally streams runtime events for real-time monitoring.
  • dispose() — releases resources when the runtime is no longer needed.

Any class that structurally implements these methods satisfies the protocol.

fromtypingimportAny, AsyncGenerator, Optionalfromuipath.runtimeimport (
UiPathRuntimeResult,
UiPathRuntimeStatus,
UiPathRuntimeSchema,
UiPathRuntimeEvent,
UiPathExecuteOptions,
UiPathStreamOptions,
)
fromuipath.runtime.eventsimportUiPathRuntimeStateEventclassMyRuntime:
"""Example runtime implementing the UiPath runtime protocols."""asyncdefget_schema(self) ->UiPathRuntimeSchema:
returnUiPathRuntimeSchema(
input={
"type": "object",
"properties": {"message": {"type": "string"}},
"required": ["message"],
},
output={
"type": "object",
"properties": {"result": {"type": "string"}},
"required": ["result"],
},
)
asyncdefexecute(
self,
input: Optional[dict[str, Any]] =None,
options: Optional[UiPathExecuteOptions] =None,
) ->UiPathRuntimeResult:
message= (inputor {}).get("message", "")
returnUiPathRuntimeResult(
output={'message': 'Hello from MyRuntime'},
status=UiPathRuntimeStatus.SUCCESSFUL,
)
asyncdefstream(
self,
input: Optional[dict[str, Any]] =None,
options: Optional[UiPathStreamOptions] =None,
) ->AsyncGenerator[UiPathRuntimeEvent, None]:
yieldUiPathRuntimeStateEvent(payload={"status": "starting"})
yieldUiPathRuntimeResult(
output={"completed": True},
status=UiPathRuntimeStatus.SUCCESSFUL,
)
asyncdefdispose(self) ->None:
pass

Event Streaming

Runtimes can optionally emit real-time events during execution:

fromuipath.runtime.eventsimport (
UiPathRuntimeStateEvent,
UiPathRuntimeMessageEvent,
)
fromuipath.runtime.resultimportUiPathRuntimeResultasyncforeventinruntime.stream({"query": "hello"}):
ifisinstance(event, UiPathRuntimeStateEvent):
print(f"State update: {event.payload}")
elifisinstance(event, UiPathRuntimeMessageEvent):
print(f"Message received: {event.payload}")
elifisinstance(event, UiPathRuntimeResult):
print(f"Completed: {event.output}")

If a runtime doesn’t support streaming, it raises a UiPathStreamNotSupportedError.

Structured Error Handling

Runtime errors use a consistent, structured model:

fromuipath.runtime.errorsimportUiPathRuntimeError, UiPathErrorCode, UiPathErrorCategoryraiseUiPathRuntimeError(
UiPathErrorCode.EXECUTION_ERROR,
"Agent failed",
"Failed to call external service",
UiPathErrorCategory.USER,
)

Resulting JSON contract:

{
"code": "Python.EXECUTION_ERROR",
"title": "Agent failed",
"detail": "Failed to call external service",
"category": "User"
}

Runtime Factory

UiPathRuntimeFactoryProtocol provides a consistent contract for discovering and creating runtime instances.

Factories decouple runtime construction (configuration, dependencies) from runtime execution, allowing orchestration, discovery, reuse, and tracing across multiple types of runtimes.

fromtypingimportAny, AsyncGenerator, Optionalfromuipath.runtimeimport (
UiPathRuntimeResult,
UiPathRuntimeStatus,
UiPathRuntimeSchema,
UiPathExecuteOptions,
UiPathStreamOptions,
UiPathRuntimeProtocol,
UiPathRuntimeFactoryProtocol
)
classMyRuntimeFactory:
asyncdefnew_runtime(self, entrypoint: str, runtime_id: str) ->UiPathRuntimeProtocol:
returnMyRuntime()
defdiscover_entrypoints(self) ->list[str]:
return []
factory=MyRuntimeFactory()
runtime=awaitfactory.new_runtime("example", "id")
result=awaitruntime.execute()
print(result.output) # {'message': 'Hello from MyRuntime'}

Execution Context

UiPathRuntimeContext manages configuration, file I/O, and logs across runtime execution. It can read JSON input files, capture all stdout/stderr logs, and automatically write output and result files when execution completes.

fromuipath.runtimeimportUiPathRuntimeContext, UiPathRuntimeResult, UiPathRuntimeStatuswithUiPathRuntimeContext(input_file="input.json", result_file="result.json", logs_file="execution.log") asctx:
ctx.result=awaitruntime.execute(ctx.input)
# On exit: the result and logs are written automatically to the configured files

When execution fails, the context:

  • Writes a structured error contract to the result file.
  • Re-raises the original exception.

Execution Runtime

UiPathExecutionRuntime wraps any runtime with tracing, telemetry, and log collection capabilities. When running multiple runtimes in the same process, this wrapper ensures each execution's spans and logs are properly isolated and captured.

graph TB
TM[TraceManager<br/>Shared across all runtimes]
FACTORY[Factory]
RT[Runtime]
EXE[ExecutionRuntime<br/>exec-id: exec-id]
%% Factory creates runtimes
FACTORY -->|new_runtime| RT
%% Runtimes wrapped by ExecutionRuntime
RT -->|wrapped by| EXE
%% TraceManager shared with all
TM -.->|shared| EXE
%% Execution captures spans to TraceManager
EXE -->|captures spans| TM
%% Styling
style TM fill:#e1f5ff,stroke:#0277bd,stroke-width:3px
style FACTORY fill:#f3e5f5
style RT fill:#fff3e0
style EXE fill:#e8f5e9
Loading
fromuipath.coreimportUiPathTraceManagerfromuipath.runtimeimportUiPathExecutionRuntimetrace_manager=UiPathTraceManager()
runtime=MyRuntime()
executor=UiPathExecutionRuntime(
runtime,
trace_manager,
root_span="my-runtime",
execution_id="exec-123",
)
result=awaitexecutor.execute({"message": "hello"})
spans=trace_manager.get_execution_spans("exec-123") # captured spanslogs=executor.log_handler.buffer# captured logsprint(result.output) # {'message': 'Hello from MyRuntime'}

Example: Runtime Orchestration

This example demonstrates an orchestrator runtime that receives a UiPathRuntimeFactoryProtocol, creates child runtimes through it, and executes each one via UiPathExecutionRuntime, all within a single shared UiPathTraceManager.

Orchestrator Runtime
fromtypingimportAny, Optional, AsyncGeneratorfromuipath.coreimportUiPathTraceManagerfromuipath.runtimeimport (
UiPathExecutionRuntime,
UiPathRuntimeResult,
UiPathRuntimeStatus,
UiPathExecuteOptions,
UiPathStreamOptions,
UiPathRuntimeProtocol,
UiPathRuntimeFactoryProtocol
)
classChildRuntime:
"""A simple child runtime that echoes its name and input."""def__init__(self, name: str):
self.name=nameasyncdefget_schema(self):
returnNoneasyncdefexecute(
self,
input: Optional[dict[str, Any]] =None,
options: Optional[UiPathExecuteOptions] =None,
) ->UiPathRuntimeResult:
payload=inputor {}
returnUiPathRuntimeResult(
output={
"runtime": self.name,
"input": payload,
},
status=UiPathRuntimeStatus.SUCCESSFUL,
)
asyncdefstream(
self,
input: Optional[dict[str, Any]] =None,
options: Optional[UiPathStreamOptions] =None,
) ->AsyncGenerator[UiPathRuntimeResult, None]:
yieldawaitself.execute(input, options)
asyncdefdispose(self) ->None:
passclassChildRuntimeFactory:
"""Factory that creates ChildRuntime instances."""asyncdefnew_runtime(self, entrypoint: str) ->UiPathRuntimeProtocol:
returnChildRuntime(name=entrypoint)
defdiscover_entrypoints(self) ->list[str]:
return []
classOrchestratorRuntime:
"""A runtime that orchestrates multiple child runtimes via a factory."""def__init__(
self,
factory: UiPathRuntimeFactoryProtocol,
trace_manager: UiPathTraceManager,
):
self.factory=factoryself.trace_manager=trace_managerasyncdefget_schema(self):
returnNoneasyncdefexecute(
self,
input: Optional[dict[str, Any]] =None,
options: Optional[UiPathExecuteOptions] =None,
) ->UiPathRuntimeResult:
payload=inputor {}
child_inputs: list[dict[str, Any]] =payload.get("children", [])
child_results: list[dict[str, Any]] = []
fori, child_inputinenumerate(child_inputs):
# Use the factory to create a new child runtimechild_runtime=awaitself.factory.new_runtime(entrypoint=f"child-{i}", runtime_id=f"child-{i}")
# Wrap child runtime with tracing + logsexecution_id=f"child-{i}"executor=UiPathExecutionRuntime(
delegate=child_runtime,
trace_manager=self.trace_manager,
root_span=f"child-span-{i}",
execution_id=execution_id,
)
# Execute child runtimeresult=awaitexecutor.execute(child_input, options=options)
child_results.append(result.outputor {})
child_spans=trace_manager.get_execution_spans(execution_id) # Captured spans# Dispose the child runtime when finishedawaitchild_runtime.dispose()
returnUiPathRuntimeResult(
output={
"main": True,
"children": child_results,
},
status=UiPathRuntimeStatus.SUCCESSFUL,
)
asyncdefstream(
self,
input: Optional[dict[str, Any]] =None,
options: Optional[UiPathStreamOptions] =None,
) ->AsyncGenerator[UiPathRuntimeResult, None]:
yieldawaitself.execute(input, options)
asyncdefdispose(self) ->None:
pass# Example usageasyncdefmain() ->None:
trace_manager=UiPathTraceManager()
factory=ChildRuntimeFactory()
options=UiPathExecuteOptions()
withUiPathRuntimeContext(job_id="main-job-001") asctx:
runtime=OrchestratorRuntime(factory=factory, trace_manager=trace_manager)
input_data= {
"children": [
{"message": "hello from child 1"},
{"message": "hello from child 2"},
]
}
ctx.result=awaitruntime.execute(input=input_data, options=options)
print(ctx.result.output)
# Output:# {# "main": True,# "children": [# {"runtime": "child-0", "input": {"message": "hello from child 1"}},# {"runtime": "child-1", "input": {"message": "hello from child 2"}}# ]# }

Building a New Integration

This repository includes a complete blueprint for building new framework integrations using Claude Code (or any AI coding assistant):

  • INTEGRATION_GENOME.md — A structured, phase-by-phase specification that guides you through building a full UiPath runtime integration for any Python agentic framework. Covers project scaffolding, config/loader, schema inference, execute/stream, HITL, factory registration, LLM Gateway, and CLI middleware.
  • CLAUDE.md — Project instructions and structure overview for AI-assisted development.

About

Runtime abstractions and contracts for the UiPath Python SDK.

Topics

Resources

Contributing

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages