Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-langgraph-sdk for 
openSUSE:Factory checked in at 2026-10-27 16:58:23
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-langgraph-sdk (Old)
 and      /work/SRC/openSUSE:Factory/.python-langgraph-sdk.new.2252680 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-langgraph-sdk"

Tue Oct 27 16:58:23 2026 rev:10 rq:1392921 version:0.4.10

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-langgraph-sdk/python-langgraph-sdk.changes    
    2026-10-26 10:04:34.384214609 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-langgraph-sdk.new.2252680/python-langgraph-sdk.changes
   2026-10-27 16:58:32.471551411 +0100
@@ -1,0 +2,11 @@
+Tue Oct 27 06:33:57 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to 0.4.10:
+  * Retry runs.wait with a bodyless GET and raise run errors
+    in the sync wait
+  * Follow the SSE spec for multi-line data, empty ids and
+    a leading BOM
+  * Accept durability, stream_resumable and context in the
+    runs overloads
+
+-------------------------------------------------------------------

Old:
----
  langgraph_sdk-0.4.9.tar.gz

New:
----
  langgraph_sdk-0.4.10.tar.gz

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

Other differences:
------------------
++++++ python-langgraph-sdk.spec ++++++
--- /var/tmp/diff_new_pack.XILeGN/_old  2026-10-27 16:58:34.405632356 +0100
+++ /var/tmp/diff_new_pack.XILeGN/_new  2026-10-27 16:58:34.406632398 +0100
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-langgraph-sdk
-Version:        0.4.9
+Version:        0.4.10
 Release:        0
 Summary:        SDK for interacting with the LangGraph API
 License:        MIT

++++++ langgraph_sdk-0.4.9.tar.gz -> langgraph_sdk-0.4.10.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langgraph_sdk-0.4.9/PKG-INFO 
new/langgraph_sdk-0.4.10/PKG-INFO
--- old/langgraph_sdk-0.4.9/PKG-INFO    2020-02-02 01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.10/PKG-INFO   2020-02-02 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.5
 Name: langgraph-sdk
-Version: 0.4.9
+Version: 0.4.10
 Summary: SDK for interacting with LangGraph API
 Project-URL: Source, 
https://github.com/langchain-ai/langgraph/tree/main/libs/sdk-py
 Project-URL: Twitter, https://x.com/langchain_oss
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langgraph_sdk-0.4.9/langgraph_sdk/__init__.py 
new/langgraph_sdk-0.4.10/langgraph_sdk/__init__.py
--- old/langgraph_sdk-0.4.9/langgraph_sdk/__init__.py   2020-02-02 
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.10/langgraph_sdk/__init__.py  2020-02-02 
01:00:00.000000000 +0100
@@ -5,7 +5,7 @@
 from langgraph_sdk.priority import Priority
 from langgraph_sdk.priority.types import PriorityContext, PrioritySettings
 
-__version__ = "0.4.9"
+__version__ = "0.4.10"
 
 __all__ = [
     "Auth",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langgraph_sdk-0.4.9/langgraph_sdk/_async/http.py 
new/langgraph_sdk-0.4.10/langgraph_sdk/_async/http.py
--- old/langgraph_sdk-0.4.9/langgraph_sdk/_async/http.py        2020-02-02 
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.10/langgraph_sdk/_async/http.py       2020-02-02 
01:00:00.000000000 +0100
@@ -179,7 +179,7 @@
                 return await self.request_reconnect(
                     loc,
                     "GET",
-                    headers=request_headers,
+                    headers=headers,
                     # don't pass on_response so it's only called once
                     reconnect_limit=reconnect_limit - 1,
                 )
@@ -217,7 +217,7 @@
             current_headers = dict(
                 request_headers if reconnect_path is None else 
reconnect_headers
             )
-            if last_event_id is not None:
+            if last_event_id:
                 current_headers["Last-Event-ID"] = last_event_id
 
             current_method = method if reconnect_path is None else "GET"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langgraph_sdk-0.4.9/langgraph_sdk/_async/runs.py 
new/langgraph_sdk-0.4.10/langgraph_sdk/_async/runs.py
--- old/langgraph_sdk-0.4.9/langgraph_sdk/_async/runs.py        2020-02-02 
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.10/langgraph_sdk/_async/runs.py       2020-02-02 
01:00:00.000000000 +0100
@@ -99,6 +99,7 @@
         headers: Mapping[str, str] | None = None,
         params: QueryParamTypes | None = None,
         on_run_created: Callable[[RunCreateMetadata], None] | None = None,
+        durability: Durability | None = None,
         version: Literal["v1"] = "v1",
     ) -> AsyncIterator[StreamPart]: ...
 
@@ -131,6 +132,7 @@
         headers: Mapping[str, str] | None = None,
         params: QueryParamTypes | None = None,
         on_run_created: Callable[[RunCreateMetadata], None] | None = None,
+        durability: Durability | None = None,
         version: Literal["v2"],
     ) -> AsyncIterator[StreamPartV2]: ...
 
@@ -147,6 +149,7 @@
         stream_resumable: bool = False,
         metadata: Mapping[str, Any] | None = None,
         config: Config | None = None,
+        context: Context | None = None,
         checkpoint_during: bool | None = None,
         interrupt_before: All | Sequence[str] | None = None,
         interrupt_after: All | Sequence[str] | None = None,
@@ -160,6 +163,7 @@
         headers: Mapping[str, str] | None = None,
         params: QueryParamTypes | None = None,
         on_run_created: Callable[[RunCreateMetadata], None] | None = None,
+        durability: Durability | None = None,
         version: Literal["v1"] = "v1",
     ) -> AsyncIterator[StreamPart]: ...
 
@@ -176,6 +180,7 @@
         stream_resumable: bool = False,
         metadata: Mapping[str, Any] | None = None,
         config: Config | None = None,
+        context: Context | None = None,
         checkpoint_during: bool | None = None,
         interrupt_before: All | Sequence[str] | None = None,
         interrupt_after: All | Sequence[str] | None = None,
@@ -189,6 +194,7 @@
         headers: Mapping[str, str] | None = None,
         params: QueryParamTypes | None = None,
         on_run_created: Callable[[RunCreateMetadata], None] | None = None,
+        durability: Durability | None = None,
         version: Literal["v2"],
     ) -> AsyncIterator[StreamPartV2]: ...
 
@@ -385,6 +391,7 @@
         headers: Mapping[str, str] | None = None,
         params: QueryParamTypes | None = None,
         on_run_created: Callable[[RunCreateMetadata], None] | None = None,
+        durability: Durability | None = None,
     ) -> Run: ...
 
     @overload
@@ -414,6 +421,7 @@
         headers: Mapping[str, str] | None = None,
         params: QueryParamTypes | None = None,
         on_run_created: Callable[[RunCreateMetadata], None] | None = None,
+        durability: Durability | None = None,
     ) -> Run: ...
 
     async def create(
@@ -647,6 +655,7 @@
         headers: Mapping[str, str] | None = None,
         params: QueryParamTypes | None = None,
         on_run_created: Callable[[RunCreateMetadata], None] | None = None,
+        durability: Durability | None = None,
     ) -> builtins.list[dict] | dict[str, Any]: ...
 
     @overload
@@ -673,6 +682,7 @@
         headers: Mapping[str, str] | None = None,
         params: QueryParamTypes | None = None,
         on_run_created: Callable[[RunCreateMetadata], None] | None = None,
+        durability: Durability | None = None,
     ) -> builtins.list[dict] | dict[str, Any]: ...
 
     async def wait(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langgraph_sdk-0.4.9/langgraph_sdk/_sync/http.py 
new/langgraph_sdk-0.4.10/langgraph_sdk/_sync/http.py
--- old/langgraph_sdk-0.4.9/langgraph_sdk/_sync/http.py 2020-02-02 
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.10/langgraph_sdk/_sync/http.py        2020-02-02 
01:00:00.000000000 +0100
@@ -179,7 +179,7 @@
                 return self.request_reconnect(
                     loc,
                     "GET",
-                    headers=request_headers,
+                    headers=headers,
                     # don't pass on_response so it's only called once
                     reconnect_limit=reconnect_limit - 1,
                 )
@@ -219,7 +219,7 @@
             current_headers = dict(
                 request_headers if reconnect_path is None else 
reconnect_headers
             )
-            if last_event_id is not None:
+            if last_event_id:
                 current_headers["Last-Event-ID"] = last_event_id
 
             current_method = method if reconnect_path is None else "GET"
@@ -286,7 +286,9 @@
             break
 
 
-def _encode_json(json: Any) -> tuple[dict[str, str], bytes]:
+def _encode_json(json: Any) -> tuple[dict[str, str], bytes | None]:
+    if json is None:
+        return {}, None
     body = orjson.dumps(
         json,
         _orjson_default,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langgraph_sdk-0.4.9/langgraph_sdk/_sync/runs.py 
new/langgraph_sdk-0.4.10/langgraph_sdk/_sync/runs.py
--- old/langgraph_sdk-0.4.9/langgraph_sdk/_sync/runs.py 2020-02-02 
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.10/langgraph_sdk/_sync/runs.py        2020-02-02 
01:00:00.000000000 +0100
@@ -80,6 +80,7 @@
         command: Command | None = None,
         stream_mode: StreamMode | Sequence[StreamMode] = "values",
         stream_subgraphs: bool = False,
+        stream_resumable: bool = False,
         metadata: Mapping[str, Any] | None = None,
         config: Config | None = None,
         context: Context | None = None,
@@ -98,6 +99,7 @@
         headers: Mapping[str, str] | None = None,
         params: QueryParamTypes | None = None,
         on_run_created: Callable[[RunCreateMetadata], None] | None = None,
+        durability: Durability | None = None,
         version: Literal["v1"] = "v1",
     ) -> Iterator[StreamPart]: ...
 
@@ -111,6 +113,7 @@
         command: Command | None = None,
         stream_mode: StreamMode | Sequence[StreamMode] = "values",
         stream_subgraphs: bool = False,
+        stream_resumable: bool = False,
         metadata: Mapping[str, Any] | None = None,
         config: Config | None = None,
         context: Context | None = None,
@@ -129,6 +132,7 @@
         headers: Mapping[str, str] | None = None,
         params: QueryParamTypes | None = None,
         on_run_created: Callable[[RunCreateMetadata], None] | None = None,
+        durability: Durability | None = None,
         version: Literal["v2"],
     ) -> Iterator[StreamPartV2]: ...
 
@@ -159,6 +163,7 @@
         headers: Mapping[str, str] | None = None,
         params: QueryParamTypes | None = None,
         on_run_created: Callable[[RunCreateMetadata], None] | None = None,
+        durability: Durability | None = None,
         version: Literal["v1"] = "v1",
     ) -> Iterator[StreamPart]: ...
 
@@ -189,6 +194,7 @@
         headers: Mapping[str, str] | None = None,
         params: QueryParamTypes | None = None,
         on_run_created: Callable[[RunCreateMetadata], None] | None = None,
+        durability: Durability | None = None,
         version: Literal["v2"],
     ) -> Iterator[StreamPartV2]: ...
 
@@ -380,6 +386,7 @@
         headers: Mapping[str, str] | None = None,
         params: QueryParamTypes | None = None,
         on_run_created: Callable[[RunCreateMetadata], None] | None = None,
+        durability: Durability | None = None,
     ) -> Run: ...
 
     @overload
@@ -409,6 +416,7 @@
         headers: Mapping[str, str] | None = None,
         params: QueryParamTypes | None = None,
         on_run_created: Callable[[RunCreateMetadata], None] | None = None,
+        durability: Durability | None = None,
     ) -> Run: ...
 
     def create(
@@ -642,6 +650,7 @@
         headers: Mapping[str, str] | None = None,
         params: QueryParamTypes | None = None,
         on_run_created: Callable[[RunCreateMetadata], None] | None = None,
+        durability: Durability | None = None,
     ) -> builtins.list[dict] | dict[str, Any]: ...
 
     @overload
@@ -668,6 +677,7 @@
         headers: Mapping[str, str] | None = None,
         params: QueryParamTypes | None = None,
         on_run_created: Callable[[RunCreateMetadata], None] | None = None,
+        durability: Durability | None = None,
     ) -> builtins.list[dict] | dict[str, Any]: ...
 
     def wait(
@@ -815,7 +825,6 @@
             "checkpoint_during": checkpoint_during,
             "on_completion": on_completion,
             "after_seconds": after_seconds,
-            "raise_error": raise_error,
             "durability": durability,
             "langsmith_tracer": langsmith_tracing,
         }
@@ -830,7 +839,7 @@
             if thread_id is not None
             else "/runs/wait"
         )
-        return self.http.request_reconnect(
+        response = self.http.request_reconnect(
             endpoint,
             "POST",
             json={k: v for k, v in payload.items() if v is not None},
@@ -838,6 +847,16 @@
             headers=headers,
             on_response=on_response if on_run_created else None,
         )
+        if (
+            raise_error
+            and isinstance(response, dict)
+            and "__error__" in response
+            and isinstance(response["__error__"], dict)
+        ):
+            raise Exception(
+                f"{response['__error__'].get('error')}: 
{response['__error__'].get('message')}"
+            )
+        return response
 
     def list(
         self,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langgraph_sdk-0.4.9/langgraph_sdk/sse.py 
new/langgraph_sdk-0.4.10/langgraph_sdk/sse.py
--- old/langgraph_sdk-0.4.9/langgraph_sdk/sse.py        2020-02-02 
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.10/langgraph_sdk/sse.py       2020-02-02 
01:00:00.000000000 +0100
@@ -79,18 +79,27 @@
     def __init__(self) -> None:
         self._event = ""
         self._data = bytearray()
-        self._last_event_id = ""
+        self._last_event_id: str | None = None
         self._retry: int | None = None
+        self._at_stream_start = True
 
     @property
     def last_event_id(self) -> str | None:
-        """Return the last event identifier that was seen."""
+        """Return the last event identifier that was seen.
 
-        return self._last_event_id or None
+        `None` until the stream sends an `id` field, and `""` after an empty
+        one, which resets the reconnect cursor.
+        """
+
+        return self._last_event_id
 
     def decode(self, line: bytes) -> StreamPart | None:
         # See: 
https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation
 
+        if self._at_stream_start:
+            self._at_stream_start = False
+            line = line.removeprefix(b"\xef\xbb\xbf")
+
         if not line:
             if (
                 not self._event
@@ -103,7 +112,7 @@
             sse = StreamPart(
                 event=self._event,
                 data=orjson.loads(self._data) if self._data else None,  # ty: 
ignore[invalid-argument-type]
-                id=self.last_event_id,
+                id=self._last_event_id or None,
             )
 
             # NOTE: as per the SSE spec, do not reset last_event_id.
@@ -124,6 +133,8 @@
         if fieldname == b"event":
             self._event = value.decode()
         elif fieldname == b"data":
+            if self._data:
+                self._data.extend(b"\n")
             self._data.extend(value)
         elif fieldname == b"id":
             if b"\0" in value:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langgraph_sdk-0.4.9/tests/test_api_parity.py 
new/langgraph_sdk-0.4.10/tests/test_api_parity.py
--- old/langgraph_sdk-0.4.9/tests/test_api_parity.py    2020-02-02 
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.10/tests/test_api_parity.py   2020-02-02 
01:00:00.000000000 +0100
@@ -1,7 +1,9 @@
 from __future__ import annotations
 
+import ast
 import inspect
 import re
+from pathlib import Path
 
 import pytest
 
@@ -128,3 +130,45 @@
             f"Return annotation mismatch for {async_cls.__name__}.{name}: "
             f"async={a_ret}, sync={s_ret}"
         )
+
+
+# Stateless overloads (`thread_id: None`) leave out the thread-only parameters,
+# and stateful ones (`thread_id: str`) leave out `on_completion`, which only
+# applies to stateless runs.
+_RUN_OVERLOAD_OMISSIONS = {
+    "None": {"checkpoint", "checkpoint_id", "multitask_strategy"},
+    "str": {"on_completion"},
+}
+
+
[email protected]("client_cls", [RunsClient, SyncRunsClient])
+def test_run_overloads_accept_implementation_params(client_cls) -> None:
+    tree = ast.parse(Path(inspect.getfile(client_cls)).read_text())
+    cls = next(
+        node
+        for node in tree.body
+        if isinstance(node, ast.ClassDef) and node.name == client_cls.__name__
+    )
+    defs = [
+        node
+        for node in cls.body
+        if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
+        and node.name in {"stream", "create", "wait"}
+    ]
+    impl_params = {
+        node.name: {arg.arg for arg in node.args.kwonlyargs}
+        for node in defs
+        if not node.decorator_list
+    }
+    gaps = []
+    for stub in defs:
+        if not stub.decorator_list:
+            continue
+        thread_id = next(arg for arg in stub.args.args if arg.arg == 
"thread_id")
+        assert thread_id.annotation is not None
+        kind = ast.unparse(thread_id.annotation)
+        expected = impl_params[stub.name] - _RUN_OVERLOAD_OMISSIONS[kind]
+        if missing := expected - {arg.arg for arg in stub.args.kwonlyargs}:
+            gaps.append(f"{stub.name}(thread_id: {kind}) line {stub.lineno}: 
{missing}")
+
+    assert not gaps, gaps
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langgraph_sdk-0.4.9/tests/test_client_stream.py 
new/langgraph_sdk-0.4.10/tests/test_client_stream.py
--- old/langgraph_sdk-0.4.9/tests/test_client_stream.py 2020-02-02 
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.10/tests/test_client_stream.py        2020-02-02 
01:00:00.000000000 +0100
@@ -5,6 +5,7 @@
 from typing import Any
 
 import httpx
+import orjson
 import pytest
 from typing_extensions import assert_type
 
@@ -110,6 +111,25 @@
         assert len(parts) == 79
 
 
+def test_sse_decoder_joins_data_lines_with_a_newline():
+    decoder = SSEDecoder()
+    for line in (b"data: [1,", b"data: 2]"):
+        decoder.decode(line)
+    assert decoder.decode(b"") == StreamPart(event="", data=[1, 2], id=None)  
# ty: ignore[invalid-argument-type]
+
+    for line in (b"data: [1", b"data: 0]"):
+        decoder.decode(line)
+    with pytest.raises(orjson.JSONDecodeError):
+        decoder.decode(b"")
+
+
+def test_sse_decoder_strips_a_leading_bom():
+    decoder = SSEDecoder()
+    for line in (b"\xef\xbb\xbfevent: values", b"data: 1"):
+        decoder.decode(line)
+    assert decoder.decode(b"") == StreamPart(event="values", data=1, id=None)  
# ty: ignore[invalid-argument-type]
+
+
 # --- HTTP client streaming ---
 
 
@@ -292,6 +312,52 @@
     ]
 
 
+def _drop_after_an_empty_id(stream_cls: type, reconnects: list[httpx.Request]):
+    def handler(request: httpx.Request) -> httpx.Response:
+        if request.method == "POST":
+            return httpx.Response(
+                200,
+                headers={"Content-Type": "text/event-stream", "Location": 
"/reconnect"},
+                stream=stream_cls(
+                    [
+                        b"id: 1\nevent: values\ndata: 1\n\n",
+                        b"id:\nevent: values\ndata: 2\n\n",
+                    ],
+                    httpx.RemoteProtocolError("incomplete chunked read"),
+                ),
+            )
+        reconnects.append(request)
+        return httpx.Response(
+            200,
+            headers={"Content-Type": "text/event-stream"},
+            stream=stream_cls([b"event: end\ndata: null\n\n"]),
+        )
+
+    return handler
+
+
+def test_sync_stream_reconnects_without_a_cursor_after_an_empty_id():
+    reconnects: list[httpx.Request] = []
+    transport = httpx.MockTransport(_drop_after_an_empty_id(ListByteStream, 
reconnects))
+    with httpx.Client(transport=transport, base_url="https://example.com";) as 
client:
+        list(SyncHttpClient(client).stream("/stream", "POST", json={}))
+
+    assert "last-event-id" not in reconnects[0].headers
+
+
+async def test_async_stream_reconnects_without_a_cursor_after_an_empty_id():
+    reconnects: list[httpx.Request] = []
+    transport = httpx.MockTransport(
+        _drop_after_an_empty_id(AsyncListByteStream, reconnects)
+    )
+    async with httpx.AsyncClient(
+        transport=transport, base_url="https://example.com";
+    ) as client:
+        [part async for part in HttpClient(client).stream("/stream", "POST", 
json={})]
+
+    assert "last-event-id" not in reconnects[0].headers
+
+
 # --- _sse_to_v2_dict conversion ---
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langgraph_sdk-0.4.9/tests/test_runs_client.py 
new/langgraph_sdk-0.4.10/tests/test_runs_client.py
--- old/langgraph_sdk-0.4.9/tests/test_runs_client.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.10/tests/test_runs_client.py  2020-02-02 
01:00:00.000000000 +0100
@@ -0,0 +1,119 @@
+from __future__ import annotations
+
+import json
+from collections.abc import AsyncIterator, Iterator
+
+import httpx
+import pytest
+
+from langgraph_sdk.client import (
+    HttpClient,
+    RunsClient,
+    SyncHttpClient,
+    SyncRunsClient,
+)
+
+
+class _BodyDropsMidRead(httpx.SyncByteStream, httpx.AsyncByteStream):
+    def __iter__(self) -> Iterator[bytes]:
+        yield b'{"partial'
+        raise httpx.ReadError("connection dropped")
+
+    async def __aiter__(self) -> AsyncIterator[bytes]:
+        yield b'{"partial'
+        raise httpx.ReadError("connection dropped")
+
+
+def _wait_handler(requests: list[httpx.Request]):
+    def handler(request: httpx.Request) -> httpx.Response:
+        requests.append(request)
+        if request.method == "POST":
+            return httpx.Response(
+                200,
+                headers={"Location": "/threads/t1/runs/r1/join"},
+                stream=_BodyDropsMidRead(),
+            )
+        return httpx.Response(200, json={"done": True})
+
+    return handler
+
+
+def _assert_bodyless_get(request: httpx.Request) -> None:
+    assert request.method == "GET"
+    assert request.url.path == "/threads/t1/runs/r1/join"
+    assert "content-length" not in request.headers, request.headers
+    assert "content-type" not in request.headers, request.headers
+    assert request.read() == b""
+
+
+def test_sync_wait_reconnects_with_a_bodyless_get():
+    requests: list[httpx.Request] = []
+    transport = httpx.MockTransport(_wait_handler(requests))
+    with httpx.Client(transport=transport, base_url="https://example.com";) as 
client:
+        runs = SyncRunsClient(SyncHttpClient(client))
+        with pytest.warns(UserWarning, match="attempting reconnect"):
+            result = runs.wait("t1", "agent", input={"question": "hi"})
+
+    assert result == {"done": True}
+    _assert_bodyless_get(requests[1])
+
+
+async def test_async_wait_reconnects_with_a_bodyless_get():
+    requests: list[httpx.Request] = []
+    transport = httpx.MockTransport(_wait_handler(requests))
+    async with httpx.AsyncClient(
+        transport=transport, base_url="https://example.com";
+    ) as client:
+        runs = RunsClient(HttpClient(client))
+        with pytest.warns(UserWarning, match="attempting reconnect"):
+            result = await runs.wait("t1", "agent", input={"question": "hi"})
+
+    assert result == {"done": True}
+    _assert_bodyless_get(requests[1])
+
+
+def test_sync_wait_raises_the_run_error():
+    requests: list[httpx.Request] = []
+
+    def handler(request: httpx.Request) -> httpx.Response:
+        requests.append(request)
+        return httpx.Response(
+            200, json={"__error__": {"error": "RuntimeError", "message": 
"boom"}}
+        )
+
+    transport = httpx.MockTransport(handler)
+    with httpx.Client(transport=transport, base_url="https://example.com";) as 
client:
+        runs = SyncRunsClient(SyncHttpClient(client))
+        with pytest.raises(Exception, match="RuntimeError: boom"):
+            runs.wait("t1", "agent", input={}, raise_error=True)
+
+    assert "raise_error" not in json.loads(requests[0].content)
+
+
[email protected]("asynchronous", [False, True])
+async def test_wait_returns_the_run_error_without_raise_error(asynchronous):
+    requests: list[httpx.Request] = []
+    run_error = {"__error__": {"error": "RuntimeError", "message": "boom"}}
+
+    def handler(request: httpx.Request) -> httpx.Response:
+        requests.append(request)
+        return httpx.Response(200, json=run_error)
+
+    transport = httpx.MockTransport(handler)
+    if asynchronous:
+        async with httpx.AsyncClient(
+            transport=transport, base_url="https://example.com";
+        ) as client:
+            result = await RunsClient(HttpClient(client)).wait(
+                "t1", "agent", input={}, raise_error=False
+            )
+    else:
+        with httpx.Client(
+            transport=transport, base_url="https://example.com";
+        ) as client:
+            result = SyncRunsClient(SyncHttpClient(client)).wait(
+                "t1", "agent", input={}, raise_error=False
+            )
+
+    assert result == run_error
+    assert "raise_error" not in json.loads(requests[0].content)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langgraph_sdk-0.4.9/uv.lock 
new/langgraph_sdk-0.4.10/uv.lock
--- old/langgraph_sdk-0.4.9/uv.lock     2020-02-02 01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.10/uv.lock    2020-02-02 01:00:00.000000000 +0100
@@ -301,7 +301,7 @@
 
 [[package]]
 name = "langgraph"
-version = "1.2.16"
+version = "1.2.18"
 source = { editable = "../langgraph" }
 dependencies = [
     { name = "langchain-core" },
@@ -385,7 +385,7 @@
 
 [[package]]
 name = "langgraph-checkpoint"
-version = "4.3.0"
+version = "4.3.1"
 source = { editable = "../checkpoint" }
 dependencies = [
     { name = "langchain-core" },

Reply via email to