Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-langchain-anthropic for 
openSUSE:Factory checked in at 2026-07-26 11:30:01
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-langchain-anthropic (Old)
 and      /work/SRC/openSUSE:Factory/.python-langchain-anthropic.new.2004 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-langchain-anthropic"

Sun Jul 26 11:30:01 2026 rev:3 rq:1367770 version:1.5.2

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-langchain-anthropic/python-langchain-anthropic.changes
    2026-07-22 19:08:38.636330182 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-langchain-anthropic.new.2004/python-langchain-anthropic.changes
  2026-07-26 11:32:38.183316377 +0200
@@ -1,0 +2,11 @@
+Sat Jul 25 19:03:47 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to version 1.5.2:
+  * Add Claude Opus 5 support
+  * Enable structured output for Claude Opus 4.8
+  * Support the langsmith gateway through an environment
+    variable
+- Raise the anthropic floor to 0.120.0 and the langchain-core
+  floor to 1.5.1, following upstream requires
+
+-------------------------------------------------------------------

Old:
----
  langchain_anthropic-1.5.0.tar.gz

New:
----
  langchain_anthropic-1.5.2.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-langchain-anthropic.spec ++++++
--- /var/tmp/diff_new_pack.a39AwW/_old  2026-07-26 11:32:38.707334427 +0200
+++ /var/tmp/diff_new_pack.a39AwW/_new  2026-07-26 11:32:38.711334565 +0200
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-langchain-anthropic
-Version:        1.5.0
+Version:        1.5.2
 Release:        0
 Summary:        Integration package connecting Claude (Anthropic) APIs and 
LangChain
 License:        MIT
@@ -28,8 +28,8 @@
 BuildRequires:  %{python_module pip}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
-Requires:       python-anthropic >= 0.96.0
-Requires:       python-langchain-core >= 1.5.0
+Requires:       python-anthropic >= 0.120.0
+Requires:       python-langchain-core >= 1.5.1
 Requires:       python-pydantic >= 2.7.4
 BuildArch:      noarch
 # SECTION test requirements

++++++ langchain_anthropic-1.5.0.tar.gz -> langchain_anthropic-1.5.2.tar.gz 
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langchain_anthropic-1.5.0/PKG-INFO 
new/langchain_anthropic-1.5.2/PKG-INFO
--- old/langchain_anthropic-1.5.0/PKG-INFO      2020-02-02 01:00:00.000000000 
+0100
+++ new/langchain_anthropic-1.5.2/PKG-INFO      2020-02-02 01:00:00.000000000 
+0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: langchain-anthropic
-Version: 1.5.0
+Version: 1.5.2
 Summary: Integration package connecting Claude (Anthropic) APIs and LangChain
 Project-URL: Homepage, 
https://docs.langchain.com/oss/python/integrations/providers/anthropic
 Project-URL: Documentation, 
https://reference.langchain.com/python/integrations/langchain_anthropic/
@@ -23,8 +23,8 @@
 Classifier: Programming Language :: Python :: 3.14
 Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
 Requires-Python: <4.0.0,>=3.10.0
-Requires-Dist: anthropic<1.0.0,>=0.96.0
-Requires-Dist: langchain-core<2.0.0,>=1.5.0
+Requires-Dist: anthropic<1.0.0,>=0.120.0
+Requires-Dist: langchain-core<2.0.0,>=1.5.1
 Requires-Dist: pydantic<3.0.0,>=2.7.4
 Description-Content-Type: text/markdown
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/langchain_anthropic-1.5.0/langchain_anthropic/_version.py 
new/langchain_anthropic-1.5.2/langchain_anthropic/_version.py
--- old/langchain_anthropic-1.5.0/langchain_anthropic/_version.py       
2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_anthropic-1.5.2/langchain_anthropic/_version.py       
2020-02-02 01:00:00.000000000 +0100
@@ -1,3 +1,3 @@
 """Version information for `langchain-anthropic`."""
 
-__version__ = "1.5.0"
+__version__ = "1.5.2"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/langchain_anthropic-1.5.0/langchain_anthropic/chat_models.py 
new/langchain_anthropic-1.5.2/langchain_anthropic/chat_models.py
--- old/langchain_anthropic-1.5.0/langchain_anthropic/chat_models.py    
2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_anthropic-1.5.2/langchain_anthropic/chat_models.py    
2020-02-02 01:00:00.000000000 +0100
@@ -48,7 +48,8 @@
 from langchain_core.outputs import ChatGeneration, ChatGenerationChunk, 
ChatResult
 from langchain_core.runnables import Runnable, RunnableMap, RunnablePassthrough
 from langchain_core.tools import BaseTool
-from langchain_core.utils import from_env, get_pydantic_field_names, 
secret_from_env
+from langchain_core.utils import from_env, get_pydantic_field_names
+from langchain_core.utils._gateway import _apply_gateway_config
 from langchain_core.utils.function_calling import (
     convert_to_json_schema,
     convert_to_openai_tool,
@@ -959,24 +960,21 @@
     stop_sequences: list[str] | None = Field(None, alias="stop")
     """Default stop sequences."""
 
-    anthropic_api_url: str | None = Field(
-        alias="base_url",
-        default_factory=from_env(
-            ["ANTHROPIC_API_URL", "ANTHROPIC_BASE_URL"],
-            default="https://api.anthropic.com";,
-        ),
-    )
+    anthropic_api_url: str | None = Field(default=None, alias="base_url")
     """Base URL for API requests. Only specify if using a proxy or service 
emulator.
 
     If a value isn't passed in, will attempt to read the value first from
     `ANTHROPIC_API_URL` and if that is not set, `ANTHROPIC_BASE_URL`.
+
+    If `LANGSMITH_GATEWAY` is set, it is used as a fallback after those env 
vars.
     """
 
-    anthropic_api_key: SecretStr = Field(
-        alias="api_key",
-        default_factory=secret_from_env("ANTHROPIC_API_KEY", default=""),
-    )
-    """Automatically read from env var `ANTHROPIC_API_KEY` if not provided."""
+    anthropic_api_key: SecretStr = Field(default=SecretStr(""), 
alias="api_key")
+    """Automatically read from env var `ANTHROPIC_API_KEY` if not provided.
+
+    If `LANGSMITH_GATEWAY` is enabled and the base URL points at the gateway,
+    `LANGSMITH_GATEWAY_API_KEY` is used instead.
+    """
 
     anthropic_proxy: str | None = Field(
         default_factory=from_env("ANTHROPIC_PROXY", default=None)
@@ -1021,17 +1019,19 @@
     Examples:
 
     - `#!python {"type": "enabled", "budget_tokens": 10_000}` (pre-4.7 models)
-    - `#!python {"type": "adaptive"}` (Opus 4.6+, Sonnet 5)
-    - `#!python {"type": "adaptive", "display": "summarized"}` (Opus 4.7+, 
Sonnet 5)
-    - `#!python {"type": "disabled"}` (Sonnet 5, where adaptive thinking is
-      on by default)
+    - `#!python {"type": "adaptive"}` (Opus 4.6+, Opus 5, Sonnet 5)
+    - `#!python {"type": "adaptive", "display": "summarized"}` (Opus 4.7+,
+      Opus 5, Sonnet 5)
+    - `#!python {"type": "disabled"}` (Opus 5 and Sonnet 5, where adaptive
+      thinking is on by default)
 
-    !!! note "Claude Opus 4.7+ and Sonnet 5"
+    !!! note "Claude Opus 4.7+, Opus 5, and Sonnet 5"
 
         `budget_tokens` is removed on these models — use `{"type": "adaptive"}`
         with `output_config.effort` to control reasoning effort. The default
         `display` is `"omitted"`; set it to `"summarized"` to receive
-        summarized reasoning in the response.
+        summarized reasoning in the response. On Opus 5, disabled thinking is
+        supported only at `"high"` effort or below.
     """
 
     output_config: dict[str, Any] | None = None
@@ -1208,6 +1208,31 @@
         self._add_version("langchain-anthropic", __version__)
         return self
 
+    @model_validator(mode="before")
+    @classmethod
+    def _resolve_gateway(cls, values: Any) -> Any:
+        """Resolve the base URL and API key, applying LangSmith gateway 
settings.
+
+        An explicit ``base_url``/``api_key`` always wins. Otherwise the base 
URL
+        falls back to ``ANTHROPIC_API_URL``/``ANTHROPIC_BASE_URL``, then the
+        LangSmith gateway, then the Anthropic default. The gateway key is
+        preferred only when the base URL came from the gateway; for any other
+        endpoint the provider key wins, and the gateway key is a candidate only
+        when the gateway is enabled.
+        """
+        if isinstance(values, dict):
+            _apply_gateway_config(
+                values,
+                cls,
+                base_url_field="anthropic_api_url",
+                api_key_field="anthropic_api_key",
+                provider_path="anthropic",
+                base_url_env=["ANTHROPIC_API_URL", "ANTHROPIC_BASE_URL"],
+                api_key_env="ANTHROPIC_API_KEY",
+                default_base_url="https://api.anthropic.com";,
+            )
+        return values
+
     def _resolve_model_profile(self) -> ModelProfile | None:
         profile = _get_default_model_profile(self.model) or None
         if profile is not None and self.betas and "context-1m-2025-08-07" in 
self.betas:
@@ -1265,6 +1290,51 @@
         }
         return anthropic.AsyncClient(**params)
 
+    def _assert_valid_model_configuration(self, kwargs: Mapping[str, Any]) -> 
None:
+        """Validate resolved request configuration against model-specific 
invariants."""
+        request_config = {**self.model_kwargs, **kwargs}
+        thinking = request_config.get("thinking")
+        if self.thinking is not None:
+            thinking = self.thinking
+
+        output_config = dict(self.output_config or {})
+        if self.reasoning_effort:
+            output_config["effort"] = self.reasoning_effort
+        request_output_config = request_config.get("output_config")
+        if isinstance(request_output_config, dict):
+            output_config.update(request_output_config)
+        effort = request_config.get("effort")
+        if effort is None:
+            effort = request_config.get("reasoning_effort")
+        if effort:
+            output_config["effort"] = effort
+
+        if (
+            self.model.startswith("claude-opus-5")
+            and isinstance(thinking, Mapping)
+            and thinking.get("type") == "enabled"
+        ):
+            msg = (
+                '`thinking={"type": "enabled", "budget_tokens": ...}` is not '
+                f"supported for {self.model}; use adaptive thinking and "
+                "`output_config.effort` instead."
+            )
+            raise ValueError(msg)
+
+        if (
+            self.model.startswith("claude-opus-5")
+            and isinstance(thinking, Mapping)
+            and thinking.get("type") == "disabled"
+            and output_config.get("effort") in {"xhigh", "max"}
+        ):
+            msg = (
+                '`thinking={"type": "disabled"}` is not supported for '
+                f"{self.model} with "
+                f"`output_config.effort={output_config['effort']!r}`; use 
adaptive "
+                "thinking, omit `thinking`, or set effort to `high` or below."
+            )
+            raise ValueError(msg)
+
     def _get_request_payload(
         self,
         input_: LanguageModelInput,
@@ -1273,6 +1343,7 @@
         **kwargs: Any,
     ) -> dict:
         """Get the request payload for the Anthropic API."""
+        self._assert_valid_model_configuration(kwargs)
         messages = self._convert_input(input_).to_messages()
 
         for idx, message in enumerate(messages):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/langchain_anthropic-1.5.0/langchain_anthropic/data/_profiles.py 
new/langchain_anthropic-1.5.2/langchain_anthropic/data/_profiles.py
--- old/langchain_anthropic-1.5.0/langchain_anthropic/data/_profiles.py 
2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_anthropic-1.5.2/langchain_anthropic/data/_profiles.py 
2020-02-02 01:00:00.000000000 +0100
@@ -297,7 +297,41 @@
         "video_outputs": False,
         "reasoning_output": True,
         "tool_calling": True,
-        "structured_output": False,
+        "structured_output": True,
+        "attachment": True,
+        "temperature": False,
+        "image_url_inputs": True,
+        "pdf_tool_message": True,
+        "image_tool_message": True,
+        "tool_call_streaming": True,
+        "reasoning_effort_levels": [
+            "low",
+            "medium",
+            "high",
+            "xhigh",
+            "max",
+        ],
+        "reasoning_effort_default": "high",
+    },
+    "claude-opus-5": {
+        "name": "Claude Opus 5",
+        "release_date": "2026-07-24",
+        "last_updated": "2026-07-24",
+        "open_weights": False,
+        "max_input_tokens": 1000000,
+        "max_output_tokens": 128000,
+        "text_inputs": True,
+        "image_inputs": True,
+        "audio_inputs": False,
+        "pdf_inputs": True,
+        "video_inputs": False,
+        "text_outputs": True,
+        "image_outputs": False,
+        "audio_outputs": False,
+        "video_outputs": False,
+        "reasoning_output": True,
+        "tool_calling": True,
+        "structured_output": True,
         "attachment": True,
         "temperature": False,
         "image_url_inputs": True,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/langchain_anthropic-1.5.0/langchain_anthropic/data/profile_augmentations.toml
 
new/langchain_anthropic-1.5.2/langchain_anthropic/data/profile_augmentations.toml
--- 
old/langchain_anthropic-1.5.0/langchain_anthropic/data/profile_augmentations.toml
   2020-02-02 01:00:00.000000000 +0100
+++ 
new/langchain_anthropic-1.5.2/langchain_anthropic/data/profile_augmentations.toml
   2020-02-02 01:00:00.000000000 +0100
@@ -42,6 +42,12 @@
 reasoning_effort_default = "high"
 
 [overrides."claude-opus-4-8"]
+structured_output = true
+reasoning_effort_levels = ["low", "medium", "high", "xhigh", "max"]
+reasoning_effort_default = "high"
+
+[overrides."claude-opus-5"]
+structured_output = true
 reasoning_effort_levels = ["low", "medium", "high", "xhigh", "max"]
 reasoning_effort_default = "high"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langchain_anthropic-1.5.0/pyproject.toml 
new/langchain_anthropic-1.5.2/pyproject.toml
--- old/langchain_anthropic-1.5.0/pyproject.toml        2020-02-02 
01:00:00.000000000 +0100
+++ new/langchain_anthropic-1.5.2/pyproject.toml        2020-02-02 
01:00:00.000000000 +0100
@@ -20,11 +20,11 @@
     "Topic :: Scientific/Engineering :: Artificial Intelligence",
 ]
 
-version = "1.5.0"
+version = "1.5.2"
 requires-python = ">=3.10.0,<4.0.0"
 dependencies = [
-    "anthropic>=0.96.0,<1.0.0",
-    "langchain-core>=1.5.0,<2.0.0",
+    "anthropic>=0.120.0,<1.0.0",
+    "langchain-core>=1.5.1,<2.0.0",
     "pydantic>=2.7.4,<3.0.0",
 ]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/langchain_anthropic-1.5.0/tests/integration_tests/test_chat_models.py 
new/langchain_anthropic-1.5.2/tests/integration_tests/test_chat_models.py
--- old/langchain_anthropic-1.5.0/tests/integration_tests/test_chat_models.py   
2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_anthropic-1.5.2/tests/integration_tests/test_chat_models.py   
2020-02-02 01:00:00.000000000 +0100
@@ -1353,13 +1353,13 @@
 def test_reasoning_effort_defaults_adaptive_thinking() -> None:
     """`reasoning_effort` defaults `thinking` to adaptive on models that 
support it.
 
-    Regression test for a model (Opus 4.7+, Sonnet 5) actually accepting the
+    Regression test for a model (Opus 4.7+, Opus 5, Sonnet 5) actually 
accepting the
     resulting `{"type": "adaptive", "display": "summarized"}` thinking config,
     not just that the payload is well-formed locally.
     """
     llm = ChatAnthropic(
-        model="claude-opus-4-7",
-        reasoning_effort="xhigh",
+        model="claude-opus-5",
+        reasoning_effort="high",
         max_tokens=2_000,
     )
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/langchain_anthropic-1.5.0/tests/unit_tests/test_chat_models.py 
new/langchain_anthropic-1.5.2/tests/unit_tests/test_chat_models.py
--- old/langchain_anthropic-1.5.0/tests/unit_tests/test_chat_models.py  
2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_anthropic-1.5.2/tests/unit_tests/test_chat_models.py  
2020-02-02 01:00:00.000000000 +0100
@@ -2826,6 +2826,20 @@
     }
 
 
+def test_claude_opus_5_profile_supports_structured_output() -> None:
+    model = ChatAnthropic(model="claude-opus-5")
+    assert model.profile
+    assert model.profile["structured_output"] is True
+    assert model.profile["max_input_tokens"] == 1_000_000
+    assert model.profile["reasoning_effort_levels"] == [
+        "low",
+        "medium",
+        "high",
+        "xhigh",
+        "max",
+    ]
+
+
 def test_profile() -> None:
     model = ChatAnthropic(model="claude-sonnet-4-5-20250929")
     assert model.profile
@@ -3034,12 +3048,12 @@
     reasoning mode to apply it to. Only models whose profile advertises
     `xhigh` (Opus 4.7+, Sonnet 5) accept this `thinking` shape.
     """
-    model = ChatAnthropic(model="claude-opus-4-7", reasoning_effort="high")
+    model = ChatAnthropic(model="claude-opus-5", reasoning_effort="low")
 
     payload = model._get_request_payload("Test query")
 
     assert payload["thinking"] == {"type": "adaptive", "display": "summarized"}
-    assert payload["output_config"]["effort"] == "high"
+    assert payload["output_config"]["effort"] == "low"
 
 
 def test_reasoning_effort_as_call_time_kwarg_defaults_adaptive_thinking() -> 
None:
@@ -3093,6 +3107,63 @@
     assert payload["thinking"] == {"type": "disabled"}
 
 
[email protected]("effort", ["xhigh", "max"])
+def test_opus_5_rejects_disabled_thinking_at_high_effort(effort: str) -> None:
+    """Opus 5 permits disabled thinking only through `high` effort."""
+    model = ChatAnthropic(
+        model="claude-opus-5",
+        thinking={"type": "disabled"},
+        output_config={"effort": effort},
+    )
+
+    with pytest.raises(
+        ValueError,
+        match=r"not supported for claude-opus-5.*set effort to `high` or 
below",
+    ):
+        model._get_request_payload("Test query")
+
+
+def test_opus_5_allows_disabled_thinking_at_high_effort() -> None:
+    """Opus 5 accepts disabled thinking at `high` effort."""
+    model = ChatAnthropic(
+        model="claude-opus-5",
+        thinking={"type": "disabled"},
+        output_config={"effort": "max"},
+    )
+
+    payload = model._get_request_payload("Test query", 
output_config={"effort": "high"})
+
+    assert payload["thinking"] == {"type": "disabled"}
+    assert payload["output_config"]["effort"] == "high"
+
+
[email protected]("effort", ["xhigh", "max"])
+def test_opus_5_rejects_call_time_disabled_thinking_at_high_effort(
+    effort: str,
+) -> None:
+    """Preflight validates call-time effort overrides before message 
conversion."""
+    model = ChatAnthropic(
+        model="claude-opus-5",
+        thinking={"type": "disabled"},
+    )
+
+    with pytest.raises(ValueError, match=r"not supported for claude-opus-5"):
+        model._get_request_payload("Test query", output_config={"effort": 
effort})
+
+
[email protected]("effort", ["low", "medium", "high", "xhigh", "max"])
+def test_opus_5_rejects_manual_thinking_at_all_effort_levels(effort: str) -> 
None:
+    """Opus 5 does not support manual extended thinking."""
+    model = ChatAnthropic(
+        model="claude-opus-5",
+        thinking={"type": "enabled", "budget_tokens": 1_024},
+        output_config={"effort": effort},
+    )
+
+    with pytest.raises(ValueError, match=r"use adaptive thinking"):
+        model._get_request_payload("Test query")
+
+
 def test_effort_also_defaults_adaptive_thinking() -> None:
     """Test that `effort` composes with the adaptive-thinking default too.
 
@@ -3780,3 +3851,94 @@
     message_finish = cast("dict[str, Any]", stream_events[-1])
     assert message_finish["event"] == "message-finish"
     assert message_finish["metadata"]["stop_reason"] == "tool_use"
+
+
+def test_langsmith_gateway_true(monkeypatch: pytest.MonkeyPatch) -> None:
+    monkeypatch.setenv("LANGSMITH_GATEWAY", "true")
+    monkeypatch.delenv("ANTHROPIC_API_URL", raising=False)
+    monkeypatch.delenv("ANTHROPIC_BASE_URL", raising=False)
+    llm = ChatAnthropic(model=MODEL_NAME, api_key="test")
+    assert llm.anthropic_api_url == 
"https://gateway.smith.langchain.com/anthropic";
+
+
+def test_langsmith_gateway_false(monkeypatch: pytest.MonkeyPatch) -> None:
+    monkeypatch.setenv("LANGSMITH_GATEWAY", "false")
+    monkeypatch.delenv("ANTHROPIC_API_URL", raising=False)
+    monkeypatch.delenv("ANTHROPIC_BASE_URL", raising=False)
+    llm = ChatAnthropic(model=MODEL_NAME, api_key="test")
+    assert llm.anthropic_api_url == "https://api.anthropic.com";
+
+
+def test_langsmith_gateway_unset(monkeypatch: pytest.MonkeyPatch) -> None:
+    monkeypatch.delenv("LANGSMITH_GATEWAY", raising=False)
+    monkeypatch.delenv("ANTHROPIC_API_URL", raising=False)
+    monkeypatch.delenv("ANTHROPIC_BASE_URL", raising=False)
+    llm = ChatAnthropic(model=MODEL_NAME, api_key="test")
+    assert llm.anthropic_api_url == "https://api.anthropic.com";
+
+
+def test_langsmith_gateway_custom_url(monkeypatch: pytest.MonkeyPatch) -> None:
+    monkeypatch.setenv("LANGSMITH_GATEWAY", "https://my-gateway.example.com/";)
+    monkeypatch.delenv("ANTHROPIC_API_URL", raising=False)
+    monkeypatch.delenv("ANTHROPIC_BASE_URL", raising=False)
+    llm = ChatAnthropic(model=MODEL_NAME, api_key="test")
+    assert llm.anthropic_api_url == "https://my-gateway.example.com/anthropic";
+
+
+def test_langsmith_gateway_provider_env_overrides_gateway(
+    monkeypatch: pytest.MonkeyPatch,
+) -> None:
+    monkeypatch.setenv("LANGSMITH_GATEWAY", "true")
+    monkeypatch.delenv("ANTHROPIC_API_URL", raising=False)
+    monkeypatch.setenv("ANTHROPIC_BASE_URL", "https://api.anthropic.com";)
+    llm = ChatAnthropic(model=MODEL_NAME, api_key="test")
+    assert llm.anthropic_api_url == "https://api.anthropic.com";
+
+
+def test_langsmith_gateway_api_key(monkeypatch: pytest.MonkeyPatch) -> None:
+    monkeypatch.setenv("LANGSMITH_GATEWAY", "true")
+    monkeypatch.setenv("LANGSMITH_GATEWAY_API_KEY", "gateway-key")
+    monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False)
+    monkeypatch.delenv("ANTHROPIC_API_URL", raising=False)
+    monkeypatch.delenv("ANTHROPIC_BASE_URL", raising=False)
+    llm = ChatAnthropic(model=MODEL_NAME)
+    assert llm.anthropic_api_key.get_secret_value() == "gateway-key"
+
+
+def test_langsmith_gateway_api_key_not_used_without_gateway(
+    monkeypatch: pytest.MonkeyPatch,
+) -> None:
+    monkeypatch.delenv("LANGSMITH_GATEWAY", raising=False)
+    monkeypatch.setenv("LANGSMITH_GATEWAY_API_KEY", "gateway-key")
+    monkeypatch.setenv("ANTHROPIC_API_KEY", "provider-key")
+    monkeypatch.delenv("ANTHROPIC_API_URL", raising=False)
+    monkeypatch.delenv("ANTHROPIC_BASE_URL", raising=False)
+    llm = ChatAnthropic(model=MODEL_NAME)
+    assert llm.anthropic_api_key.get_secret_value() == "provider-key"
+
+
+def test_langsmith_gateway_api_key_overrides_provider_key(
+    monkeypatch: pytest.MonkeyPatch,
+) -> None:
+    monkeypatch.setenv("LANGSMITH_GATEWAY", "true")
+    monkeypatch.setenv("LANGSMITH_GATEWAY_API_KEY", "gateway-key")
+    monkeypatch.setenv("ANTHROPIC_API_KEY", "provider-key")
+    monkeypatch.delenv("ANTHROPIC_API_URL", raising=False)
+    monkeypatch.delenv("ANTHROPIC_BASE_URL", raising=False)
+    llm = ChatAnthropic(model=MODEL_NAME)
+    assert llm.anthropic_api_key.get_secret_value() == "gateway-key"
+
+
+def test_langsmith_gateway_provider_base_url_uses_provider_key(
+    monkeypatch: pytest.MonkeyPatch,
+) -> None:
+    # Base URL overridden away from the gateway -> provider key wins over the
+    # gateway key, even though the gateway is enabled.
+    monkeypatch.setenv("LANGSMITH_GATEWAY", "true")
+    monkeypatch.setenv("LANGSMITH_GATEWAY_API_KEY", "gateway-key")
+    monkeypatch.setenv("ANTHROPIC_API_KEY", "provider-key")
+    monkeypatch.delenv("ANTHROPIC_API_URL", raising=False)
+    monkeypatch.setenv("ANTHROPIC_BASE_URL", "https://api.anthropic.com";)
+    llm = ChatAnthropic(model=MODEL_NAME)
+    assert llm.anthropic_api_url == "https://api.anthropic.com";
+    assert llm.anthropic_api_key.get_secret_value() == "provider-key"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langchain_anthropic-1.5.0/uv.lock 
new/langchain_anthropic-1.5.2/uv.lock
--- old/langchain_anthropic-1.5.0/uv.lock       2020-02-02 01:00:00.000000000 
+0100
+++ new/langchain_anthropic-1.5.2/uv.lock       2020-02-02 01:00:00.000000000 
+0100
@@ -29,7 +29,7 @@
 
 [[package]]
 name = "anthropic"
-version = "0.96.0"
+version = "0.120.0"
 source = { registry = "https://pypi.org/simple"; }
 dependencies = [
     { name = "anyio" },
@@ -41,9 +41,9 @@
     { name = "sniffio" },
     { name = "typing-extensions" },
 ]
-sdist = { url = 
"https://files.pythonhosted.org/packages/b9/7e/672f533dee813028d2c699bfd2a7f52c9118d7353680d9aa44b9e23f717f/anthropic-0.96.0.tar.gz";,
 hash = 
"sha256:9de947b737f39452f68aa520f1c2239d44119c9b73b0fb6d4e6ca80f00279ee6", size 
= 658210, upload-time = "2026-04-16T14:28:02.846Z" }
+sdist = { url = 
"https://files.pythonhosted.org/packages/92/5c/3331da4fc009d448008a50c78d86cc929e8c937cd1442245ce3f80561c4e/anthropic-0.120.0.tar.gz";,
 hash = 
"sha256:6ba6007dc9b00365b20f6101a6618f5196ac1ceef81512e4b5cc0e7436d4975d", size 
= 1008042, upload-time = "2026-07-24T16:32:52.384Z" }
 wheels = [
-    { url = 
"https://files.pythonhosted.org/packages/48/5a/72f33204064b6e87601a71a6baf8d855769f8a0c1eaae8d06a1094872371/anthropic-0.96.0-py3-none-any.whl";,
 hash = 
"sha256:9a6e335a354602a521cd9e777e92bfd46ba6e115bf9bbfe6135311e8fb2015b2", size 
= 635930, upload-time = "2026-04-16T14:28:01.436Z" },
+    { url = 
"https://files.pythonhosted.org/packages/1b/8a/8522bdf809e1f95f0d9c936540987a3f6afba01d2921a2bf488dedf836a8/anthropic-0.120.0-py3-none-any.whl";,
 hash = 
"sha256:591bd531563ec7b63a1e138f5c11f14cb94edda99623b349c2ce2ece8e08b8a5", size 
= 1022602, upload-time = "2026-07-24T16:32:50.506Z" },
 ]
 
 [[package]]
@@ -617,7 +617,7 @@
 
 [[package]]
 name = "langchain-anthropic"
-version = "1.5.0"
+version = "1.5.2"
 source = { editable = "." }
 dependencies = [
     { name = "anthropic" },
@@ -657,7 +657,7 @@
 
 [package.metadata]
 requires-dist = [
-    { name = "anthropic", specifier = ">=0.96.0,<1.0.0" },
+    { name = "anthropic", specifier = ">=0.120.0,<1.0.0" },
     { name = "langchain-core", editable = "../../core" },
     { name = "pydantic", specifier = ">=2.7.4,<3.0.0" },
 ]
@@ -690,7 +690,7 @@
 
 [[package]]
 name = "langchain-core"
-version = "1.4.9"
+version = "1.5.1"
 source = { editable = "../../core" }
 dependencies = [
     { name = "jsonpatch" },

Reply via email to