Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-langchain-openai for
openSUSE:Factory checked in at 2026-08-15 22:41:13
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-langchain-openai (Old)
and /work/SRC/openSUSE:Factory/.python-langchain-openai.new.1258 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-langchain-openai"
Sat Aug 15 22:41:13 2026 rev:9 rq:1371289 version:1.5.1
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-langchain-openai/python-langchain-openai.changes
2026-08-14 22:07:18.750729026 +0200
+++
/work/SRC/openSUSE:Factory/.python-langchain-openai.new.1258/python-langchain-openai.changes
2026-08-15 22:41:40.069786441 +0200
@@ -1,0 +2,19 @@
+Sat Aug 15 05:46:04 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to 1.5.1:
+ * Preserve streamed encrypted reasoning: the encrypted_content of a
+ reasoning item is now emitted once, from the Responses API
+ response.output_item.done event, instead of being concatenated
+ with the incomplete value carried by the preceding
+ response.output_item.added event, which produced a doubled and
+ therefore unusable string
+ * Stop echoing reasoning blocks back to the Responses API when
+ their encrypted_content is present but empty
+- Run the bulk of the chat-model unit tests during %check: the whole
+ tests/unit_tests/chat_models/test_base.py module was skipped even
+ though only one of its tests needs python-langchain-tests (not in
+ Factory); it is now collected, with that one test and the two
+ token-counting test functions that would download a tiktoken BPE
+ encoding deselected instead
+
+-------------------------------------------------------------------
Old:
----
langchain_openai-1.5.0.tar.gz
New:
----
langchain_openai-1.5.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-langchain-openai.spec ++++++
--- /var/tmp/diff_new_pack.4x6fnm/_old 2026-08-15 22:41:40.749810378 +0200
+++ /var/tmp/diff_new_pack.4x6fnm/_new 2026-08-15 22:41:40.751810449 +0200
@@ -17,7 +17,7 @@
Name: python-langchain-openai
-Version: 1.5.0
+Version: 1.5.1
Release: 0
Summary: An integration package connecting OpenAI and LangChain
License: MIT
@@ -66,15 +66,16 @@
%python_expand %fdupes %{buildroot}%{$python_sitelib}
%check
-# The standard-test bridge modules (test_*_standard.py), test_base, the
-# responses streaming tests and the moderation-middleware test need
-# python-langchain-tests / python-langchain (not in Factory); the remaining
+# The standard-test bridge modules (test_*_standard.py), the responses
+# streaming tests and the moderation-middleware test need
+# python-langchain-tests / python-langchain (not in Factory), as does the
+# single deselected test_openai_stream_events_v3_lifecycle; the remaining
# unit tests run fully offline. addopts is cleared to drop the --cov default
# (pytest-cov is not needed for the build). The deselected token-counting
# tests call tiktoken with a model whose BPE encoding is not bundled, so
# tiktoken tries to download it from openaipublic.blob.core.windows.net,
# which fails in the offline build.
-%pytest tests/unit_tests -o addopts='' --ignore
tests/unit_tests/embeddings/test_azure_standard.py --ignore
tests/unit_tests/embeddings/test_base_standard.py --ignore
tests/unit_tests/chat_models/test_azure_standard.py --ignore
tests/unit_tests/chat_models/test_base.py --ignore
tests/unit_tests/chat_models/test_base_standard.py --ignore
tests/unit_tests/chat_models/test_responses_standard.py --ignore
tests/unit_tests/chat_models/test_responses_stream.py --ignore
tests/unit_tests/middleware/test_openai_moderation_middleware.py --deselect
tests/unit_tests/embeddings/test_base.py::test_embed_documents_with_custom_chunk_size
--deselect
tests/unit_tests/embeddings/test_base.py::test_embeddings_respects_token_limit
--deselect
"tests/unit_tests/llms/test_base.py::test_get_token_ids[gpt-3.5-turbo-instruct]"
--deselect
"tests/unit_tests/test_token_counts.py::test_chat_openai_get_num_tokens[gpt-5.5]"
--deselect
"tests/unit_tests/test_token_counts.py::test_chat_openai_get_num_tokens[gpt-5-nano
]" --deselect
"tests/unit_tests/test_token_counts.py::test_chat_openai_get_num_tokens[o3]"
+%pytest tests/unit_tests -o addopts='' --ignore
tests/unit_tests/embeddings/test_azure_standard.py --ignore
tests/unit_tests/embeddings/test_base_standard.py --ignore
tests/unit_tests/chat_models/test_azure_standard.py --ignore
tests/unit_tests/chat_models/test_base_standard.py --ignore
tests/unit_tests/chat_models/test_responses_standard.py --ignore
tests/unit_tests/chat_models/test_responses_stream.py --ignore
tests/unit_tests/middleware/test_openai_moderation_middleware.py --deselect
tests/unit_tests/chat_models/test_base.py::test_openai_stream_events_v3_lifecycle
--deselect tests/unit_tests/chat_models/test_base.py::test__get_encoding_model
--deselect
tests/unit_tests/chat_models/test_base.py::test_get_num_tokens_from_messages
--deselect
tests/unit_tests/embeddings/test_base.py::test_embed_documents_with_custom_chunk_size
--deselect
tests/unit_tests/embeddings/test_base.py::test_embeddings_respects_token_limit
--deselect "tests/unit_tests/llms/test_base.py::test_get_token_ids[gp
t-3.5-turbo-instruct]" --deselect
"tests/unit_tests/test_token_counts.py::test_chat_openai_get_num_tokens[gpt-5.5]"
--deselect
"tests/unit_tests/test_token_counts.py::test_chat_openai_get_num_tokens[gpt-5-nano]"
--deselect
"tests/unit_tests/test_token_counts.py::test_chat_openai_get_num_tokens[o3]"
# Recompile the installed modules as hash-based bytecode: the timestamp-based
# .pyc desync from the reproducibility-clamped .py mtimes and trip
# python-bytecode-inconsistent-mtime.
++++++ langchain_openai-1.5.0.tar.gz -> langchain_openai-1.5.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langchain_openai-1.5.0/PKG-INFO
new/langchain_openai-1.5.1/PKG-INFO
--- old/langchain_openai-1.5.0/PKG-INFO 2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_openai-1.5.1/PKG-INFO 2020-02-02 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.5
Name: langchain-openai
-Version: 1.5.0
+Version: 1.5.1
Summary: An integration package connecting OpenAI and LangChain
Project-URL: Homepage,
https://docs.langchain.com/oss/python/integrations/providers/openai
Project-URL: Documentation,
https://reference.langchain.com/python/integrations/langchain_openai/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langchain_openai-1.5.0/langchain_openai/_version.py
new/langchain_openai-1.5.1/langchain_openai/_version.py
--- old/langchain_openai-1.5.0/langchain_openai/_version.py 2020-02-02
01:00:00.000000000 +0100
+++ new/langchain_openai-1.5.1/langchain_openai/_version.py 2020-02-02
01:00:00.000000000 +0100
@@ -1,3 +1,3 @@
"""Version information for `langchain-openai`."""
-__version__ = "1.5.0"
+__version__ = "1.5.1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langchain_openai-1.5.0/langchain_openai/chat_models/base.py
new/langchain_openai-1.5.1/langchain_openai/chat_models/base.py
--- old/langchain_openai-1.5.0/langchain_openai/chat_models/base.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_openai-1.5.1/langchain_openai/chat_models/base.py
2020-02-02 01:00:00.000000000 +0100
@@ -4706,7 +4706,7 @@
new_item["phase"] = phase
input_.append(new_item)
elif block_type == "reasoning":
- if store is not False or "encrypted_content" in
block:
+ if store is not False or
block.get("encrypted_content"):
input_.append(_pop_index_and_sub_index(block))
elif block_type in (
"compaction",
@@ -5239,8 +5239,27 @@
_advance(chunk.output_index)
current_sub_index = 0
reasoning = chunk.item.model_dump(exclude_none=True, mode="json")
+ # Encrypted content is only complete on the corresponding `done`
event, which
+ # emits it below. Drop it here so the two events don't merge into a
doubled
+ # string (blocks sharing an `index` are merged by concatenation).
+ reasoning.pop("encrypted_content", None)
reasoning["index"] = current_index
content.append(reasoning)
+ elif (
+ chunk.type == "response.output_item.done"
+ and chunk.item.type == "reasoning"
+ and chunk.item.encrypted_content
+ ):
+ _advance(chunk.output_index)
+ content.append(
+ {
+ "type": "reasoning",
+ "id": chunk.item.id,
+ "summary": [],
+ "encrypted_content": chunk.item.encrypted_content,
+ "index": current_index,
+ }
+ )
elif chunk.type == "response.reasoning_summary_part.added":
_advance(chunk.output_index)
content.append(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langchain_openai-1.5.0/pyproject.toml
new/langchain_openai-1.5.1/pyproject.toml
--- old/langchain_openai-1.5.0/pyproject.toml 2020-02-02 01:00:00.000000000
+0100
+++ new/langchain_openai-1.5.1/pyproject.toml 2020-02-02 01:00:00.000000000
+0100
@@ -20,7 +20,7 @@
"Topic :: Scientific/Engineering :: Artificial Intelligence",
]
-version = "1.5.0"
+version = "1.5.1"
requires-python = ">=3.10.0,<4.0.0"
dependencies = [
"langchain-core>=1.5.4,<2.0.0",
Binary files
old/langchain_openai-1.5.0/tests/cassettes/test_mcp_builtin_zdr.yaml.gz and
new/langchain_openai-1.5.1/tests/cassettes/test_mcp_builtin_zdr.yaml.gz differ
Binary files
old/langchain_openai-1.5.0/tests/cassettes/test_stream_encrypted_reasoning.yaml.gz
and
new/langchain_openai-1.5.1/tests/cassettes/test_stream_encrypted_reasoning.yaml.gz
differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langchain_openai-1.5.0/tests/integration_tests/chat_models/test_base.py
new/langchain_openai-1.5.1/tests/integration_tests/chat_models/test_base.py
--- old/langchain_openai-1.5.0/tests/integration_tests/chat_models/test_base.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_openai-1.5.1/tests/integration_tests/chat_models/test_base.py
2020-02-02 01:00:00.000000000 +0100
@@ -34,6 +34,26 @@
MAX_TOKEN_COUNT = 100
+# Whether requests route through the LangSmith gateway. Mirrors the truthiness
+# used by `langchain_core`'s gateway resolution.
+_GATEWAY_ENABLED = (os.environ.get("LANGSMITH_GATEWAY") or "").lower() not in (
+ "",
+ "false",
+ "0",
+ "no",
+)
+
+
+def _gateway_or_provider_key() -> str:
+ """Return an API key valid for the endpoint the base URL resolves to.
+
+ When the LangSmith gateway is enabled, requests route through it and must
+ authenticate with the gateway key rather than the provider key.
+ """
+ if _GATEWAY_ENABLED:
+ return os.environ["LANGSMITH_GATEWAY_API_KEY"]
+ return os.environ["OPENAI_API_KEY"]
+
@pytest.mark.scheduled
def test_chat_openai() -> None:
@@ -66,7 +86,7 @@
def test_callable_api_key(monkeypatch: pytest.MonkeyPatch) -> None:
- original_key = os.environ["OPENAI_API_KEY"]
+ original_key = _gateway_or_provider_key()
calls = {"sync": 0}
@@ -83,7 +103,7 @@
async def test_callable_api_key_async(monkeypatch: pytest.MonkeyPatch) -> None:
- original_key = os.environ["OPENAI_API_KEY"]
+ original_key = _gateway_or_provider_key()
calls = {"sync": 0, "async": 0}
@@ -366,7 +386,10 @@
assert full.usage_metadata["input_tokens"] > 0
assert full.usage_metadata["output_tokens"] > 0
assert full.usage_metadata["total_tokens"] > 0
- else:
+ # The LangSmith gateway always emits a usage chunk regardless of
+ # `stream_options.include_usage`, so the opt-out assertions below only
+ # hold when not routing through it.
+ elif not _GATEWAY_ENABLED:
assert chunks_with_token_counts == 0
assert full.usage_metadata is None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langchain_openai-1.5.0/tests/integration_tests/chat_models/test_responses_api.py
new/langchain_openai-1.5.1/tests/integration_tests/chat_models/test_responses_api.py
---
old/langchain_openai-1.5.0/tests/integration_tests/chat_models/test_responses_api.py
2020-02-02 01:00:00.000000000 +0100
+++
new/langchain_openai-1.5.1/tests/integration_tests/chat_models/test_responses_api.py
2020-02-02 01:00:00.000000000 +0100
@@ -782,6 +782,35 @@
assert isinstance(response_2, AIMessage)
[email protected]
+def test_stream_encrypted_reasoning() -> None:
+ llm = ChatOpenAI(
+ model="gpt-5.6-luna",
+ use_responses_api=True,
+ reasoning_effort="medium",
+ store=False,
+ include=["reasoning.encrypted_content"],
+ )
+ message_1 = {
+ "role": "user",
+ "content": "What was the third tallest buliding in the year 2000?",
+ }
+ response_1 = llm.stream_events([message_1], version="v3").output
+ total_reasoning_blocks = 0
+ for block in response_1.content_blocks:
+ if block["type"] == "reasoning":
+ total_reasoning_blocks += 1
+ assert isinstance(block.get("id"), str)
+ assert block.get("id", "").startswith("rs_")
+ assert isinstance(block["extras"].get("encrypted_content"), str)
+ assert isinstance(block.get("index"), str)
+
+ # Check we can pass back summaries
+ message_2 = {"role": "user", "content": "Thank you."}
+ response_2 = llm.invoke([message_1, response_1, message_2])
+ assert isinstance(response_2, AIMessage)
+
+
@pytest.mark.default_cassette("test_code_interpreter.yaml.gz")
@pytest.mark.vcr
@pytest.mark.parametrize(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langchain_openai-1.5.0/tests/unit_tests/chat_models/test_base.py
new/langchain_openai-1.5.1/tests/unit_tests/chat_models/test_base.py
--- old/langchain_openai-1.5.0/tests/unit_tests/chat_models/test_base.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_openai-1.5.1/tests/unit_tests/chat_models/test_base.py
2020-02-02 01:00:00.000000000 +0100
@@ -3052,12 +3052,14 @@
def
test__construct_responses_api_input_store_false_replays_stateless_history() ->
None:
ai_message = AIMessage(
content=[
+ # Dropped: no encrypted content to replay, in both shapes it can
take.
{"type": "reasoning", "id": "rs_123", "summary": []},
+ {"type": "reasoning", "encrypted_content": ""},
{
"type": "reasoning",
- "id": "rs_456",
+ "id": "rs_789",
"summary": [],
- "encrypted_content": "",
+ "encrypted_content": "encrypted-reasoning",
},
{"type": "text", "text": "Use pathlib.rglob.", "id": "msg_123"},
],
@@ -3069,9 +3071,9 @@
assert result == [
{
"type": "reasoning",
- "id": "rs_456",
+ "id": "rs_789",
"summary": [],
- "encrypted_content": "",
+ "encrypted_content": "encrypted-reasoning",
},
{
"type": "message",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langchain_openai-1.5.0/tests/unit_tests/chat_models/test_responses_stream.py
new/langchain_openai-1.5.1/tests/unit_tests/chat_models/test_responses_stream.py
---
old/langchain_openai-1.5.0/tests/unit_tests/chat_models/test_responses_stream.py
2020-02-02 01:00:00.000000000 +0100
+++
new/langchain_openai-1.5.1/tests/unit_tests/chat_models/test_responses_stream.py
2020-02-02 01:00:00.000000000 +0100
@@ -47,6 +47,9 @@
from openai.types.shared.response_format_text import ResponseFormatText
from langchain_openai import ChatOpenAI
+from langchain_openai.chat_models.base import (
+ _convert_responses_chunk_to_generation_chunk,
+)
from tests.unit_tests.chat_models.test_base import MockSyncContextManager
MODEL = "gpt-5.4"
@@ -349,6 +352,8 @@
id="rs_234",
summary=[],
type="reasoning",
+ # Deliberately populated: pins that the `added` event's encrypted
content
+ # is dropped rather than merged with the `done` event's copy below.
encrypted_content="encrypted-content",
status=None,
),
@@ -766,6 +771,74 @@
assert dumped == payload["input"][idx]
[email protected]("output_version", ["responses/v1", "v1"])
+def test_responses_stream_encrypted_reasoning_replays_with_store_false(
+ output_version: str,
+) -> None:
+ """Streamed encrypted reasoning survives a stateless (`store=False`)
replay.
+
+ Regression test for the round trip users actually hit: with `store=False`,
+ reasoning can only be replayed via its encrypted content, so a reasoning
item
+ that carried one must come back with it intact -- exactly once -- while an
item
+ that carried none is dropped rather than replayed as an unresolvable item
ID.
+ """
+ llm = ChatOpenAI(
+ model=MODEL, use_responses_api=True, output_version=output_version,
store=False
+ )
+ mock_client = MagicMock()
+
+ def mock_create(*args: Any, **kwargs: Any) -> MockSyncContextManager:
+ return MockSyncContextManager(responses_stream)
+
+ mock_client.responses.create = mock_create
+
+ full: BaseMessageChunk | None = None
+ with patch.object(llm, "root_client", mock_client):
+ for chunk in llm.stream("test"):
+ full = chunk if full is None else full + chunk
+ assert isinstance(full, AIMessageChunk)
+
+ payload = llm._get_request_payload([full], store=False)
+ reasoning_items = [
+ item for item in payload["input"] if item.get("type") == "reasoning"
+ ]
+
+ # `rs_123` carried no encrypted content and is dropped; `rs_234` is
replayed.
+ assert [item["id"] for item in reasoning_items] == ["rs_234"]
+ assert reasoning_items[0]["encrypted_content"] == "encrypted-content"
+
+
+def test_responses_reasoning_done_without_encrypted_content_emits_no_chunk()
-> None:
+ """A reasoning `done` event with no encrypted content yields no chunk at
all.
+
+ The event carries nothing the `added` event has not already surfaced, so
+ emitting a chunk for it would mean an extra empty `on_llm_new_token`
callback
+ for every reasoning item -- the common case, since encrypted content is
only
+ populated when the caller opts into it.
+ """
+ for encrypted_content in (None, ""):
+ event = ResponseOutputItemDoneEvent(
+ item=ResponseReasoningItem(
+ id="rs_123",
+ summary=[Summary(text="reasoning", type="summary_text")],
+ type="reasoning",
+ encrypted_content=encrypted_content,
+ status=None,
+ ),
+ output_index=0,
+ sequence_number=1,
+ type="response.output_item.done",
+ )
+
+ _, _, _, generation_chunk =
_convert_responses_chunk_to_generation_chunk(
+ event, 0, 0, 0
+ )
+
+ assert generation_chunk is None, (
+ f"expected no chunk for encrypted_content={encrypted_content!r}"
+ )
+
+
def test_responses_stream_events_v3_emits_reasoning_lifecycle() -> None:
"""v3 streaming emits `content-block-finish` events for reasoning blocks.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langchain_openai-1.5.0/uv.lock
new/langchain_openai-1.5.1/uv.lock
--- old/langchain_openai-1.5.0/uv.lock 2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_openai-1.5.1/uv.lock 2020-02-02 01:00:00.000000000 +0100
@@ -771,7 +771,7 @@
[[package]]
name = "langchain-openai"
-version = "1.5.0"
+version = "1.5.1"
source = { editable = "." }
dependencies = [
{ name = "certifi" },