diff --git a/pyproject.toml b/pyproject.toml index 163897045..347396819 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "uipath-langchain" -version = "0.13.17" +version = "0.13.18" 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" diff --git a/src/uipath_langchain/chat/_legacy/chat_model_factory.py b/src/uipath_langchain/chat/_legacy/chat_model_factory.py index 940cfcf75..fcc31de40 100644 --- a/src/uipath_langchain/chat/_legacy/chat_model_factory.py +++ b/src/uipath_langchain/chat/_legacy/chat_model_factory.py @@ -15,8 +15,8 @@ APIFlavor.OPENAI_COMPLETIONS: LLMProvider.OPENAI, APIFlavor.AWS_BEDROCK_CONVERSE: LLMProvider.BEDROCK, APIFlavor.AWS_BEDROCK_INVOKE: LLMProvider.BEDROCK, + APIFlavor.ANTHROPIC_MESSAGES: LLMProvider.BEDROCK, APIFlavor.VERTEX_GEMINI_GENERATE_CONTENT: LLMProvider.VERTEX, - APIFlavor.VERTEX_ANTHROPIC_CLAUDE: LLMProvider.VERTEX, } @@ -103,7 +103,7 @@ def _create_bedrock_llm( sampling_kwargs["temperature"] = temperature match api_flavor: - case APIFlavor.AWS_BEDROCK_CONVERSE: + case APIFlavor.AWS_BEDROCK_CONVERSE | APIFlavor.ANTHROPIC_MESSAGES: return UiPathChatBedrockConverse( model_name=model, max_tokens=max_tokens, @@ -154,8 +154,6 @@ def _create_vertex_llm( **sampling_kwargs, **kwargs, ) - case APIFlavor.VERTEX_ANTHROPIC_CLAUDE: - raise ValueError(f"api_flavor={api_flavor} is not yet supported for Vertex") case _: raise ValueError(f"Unknown api_flavor={api_flavor} for Vertex") @@ -166,7 +164,9 @@ def _resolve_vendor(api_flavor: APIFlavor) -> LLMProvider: def _resolve_api_flavor(vendor: LLMProvider, model_name: str) -> APIFlavor: if vendor == LLMProvider.VERTEX and "claude" in model_name: - return APIFlavor.VERTEX_ANTHROPIC_CLAUDE + raise ValueError( + f"Anthropic Claude on Vertex is not supported for model '{model_name}'" + ) return _DEFAULT_API_FLAVOR[vendor] diff --git a/src/uipath_langchain/chat/_legacy/types.py b/src/uipath_langchain/chat/_legacy/types.py index 60cedfc78..c79c2c1b0 100644 --- a/src/uipath_langchain/chat/_legacy/types.py +++ b/src/uipath_langchain/chat/_legacy/types.py @@ -17,4 +17,4 @@ class APIFlavor(StrEnum): AWS_BEDROCK_CONVERSE = "AwsBedrockConverse" AWS_BEDROCK_INVOKE = "AwsBedrockInvoke" VERTEX_GEMINI_GENERATE_CONTENT = "GeminiGenerateContent" - VERTEX_ANTHROPIC_CLAUDE = "AnthropicClaude" + ANTHROPIC_MESSAGES = "AnthropicMessages" diff --git a/tests/chat/test_chat_model_factory.py b/tests/chat/test_chat_model_factory.py index 8deda61e2..4b7305441 100644 --- a/tests/chat/test_chat_model_factory.py +++ b/tests/chat/test_chat_model_factory.py @@ -125,15 +125,15 @@ def test_only_api_flavor_vertex_gemini(self): def test_only_api_flavor_vertex_anthropic(self): """Test deriving vendor from AnthropicClaude api_flavor.""" model = { - "modelName": "claude-3-sonnet", + "modelName": "anthropic.claude-sonnet-4-6", "vendor": None, - "apiFlavor": "AnthropicClaude", + "apiFlavor": "AnthropicMessages", } vendor, api_flavor = _compute_vendor_and_api_flavor(model) - assert vendor == LLMProvider.VERTEX - assert api_flavor == APIFlavor.VERTEX_ANTHROPIC_CLAUDE + assert vendor == LLMProvider.BEDROCK + assert api_flavor == APIFlavor.ANTHROPIC_MESSAGES def test_only_api_flavor_vendor_missing_key(self): """Test when vendor key is missing entirely (not just None).""" @@ -189,17 +189,18 @@ def test_only_vendor_vertex_default_flavor(self): assert api_flavor == APIFlavor.VERTEX_GEMINI_GENERATE_CONTENT def test_only_vendor_vertex_claude_special_case(self): - """Test Vertex vendor with Claude in model name uses VERTEX_ANTHROPIC_CLAUDE.""" + """Test Vertex vendor with Claude in model name raises error.""" model = { "modelName": "claude-3-sonnet@20240229", "vendor": "VertexAi", "apiFlavor": None, } - vendor, api_flavor = _compute_vendor_and_api_flavor(model) + with pytest.raises(ValueError) as exc_info: + _compute_vendor_and_api_flavor(model) - assert vendor == LLMProvider.VERTEX - assert api_flavor == APIFlavor.VERTEX_ANTHROPIC_CLAUDE + assert "Vertex" in str(exc_info.value) + assert "claude-3-sonnet@20240229" in str(exc_info.value) def test_only_vendor_vertex_claude_case_sensitive(self): """Test that 'claude' detection is case-sensitive (lowercase only).""" @@ -386,6 +387,31 @@ def test_sonnet_4_5_bedrock_converse_forwards_temperature(self, mocker): _, kwargs = mock_cls.call_args assert kwargs.get("temperature") == 0.7 + def test_anthropic_messages_routes_to_bedrock_converse(self, mocker): + """Flavor AnthropicMessages flavor must be routed to UiPathChatBedrockConverse.""" + pytest.importorskip("langchain_aws") + mocker.patch( + "uipath_langchain.chat._legacy.chat_model_factory._get_model_info", + return_value={ + "modelName": "anthropic.claude-sonnet-4-6", + "vendor": "AwsBedrock", + "apiFlavor": "AnthropicMessages", + "modelDetails": {"shouldSkipTemperature": False}, + }, + ) + mock_cls = mocker.patch( + "uipath_langchain.chat._legacy.bedrock.UiPathChatBedrockConverse" + ) + + get_chat_model( + model="anthropic.claude-sonnet-4-6", + temperature=0.7, + max_tokens=4096, + agenthub_config="cfg", + ) + + mock_cls.assert_called_once() + def test_gpt_openai_responses_forwards_temperature_when_flag_absent(self, mocker): """Older discovery payloads have ``modelDetails: null``; the gate must default to not-skipping and UiPathChatOpenAI must receive the diff --git a/uv.lock b/uv.lock index c626543e7..cba4e4251 100644 --- a/uv.lock +++ b/uv.lock @@ -4439,7 +4439,7 @@ wheels = [ [[package]] name = "uipath-langchain" -version = "0.13.17" +version = "0.13.18" source = { editable = "." } dependencies = [ { name = "a2a-sdk" },