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-11-07 23:33:48
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-langgraph-sdk (Old)
and /work/SRC/openSUSE:Factory/.python-langgraph-sdk.new.3759290 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-langgraph-sdk"
Sat Nov 7 23:33:48 2026 rev:13 rq:1396037 version:0.4.14
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-langgraph-sdk/python-langgraph-sdk.changes
2026-11-06 20:04:55.307706728 +0100
+++
/work/SRC/openSUSE:Factory/.python-langgraph-sdk.new.3759290/python-langgraph-sdk.changes
2026-11-07 23:34:40.642664877 +0100
@@ -1,0 +2,17 @@
+Sat Nov 7 12:43:48 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to 0.4.14:
+ * runs.create, runs.stream and runs.wait gain strict_resume:
+ a resume answering an interrupt that is not waiting fails
+ with UnknownInterruptError instead of being silently ignored
+ * StreamMode gains tools and lifecycle modes for runs.stream
+
+-------------------------------------------------------------------
+Sat Nov 7 12:43:48 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to 0.4.13:
+ * Add cancel_reason to Run
+ * threads.get_state and threads.get_history gain select,
+ letting the server skip loading unneeded state keys
+
+-------------------------------------------------------------------
Old:
----
langgraph_sdk-0.4.12.tar.gz
New:
----
langgraph_sdk-0.4.14.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-langgraph-sdk.spec ++++++
--- /var/tmp/diff_new_pack.GTV6O7/_old 2026-11-07 23:34:41.420697024 +0100
+++ /var/tmp/diff_new_pack.GTV6O7/_new 2026-11-07 23:34:41.422697107 +0100
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-langgraph-sdk
-Version: 0.4.12
+Version: 0.4.14
Release: 0
Summary: SDK for interacting with the LangGraph API
License: MIT
++++++ langgraph_sdk-0.4.12.tar.gz -> langgraph_sdk-0.4.14.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_sdk-0.4.12/PKG-INFO
new/langgraph_sdk-0.4.14/PKG-INFO
--- old/langgraph_sdk-0.4.12/PKG-INFO 2020-02-02 01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.14/PKG-INFO 2020-02-02 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.5
Name: langgraph-sdk
-Version: 0.4.12
+Version: 0.4.14
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.12/langgraph_sdk/__init__.py
new/langgraph_sdk-0.4.14/langgraph_sdk/__init__.py
--- old/langgraph_sdk-0.4.12/langgraph_sdk/__init__.py 2020-02-02
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.14/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.12"
+__version__ = "0.4.14"
__all__ = [
"Auth",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_sdk-0.4.12/langgraph_sdk/_async/runs.py
new/langgraph_sdk-0.4.14/langgraph_sdk/_async/runs.py
--- old/langgraph_sdk-0.4.12/langgraph_sdk/_async/runs.py 2020-02-02
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.14/langgraph_sdk/_async/runs.py 2020-02-02
01:00:00.000000000 +0100
@@ -100,6 +100,7 @@
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
durability: Durability | None = None,
+ strict_resume: bool | None = None,
version: Literal["v1"] = "v1",
) -> AsyncIterator[StreamPart]: ...
@@ -133,6 +134,7 @@
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
durability: Durability | None = None,
+ strict_resume: bool | None = None,
version: Literal["v2"],
) -> AsyncIterator[StreamPartV2]: ...
@@ -228,6 +230,7 @@
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
durability: Durability | None = None,
+ strict_resume: bool | None = None,
version: StreamVersion = "v1",
) -> AsyncIterator[StreamPart | StreamPartV2]:
"""Create a run and stream the results.
@@ -272,6 +275,10 @@
"async" means checkpoints are persisted async while next graph
step executes, replaces checkpoint_during=True
"sync" means checkpoints are persisted sync after graph step
executes, replaces checkpoint_during=False
"exit" means checkpoints are only persisted when the run
exits, does not save intermediate steps
+ strict_resume: Refuse a resume that answers an interrupt that
isn't waiting,
+ instead of ignoring the answer: the run fails with
`UnknownInterruptError`
+ and the thread stays as it was. Takes effect on servers whose
`/info`
+ reports `strict_resume`.
version: Stream format version. "v1" (default) returns raw SSE
StreamPart
NamedTuples. "v2" returns typed dicts with `type`, `ns`, and
`data` keys.
@@ -305,7 +312,7 @@
StreamPart(event='metadata', data={'run_id':
'1ef4a9b8-d7da-679a-a45a-872054341df2'})
StreamPart(event='values', data={'messages': [{'content': 'how are
you?', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human',
'name': None, 'id': 'fe0a5778-cfe9-42ee-b807-0adaa1873c10', 'example': False}]})
StreamPart(event='values', data={'messages': [{'content': 'how are
you?', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human',
'name': None, 'id': 'fe0a5778-cfe9-42ee-b807-0adaa1873c10', 'example': False},
{'content': "I'm doing well, thanks for asking! I'm an AI assistant created by
Anthropic to be helpful, honest, and harmless.", 'additional_kwargs': {},
'response_metadata': {}, 'type': 'ai', 'name': None, 'id':
'run-159b782c-b679-4830-83c6-cef87798fe8b', 'example': False, 'tool_calls': [],
'invalid_tool_calls': [], 'usage_metadata': None}]})
- StreamPart(event='end', data=None)
+ StreamPart(event='end', data={'run_id':
'1ef4a9b8-d7da-679a-a45a-872054341df2', 'status': 'success'})
```
"""
@@ -341,6 +348,7 @@
"on_completion": on_completion,
"after_seconds": after_seconds,
"durability": durability,
+ "strict_resume": strict_resume,
"langsmith_tracer": langsmith_tracing,
}
endpoint = (
@@ -422,6 +430,7 @@
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
durability: Durability | None = None,
+ strict_resume: bool | None = None,
) -> Run: ...
async def create(
@@ -452,6 +461,7 @@
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
durability: Durability | None = None,
+ strict_resume: bool | None = None,
) -> Run:
"""Create a background run.
@@ -491,6 +501,10 @@
"async" means checkpoints are persisted async while next graph
step executes, replaces checkpoint_during=True
"sync" means checkpoints are persisted sync after graph step
executes, replaces checkpoint_during=False
"exit" means checkpoints are only persisted when the run
exits, does not save intermediate steps
+ strict_resume: Refuse a resume that answers an interrupt that
isn't waiting,
+ instead of ignoring the answer: the run fails with
`UnknownInterruptError`
+ and the thread stays as it was. Takes effect on servers whose
`/info`
+ reports `strict_resume`.
Returns:
The created background run.
@@ -595,6 +609,7 @@
"on_completion": on_completion,
"after_seconds": after_seconds,
"durability": durability,
+ "strict_resume": strict_resume,
"langsmith_tracer": langsmith_tracing,
}
payload = {k: v for k, v in payload.items() if v is not None}
@@ -656,6 +671,7 @@
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
durability: Durability | None = None,
+ strict_resume: bool | None = None,
) -> builtins.list[dict] | dict[str, Any]: ...
@overload
@@ -712,6 +728,7 @@
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
durability: Durability | None = None,
+ strict_resume: bool | None = None,
) -> builtins.list[dict] | dict[str, Any]:
"""Create a run, wait until it finishes and return the final state.
@@ -749,6 +766,10 @@
"async" means checkpoints are persisted async while next graph
step executes, replaces checkpoint_during=True
"sync" means checkpoints are persisted sync after graph step
executes, replaces checkpoint_during=False
"exit" means checkpoints are only persisted when the run
exits, does not save intermediate steps
+ strict_resume: Refuse a resume that answers an interrupt that
isn't waiting,
+ instead of ignoring the answer: the run fails with
`UnknownInterruptError`
+ and the thread stays as it was. Takes effect on servers whose
`/info`
+ reports `strict_resume`.
Returns:
The output of the run.
@@ -829,6 +850,7 @@
"on_completion": on_completion,
"after_seconds": after_seconds,
"durability": durability,
+ "strict_resume": strict_resume,
"langsmith_tracer": langsmith_tracing,
}
endpoint = (
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_sdk-0.4.12/langgraph_sdk/_async/threads.py
new/langgraph_sdk-0.4.14/langgraph_sdk/_async/threads.py
--- old/langgraph_sdk-0.4.12/langgraph_sdk/_async/threads.py 2020-02-02
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.14/langgraph_sdk/_async/threads.py 2020-02-02
01:00:00.000000000 +0100
@@ -21,6 +21,7 @@
ThreadSelectField,
ThreadSortBy,
ThreadState,
+ ThreadStateSelectField,
ThreadStatus,
ThreadStreamMode,
ThreadUpdateStateResponse,
@@ -489,6 +490,7 @@
checkpoint_id: str | None = None, # deprecated
*,
subgraphs: bool = False,
+ select: list[ThreadStateSelectField] | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
) -> ThreadState:
@@ -499,6 +501,9 @@
checkpoint: The checkpoint to get the state of.
checkpoint_id: (deprecated) The checkpoint ID to get the state of.
subgraphs: Include subgraphs states.
+ select: Fields to include in the response. Use `values.<key>` to
+ return a single state key (e.g. `values.messages`), which lets
the
+ server skip loading the rest of the state. Defaults to all
fields.
headers: Optional custom headers to include with the request.
params: Optional query parameters to include with the request.
@@ -591,16 +596,30 @@
}
}
```
+
+ Fetch only the `messages` state key:
+
+ ```python
+ thread_state = await client.threads.get_state(
+ thread_id="my_thread_id",
+ select=["values.messages"],
+ )
+ ```
"""
if checkpoint:
+ payload: dict[str, Any] = {"checkpoint": checkpoint, "subgraphs":
subgraphs}
+ if select:
+ payload["select"] = select
return await self.http.post(
f"/threads/{_quote_path_param(thread_id)}/state/checkpoint",
- json={"checkpoint": checkpoint, "subgraphs": subgraphs},
+ json=payload,
headers=headers,
params=params,
)
elif checkpoint_id:
- get_params = {"subgraphs": subgraphs}
+ get_params: dict[str, Any] = {"subgraphs": subgraphs}
+ if select:
+ get_params["select"] = select
if params:
get_params = {**get_params, **dict(params)}
return await self.http.get(
@@ -609,7 +628,9 @@
headers=headers,
)
else:
- get_params = {"subgraphs": subgraphs}
+ get_params: dict[str, Any] = {"subgraphs": subgraphs}
+ if select:
+ get_params["select"] = select
if params:
get_params = {**get_params, **dict(params)}
return await self.http.get(
@@ -692,6 +713,7 @@
before: str | Checkpoint | None = None,
metadata: Mapping[str, Any] | None = None,
checkpoint: Checkpoint | None = None,
+ select: list[ThreadStateSelectField] | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
) -> list[ThreadState]:
@@ -703,6 +725,9 @@
limit: The maximum number of states to return.
before: Return states before this checkpoint.
metadata: Filter states by metadata key-value pairs.
+ select: Fields to include in the response. Use `values.<key>` to
+ return a single state key (e.g. `values.messages`), which lets
the
+ server skip loading the rest of the state. Defaults to all
fields.
headers: Optional custom headers to include with the request.
params: Optional query parameters to include with the request.
@@ -729,6 +754,8 @@
payload["metadata"] = metadata
if checkpoint:
payload["checkpoint"] = checkpoint
+ if select:
+ payload["select"] = select
return await self.http.post(
f"/threads/{_quote_path_param(thread_id)}/history",
json=payload,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_sdk-0.4.12/langgraph_sdk/_sync/runs.py
new/langgraph_sdk-0.4.14/langgraph_sdk/_sync/runs.py
--- old/langgraph_sdk-0.4.12/langgraph_sdk/_sync/runs.py 2020-02-02
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.14/langgraph_sdk/_sync/runs.py 2020-02-02
01:00:00.000000000 +0100
@@ -100,6 +100,7 @@
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
durability: Durability | None = None,
+ strict_resume: bool | None = None,
version: Literal["v1"] = "v1",
) -> Iterator[StreamPart]: ...
@@ -133,6 +134,7 @@
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
durability: Durability | None = None,
+ strict_resume: bool | None = None,
version: Literal["v2"],
) -> Iterator[StreamPartV2]: ...
@@ -228,6 +230,7 @@
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
durability: Durability | None = None,
+ strict_resume: bool | None = None,
version: StreamVersion = "v1",
) -> Iterator[StreamPart | StreamPartV2]:
"""Create a run and stream the results.
@@ -271,6 +274,10 @@
"async" means checkpoints are persisted async while next graph
step executes, replaces checkpoint_during=True
"sync" means checkpoints are persisted sync after graph step
executes, replaces checkpoint_during=False
"exit" means checkpoints are only persisted when the run
exits, does not save intermediate steps
+ strict_resume: Refuse a resume that answers an interrupt that
isn't waiting,
+ instead of ignoring the answer: the run fails with
`UnknownInterruptError`
+ and the thread stays as it was. Takes effect on servers whose
`/info`
+ reports `strict_resume`.
version: Stream format version. "v1" (default) returns raw SSE
StreamPart
NamedTuples. "v2" returns typed dicts with `type`, `ns`, and
`data` keys.
@@ -302,7 +309,7 @@
StreamPart(event='metadata', data={'run_id':
'1ef4a9b8-d7da-679a-a45a-872054341df2'})
StreamPart(event='values', data={'messages': [{'content': 'how are
you?', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human',
'name': None, 'id': 'fe0a5778-cfe9-42ee-b807-0adaa1873c10', 'example': False}]})
StreamPart(event='values', data={'messages': [{'content': 'how are
you?', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human',
'name': None, 'id': 'fe0a5778-cfe9-42ee-b807-0adaa1873c10', 'example': False},
{'content': "I'm doing well, thanks for asking! I'm an AI assistant created by
Anthropic to be helpful, honest, and harmless.", 'additional_kwargs': {},
'response_metadata': {}, 'type': 'ai', 'name': None, 'id':
'run-159b782c-b679-4830-83c6-cef87798fe8b', 'example': False, 'tool_calls': [],
'invalid_tool_calls': [], 'usage_metadata': None}]})
- StreamPart(event='end', data=None)
+ StreamPart(event='end', data={'run_id':
'1ef4a9b8-d7da-679a-a45a-872054341df2', 'status': 'success'})
```
"""
if checkpoint_during is not None:
@@ -336,6 +343,7 @@
"on_completion": on_completion,
"after_seconds": after_seconds,
"durability": durability,
+ "strict_resume": strict_resume,
"langsmith_tracer": langsmith_tracing,
}
endpoint = (
@@ -417,6 +425,7 @@
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
durability: Durability | None = None,
+ strict_resume: bool | None = None,
) -> Run: ...
def create(
@@ -447,6 +456,7 @@
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
durability: Durability | None = None,
+ strict_resume: bool | None = None,
) -> Run:
"""Create a background run.
@@ -486,6 +496,10 @@
"async" means checkpoints are persisted async while next graph
step executes, replaces checkpoint_during=True
"sync" means checkpoints are persisted sync after graph step
executes, replaces checkpoint_during=False
"exit" means checkpoints are only persisted when the run
exits, does not save intermediate steps
+ strict_resume: Refuse a resume that answers an interrupt that
isn't waiting,
+ instead of ignoring the answer: the run fails with
`UnknownInterruptError`
+ and the thread stays as it was. Takes effect on servers whose
`/info`
+ reports `strict_resume`.
Returns:
The created background `Run`.
@@ -590,6 +604,7 @@
"on_completion": on_completion,
"after_seconds": after_seconds,
"durability": durability,
+ "strict_resume": strict_resume,
"langsmith_tracer": langsmith_tracing,
}
payload = {k: v for k, v in payload.items() if v is not None}
@@ -651,6 +666,7 @@
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
durability: Durability | None = None,
+ strict_resume: bool | None = None,
) -> builtins.list[dict] | dict[str, Any]: ...
@overload
@@ -707,6 +723,7 @@
params: QueryParamTypes | None = None,
on_run_created: Callable[[RunCreateMetadata], None] | None = None,
durability: Durability | None = None,
+ strict_resume: bool | None = None,
) -> builtins.list[dict] | dict[str, Any]:
"""Create a run, wait until it finishes and return the final state.
@@ -745,6 +762,10 @@
"async" means checkpoints are persisted async while next graph
step executes, replaces checkpoint_during=True
"sync" means checkpoints are persisted sync after graph step
executes, replaces checkpoint_during=False
"exit" means checkpoints are only persisted when the run
exits, does not save intermediate steps
+ strict_resume: Refuse a resume that answers an interrupt that
isn't waiting,
+ instead of ignoring the answer: the run fails with
`UnknownInterruptError`
+ and the thread stays as it was. Takes effect on servers whose
`/info`
+ reports `strict_resume`.
Returns:
The output of the `Run`.
@@ -826,6 +847,7 @@
"on_completion": on_completion,
"after_seconds": after_seconds,
"durability": durability,
+ "strict_resume": strict_resume,
"langsmith_tracer": langsmith_tracing,
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_sdk-0.4.12/langgraph_sdk/_sync/threads.py
new/langgraph_sdk-0.4.14/langgraph_sdk/_sync/threads.py
--- old/langgraph_sdk-0.4.12/langgraph_sdk/_sync/threads.py 2020-02-02
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.14/langgraph_sdk/_sync/threads.py 2020-02-02
01:00:00.000000000 +0100
@@ -21,6 +21,7 @@
ThreadSelectField,
ThreadSortBy,
ThreadState,
+ ThreadStateSelectField,
ThreadStatus,
ThreadStreamMode,
ThreadUpdateStateResponse,
@@ -480,6 +481,7 @@
checkpoint_id: str | None = None, # deprecated
*,
subgraphs: bool = False,
+ select: list[ThreadStateSelectField] | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
) -> ThreadState:
@@ -489,6 +491,9 @@
thread_id: The ID of the thread to get the state of.
checkpoint: The checkpoint to get the state of.
subgraphs: Include subgraphs states.
+ select: Fields to include in the response. Use `values.<key>` to
+ return a single state key (e.g. `values.messages`), which lets
the
+ server skip loading the rest of the state. Defaults to all
fields.
headers: Optional custom headers to include with the request.
Returns:
@@ -581,16 +586,29 @@
}
```
+ Fetch only the `messages` state key:
+
+ ```python
+ thread_state = client.threads.get_state(
+ thread_id="my_thread_id",
+ select=["values.messages"],
+ )
+ ```
"""
if checkpoint:
+ payload: dict[str, Any] = {"checkpoint": checkpoint, "subgraphs":
subgraphs}
+ if select:
+ payload["select"] = select
return self.http.post(
f"/threads/{_quote_path_param(thread_id)}/state/checkpoint",
- json={"checkpoint": checkpoint, "subgraphs": subgraphs},
+ json=payload,
headers=headers,
params=params,
)
elif checkpoint_id:
- get_params = {"subgraphs": subgraphs}
+ get_params: dict[str, Any] = {"subgraphs": subgraphs}
+ if select:
+ get_params["select"] = select
if params:
get_params = {**get_params, **dict(params)}
return self.http.get(
@@ -599,7 +617,9 @@
headers=headers,
)
else:
- get_params = {"subgraphs": subgraphs}
+ get_params: dict[str, Any] = {"subgraphs": subgraphs}
+ if select:
+ get_params["select"] = select
if params:
get_params = {**get_params, **dict(params)}
return self.http.get(
@@ -679,6 +699,7 @@
before: str | Checkpoint | None = None,
metadata: Mapping[str, Any] | None = None,
checkpoint: Checkpoint | None = None,
+ select: list[ThreadStateSelectField] | None = None,
headers: Mapping[str, str] | None = None,
params: QueryParamTypes | None = None,
) -> list[ThreadState]:
@@ -690,6 +711,9 @@
limit: The maximum number of states to return.
before: Return states before this checkpoint.
metadata: Filter states by metadata key-value pairs.
+ select: Fields to include in the response. Use `values.<key>` to
+ return a single state key (e.g. `values.messages`), which lets
the
+ server skip loading the rest of the state. Defaults to all
fields.
headers: Optional custom headers to include with the request.
Returns:
@@ -717,6 +741,8 @@
payload["metadata"] = metadata
if checkpoint:
payload["checkpoint"] = checkpoint
+ if select:
+ payload["select"] = select
return self.http.post(
f"/threads/{_quote_path_param(thread_id)}/history",
json=payload,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_sdk-0.4.12/langgraph_sdk/schema.py
new/langgraph_sdk-0.4.14/langgraph_sdk/schema.py
--- old/langgraph_sdk-0.4.12/langgraph_sdk/schema.py 2020-02-02
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.14/langgraph_sdk/schema.py 2020-02-02
01:00:00.000000000 +0100
@@ -58,6 +58,8 @@
"debug",
"custom",
"messages-tuple",
+ "tools",
+ "lifecycle",
]
"""
Defines the mode of streaming:
@@ -69,6 +71,8 @@
- "tasks": Stream task start and finish events.
- "debug": Stream detailed debug information.
- "custom": Stream custom events.
+- "tools": Stream tool events: `on_tool_start`, `on_tool_event`, `on_tool_end`
and `on_tool_error`.
+- "lifecycle": Stream an event when each subgraph starts and ends, with the id
of the tool call that started it.
"""
DisconnectMode = Literal["cancel", "continue"]
@@ -380,6 +384,8 @@
"""The run metadata."""
multitask_strategy: MultitaskStrategy
"""Strategy to handle concurrent runs on the same thread."""
+ cancel_reason: NotRequired[str | None]
+ """Why the run was cancelled, if it was. Omitted by older servers."""
class Cron(TypedDict):
@@ -480,6 +486,21 @@
"interrupts",
]
+ThreadStateSelectField = (
+ Literal[
+ "values",
+ "next",
+ "tasks",
+ "checkpoint",
+ "metadata",
+ "created_at",
+ "parent_checkpoint",
+ "interrupts",
+ ]
+ | str
+)
+"""Also accepts `values.<key>` for a single state key, e.g.
`values.messages`."""
+
RunSelectField = Literal[
"run_id",
"thread_id",
@@ -490,6 +511,7 @@
"metadata",
"kwargs",
"multitask_strategy",
+ "cancel_reason",
]
CronSelectField = Literal[
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_sdk-0.4.12/tests/test_api_parity.py
new/langgraph_sdk-0.4.14/tests/test_api_parity.py
--- old/langgraph_sdk-0.4.12/tests/test_api_parity.py 2020-02-02
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.14/tests/test_api_parity.py 2020-02-02
01:00:00.000000000 +0100
@@ -136,7 +136,7 @@
# 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"},
+ "None": {"checkpoint", "checkpoint_id", "multitask_strategy",
"strict_resume"},
"str": {"on_completion"},
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_sdk-0.4.12/tests/test_runs_client.py
new/langgraph_sdk-0.4.14/tests/test_runs_client.py
--- old/langgraph_sdk-0.4.12/tests/test_runs_client.py 2020-02-02
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.14/tests/test_runs_client.py 2020-02-02
01:00:00.000000000 +0100
@@ -212,3 +212,55 @@
assert result == run_error
assert "raise_error" not in json.loads(requests[0].content)
+
+
+def _strict_resume_handler(requests: list[httpx.Request]):
+ def handler(request: httpx.Request) -> httpx.Response:
+ requests.append(request)
+ if request.url.path.endswith("/stream"):
+ return httpx.Response(
+ 200,
+ headers={"Content-Type": "text/event-stream"},
+ content=b"event: end\ndata: null\n\n",
+ )
+ return httpx.Response(200, json={"run_id": "r1"})
+
+ return handler
+
+
[email protected]("method", ["create", "stream", "wait"])
[email protected]("asynchronous", [False, True])
[email protected]("strict_resume", [True, None], ids=["opted-in",
"default"])
+async def test_runs_send_strict_resume_only_when_set(
+ method: str, asynchronous: bool, strict_resume: bool | None
+):
+ requests: list[httpx.Request] = []
+ transport = httpx.MockTransport(_strict_resume_handler(requests))
+ kwargs: dict[str, Any] = {
+ "command": {"resume": {"0" * 32: "yes"}},
+ "strict_resume": strict_resume,
+ }
+ if asynchronous:
+ async with httpx.AsyncClient(
+ transport=transport, base_url="https://example.com"
+ ) as client:
+ result = getattr(RunsClient(HttpClient(client)), method)(
+ "t1", "agent", **kwargs
+ )
+ if method == "stream":
+ async for _ in result:
+ pass
+ else:
+ await result
+ else:
+ with httpx.Client(
+ transport=transport, base_url="https://example.com"
+ ) as client:
+ result = getattr(SyncRunsClient(SyncHttpClient(client)), method)(
+ "t1", "agent", **kwargs
+ )
+ if method == "stream":
+ for _ in result:
+ pass
+
+ assert json.loads(requests[0].content).get("strict_resume") ==
strict_resume
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_sdk-0.4.12/tests/test_threads_client.py
new/langgraph_sdk-0.4.14/tests/test_threads_client.py
--- old/langgraph_sdk-0.4.12/tests/test_threads_client.py 2020-02-02
01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.14/tests/test_threads_client.py 2020-02-02
01:00:00.000000000 +0100
@@ -11,6 +11,14 @@
SyncThreadsClient,
ThreadsClient,
)
+from langgraph_sdk.schema import Checkpoint
+
+CHECKPOINT: Checkpoint = {
+ "thread_id": "thread_123",
+ "checkpoint_ns": "",
+ "checkpoint_id": "cp_1",
+ "checkpoint_map": None,
+}
@pytest.mark.asyncio
@@ -56,3 +64,121 @@
)
assert result is None
+
+
[email protected]
+async def test_async_threads_get_state_select():
+ requests: list[httpx.Request] = []
+
+ async def handler(request: httpx.Request) -> httpx.Response:
+ requests.append(request)
+ return httpx.Response(200, json={})
+
+ transport = httpx.MockTransport(handler)
+ async with httpx.AsyncClient(
+ transport=transport, base_url="https://example.com"
+ ) as client:
+ threads_client = ThreadsClient(HttpClient(client))
+ await threads_client.get_state("thread_123",
select=["values.messages", "next"])
+ await threads_client.get_state(
+ "thread_123", checkpoint_id="cp_1", select=["values.messages"]
+ )
+ await threads_client.get_state(
+ "thread_123",
+ checkpoint=CHECKPOINT,
+ select=["values.messages"],
+ )
+ await threads_client.get_state("thread_123")
+
+ latest, by_id, by_checkpoint, default = requests
+ assert latest.method == "GET"
+ assert latest.url.path == "/threads/thread_123/state"
+ assert latest.url.params.get_list("select") == ["values.messages", "next"]
+ assert by_id.method == "GET"
+ assert by_id.url.path == "/threads/thread_123/state/cp_1"
+ assert by_id.url.params.get_list("select") == ["values.messages"]
+ assert by_checkpoint.method == "POST"
+ assert by_checkpoint.url.path == "/threads/thread_123/state/checkpoint"
+ assert json.loads(by_checkpoint.content) == {
+ "checkpoint": CHECKPOINT,
+ "subgraphs": False,
+ "select": ["values.messages"],
+ }
+ assert "select" not in default.url.params
+
+
[email protected]
+async def test_async_threads_get_history_select():
+ bodies: list[dict] = []
+
+ async def handler(request: httpx.Request) -> httpx.Response:
+ assert request.method == "POST"
+ assert request.url.path == "/threads/thread_123/history"
+ bodies.append(json.loads(request.content))
+ return httpx.Response(200, json=[])
+
+ transport = httpx.MockTransport(handler)
+ async with httpx.AsyncClient(
+ transport=transport, base_url="https://example.com"
+ ) as client:
+ threads_client = ThreadsClient(HttpClient(client))
+ await threads_client.get_history("thread_123",
select=["values.messages"])
+ await threads_client.get_history("thread_123")
+
+ assert bodies == [{"limit": 10, "select": ["values.messages"]}, {"limit":
10}]
+
+
+def test_sync_threads_get_state_select():
+ requests: list[httpx.Request] = []
+
+ def handler(request: httpx.Request) -> httpx.Response:
+ requests.append(request)
+ return httpx.Response(200, json={})
+
+ transport = httpx.MockTransport(handler)
+ with httpx.Client(transport=transport, base_url="https://example.com") as
client:
+ threads_client = SyncThreadsClient(SyncHttpClient(client))
+ threads_client.get_state("thread_123", select=["values.messages",
"next"])
+ threads_client.get_state(
+ "thread_123", checkpoint_id="cp_1", select=["values.messages"]
+ )
+ threads_client.get_state(
+ "thread_123",
+ checkpoint=CHECKPOINT,
+ select=["values.messages"],
+ )
+ threads_client.get_state("thread_123")
+
+ latest, by_id, by_checkpoint, default = requests
+ assert latest.method == "GET"
+ assert latest.url.path == "/threads/thread_123/state"
+ assert latest.url.params.get_list("select") == ["values.messages", "next"]
+ assert by_id.method == "GET"
+ assert by_id.url.path == "/threads/thread_123/state/cp_1"
+ assert by_id.url.params.get_list("select") == ["values.messages"]
+ assert by_checkpoint.method == "POST"
+ assert by_checkpoint.url.path == "/threads/thread_123/state/checkpoint"
+ assert json.loads(by_checkpoint.content) == {
+ "checkpoint": CHECKPOINT,
+ "subgraphs": False,
+ "select": ["values.messages"],
+ }
+ assert "select" not in default.url.params
+
+
+def test_sync_threads_get_history_select():
+ bodies: list[dict] = []
+
+ def handler(request: httpx.Request) -> httpx.Response:
+ assert request.method == "POST"
+ assert request.url.path == "/threads/thread_123/history"
+ bodies.append(json.loads(request.content))
+ return httpx.Response(200, json=[])
+
+ transport = httpx.MockTransport(handler)
+ with httpx.Client(transport=transport, base_url="https://example.com") as
client:
+ threads_client = SyncThreadsClient(SyncHttpClient(client))
+ threads_client.get_history("thread_123", select=["values.messages"])
+ threads_client.get_history("thread_123")
+
+ assert bodies == [{"limit": 10, "select": ["values.messages"]}, {"limit":
10}]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_sdk-0.4.12/uv.lock
new/langgraph_sdk-0.4.14/uv.lock
--- old/langgraph_sdk-0.4.12/uv.lock 2020-02-02 01:00:00.000000000 +0100
+++ new/langgraph_sdk-0.4.14/uv.lock 2020-02-02 01:00:00.000000000 +0100
@@ -301,7 +301,7 @@
[[package]]
name = "langgraph"
-version = "1.2.19"
+version = "1.2.20"
source = { editable = "../langgraph" }
dependencies = [
{ name = "langchain-core" },