diff --git a/pyproject.toml b/pyproject.toml index 92290ce6f..b8d50b860 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,13 +1,13 @@ [project] name = "uipath-langchain" -version = "0.14.15" +version = "0.14.16" 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.13.7, <2.14.0", "uipath-core>=0.5.29, <0.6.0", - "uipath-platform>=0.2.12, <0.3.0", + "uipath-platform==0.2.14.dev1018287328", "uipath-runtime>=0.12.5, <0.13.0", "uipath-llm-client>=1.17.1, <1.18.0", "langgraph>=1.1.8, <2.0.0", @@ -172,3 +172,6 @@ name = "testpypi" url = "https://test.pypi.org/simple/" publish-url = "https://test.pypi.org/legacy/" explicit = true + +[tool.uv.sources] +uipath-platform = { index = "testpypi" } diff --git a/src/uipath_langchain/agent/tools/a2a/a2a_tool.py b/src/uipath_langchain/agent/tools/a2a/a2a_tool.py index 725eda178..31462ad2e 100644 --- a/src/uipath_langchain/agent/tools/a2a/a2a_tool.py +++ b/src/uipath_langchain/agent/tools/a2a/a2a_tool.py @@ -78,9 +78,9 @@ class A2aClient: pool when done. """ - def __init__(self, agent_card: AgentCard, slug: str) -> None: + def __init__(self, agent_card: AgentCard, resource_name: str) -> None: self._agent_card = agent_card - self._slug = slug + self._resource_name = resource_name self._lock = asyncio.Lock() self._client: Client | None = None self._http_client: httpx.AsyncClient | None = None @@ -96,11 +96,12 @@ async def get(self) -> Client: sdk = UiPath() folder_path = get_execution_folder_path() agent = await sdk.remote_a2a.retrieve_async( - slug=self._slug, folder_path=folder_path + name=self._resource_name, + folder_path=folder_path, ) if not agent.a2a_url: raise ValueError( - f"Remote A2A agent '{self._slug}' has no a2a_url configured" + f"Remote A2A agent '{self._resource_name}' has no a2a_url configured" ) self._agent_card.url = agent.a2a_url @@ -404,7 +405,7 @@ def create_a2a_tools_and_clients( default_output_modes=["text/plain"], ) - a2a_client = A2aClient(agent_card, resource.slug) + a2a_client = A2aClient(agent_card, resource.name) tool = _create_a2a_tool(resource, a2a_client, agent_card) tools.append(tool) clients.append(a2a_client) diff --git a/src/uipath_langchain/agent/tools/mcp/mcp_client.py b/src/uipath_langchain/agent/tools/mcp/mcp_client.py index 4329e7b0b..600f5b3ab 100644 --- a/src/uipath_langchain/agent/tools/mcp/mcp_client.py +++ b/src/uipath_langchain/agent/tools/mcp/mcp_client.py @@ -82,10 +82,11 @@ def __init__( """Initialize the MCP tool session. The MCP server URL and authorization headers are retrieved lazily - from the UiPath SDK on first use, using the config's slug and folder_path. + from the UiPath SDK on first use, using the config's display name and + folder_path. Args: - config: The MCP resource configuration containing slug and folder_path. + config: The MCP resource configuration containing name and folder_path. timeout: Optional timeout configuration for HTTP requests. max_retries: Maximum number of retries on session disconnect errors. session_info_factory: Factory for creating SessionInfo instances. @@ -152,7 +153,7 @@ async def _initialize_client(self) -> None: """ folder_path = get_execution_folder_path() logger.debug( - f"Initializing MCP client for '{self._config.slug}' " + f"Initializing MCP client for '{self._config.name}' " f"in folder '{folder_path}'" ) @@ -162,11 +163,12 @@ async def _initialize_client(self) -> None: # Retrieve MCP server URL from SDK sdk = UiPath() mcp_server = await sdk.mcp.retrieve_async( - slug=self._config.slug, folder_path=folder_path + name=self._config.name, + folder_path=folder_path, ) if mcp_server.mcp_url is None: - raise ValueError(f"MCP server '{self._config.slug}' has no URL configured") + raise ValueError(f"MCP server '{self._config.name}' has no URL configured") self._url = mcp_server.mcp_url self._headers = {"Authorization": f"Bearer {sdk._config.secret}"} diff --git a/tests/agent/tools/test_a2a_tool.py b/tests/agent/tools/test_a2a_tool.py index b27cb2936..d5dd8d0a7 100644 --- a/tests/agent/tools/test_a2a_tool.py +++ b/tests/agent/tools/test_a2a_tool.py @@ -84,8 +84,7 @@ def test_create_tools_builds_one_client_per_enabled_resource() -> None: assert len(tools) == 1 assert len(clients) == 1 - # The client carries the slug used to resolve the proxy URL at runtime. - assert clients[0]._slug == "remote-agent-slug" + assert clients[0]._resource_name == "remote-agent" # The card is built from the cached card; the URL is not yet resolved. assert clients[0]._agent_card.name == "Remote Agent" @@ -96,7 +95,7 @@ def test_create_tools_builds_default_card_without_cached_card() -> None: tools, clients = create_a2a_tools_and_clients([resource]) assert len(tools) == 1 - assert clients[0]._slug == "remote-agent-slug" + assert clients[0]._resource_name == "remote-agent" assert clients[0]._agent_card.name == "remote-agent" @@ -114,8 +113,13 @@ def __init__(self, a2a_url: str | None) -> None: self._a2a_url = a2a_url self.calls: list[tuple[str, str | None]] = [] - async def retrieve_async(self, *, slug: str, folder_path: str | None): - self.calls.append((slug, folder_path)) + async def retrieve_async( + self, + *, + name: str, + folder_path: str | None, + ): + self.calls.append((name, folder_path)) return SimpleNamespace(a2a_url=self._a2a_url) @@ -125,7 +129,7 @@ def __init__(self, a2a_url: str | None) -> None: self._config = SimpleNamespace(secret="token") -def _patch_runtime(monkeypatch: pytest.MonkeyPatch, sdk: _FakeSdk) -> dict[str, Any]: +def _patch_runtime(monkeypatch: pytest.MonkeyPatch, sdk: Any) -> dict[str, Any]: """Patch the SDK, folder-path resolver, and A2A client factory.""" import uipath.platform as uipath_platform from a2a.client import ClientFactory @@ -158,14 +162,14 @@ async def test_client_resolves_proxy_url_via_retrieve( default_input_modes=["text/plain"], default_output_modes=["text/plain"], ) - client = A2aClient(card, slug="remote-agent-slug") + client = A2aClient(card, resource_name="Remote Agent") result = await client.get() assert result is handles["connected"] # URL resolved from the retrieved agent's a2a_url, not the cached card URL. assert card.url == PROXY_URL - assert sdk.remote_a2a.calls == [("remote-agent-slug", "Shared")] + assert sdk.remote_a2a.calls == [("Remote Agent", "Shared")] await client.dispose() @@ -186,7 +190,7 @@ async def test_client_raises_when_agent_has_no_proxy_url( default_input_modes=["text/plain"], default_output_modes=["text/plain"], ) - client = A2aClient(card, slug="remote-agent-slug") + client = A2aClient(card, resource_name="Remote Agent") with pytest.raises(ValueError, match="has no a2a_url"): await client.get() diff --git a/tests/agent/tools/test_mcp/test_mcp_client.py b/tests/agent/tools/test_mcp/test_mcp_client.py index 7b8e93113..dc3d117a3 100644 --- a/tests/agent/tools/test_mcp/test_mcp_client.py +++ b/tests/agent/tools/test_mcp/test_mcp_client.py @@ -849,10 +849,10 @@ async def test_dispose_clears_tools_cache( @pytest.mark.asyncio @patch.dict(os.environ, {"UIPATH_FOLDER_PATH": "/Shared/TestFolder"}) @patch("httpx.AsyncClient") - async def test_retrieve_async_uses_execution_folder_path( + async def test_retrieve_async_uses_name_and_execution_folder_path( self, mock_async_client_class, mcp_resource_config ): - """Test that retrieve_async is called with folder_path from the execution environment.""" + """Test that name resolution receives both identities and the execution folder.""" mock_sdk = MagicMock() mock_server = MagicMock() mock_server.mcp_url = "https://test.uipath.com/mcp" @@ -876,7 +876,8 @@ async def test_retrieve_async_uses_execution_folder_path( await session.call_tool("test_tool", {"query": "test"}) mock_sdk.mcp.retrieve_async.assert_called_once_with( - slug="test-server", folder_path="/Shared/TestFolder" + name="test_server", + folder_path="/Shared/TestFolder", ) await session.dispose() diff --git a/uv.lock b/uv.lock index b1a4878fc..707aea0d5 100644 --- a/uv.lock +++ b/uv.lock @@ -4498,7 +4498,7 @@ wheels = [ [[package]] name = "uipath-langchain" -version = "0.14.15" +version = "0.14.16" source = { editable = "." } dependencies = [ { name = "a2a-sdk" }, @@ -4588,7 +4588,7 @@ requires-dist = [ { name = "uipath-langchain-client", extras = ["openai"], specifier = ">=1.17.1,<1.18.0" }, { name = "uipath-langchain-client", extras = ["vertexai"], marker = "extra == 'vertex'", specifier = ">=1.17.1,<1.18.0" }, { name = "uipath-llm-client", specifier = ">=1.17.1,<1.18.0" }, - { name = "uipath-platform", specifier = ">=0.2.12,<0.3.0" }, + { name = "uipath-platform", specifier = "==0.2.14.dev1018287328", index = "https://test.pypi.org/simple/" }, { name = "uipath-runtime", specifier = ">=0.12.5,<0.13.0" }, ] provides-extras = ["anthropic", "vertex", "bedrock", "fireworks", "all"] @@ -4672,9 +4672,10 @@ wheels = [ [[package]] name = "uipath-platform" -version = "0.2.12" -source = { registry = "https://pypi.org/simple" } +version = "0.2.14.dev1018287328" +source = { registry = "https://test.pypi.org/simple/" } dependencies = [ + { name = "anyio" }, { name = "httpx" }, { name = "pydantic-function-models" }, { name = "sqlparse" }, @@ -4682,9 +4683,9 @@ dependencies = [ { name = "truststore" }, { name = "uipath-core" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c1/57/d5db35a96fe6acedb74f8c8ce28175e296e9968df9279b244027f151b09e/uipath_platform-0.2.12.tar.gz", hash = "sha256:d60c699f7ca2357106dafd001aa8644d4ba1a7a27d328ab456993627b809fdcc", size = 427943, upload-time = "2026-07-21T09:25:47.829Z" } +sdist = { url = "https://test-files.pythonhosted.org/packages/68/6a/0bea66073b72ec8c13ce1363fed702f090c696feb103d771792e67bd689f/uipath_platform-0.2.14.dev1018287328.tar.gz", hash = "sha256:25c1192e259942e90ad89d834de51aa862aceba8f0931f1f66833efaf508e4d7", size = 430881, upload-time = "2026-07-23T09:22:32.406Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/b5/2e8d8ae1683c502bbf1dde307857078d90e1907449ede83e9fb2dbfb6138/uipath_platform-0.2.12-py3-none-any.whl", hash = "sha256:2958d5d15c70b0aefd54dd865eb20eb5ceec61aac664ebe56d0ab314127f8e4b", size = 281072, upload-time = "2026-07-21T09:25:46.261Z" }, + { url = "https://test-files.pythonhosted.org/packages/77/15/4be7ee86ba80fcc5107a171c1429795074549a319c40aa8d4127f3ec1433/uipath_platform-0.2.14.dev1018287328-py3-none-any.whl", hash = "sha256:e158d3dbd241c72341276b3193dade1861ce178c85165e801f19ba8218bf529a", size = 281644, upload-time = "2026-07-23T09:22:31.04Z" }, ] [[package]]