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-29 19:00:03
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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"
Wed Jul 29 19:00:03 2026 rev:4 rq:1368300 version:1.5.3
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-langchain-anthropic/python-langchain-anthropic.changes
2026-07-26 11:32:38.183316377 +0200
+++
/work/SRC/openSUSE:Factory/.python-langchain-anthropic.new.2004/python-langchain-anthropic.changes
2026-07-29 19:01:28.370246400 +0200
@@ -1,0 +2,9 @@
+Wed Jul 29 06:30:23 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to version 1.5.3:
+ * Preserve an empty thinking field in signature_delta streaming
+ * Strip unsupported fields from system message content blocks
+- Raise the langchain-core requirement to >= 1.5.2 and the anthropic
+ build requirement to >= 0.120.0, matching upstream
+
+-------------------------------------------------------------------
Old:
----
langchain_anthropic-1.5.2.tar.gz
New:
----
langchain_anthropic-1.5.3.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-langchain-anthropic.spec ++++++
--- /var/tmp/diff_new_pack.1D2Q58/_old 2026-07-29 19:01:29.242276477 +0200
+++ /var/tmp/diff_new_pack.1D2Q58/_new 2026-07-29 19:01:29.242276477 +0200
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-langchain-anthropic
-Version: 1.5.2
+Version: 1.5.3
Release: 0
Summary: Integration package connecting Claude (Anthropic) APIs and
LangChain
License: MIT
@@ -29,15 +29,15 @@
BuildRequires: fdupes
BuildRequires: python-rpm-macros
Requires: python-anthropic >= 0.120.0
-Requires: python-langchain-core >= 1.5.1
+Requires: python-langchain-core >= 1.5.2
Requires: python-pydantic >= 2.7.4
BuildArch: noarch
# SECTION test requirements
-BuildRequires: %{python_module anthropic >= 0.96.0}
+BuildRequires: %{python_module anthropic >= 0.120.0}
BuildRequires: %{python_module blockbuster}
BuildRequires: %{python_module defusedxml}
BuildRequires: %{python_module freezegun}
-BuildRequires: %{python_module langchain-core >= 1.5.0}
+BuildRequires: %{python_module langchain-core >= 1.5.2}
BuildRequires: %{python_module pydantic >= 2.7.4}
BuildRequires: %{python_module pytest-asyncio}
BuildRequires: %{python_module pytest-mock}
++++++ langchain_anthropic-1.5.2.tar.gz -> langchain_anthropic-1.5.3.tar.gz
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langchain_anthropic-1.5.2/PKG-INFO
new/langchain_anthropic-1.5.3/PKG-INFO
--- old/langchain_anthropic-1.5.2/PKG-INFO 2020-02-02 01:00:00.000000000
+0100
+++ new/langchain_anthropic-1.5.3/PKG-INFO 2020-02-02 01:00:00.000000000
+0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: langchain-anthropic
-Version: 1.5.2
+Version: 1.5.3
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/
@@ -24,7 +24,7 @@
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: <4.0.0,>=3.10.0
Requires-Dist: anthropic<1.0.0,>=0.120.0
-Requires-Dist: langchain-core<2.0.0,>=1.5.1
+Requires-Dist: langchain-core<2.0.0,>=1.5.2
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.2/langchain_anthropic/_version.py
new/langchain_anthropic-1.5.3/langchain_anthropic/_version.py
--- old/langchain_anthropic-1.5.2/langchain_anthropic/_version.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_anthropic-1.5.3/langchain_anthropic/_version.py
2020-02-02 01:00:00.000000000 +0100
@@ -1,3 +1,3 @@
"""Version information for `langchain-anthropic`."""
-__version__ = "1.5.2"
+__version__ = "1.5.3"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langchain_anthropic-1.5.2/langchain_anthropic/chat_models.py
new/langchain_anthropic-1.5.3/langchain_anthropic/chat_models.py
--- old/langchain_anthropic-1.5.2/langchain_anthropic/chat_models.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_anthropic-1.5.3/langchain_anthropic/chat_models.py
2020-02-02 01:00:00.000000000 +0100
@@ -475,6 +475,29 @@
return formatted_block
+def _format_text_block(block: dict) -> dict:
+ """Narrow a text content block to fields supported by Anthropic's API.
+
+ Drops LangChain-internal fields (e.g. the ``id`` minted by
+ ``create_text_block``) that Anthropic rejects as extra inputs.
+ """
+ formatted_block = {
+ k: v
+ for k, v in block.items()
+ if k in ("type", "text", "cache_control", "citations")
+ }
+ # Clean up citations to remove null file_id fields
+ if formatted_block.get("citations"):
+ cleaned_citations = []
+ for citation in formatted_block["citations"]:
+ cleaned_citation = {
+ k: v for k, v in citation.items() if not (k == "file_id" and v
is None)
+ }
+ cleaned_citations.append(cleaned_citation)
+ formatted_block["citations"] = cleaned_citations
+ return formatted_block
+
+
def _format_messages(
messages: Sequence[BaseMessage],
) -> tuple[str | list[dict] | None, list[dict]]:
@@ -490,7 +513,11 @@
if isinstance(message.content, list):
system = [
(
- block
+ (
+ _format_text_block(block)
+ if block.get("type") == "text"
+ else block
+ )
if isinstance(block, dict)
else {"type": "text", "text": block}
)
@@ -598,32 +625,16 @@
# accepted.
#
https://github.com/anthropics/anthropic-sdk-python/issues/461
if text.strip():
- formatted_block = {
- k: v
- for k, v in block.items()
- if k in ("type", "text", "cache_control",
"citations")
- }
- # Clean up citations to remove null file_id fields
- if formatted_block.get("citations"):
- cleaned_citations = []
- for citation in formatted_block["citations"]:
- cleaned_citation = {
- k: v
- for k, v in citation.items()
- if not (k == "file_id" and v is None)
- }
- cleaned_citations.append(cleaned_citation)
- formatted_block["citations"] =
cleaned_citations
- content.append(formatted_block)
+ content.append(_format_text_block(block))
elif block["type"] == "thinking":
- content.append(
- {
- k: v
- for k, v in block.items()
- if k
- in ("type", "thinking", "cache_control",
"signature")
- },
- )
+ formatted_thinking = {
+ k: v
+ for k, v in block.items()
+ if k in ("type", "thinking", "cache_control",
"signature")
+ }
+ if "signature" in formatted_thinking:
+ formatted_thinking.setdefault("thinking", "")
+ content.append(formatted_thinking)
elif block["type"] == "redacted_thinking":
content.append(
{
@@ -1790,6 +1801,8 @@
content_block = event.delta.model_dump()
content_block["index"] = event.index
content_block["type"] = "thinking"
+ if event.delta.type == "signature_delta":
+ content_block.setdefault("thinking", "")
message_chunk = AIMessageChunk(content=[content_block])
# Tool input JSON (streaming tool arguments)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langchain_anthropic-1.5.2/pyproject.toml
new/langchain_anthropic-1.5.3/pyproject.toml
--- old/langchain_anthropic-1.5.2/pyproject.toml 2020-02-02
01:00:00.000000000 +0100
+++ new/langchain_anthropic-1.5.3/pyproject.toml 2020-02-02
01:00:00.000000000 +0100
@@ -20,11 +20,11 @@
"Topic :: Scientific/Engineering :: Artificial Intelligence",
]
-version = "1.5.2"
+version = "1.5.3"
requires-python = ">=3.10.0,<4.0.0"
dependencies = [
"anthropic>=0.120.0,<1.0.0",
- "langchain-core>=1.5.1,<2.0.0",
+ "langchain-core>=1.5.2,<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.2/tests/unit_tests/test_chat_models.py
new/langchain_anthropic-1.5.3/tests/unit_tests/test_chat_models.py
--- old/langchain_anthropic-1.5.2/tests/unit_tests/test_chat_models.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_anthropic-1.5.3/tests/unit_tests/test_chat_models.py
2020-02-02 01:00:00.000000000 +0100
@@ -21,6 +21,7 @@
SystemMessage,
ToolMessage,
)
+from langchain_core.messages.content import create_text_block
from langchain_core.runnables import RunnableBinding
from langchain_core.tools import BaseTool, tool
from langchain_core.tracers.base import BaseTracer
@@ -1480,6 +1481,41 @@
assert expected_messages == actual_messages
+def test__format_messages_system_v1_content_blocks_drop_id() -> None:
+ """System text blocks from `create_text_block` must not leak the `id`
field.
+
+ See https://github.com/langchain-ai/langchain/issues/39100
+ """
+ messages = [
+ SystemMessage(content_blocks=[create_text_block("You are helpful.")]),
+ HumanMessage("hi"),
+ ]
+ actual_system, actual_messages = _format_messages(messages)
+ assert actual_system == [{"type": "text", "text": "You are helpful."}]
+ assert actual_messages == [{"role": "user", "content": "hi"}]
+
+
+def test__format_messages_system_text_block_preserves_supported_fields() ->
None:
+ """Sanitizing system text blocks keeps Anthropic-supported fields."""
+ messages = [
+ SystemMessage(
+ [
+ {
+ "type": "text",
+ "text": "foo",
+ "id": "lc_abc123",
+ "cache_control": {"type": "ephemeral"},
+ },
+ ],
+ ),
+ HumanMessage("hi"),
+ ]
+ actual_system, _ = _format_messages(messages)
+ assert actual_system == [
+ {"type": "text", "text": "foo", "cache_control": {"type":
"ephemeral"}},
+ ]
+
+
def test_anthropic_api_key_is_secret_string() -> None:
"""Test that the API key is stored as a SecretStr."""
chat_model = ChatAnthropic( # type: ignore[call-arg, call-arg]
@@ -2408,6 +2444,161 @@
assert block_start_event is not None
+def test_signature_delta_preserves_empty_thinking_field() -> None:
+ """A `signature_delta` chunk must include `thinking` even when empty.
+
+ When an empty adaptive-thinking block streams only a signature_delta
+ (no thinking_delta), the aggregated block must still carry the required
+ `thinking` key so the message round-trips to the API without a 400 error.
+ """
+ from anthropic.types import (
+ RawContentBlockDeltaEvent,
+ RawContentBlockStartEvent,
+ SignatureDelta,
+ ThinkingBlock,
+ )
+
+ llm = ChatAnthropic(model=MODEL_NAME) # type: ignore[call-arg]
+
+ # Step 1: process the empty content_block_start (no chunk emitted).
+ chunk, block_start_event = llm._make_message_chunk_from_anthropic_event(
+ RawContentBlockStartEvent(
+ content_block=ThinkingBlock(thinking="", signature="",
type="thinking"),
+ index=0,
+ type="content_block_start",
+ ),
+ stream_usage=True,
+ coerce_content_to_string=False,
+ block_start_event=None,
+ )
+ assert chunk is None
+ assert block_start_event is not None
+
+ # Step 2: process the signature_delta with the tracked start event.
+ chunk, _ = llm._make_message_chunk_from_anthropic_event(
+ RawContentBlockDeltaEvent(
+ delta=SignatureDelta(signature="sig_abc", type="signature_delta"),
+ index=0,
+ type="content_block_delta",
+ ),
+ stream_usage=True,
+ coerce_content_to_string=False,
+ block_start_event=block_start_event,
+ )
+ assert chunk is not None
+ assert isinstance(chunk.content, list)
+ assert len(chunk.content) == 1
+ block = chunk.content[0]
+ assert isinstance(block, dict)
+ assert block.get("type") == "thinking"
+ assert block.get("thinking") == ""
+ assert block.get("signature") == "sig_abc"
+
+
+def test_thinking_delta_preserves_thinking_field() -> None:
+ """A `thinking_delta` with text is unaffected by the empty-thinking fix.
+
+ The trailing empty string from a signature_delta must not clobber
+ thinking text already accumulated from earlier thinking_delta chunks.
+ """
+ from anthropic.types import (
+ RawContentBlockDeltaEvent,
+ RawContentBlockStartEvent,
+ RawContentBlockStopEvent,
+ RawMessageStartEvent,
+ SignatureDelta,
+ ThinkingBlock,
+ ThinkingDelta,
+ )
+
+ msg = Message(
+ id="msg_thinking",
+ content=[],
+ model=MODEL_NAME,
+ role="assistant",
+ stop_reason=None,
+ stop_sequence=None,
+ usage=Usage(input_tokens=10, output_tokens=0),
+ type="message",
+ )
+ events: list = [
+ RawMessageStartEvent(message=msg, type="message_start"),
+ RawContentBlockStartEvent(
+ content_block=ThinkingBlock(thinking="", signature="",
type="thinking"),
+ index=0,
+ type="content_block_start",
+ ),
+ RawContentBlockDeltaEvent(
+ delta=ThinkingDelta(thinking="Let me ", type="thinking_delta"),
+ index=0,
+ type="content_block_delta",
+ ),
+ RawContentBlockDeltaEvent(
+ delta=ThinkingDelta(thinking="think.", type="thinking_delta"),
+ index=0,
+ type="content_block_delta",
+ ),
+ RawContentBlockDeltaEvent(
+ delta=SignatureDelta(signature="sig_xyz", type="signature_delta"),
+ index=0,
+ type="content_block_delta",
+ ),
+ RawContentBlockStopEvent(index=0, type="content_block_stop"),
+ ]
+
+ llm = ChatAnthropic(model=MODEL_NAME) # type: ignore[call-arg]
+ aggregate = _aggregate_anthropic_events(llm, events,
coerce_content_to_string=False)
+ assert aggregate is not None
+ assert isinstance(aggregate.content, list)
+ thinking_blocks = [
+ b
+ for b in aggregate.content
+ if isinstance(b, dict) and b.get("type") == "thinking"
+ ]
+ assert len(thinking_blocks) == 1
+ assert thinking_blocks[0]["thinking"] == "Let me think."
+ assert thinking_blocks[0]["signature"] == "sig_xyz"
+
+
+def test_format_messages_backfills_missing_thinking_field() -> None:
+ """Replaying a thinking block missing `thinking` must not 400.
+
+ Thinking blocks persisted before the streaming fix can carry a signature
+ but no `thinking` key. `_format_messages` must restore the canonical empty
+ string so the block round-trips to the API instead of failing with
+ ``400 thinking.thinking: Field required``.
+ """
+ llm = ChatAnthropic(model=MODEL_NAME) # type: ignore[call-arg]
+
+ # A corrupted block as produced by the pre-fix streaming path: signature
+ # present, required `thinking` key absent.
+ corrupted = AIMessage(
+ content=[{"type": "thinking", "signature": "sig_abc", "index": 0}]
+ )
+ payload = llm._get_request_payload(
+ [HumanMessage("hi"), corrupted, HumanMessage("continue")]
+ )
+ block = payload["messages"][1]["content"][0]
+ assert block["type"] == "thinking"
+ assert block["thinking"] == ""
+ assert block["signature"] == "sig_abc"
+
+
+def test_format_messages_preserves_nonempty_thinking_field() -> None:
+ """The backfill must not clobber real thinking text on replay."""
+ llm = ChatAnthropic(model=MODEL_NAME) # type: ignore[call-arg]
+
+ msg = AIMessage(
+ content=[
+ {"type": "thinking", "thinking": "Let me think.", "signature":
"sig_xyz"}
+ ]
+ )
+ payload = llm._get_request_payload([HumanMessage("hi"), msg])
+ block = payload["messages"][1]["content"][0]
+ assert block["thinking"] == "Let me think."
+ assert block["signature"] == "sig_xyz"
+
+
def test_strict_tool_use() -> None:
model = ChatAnthropic(
model=MODEL_NAME, # type: ignore[call-arg]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langchain_anthropic-1.5.2/uv.lock
new/langchain_anthropic-1.5.3/uv.lock
--- old/langchain_anthropic-1.5.2/uv.lock 2020-02-02 01:00:00.000000000
+0100
+++ new/langchain_anthropic-1.5.3/uv.lock 2020-02-02 01:00:00.000000000
+0100
@@ -617,7 +617,7 @@
[[package]]
name = "langchain-anthropic"
-version = "1.5.2"
+version = "1.5.3"
source = { editable = "." }
dependencies = [
{ name = "anthropic" },
@@ -690,7 +690,7 @@
[[package]]
name = "langchain-core"
-version = "1.5.1"
+version = "1.5.2"
source = { editable = "../../core" }
dependencies = [
{ name = "jsonpatch" },
@@ -721,7 +721,7 @@
dev = [
{ name = "grandalf", specifier = ">=0.8.0,<1.0.0" },
{ name = "jupyter", specifier = ">=1.0.0,<2.0.0" },
- { name = "setuptools", specifier = ">=67.6.1,<83.0.0" },
+ { name = "setuptools", specifier = ">=67.6.1,<84.0.0" },
]
lint = [{ name = "ruff", specifier = ">=0.15.0,<0.16.0" }]
test = [