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" },

Reply via email to