Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

All notable changes to `uipath_llm_client` (core package) will be documented in this file.

## [1.9.1] - 2026-04-17

### Added
- `utils.model_family.is_anthropic_model_name()` helper and `ANTHROPIC_MODEL_NAME_KEYWORDS` tuple — name-based Claude detection for BYOM deployments where discovery does not expose `modelFamily`

### Fixed
- `UiPathLiteLLM` now detects Claude-family models by name when `modelFamily` is unavailable (BYOM), correctly routing Bedrock/Vertex provider selection and default flavors

## [1.9.0] - 2026-04-17

### Added
Expand Down
8 changes: 8 additions & 0 deletions packages/uipath_langchain_client/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

All notable changes to `uipath_langchain_client` will be documented in this file.

## [1.9.1] - 2026-04-17

### Fixed
- Detect Anthropic-family models by additional name keywords (`anthropic`, `opus`, `sonnet`, `haiku`, `mythos`) alongside `claude` — applies to Bedrock INVOKE factory routing and the normalized client's empty tool-call content workaround. Uses the shared `is_anthropic_model_name()` helper from core 1.9.1.

### Changed
- Minimum `uipath-llm-client` bumped to 1.9.1 for the shared `is_anthropic_model_name()` helper

## [1.9.0] - 2026-04-17

### Changed
Expand Down
2 changes: 1 addition & 1 deletion packages/uipath_langchain_client/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"langchain>=1.2.15",
"uipath-llm-client>=1.9.0",
"uipath-llm-client>=1.9.1",
]

[project.optional-dependencies]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
__title__ = "UiPath LangChain Client"
__description__ = "A Python client for interacting with UiPath's LLM services via LangChain."
__version__ = "1.9.0"
__version__ = "1.9.1"
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@
get_captured_response_headers,
set_captured_response_headers,
)
from uipath.llm_client.utils.retry import RetryConfig
from uipath_langchain_client.settings import (
UiPathAPIConfig,
UiPathBaseSettings,
get_default_client_settings,
)
from uipath_langchain_client.utils import RetryConfig


class UiPathBaseLLMClient(BaseModel, ABC):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,14 @@
from typing_extensions import Self

from uipath.llm_client.clients.litellm import UiPathLiteLLM
from uipath.llm_client.settings.constants import ApiFlavor, ApiType, RoutingMode, VendorType
from uipath_langchain_client.base_client import UiPathBaseChatModel
from uipath_langchain_client.settings import UiPathAPIConfig
from uipath_langchain_client.settings import (
ApiFlavor,
ApiType,
RoutingMode,
UiPathAPIConfig,
VendorType,
)

try:
from langchain_litellm import ChatLiteLLM
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@
from typing_extensions import Self

from uipath.llm_client.clients.litellm import UiPathLiteLLM
from uipath.llm_client.settings.constants import ApiFlavor, ApiType, RoutingMode, VendorType
from uipath_langchain_client.base_client import UiPathBaseEmbeddings
from uipath_langchain_client.settings import UiPathAPIConfig
from uipath_langchain_client.settings import (
ApiFlavor,
ApiType,
RoutingMode,
UiPathAPIConfig,
VendorType,
)


class UiPathLiteLLMEmbeddings(UiPathBaseEmbeddings):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@

from uipath_langchain_client.base_client import UiPathBaseChatModel
from uipath_langchain_client.settings import ApiType, RoutingMode, UiPathAPIConfig
from uipath_langchain_client.utils import is_anthropic_model_name

_DictOrPydanticClass = Union[dict[str, Any], type[BaseModel], type]
_DictOrPydantic = Union[dict[str, Any], BaseModel]
Expand Down Expand Up @@ -412,7 +413,7 @@ def _preprocess_request(
converted_message["content"] = ""
if (
self.model_name
and "claude" in self.model_name.lower()
and is_anthropic_model_name(self.model_name)
and not converted_message["content"]
):
converted_message["content"] = "tool_call"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
VendorType,
get_default_client_settings,
)
from uipath_langchain_client.utils import is_anthropic_model_name


def get_chat_model(
Expand Down Expand Up @@ -172,7 +173,9 @@ def get_chat_model(
**model_kwargs,
)
case VendorType.AWSBEDROCK:
if model_family == ModelFamily.ANTHROPIC_CLAUDE and api_flavor is None:
if (
model_family == ModelFamily.ANTHROPIC_CLAUDE and api_flavor != ApiFlavor.CONVERSE
) or (api_flavor == ApiFlavor.INVOKE and is_anthropic_model_name(model_name)):
from uipath_langchain_client.clients.bedrock.chat_models import (
UiPathChatAnthropicBedrock,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
UiPathTooManyRequestsError,
UiPathUnprocessableEntityError,
)
from uipath.llm_client.utils.model_family import (
ANTHROPIC_MODEL_NAME_KEYWORDS,
is_anthropic_model_name,
)
from uipath.llm_client.utils.retry import RetryConfig

__all__ = [
Expand All @@ -30,4 +34,6 @@
"UiPathServiceUnavailableError",
"UiPathGatewayTimeoutError",
"UiPathTooManyRequestsError",
"ANTHROPIC_MODEL_NAME_KEYWORDS",
"is_anthropic_model_name",
]
2 changes: 1 addition & 1 deletion src/uipath/llm_client/__version__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
__title__ = "UiPath LLM Client"
__description__ = "A Python client for interacting with UiPath's LLM services."
__version__ = "1.9.0"
__version__ = "1.9.1"
24 changes: 12 additions & 12 deletions src/uipath/llm_client/clients/litellm/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
RoutingMode,
VendorType,
)
from uipath.llm_client.utils.model_family import is_anthropic_model_name
from uipath.llm_client.utils.retry import RetryConfig

# Route OpenAI chat completions through base_llm_http_handler (accepts HTTPHandler)
Expand Down Expand Up @@ -191,7 +192,6 @@ def _discover_and_build_api_config(
model_info = self._client_settings.get_model_info(self._model_name, vendor_type=vendor_type)

model_family = model_info.get("modelFamily", None)

discovered_vendor = model_info.get("vendor", None)
discovered_flavor = model_info.get("apiFlavor", None)

Expand All @@ -217,20 +217,18 @@ def _discover_and_build_api_config(
if resolved_flavor is None and resolved_vendor in ("openai", "azure"):
resolved_flavor = ApiFlavor.CHAT_COMPLETIONS

# Claude detection: modelFamily from discovery, or name heuristic for BYOM
# (BYOM discovery does not expose modelFamily).
is_claude = model_family == ModelFamily.ANTHROPIC_CLAUDE or (
model_family is None and is_anthropic_model_name(self._model_name)
)

# Claude on Bedrock defaults to invoke
if (
resolved_flavor is None
and resolved_vendor == "awsbedrock"
and model_family == ModelFamily.ANTHROPIC_CLAUDE
):
if resolved_flavor is None and resolved_vendor == "awsbedrock" and is_claude:
resolved_flavor = ApiFlavor.INVOKE

# Claude on Vertex defaults to anthropic-claude
if (
resolved_flavor is None
and resolved_vendor == "vertexai"
and model_family == ModelFamily.ANTHROPIC_CLAUDE
):
if resolved_flavor is None and resolved_vendor == "vertexai" and is_claude:
resolved_flavor = ApiFlavor.ANTHROPIC_CLAUDE

api_config = UiPathAPIConfig(
Expand All @@ -247,7 +245,9 @@ def _resolve_llm_provider(self) -> str:
The model_family disambiguates cases where the same vendor hosts
models from different providers (e.g. Claude on Vertex AI or Bedrock).
"""
is_claude = self._model_family == ModelFamily.ANTHROPIC_CLAUDE
is_claude = self._model_family == ModelFamily.ANTHROPIC_CLAUDE or (
self._model_family is None and is_anthropic_model_name(self._model_name)
)
vendor = str(self._api_config.vendor_type or "openai")

# Claude on Vertex AI → vertex_ai (uses VertexAIAnthropicConfig)
Expand Down
20 changes: 20 additions & 0 deletions src/uipath/llm_client/utils/model_family.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""Heuristic helpers for identifying a model's family from its name.

Discovery metadata (``modelFamily``) is the authoritative source, but BYOM
deployments do not expose it. These helpers provide a name-based fallback.
"""

ANTHROPIC_MODEL_NAME_KEYWORDS: tuple[str, ...] = (
"anthropic",
"claude",
"opus",
"sonnet",
"haiku",
"mythos",
)


def is_anthropic_model_name(model_name: str) -> bool:
"""Return True if ``model_name`` looks like an Anthropic Claude-family model."""
lower = model_name.lower()
return any(kw in lower for kw in ANTHROPIC_MODEL_NAME_KEYWORDS)