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