From 8c7ccdb79a6bc2c6bb72e46711109b5bbbd0a096 Mon Sep 17 00:00:00 2001 From: Cristian Pufu Date: Sun, 9 Nov 2025 18:46:34 +0200 Subject: [PATCH] fix: add custom log handler --- pyproject.toml | 4 ++-- src/uipath/dev/__init__.py | 12 +++++++++--- src/uipath/dev/_demo/mock_runtime.py | 19 ++----------------- src/uipath/dev/_utils/_logger.py | 7 +++++-- uv.lock | 10 +++++----- 5 files changed, 23 insertions(+), 29 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1a7a1be..c27210f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,11 +1,11 @@ [project] name = "uipath-dev" -version = "0.0.1" +version = "0.0.2" description = "UiPath Developer Console" readme = { file = "README.md", content-type = "text/markdown" } requires-python = ">=3.11" dependencies = [ - "uipath-runtime>=0.0.4", + "uipath-runtime>=0.0.5, <0.1.0", "textual>=6.5.0", "pyperclip>=1.11.0", ] diff --git a/src/uipath/dev/__init__.py b/src/uipath/dev/__init__.py index 4364546..c5f1e45 100644 --- a/src/uipath/dev/__init__.py +++ b/src/uipath/dev/__init__.py @@ -31,7 +31,7 @@ from uipath.dev.models.messages import LogMessage, TraceMessage from ._utils._exporter import RunContextExporter -from ._utils._logger import patch_textual_stderr +from ._utils._logger import RunContextLogHandler, patch_textual_stderr class UiPathDeveloperConsole(App[Any]): @@ -203,10 +203,16 @@ async def _execute_runtime(self, run: ExecutionRun): run.status = "running" run.start_time = datetime.now() - + log_handler = RunContextLogHandler( + run_id=run.id, + callback=self._handle_log_message, + ) runtime = self.runtime_factory.new_runtime(entrypoint=run.entrypoint) execution_runtime = UiPathExecutionRuntime( - delegate=runtime, trace_manager=self.trace_manager, execution_id=run.id + delegate=runtime, + trace_manager=self.trace_manager, + log_handler=log_handler, + execution_id=run.id, ) result = await execution_runtime.execute(execution_input, execution_options) diff --git a/src/uipath/dev/_demo/mock_runtime.py b/src/uipath/dev/_demo/mock_runtime.py index 922bcc7..e3ff035 100644 --- a/src/uipath/dev/_demo/mock_runtime.py +++ b/src/uipath/dev/_demo/mock_runtime.py @@ -46,8 +46,7 @@ async def execute( tracer = trace.get_tracer("uipath.dev.mock-runtime") - execution_id = getattr(self.context, "job_id", None) or "mock-execution" - entrypoint = getattr(self.context, "entrypoint", None) or "mock-entrypoint" + entrypoint = "mock-entrypoint" message = str(payload.get("message", "")) message_length = len(message) @@ -56,7 +55,6 @@ async def execute( attributes={ "uipath.runtime.name": "MockRuntime", "uipath.runtime.type": "agent", - "uipath.execution.id": execution_id, "uipath.runtime.entrypoint": entrypoint, "uipath.input.message.length": message_length, "uipath.input.has_message": "message" in payload, @@ -65,11 +63,10 @@ async def execute( logger.info( "MockRuntime: starting execution", extra={ - "uipath.execution.id": execution_id, "uipath.runtime.entrypoint": entrypoint, }, ) - print(f"[MockRuntime] Starting execution (execution_id={execution_id})") + print(f"[MockRuntime] Starting execution with payload={payload!r}") # Stage 1: Initialization with tracer.start_as_current_span( @@ -77,7 +74,6 @@ async def execute( attributes={ "uipath.step.name": "initialize-environment", "uipath.step.kind": "init", - "uipath.execution.id": execution_id, }, ): logger.info("MockRuntime: initializing environment") @@ -90,7 +86,6 @@ async def execute( attributes={ "uipath.step.name": "validate-input", "uipath.step.kind": "validation", - "uipath.execution.id": execution_id, "uipath.input.has_message": "message" in payload, }, ) as validate_span: @@ -110,7 +105,6 @@ async def execute( attributes={ "uipath.step.name": "preprocess-data", "uipath.step.kind": "preprocess", - "uipath.execution.id": execution_id, "uipath.input.size.bytes": len(str(payload).encode("utf-8")), }, ): @@ -124,7 +118,6 @@ async def execute( attributes={ "uipath.step.name": "compute-result", "uipath.step.kind": "compute", - "uipath.execution.id": execution_id, }, ): logger.info("MockRuntime: compute phase started") @@ -136,7 +129,6 @@ async def execute( attributes={ "uipath.step.name": "compute-embeddings", "uipath.step.kind": "compute-subtask", - "uipath.execution.id": execution_id, }, ): logger.info("MockRuntime: computing embeddings") @@ -149,7 +141,6 @@ async def execute( attributes={ "uipath.step.name": "query-knowledgebase", "uipath.step.kind": "io", - "uipath.execution.id": execution_id, "uipath.kb.query.length": message_length, }, ): @@ -163,7 +154,6 @@ async def execute( attributes={ "uipath.step.name": "postprocess-results", "uipath.step.kind": "postprocess", - "uipath.execution.id": execution_id, }, ): logger.info("MockRuntime: post-processing results") @@ -175,7 +165,6 @@ async def execute( attributes={ "uipath.step.name": "generate-output", "uipath.step.kind": "postprocess-subtask", - "uipath.execution.id": execution_id, }, ): logger.info("MockRuntime: generating structured output") @@ -188,7 +177,6 @@ async def execute( attributes={ "uipath.step.name": "persist-artifacts", "uipath.step.kind": "io", - "uipath.execution.id": execution_id, "uipath.persistence.enabled": False, }, ): @@ -202,7 +190,6 @@ async def execute( attributes={ "uipath.step.name": "cleanup-resources", "uipath.step.kind": "cleanup", - "uipath.execution.id": execution_id, }, ): logger.info("MockRuntime: cleaning up resources") @@ -212,7 +199,6 @@ async def execute( result_payload = { "result": f"Mock runtime processed: {payload.get('message', '')}", "metadata": { - "execution_id": execution_id, "entrypoint": entrypoint, "message_length": message_length, }, @@ -228,7 +214,6 @@ async def execute( logger.info( "MockRuntime: execution completed successfully", extra={ - "uipath.execution.id": execution_id, "uipath.runtime.status": "success", }, ) diff --git a/src/uipath/dev/_utils/_logger.py b/src/uipath/dev/_utils/_logger.py index 9f47328..20c3972 100644 --- a/src/uipath/dev/_utils/_logger.py +++ b/src/uipath/dev/_utils/_logger.py @@ -7,10 +7,12 @@ from datetime import datetime from typing import Callable, Pattern +from uipath.runtime.logging import UiPathRuntimeExecutionLogHandler + from uipath.dev.models.messages import LogMessage -class RunContextLogHandler(logging.Handler): +class RunContextLogHandler(UiPathRuntimeExecutionLogHandler): """Custom log handler that sends logs to CLI UI.""" def __init__( @@ -18,9 +20,10 @@ def __init__( run_id: str, callback: Callable[[LogMessage], None], ): - super().__init__() + super().__init__(run_id) self.run_id = run_id self.callback = callback + self.setFormatter(logging.Formatter("%(message)s")) def emit(self, record: logging.LogRecord): """Emit a log record to CLI UI.""" diff --git a/uv.lock b/uv.lock index 34fb93d..4d57a20 100644 --- a/uv.lock +++ b/uv.lock @@ -1002,7 +1002,7 @@ wheels = [ [[package]] name = "uipath-dev" -version = "0.0.1" +version = "0.0.2" source = { editable = "." } dependencies = [ { name = "pyperclip" }, @@ -1029,7 +1029,7 @@ dev = [ requires-dist = [ { name = "pyperclip", specifier = ">=1.11.0" }, { name = "textual", specifier = ">=6.5.0" }, - { name = "uipath-runtime", specifier = ">=0.0.4" }, + { name = "uipath-runtime", specifier = ">=0.0.5,<0.1.0" }, ] [package.metadata.requires-dev] @@ -1049,7 +1049,7 @@ dev = [ [[package]] name = "uipath-runtime" -version = "0.0.4" +version = "0.0.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-instrumentation" }, @@ -1057,9 +1057,9 @@ dependencies = [ { name = "pydantic" }, { name = "uipath-core" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6e/03/2cc1034e764a4708b75e98354f1abfedf51b0672dd7cef5c23d5f0c31f3d/uipath_runtime-0.0.4.tar.gz", hash = "sha256:2fab9512ca8f3c317c1b86d0dedc4e694bae671d1198d35a664aacd30ac794da", size = 78264, upload-time = "2025-11-09T06:07:58.904Z" } +sdist = { url = "https://files.pythonhosted.org/packages/45/81/c1ef659dec890746838700d86ae1359d44eac6a4a484a5a5814d668e210d/uipath_runtime-0.0.5.tar.gz", hash = "sha256:872907939e3166c9c171109a17b924ab2c568dae9cfee7da142c541fd1fb4482", size = 80964, upload-time = "2025-11-09T16:15:08.587Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/8e/9cbcdb7d7a37297212155c714f3a1624208924d6f759549066674e673b9e/uipath_runtime-0.0.4-py3-none-any.whl", hash = "sha256:0e90b2c5d51d1cab60f9736c9d2d514a71dc39fcc70e49bd60f255f74a80ceb4", size = 24990, upload-time = "2025-11-09T06:07:57.471Z" }, + { url = "https://files.pythonhosted.org/packages/60/eb/ef3ea7be07933ce38366c4ccad69fbcda628aa6ab32e1c0e5757ef913265/uipath_runtime-0.0.5-py3-none-any.whl", hash = "sha256:ff359f4d5b8821d9589da519c65d6026d8672a18ecb21d2631ec132495f537b2", size = 26771, upload-time = "2025-11-09T16:15:06.995Z" }, ] [[package]]