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

Reply via email to