diff --git a/packages/uipath-platform/pyproject.toml b/packages/uipath-platform/pyproject.toml index eab210d34..b12e287e3 100644 --- a/packages/uipath-platform/pyproject.toml +++ b/packages/uipath-platform/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "uipath-platform" -version = "0.2.17" +version = "0.2.18" description = "HTTP client library for programmatic access to UiPath Platform" readme = { file = "README.md", content-type = "text/markdown" } requires-python = ">=3.11" diff --git a/packages/uipath-platform/src/uipath/platform/common/__init__.py b/packages/uipath-platform/src/uipath/platform/common/__init__.py index 802ec67bc..2d39e561b 100644 --- a/packages/uipath-platform/src/uipath/platform/common/__init__.py +++ b/packages/uipath-platform/src/uipath/platform/common/__init__.py @@ -16,7 +16,7 @@ ResourceOverwritesContext, resource_override, ) -from ._config import UiPathApiConfig, UiPathConfig +from ._config import UiPathApiConfig, UiPathConfig, resolve_coded_agenthub_config from ._endpoints_manager import EndpointManager from ._execution_context import ExecutionSourceContext, UiPathExecutionContext from ._folder_context import FolderContext, header_folder @@ -86,6 +86,7 @@ "FolderContext", "TokenData", "UiPathConfig", + "resolve_coded_agenthub_config", "CreateTask", "CreateEscalation", "WaitEscalation", diff --git a/packages/uipath-platform/src/uipath/platform/common/_config.py b/packages/uipath-platform/src/uipath/platform/common/_config.py index 549844db8..d7e960fb6 100644 --- a/packages/uipath-platform/src/uipath/platform/common/_config.py +++ b/packages/uipath-platform/src/uipath/platform/common/_config.py @@ -225,3 +225,25 @@ def _internal_arguments(self) -> dict[str, Any] | None: UiPathConfig = ConfigurationManager() + + +def resolve_coded_agenthub_config() -> str | None: + """AgentHub config header value for a coded-agent run, or ``None`` when deployed. + + Design-time runs — local, Studio Web, or a debug session — return + ``codedagentsplayground`` so the agent's LLM calls draw the CodedAgents.Playground + licensing pool. A deployed run — a real Orchestrator job that is neither a Studio + Web project nor rooted to a debug session — returns ``None``, which the LLM gateway + resolves to the ``AgentHub.LLM`` operation code. + + Shared by the coded-agent frameworks (langchain / llamaindex / openai-agents) so + they classify design-time vs deployed identically. + """ + from uipath.platform.constants import AGENTHUB_CONFIG_CODED_AGENTS_PLAYGROUND + + deployed = ( + bool(UiPathConfig.job_key) + and not UiPathConfig.is_studio_project + and not UiPathConfig.is_rooted_to_debug_job + ) + return None if deployed else AGENTHUB_CONFIG_CODED_AGENTS_PLAYGROUND diff --git a/packages/uipath-platform/src/uipath/platform/constants/__init__.py b/packages/uipath-platform/src/uipath/platform/constants/__init__.py index fc28a10c8..5c7ce31aa 100644 --- a/packages/uipath-platform/src/uipath/platform/constants/__init__.py +++ b/packages/uipath-platform/src/uipath/platform/constants/__init__.py @@ -49,6 +49,9 @@ HEADER_PROCESS_KEY = "x-uipath-processkey" HEADER_TRACE_ID = "x-uipath-traceid" HEADER_AGENTHUB_CONFIG = "x-uipath-agenthub-config" +# Value for HEADER_AGENTHUB_CONFIG that maps to the CodedAgents.Playground licensing +# operation code (matches AgentHubService AgentHubConfigValues.CodedAgentsPlayground). +AGENTHUB_CONFIG_CODED_AGENTS_PLAYGROUND = "codedagentsplayground" HEADER_GUARDRAILS_SOURCE = "x-uipath-guardrails-source" HEADER_LLMGATEWAY_BYO_CONNECTION_ID = "x-uipath-llmgateway-byoisconnectionid" HEADER_SW_LOCK_KEY = "x-uipath-sw-lockkey" diff --git a/packages/uipath-platform/tests/common/test_config_env_vars.py b/packages/uipath-platform/tests/common/test_config_env_vars.py index 1e48ac894..bcaf01a6d 100644 --- a/packages/uipath-platform/tests/common/test_config_env_vars.py +++ b/packages/uipath-platform/tests/common/test_config_env_vars.py @@ -2,8 +2,12 @@ import pytest -from uipath.platform.common._config import UiPathConfig +from uipath.platform.common._config import ( + UiPathConfig, + resolve_coded_agenthub_config, +) from uipath.platform.constants import ( + AGENTHUB_CONFIG_CODED_AGENTS_PLAYGROUND, ENTRY_POINTS_FILE, ENV_BASE_URL, ENV_FOLDER_KEY, @@ -190,3 +194,44 @@ def test_has_eval_folder(self, monkeypatch, tmp_path): assert UiPathConfig.has_eval_folder is False (tmp_path / EVALS_FOLDER).mkdir() assert UiPathConfig.has_eval_folder is True + + +class TestResolveCodedAgentHubConfig: + @pytest.fixture(autouse=True) + def _isolated_config(self, monkeypatch, tmp_path): + # Run in an empty dir so is_rooted_to_debug_job has no stray uipath.json, + # and reset the cached internal arguments around each case. + monkeypatch.chdir(tmp_path) + UiPathConfig.reset() + yield + UiPathConfig.reset() + + def test_local_run_is_design_time(self): + # No job key -> local/design-time -> coded playground marker. + assert ( + resolve_coded_agenthub_config() == AGENTHUB_CONFIG_CODED_AGENTS_PLAYGROUND + ) + + def test_deployed_job_returns_none(self, monkeypatch): + # Real job, not a studio project, not a debug session -> None (AgentHub.LLM). + monkeypatch.setenv(ENV_JOB_KEY, "deployed-job") + assert resolve_coded_agenthub_config() is None + + def test_studio_web_job_is_design_time(self, monkeypatch): + # Job present but a studio project -> design-time. + monkeypatch.setenv(ENV_JOB_KEY, "sw-job") + monkeypatch.setenv(ENV_UIPATH_PROJECT_ID, "project-id") + assert ( + resolve_coded_agenthub_config() == AGENTHUB_CONFIG_CODED_AGENTS_PLAYGROUND + ) + + def test_debug_rooted_job_is_design_time(self, monkeypatch, tmp_path): + # Job present, no studio project, but rooted to a debug session -> design-time. + monkeypatch.setenv(ENV_JOB_KEY, "debug-job") + (tmp_path / "uipath.json").write_text( + '{"runtime": {"internalArguments": {"isDebug": true}}}' + ) + UiPathConfig.reset() + assert ( + resolve_coded_agenthub_config() == AGENTHUB_CONFIG_CODED_AGENTS_PLAYGROUND + ) diff --git a/packages/uipath-platform/uv.lock b/packages/uipath-platform/uv.lock index 2e506b0af..99067a7a6 100644 --- a/packages/uipath-platform/uv.lock +++ b/packages/uipath-platform/uv.lock @@ -3,7 +3,7 @@ revision = 3 requires-python = ">=3.11" [options] -exclude-newer = "2026-07-29T07:23:36.9681123Z" +exclude-newer = "0001-01-01T00:00:00Z" # This has no effect and is included for backwards compatibility when using relative exclude-newer values. exclude-newer-span = "P2D" [options.exclude-newer-package] @@ -1095,7 +1095,7 @@ dev = [ [[package]] name = "uipath-platform" -version = "0.2.17" +version = "0.2.18" source = { editable = "." } dependencies = [ { name = "anyio" },