Skip to content

Commit 17f595d

Browse files
committed
fix: suppress agenthub_config default on direct chat-model construction
1 parent a3e89aa commit 17f595d

9 files changed

Lines changed: 168 additions & 11 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uipath-langchain"
3-
version = "0.10.15"
3+
version = "0.10.16"
44
description = "Python SDK that enables developers to build and deploy LangGraph agents to the UiPath Cloud Platform"
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.11"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import os
2+
3+
from pydantic import model_validator
4+
5+
6+
class _AgentHubConfigDefaultMixin:
7+
@model_validator(mode="after")
8+
def _clear_agenthub_config_default(self):
9+
if os.getenv("UIPATH_AGENTHUB_CONFIG") is None:
10+
client_settings = getattr(self, "client_settings", None)
11+
if client_settings is not None and hasattr(
12+
client_settings, "agenthub_config"
13+
):
14+
client_settings.agenthub_config = None
15+
return self

src/uipath_langchain/chat/bedrock.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,42 @@
33

44
from pydantic import model_validator
55
from uipath_langchain_client.clients.bedrock.chat_models import (
6-
UiPathChatAnthropicBedrock,
7-
UiPathChatBedrock,
6+
UiPathChatAnthropicBedrock as _UpstreamUiPathChatAnthropicBedrock,
7+
)
8+
from uipath_langchain_client.clients.bedrock.chat_models import (
9+
UiPathChatBedrock as _UpstreamUiPathChatBedrock,
810
)
911
from uipath_langchain_client.clients.bedrock.chat_models import (
1012
UiPathChatBedrockConverse as _UpstreamUiPathChatBedrockConverse,
1113
)
1214

15+
from ._settings import _AgentHubConfigDefaultMixin
16+
1317
DEFAULT_MODEL_NAME = "anthropic.claude-haiku-4-5-20251001-v1:0"
1418

1519

1620
def _default_factory() -> str:
1721
return os.getenv("UIPATH_MODEL_NAME", DEFAULT_MODEL_NAME)
1822

1923

24+
class UiPathChatBedrock(_AgentHubConfigDefaultMixin, _UpstreamUiPathChatBedrock):
25+
pass
26+
27+
28+
class UiPathChatAnthropicBedrock(
29+
_AgentHubConfigDefaultMixin, _UpstreamUiPathChatAnthropicBedrock
30+
):
31+
pass
32+
33+
2034
for _cls in (UiPathChatBedrock, UiPathChatAnthropicBedrock):
2135
_cls.model_fields["model_name"].default_factory = _default_factory
2236
_cls.model_rebuild(force=True)
2337

2438

25-
class UiPathChatBedrockConverse(_UpstreamUiPathChatBedrockConverse):
39+
class UiPathChatBedrockConverse(
40+
_AgentHubConfigDefaultMixin, _UpstreamUiPathChatBedrockConverse
41+
):
2642
@model_validator(mode="before")
2743
@classmethod
2844
def _inject_default_model(cls, values: Any) -> Any:

src/uipath_langchain/chat/models.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import os
22

3-
from uipath_langchain_client.clients.normalized.chat_models import UiPathChat
3+
from uipath_langchain_client.clients.normalized.chat_models import (
4+
UiPathChat as _UpstreamUiPathChat,
5+
)
46

7+
from ._settings import _AgentHubConfigDefaultMixin
58
from .openai import UiPathAzureChatOpenAI, UiPathChatOpenAI
69

710
DEFAULT_MODEL_NAME = "gpt-4.1-mini-2025-04-14"
@@ -11,6 +14,10 @@ def _default_factory() -> str:
1114
return os.getenv("UIPATH_MODEL_NAME", DEFAULT_MODEL_NAME)
1215

1316

17+
class UiPathChat(_AgentHubConfigDefaultMixin, _UpstreamUiPathChat):
18+
pass
19+
20+
1421
UiPathChat.model_fields["model_name"].default_factory = _default_factory
1522
UiPathChat.model_rebuild(force=True)
1623

src/uipath_langchain/chat/openai.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,31 @@
11
import os
22

33
from uipath_langchain_client.clients.openai.chat_models import (
4-
UiPathAzureChatOpenAI,
5-
UiPathChatOpenAI,
4+
UiPathAzureChatOpenAI as _UpstreamUiPathAzureChatOpenAI,
5+
)
6+
from uipath_langchain_client.clients.openai.chat_models import (
7+
UiPathChatOpenAI as _UpstreamUiPathChatOpenAI,
68
)
79

10+
from ._settings import _AgentHubConfigDefaultMixin
11+
812
DEFAULT_MODEL_NAME = "gpt-4.1-mini-2025-04-14"
913

1014

1115
def _default_factory() -> str:
1216
return os.getenv("UIPATH_MODEL_NAME", DEFAULT_MODEL_NAME)
1317

1418

19+
class UiPathChatOpenAI(_AgentHubConfigDefaultMixin, _UpstreamUiPathChatOpenAI):
20+
pass
21+
22+
23+
class UiPathAzureChatOpenAI(
24+
_AgentHubConfigDefaultMixin, _UpstreamUiPathAzureChatOpenAI
25+
):
26+
pass
27+
28+
1529
for _cls in (UiPathAzureChatOpenAI, UiPathChatOpenAI):
1630
_cls.model_fields["model_name"].default_factory = _default_factory
1731
_cls.model_rebuild(force=True)

src/uipath_langchain/chat/vertex.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
import os
22

33
from uipath_langchain_client.clients.google.chat_models import (
4-
UiPathChatGoogleGenerativeAI,
4+
UiPathChatGoogleGenerativeAI as _UpstreamUiPathChatGoogleGenerativeAI,
55
)
66

7+
from ._settings import _AgentHubConfigDefaultMixin
8+
79
DEFAULT_MODEL_NAME = "gemini-2.5-flash"
810

911

1012
def _default_factory() -> str:
1113
return os.getenv("UIPATH_MODEL_NAME", DEFAULT_MODEL_NAME)
1214

1315

16+
class UiPathChatGoogleGenerativeAI(
17+
_AgentHubConfigDefaultMixin, _UpstreamUiPathChatGoogleGenerativeAI
18+
):
19+
pass
20+
21+
1422
UiPathChatGoogleGenerativeAI.model_fields[
1523
"model_name"
1624
].default_factory = _default_factory
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
"""Tests for the chat-client agenthub_config default behavior.
2+
3+
Direct construction of UiPathChat / UiPathChatOpenAI / UiPathAzureChatOpenAI /
4+
UiPathChatBedrock / UiPathChatBedrockConverse / UiPathChatAnthropicBedrock /
5+
UiPathChatGoogleGenerativeAI / UiPathChatVertex must default
6+
client_settings.agenthub_config to None, so ad-hoc local SDK use isn't
7+
treated as deployed-runtime traffic by AOps governance.
8+
9+
The upstream classes (used by chat_model_factory for deployed runtimes)
10+
must keep the upstream library default of "agentsruntime", proving the
11+
local override does not leak globally onto the upstream class.
12+
"""
13+
14+
import pytest
15+
16+
from uipath_langchain.chat import (
17+
UiPathAzureChatOpenAI,
18+
UiPathChat,
19+
UiPathChatAnthropicBedrock,
20+
UiPathChatBedrock,
21+
UiPathChatBedrockConverse,
22+
UiPathChatGoogleGenerativeAI,
23+
UiPathChatOpenAI,
24+
UiPathChatVertex,
25+
)
26+
27+
_FAKE_JWT = (
28+
"eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9."
29+
"eyJzdWIiOiAidGVzdCIsICJpc3MiOiAidGVzdCJ9."
30+
"signature"
31+
)
32+
33+
34+
@pytest.fixture(autouse=True)
35+
def _platform_env(monkeypatch):
36+
monkeypatch.setenv("UIPATH_ACCESS_TOKEN", _FAKE_JWT)
37+
monkeypatch.setenv("UIPATH_URL", "https://example.com/org/tenant/orchestrator_/")
38+
monkeypatch.setenv("UIPATH_TENANT_ID", "tenant")
39+
monkeypatch.setenv("UIPATH_ORGANIZATION_ID", "org")
40+
monkeypatch.delenv("UIPATH_AGENTHUB_CONFIG", raising=False)
41+
monkeypatch.delenv("UIPATH_MODEL_NAME", raising=False)
42+
43+
44+
_DIRECT_CTOR_CASES = [
45+
UiPathChat,
46+
UiPathAzureChatOpenAI,
47+
UiPathChatOpenAI,
48+
UiPathChatBedrock,
49+
UiPathChatBedrockConverse,
50+
UiPathChatAnthropicBedrock,
51+
UiPathChatGoogleGenerativeAI,
52+
UiPathChatVertex,
53+
]
54+
55+
56+
@pytest.mark.parametrize("cls", _DIRECT_CTOR_CASES)
57+
class TestDirectConstructorAgentHubConfig:
58+
def test_default_is_none(self, cls):
59+
llm = cls()
60+
assert llm.client_settings.agenthub_config is None
61+
62+
def test_env_var_is_honored(self, cls, monkeypatch):
63+
monkeypatch.setenv("UIPATH_AGENTHUB_CONFIG", "agentsplayground")
64+
llm = cls()
65+
assert llm.client_settings.agenthub_config == "agentsplayground"
66+
67+
68+
_UPSTREAM_CASES = [
69+
"uipath_langchain_client.clients.normalized.chat_models:UiPathChat",
70+
"uipath_langchain_client.clients.openai.chat_models:UiPathChatOpenAI",
71+
"uipath_langchain_client.clients.openai.chat_models:UiPathAzureChatOpenAI",
72+
"uipath_langchain_client.clients.bedrock.chat_models:UiPathChatBedrock",
73+
"uipath_langchain_client.clients.bedrock.chat_models:UiPathChatBedrockConverse",
74+
"uipath_langchain_client.clients.bedrock.chat_models:UiPathChatAnthropicBedrock",
75+
"uipath_langchain_client.clients.google.chat_models:UiPathChatGoogleGenerativeAI",
76+
]
77+
78+
79+
@pytest.mark.parametrize("upstream_path", _UPSTREAM_CASES)
80+
class TestUpstreamAgentHubConfigUntouched:
81+
"""Deployed runtimes go through chat_model_factory, which instantiates the
82+
upstream classes directly. Those must keep the upstream library default of
83+
'agentsruntime'."""
84+
85+
def _resolve(self, upstream_path: str):
86+
import importlib
87+
88+
module_name, attr = upstream_path.split(":")
89+
return getattr(importlib.import_module(module_name), attr)
90+
91+
def test_upstream_keeps_agentsruntime_default(self, upstream_path):
92+
# make sure model rebinds are not breaking the agenthub_config
93+
import uipath_langchain.chat # noqa: F401
94+
95+
upstream_cls = self._resolve(upstream_path)
96+
llm = upstream_cls(model="gpt-4.1-mini-2025-04-14")
97+
assert llm.client_settings.agenthub_config == "agentsruntime"

tests/chat/test_default_model_name.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ def test_fireworks_raises_without_model(self):
121121

122122

123123
class TestReExportedClassIdentity:
124-
def test_uipath_chat_is_upstream_class(self):
125-
assert UiPathChat is _UpstreamUiPathChat
124+
def test_uipath_chat_is_subclass_of_upstream(self):
125+
assert issubclass(UiPathChat, _UpstreamUiPathChat)
126126

127127
def test_uipath_chat_vertex_alias_matches_google(self):
128128
assert UiPathChatVertex is UiPathChatGoogleGenerativeAI

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)