From 5b7476c0201fb7d54a45be7ae3fd0b7242fdaa37 Mon Sep 17 00:00:00 2001 From: Ionut Mihalache <67947900+ionut-mihalache-uipath@users.noreply.github.com> Date: Thu, 19 Feb 2026 18:39:17 +0200 Subject: [PATCH 1/7] feat: add extra metadata for tools --- src/uipath_langchain/agent/tools/context_tool.py | 6 ++++++ src/uipath_langchain/agent/tools/integration_tool.py | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/uipath_langchain/agent/tools/context_tool.py b/src/uipath_langchain/agent/tools/context_tool.py index d574a6f60..18898dd44 100644 --- a/src/uipath_langchain/agent/tools/context_tool.py +++ b/src/uipath_langchain/agent/tools/context_tool.py @@ -123,6 +123,8 @@ async def context_tool_fn(query: Optional[str] = None) -> dict[str, Any]: metadata={ "tool_type": "context", "display_name": resource.name, + "index_name": resource.index_name, + "context_retrieval_mode": resource.settings.retrieval_mode, }, ) @@ -202,6 +204,8 @@ async def create_deep_rag(): metadata={ "tool_type": "context", "display_name": resource.name, + "index_name": resource.index_name, + "context_retrieval_mode": resource.settings.retrieval_mode, }, ) @@ -335,6 +339,8 @@ async def context_batch_transform_wrapper( metadata={ "tool_type": "context", "display_name": resource.name, + "index_name": resource.index_name, + "context_retrieval_mode": resource.settings.retrieval_mode, }, ) tool.set_tool_wrappers(awrapper=context_batch_transform_wrapper) diff --git a/src/uipath_langchain/agent/tools/integration_tool.py b/src/uipath_langchain/agent/tools/integration_tool.py index ca9dceb4f..eac7523e2 100644 --- a/src/uipath_langchain/agent/tools/integration_tool.py +++ b/src/uipath_langchain/agent/tools/integration_tool.py @@ -201,6 +201,8 @@ async def integration_tool_wrapper( metadata={ "tool_type": "integration", "display_name": resource.name, + "connector_key": resource.properties.connection.id, + "connector_name": resource.properties.connection.name, }, ) tool.set_tool_wrappers(awrapper=integration_tool_wrapper) From a86e6f1d2f15b8d7359da806c142c1aafdd164fc Mon Sep 17 00:00:00 2001 From: "diana.grecu" Date: Wed, 25 Feb 2026 12:14:32 +0200 Subject: [PATCH 2/7] feat: send parent_operation_id as parameter --- src/uipath_langchain/agent/tools/process_tool.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/uipath_langchain/agent/tools/process_tool.py b/src/uipath_langchain/agent/tools/process_tool.py index b098fa3b5..715d9f2d2 100644 --- a/src/uipath_langchain/agent/tools/process_tool.py +++ b/src/uipath_langchain/agent/tools/process_tool.py @@ -38,6 +38,7 @@ def create_process_tool(resource: AgentProcessToolResourceConfig) -> StructuredT output_model: Any = create_model(resource.output_schema) _span_context: dict[str, Any] = {} + _bts_context: dict[str, Any] = {} async def process_tool_fn(**kwargs: Any): attachments = get_job_attachments(input_model, kwargs) @@ -52,6 +53,7 @@ async def process_tool_fn(**kwargs: Any): ) async def invoke_process(**_tool_kwargs: Any): parent_span_id = _span_context.pop("parent_span_id", None) + parent_operation_id = _bts_context.pop("parent_operation_id", None) @durable_interrupt async def start_job(): @@ -62,6 +64,7 @@ async def start_job(): folder_path=folder_path, attachments=attachments, parent_span_id=parent_span_id, + parent_operation_id=parent_operation_id, ) return WaitJob(job=job, process_folder_key=job.folder_key) @@ -92,6 +95,7 @@ async def process_tool_wrapper( "args_schema": input_model, "output_schema": output_model, "_span_context": _span_context, + "_bts_context": _bts_context, }, argument_properties=resource.argument_properties, ) From 76357f01659268acb6071c0b7034bdb7000d1ea4 Mon Sep 17 00:00:00 2001 From: "diana.grecu" Date: Wed, 25 Feb 2026 14:23:18 +0200 Subject: [PATCH 3/7] fix: failing test --- tests/agent/tools/test_process_tool.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/agent/tools/test_process_tool.py b/tests/agent/tools/test_process_tool.py index 63c2683bf..287dd50e6 100644 --- a/tests/agent/tools/test_process_tool.py +++ b/tests/agent/tools/test_process_tool.py @@ -138,6 +138,7 @@ async def test_invoke_calls_processes_invoke_async( folder_path="/Shared/MyFolder", attachments=[], parent_span_id=None, + parent_operation_id=None, ) @pytest.mark.asyncio From 39be5c61bf0293340499b46019c900532522091a Mon Sep 17 00:00:00 2001 From: "diana.grecu" Date: Wed, 25 Feb 2026 16:38:16 +0200 Subject: [PATCH 4/7] feat: add attributes to metadata dict of the tool --- src/uipath_langchain/agent/tools/escalation_tool.py | 7 +++++++ src/uipath_langchain/agent/tools/process_tool.py | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/src/uipath_langchain/agent/tools/escalation_tool.py b/src/uipath_langchain/agent/tools/escalation_tool.py index 6228ef822..31745b90c 100644 --- a/src/uipath_langchain/agent/tools/escalation_tool.py +++ b/src/uipath_langchain/agent/tools/escalation_tool.py @@ -154,6 +154,8 @@ class EscalationToolOutput(BaseModel): action: Literal["approve", "reject"] data: output_model + _bts_context: dict[str, Any] = {} + async def escalation_tool_fn(**kwargs: Any) -> dict[str, Any]: recipient: TaskRecipient | None = ( await resolve_recipient_value(channel.recipients[0]) @@ -191,6 +193,10 @@ async def create_escalation_task(): is_actionable_message_enabled=channel.properties.is_actionable_message_enabled, actionable_message_metadata=channel.properties.actionable_message_meta_data, ) + + if created_task.id is not None: + _bts_context["task_key"] = str(created_task.id) + return WaitEscalation( action=created_task, app_folder_path=channel.properties.folder_name, @@ -283,6 +289,7 @@ async def escalation_wrapper( "recipient": None, "args_schema": input_model, "output_schema": output_model, + "_bts_context": _bts_context, }, ) tool.set_tool_wrappers(awrapper=escalation_wrapper) diff --git a/src/uipath_langchain/agent/tools/process_tool.py b/src/uipath_langchain/agent/tools/process_tool.py index 715d9f2d2..194fa99fd 100644 --- a/src/uipath_langchain/agent/tools/process_tool.py +++ b/src/uipath_langchain/agent/tools/process_tool.py @@ -66,6 +66,15 @@ async def start_job(): parent_span_id=parent_span_id, parent_operation_id=parent_operation_id, ) + + if job.key: + bts_key = ( + "wait_for_agent_job_key" + if resource.type.lower() == "agent" + else "wait_for_job_key" + ) + _bts_context[bts_key] = str(job.key) + return WaitJob(job=job, process_folder_key=job.folder_key) return await start_job() From 03f4eddbd20db0c9663e73781cff5a1511fc065b Mon Sep 17 00:00:00 2001 From: "diana.grecu" Date: Wed, 25 Feb 2026 16:43:20 +0200 Subject: [PATCH 5/7] fix: failing test --- tests/agent/tools/test_process_tool.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/agent/tools/test_process_tool.py b/tests/agent/tools/test_process_tool.py index 287dd50e6..9b8b7f65e 100644 --- a/tests/agent/tools/test_process_tool.py +++ b/tests/agent/tools/test_process_tool.py @@ -121,6 +121,7 @@ async def test_invoke_calls_processes_invoke_async( ): """Test that invoking the tool calls client.processes.invoke_async.""" mock_job = MagicMock(spec=Job) + mock_job.key = "job-key-123" mock_job.folder_key = "folder-key-123" mock_client = MagicMock() @@ -149,6 +150,7 @@ async def test_invoke_interrupts_with_wait_job( ): """Test that after invoking, the tool interrupts with WaitJob.""" mock_job = MagicMock(spec=Job) + mock_job.key = "job-key-456" mock_job.folder_key = "folder-key-456" mock_client = MagicMock() @@ -174,6 +176,7 @@ async def test_invoke_passes_input_arguments( ): """Test that input arguments are correctly passed to invoke_async.""" mock_job = MagicMock(spec=Job) + mock_job.key = "job-key" mock_job.folder_key = "folder-key" mock_client = MagicMock() @@ -198,6 +201,7 @@ async def test_invoke_returns_interrupt_value( ): """Test that the tool returns the value from interrupt().""" mock_job = MagicMock(spec=Job) + mock_job.key = "job-key" mock_job.folder_key = "folder-key" mock_client = MagicMock() @@ -223,6 +227,7 @@ async def test_span_context_parent_span_id_passed_to_invoke( ): """Test that parent_span_id from _span_context is forwarded to invoke_async.""" mock_job = MagicMock(spec=Job) + mock_job.key = "job-key" mock_job.folder_key = "folder-key" mock_client = MagicMock() @@ -250,6 +255,7 @@ async def test_span_context_consumed_after_invoke( ): """Test that parent_span_id is popped (consumed) from _span_context after use.""" mock_job = MagicMock(spec=Job) + mock_job.key = "job-key" mock_job.folder_key = "folder-key" mock_client = MagicMock() @@ -275,6 +281,7 @@ async def test_span_context_defaults_to_none_when_empty( ): """Test that parent_span_id defaults to None when _span_context is empty.""" mock_job = MagicMock(spec=Job) + mock_job.key = "job-key" mock_job.folder_key = "folder-key" mock_client = MagicMock() From 88f9523bb374a06a2f5bae437c9c4e57f4db8649 Mon Sep 17 00:00:00 2001 From: "diana.grecu" Date: Wed, 25 Feb 2026 16:50:51 +0200 Subject: [PATCH 6/7] feat: small refactoring --- src/uipath_langchain/agent/tools/process_tool.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uipath_langchain/agent/tools/process_tool.py b/src/uipath_langchain/agent/tools/process_tool.py index 194fa99fd..3dc676782 100644 --- a/src/uipath_langchain/agent/tools/process_tool.py +++ b/src/uipath_langchain/agent/tools/process_tool.py @@ -5,7 +5,7 @@ from langchain.tools import BaseTool from langchain_core.messages import ToolCall from langchain_core.tools import StructuredTool -from uipath.agent.models.agent import AgentProcessToolResourceConfig +from uipath.agent.models.agent import AgentProcessToolResourceConfig, AgentToolType from uipath.eval.mocks import mockable from uipath.platform import UiPath from uipath.platform.common import WaitJob @@ -70,7 +70,7 @@ async def start_job(): if job.key: bts_key = ( "wait_for_agent_job_key" - if resource.type.lower() == "agent" + if resource.type == AgentToolType.AGENT else "wait_for_job_key" ) _bts_context[bts_key] = str(job.key) From 0d5846dd3578de68a3c5a930a91b234013c740b2 Mon Sep 17 00:00:00 2001 From: "diana.grecu" Date: Thu, 26 Feb 2026 17:07:45 +0200 Subject: [PATCH 7/7] chore: increase version --- pyproject.toml | 6 +++--- uv.lock | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 17619d74a..0c8d6b1c7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,13 +1,13 @@ [project] name = "uipath-langchain" -version = "0.7.6" +version = "0.7.7" description = "Python SDK that enables developers to build and deploy LangGraph agents to the UiPath Cloud Platform" readme = { file = "README.md", content-type = "text/markdown" } requires-python = ">=3.11" dependencies = [ - "uipath>=2.9.10, <2.10.0", + "uipath>=2.9.12, <2.10.0", "uipath-core>=0.5.2, <0.6.0", - "uipath-platform>=0.0.1, < 0.1.0", + "uipath-platform>=0.0.4, < 0.1.0", "uipath-runtime>=0.9.1, <0.10.0", "langgraph>=1.0.0, <2.0.0", "langchain-core>=1.2.11, <2.0.0", diff --git a/uv.lock b/uv.lock index 1198ca08f..3d52ade92 100644 --- a/uv.lock +++ b/uv.lock @@ -3280,7 +3280,7 @@ wheels = [ [[package]] name = "uipath" -version = "2.9.10" +version = "2.9.12" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "applicationinsights" }, @@ -3303,28 +3303,28 @@ dependencies = [ { name = "uipath-platform" }, { name = "uipath-runtime" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4d/37/8b3620075ba519377829849947f17f321f9a6ae8bc79a9fb9762faf23b45/uipath-2.9.10.tar.gz", hash = "sha256:b0d9ea5765e72ea0559cea8d9aae16c4edba4b8aa520a6481dc0467393ac2cb2", size = 2445685, upload-time = "2026-02-25T23:29:27.003Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/1b/308b3ef5e49796cb90f14b42e63be8aa9e47cb8f20cd004154845d9ced4b/uipath-2.9.12.tar.gz", hash = "sha256:a3c021243491634ba3f1fa0b58c698c360a8a728f369d56a3b3196246af87377", size = 2447228, upload-time = "2026-02-26T14:58:26.534Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/1f/109d8a483416fe4c27c35c5fcda4426a6e2e342842d570fe3fa7a1c97fc8/uipath-2.9.10-py3-none-any.whl", hash = "sha256:e07e5c5a3e74d2aa0c9688a0c890135c19003c8cde919e894c21bd10ed105a4d", size = 350656, upload-time = "2026-02-25T23:29:24.197Z" }, + { url = "https://files.pythonhosted.org/packages/6e/b3/0774ce5a8a992f5f3a04a66ce559e397d80935e5939e53c2a601bda15af1/uipath-2.9.12-py3-none-any.whl", hash = "sha256:973f99cdd1d33742d4b95654671563f42eaa39bcd33ef1a159ce0fbd3111b980", size = 352105, upload-time = "2026-02-26T14:58:25.016Z" }, ] [[package]] name = "uipath-core" -version = "0.5.2" +version = "0.5.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-instrumentation" }, { name = "opentelemetry-sdk" }, { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/17/d3/7b3cd984ca5530892a2dac945408d50f64f3f21c1fa6c5a68d9625d685f0/uipath_core-0.5.2.tar.gz", hash = "sha256:a7fd2d5c6d49117bea060c162cd380ae59fe5f2ed74bb0e4e508d51cd57e9de1", size = 119081, upload-time = "2026-02-23T10:16:48.567Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/76/568bbe81e2c502b0b3d34b35f0f2d7557ceed58fc9161820d186276b47ac/uipath_core-0.5.3.tar.gz", hash = "sha256:5ff386c9bf85006648f111496b74534925fab1de4b35d5d0c2f6dfdf81e6e103", size = 119096, upload-time = "2026-02-25T14:08:47.548Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/24/3b65d78f8028b4bf49f76ed9fc08257c0941bf64fc597caf69e2c0605584/uipath_core-0.5.2-py3-none-any.whl", hash = "sha256:7a675074e2c6b2ec00995051d1c9850f6f70543cce3161b6a6b8c2911dc16ee0", size = 42844, upload-time = "2026-02-23T10:16:47.271Z" }, + { url = "https://files.pythonhosted.org/packages/1c/35/87a346abe7485c0a63802487050e3550723bfd97925f85cc8814d34bb2a3/uipath_core-0.5.3-py3-none-any.whl", hash = "sha256:2ad9670d3d8e62d7e4f5ed090dffeff00281b8d20d159fff67cac941889d6748", size = 42858, upload-time = "2026-02-25T14:08:46.037Z" }, ] [[package]] name = "uipath-langchain" -version = "0.7.6" +version = "0.7.7" source = { editable = "." } dependencies = [ { name = "httpx" }, @@ -3391,9 +3391,9 @@ requires-dist = [ { name = "openinference-instrumentation-langchain", specifier = ">=0.1.56" }, { name = "pydantic-settings", specifier = ">=2.6.0" }, { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "uipath", specifier = ">=2.9.10,<2.10.0" }, + { name = "uipath", specifier = ">=2.9.12,<2.10.0" }, { name = "uipath-core", specifier = ">=0.5.2,<0.6.0" }, - { name = "uipath-platform", specifier = ">=0.0.1,<0.1.0" }, + { name = "uipath-platform", specifier = ">=0.0.4,<0.1.0" }, { name = "uipath-runtime", specifier = ">=0.9.1,<0.10.0" }, ] provides-extras = ["vertex", "bedrock"] @@ -3416,7 +3416,7 @@ dev = [ [[package]] name = "uipath-platform" -version = "0.0.2" +version = "0.0.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "httpx" }, @@ -3425,9 +3425,9 @@ dependencies = [ { name = "truststore" }, { name = "uipath-core" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2e/53/cd3293926c89c4a2da477b1cb386b84490905cf7a49a54e7788085932f10/uipath_platform-0.0.2.tar.gz", hash = "sha256:1d59c8be6e1b168cb08449416e25532dc5085e02574bd11d422f6fd9c053a5f5", size = 253303, upload-time = "2026-02-23T16:37:00.097Z" } +sdist = { url = "https://files.pythonhosted.org/packages/18/da/7bfaa11939f098dff16b123232ec33862d92508f8e38bd8243e2cd9cad5e/uipath_platform-0.0.4.tar.gz", hash = "sha256:fa1fddb26ca1f2fe388a876ed5e3bc629b219eb2a1288cde21c72f1c9cd4e9e3", size = 255031, upload-time = "2026-02-26T14:43:04.375Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/dd/21f313aff40f54b7e56618676f057779a92922b83d3a9da643d8d79e5d72/uipath_platform-0.0.2-py3-none-any.whl", hash = "sha256:b0b963edf150a0a0951cc25a0aace632ab39e2b73be6e7edeaf7f53bf9718c74", size = 152879, upload-time = "2026-02-23T16:36:58.747Z" }, + { url = "https://files.pythonhosted.org/packages/44/f3/a952b9dffb45b102fbdfed295d89b97de4dacc0eebbf0f6edc78896219af/uipath_platform-0.0.4-py3-none-any.whl", hash = "sha256:36cd07a3fad6db9e6a6e0741e49f42666fb5df4fd74f4defdd2e88c80396f32d", size = 156065, upload-time = "2026-02-26T14:43:02.772Z" }, ] [[package]]