From 1e767c06539cdec79f78a611e7be19bb7cd8b9cc Mon Sep 17 00:00:00 2001 From: Tat Dat Duong Date: Wed, 19 Mar 2025 20:05:08 +0100 Subject: [PATCH] feat(sdk): add `bulk_update_state` in SDK --- libs/sdk-js/package.json | 2 +- libs/sdk-js/src/client.ts | 6 +- libs/sdk-py/langgraph_sdk/client.py | 134 ++++++++++++++++++++++------ libs/sdk-py/pyproject.toml | 2 +- 4 files changed, 113 insertions(+), 31 deletions(-) diff --git a/libs/sdk-js/package.json b/libs/sdk-js/package.json index 6c3d5a06c..6f1cd8d0b 100644 --- a/libs/sdk-js/package.json +++ b/libs/sdk-js/package.json @@ -1,6 +1,6 @@ { "name": "@langchain/langgraph-sdk", - "version": "0.0.59", + "version": "0.0.60", "description": "Client library for interacting with the LangGraph API", "type": "module", "packageManager": "yarn@1.22.19", diff --git a/libs/sdk-js/src/client.ts b/libs/sdk-js/src/client.ts index 52051f1e8..c0ed9a8c9 100644 --- a/libs/sdk-js/src/client.ts +++ b/libs/sdk-js/src/client.ts @@ -641,6 +641,10 @@ export class ThreadsClient< /** * Create a new thread from a batch states. + * + * @param supersteps An array of supersteps. + * @param options Additional options. + * @returns The created thread. */ async bulkUpdateState( supersteps: Array<{ @@ -653,7 +657,7 @@ export class ThreadsClient< ifExists?: OnConflictBehavior; }, ): Promise> { - return this.fetch>("/threads/state/batch", { + return this.fetch>("/threads/state/bulk", { method: "POST", json: { supersteps: supersteps.map((s) => ({ diff --git a/libs/sdk-py/langgraph_sdk/client.py b/libs/sdk-py/langgraph_sdk/client.py index 6f4583b7f..8d96f7129 100644 --- a/libs/sdk-py/langgraph_sdk/client.py +++ b/libs/sdk-py/langgraph_sdk/client.py @@ -1142,6 +1142,55 @@ class ThreadsClient: payload["as_node"] = as_node return await self.http.post(f"/threads/{thread_id}/state", json=payload) + async def bulk_update_state( + self, + supersteps: Sequence[dict[str, Sequence[dict[str, Any]]]], + *, + graph_id: Optional[str] = None, + thread_id: Optional[str] = None, + metadata: Optional[dict[str, Any]] = None, + if_exists: Optional[OnConflictBehavior] = None, + ) -> Thread: + """Create a new thread from a batch of states. + + Args: + supersteps: A sequence of supersteps, each containing a sequence of updates. + Each update has `values` or `command` and `as_node`. + graph_id: Optional graph ID to associate with the thread. + thread_id: Optional thread ID to use. If not provided, a new one will be generated. + metadata: Optional metadata to associate with the thread. + if_exists: Optional behavior when `thread_id` already exists. + + Returns: + The created thread. + """ + + payload: Dict[str, Any] = { + "supersteps": [ + { + "updates": [ + { + "values": u["values"], + "command": u.get("command"), + "as_node": u["as_node"], + } + for u in s["updates"] + ] + } + for s in supersteps + ], + } + if thread_id: + payload["thread_id"] = thread_id + if metadata or graph_id: + payload["metadata"] = { + **(metadata or {}), + **({"graph_id": graph_id} if graph_id else {}), + } + if if_exists: + payload["if_exists"] = if_exists + return await self.http.post("/threads/state/batch", json=payload) + async def get_history( self, thread_id: str, @@ -3294,38 +3343,18 @@ class SyncThreadsClient: checkpoint: Optional[Checkpoint] = None, checkpoint_id: Optional[str] = None, # deprecated ) -> ThreadUpdateStateResponse: - """Update the state of a thread. + """Add state to a thread. Args: - thread_id: The ID of the thread to update. - values: The values to update the state with. - as_node: Update the state as if this node had just executed. - checkpoint: The checkpoint to update the state of. + thread_id: The ID of the thread. + values: The values to add to the thread state. + as_node: The node to add the state as. + checkpoint: The checkpoint to add the state to. + checkpoint_id: The ID of the checkpoint to add the state to. Deprecated. Returns: - ThreadUpdateStateResponse: Response after updating a thread's state. - - Example Usage: - - response = client.threads.update_state( - thread_id="my_thread_id", - values={"messages":[{"role": "user", "content": "hello!"}]}, - as_node="my_node", - ) - print(response) - - ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- - - { - 'checkpoint': { - 'thread_id': 'e2496803-ecd5-4e0c-a779-3226296181c2', - 'checkpoint_ns': '', - 'checkpoint_id': '1ef4a9b8-e6fb-67b1-8001-abd5184439d1', - 'checkpoint_map': {} - } - } - - """ # noqa: E501 + The response from the server. + """ payload: Dict[str, Any] = { "values": values, } @@ -3337,6 +3366,55 @@ class SyncThreadsClient: payload["as_node"] = as_node return self.http.post(f"/threads/{thread_id}/state", json=payload) + def bulk_update_state( + self, + supersteps: Sequence[dict[str, Sequence[dict[str, Any]]]], + *, + graph_id: Optional[str] = None, + thread_id: Optional[str] = None, + metadata: Optional[dict[str, Any]] = None, + if_exists: Optional[OnConflictBehavior] = None, + ) -> Thread: + """Create a new thread from a batch of states. + + Args: + supersteps: A sequence of supersteps, each containing a sequence of updates. + Each update has `values` or `command` and `as_node`. + graph_id: Optional graph ID to associate with the thread. + thread_id: Optional thread ID to use. If not provided, a new one will be generated. + metadata: Optional metadata to associate with the thread. + if_exists: Optional behavior when `thread_id` already exists. + + Returns: + The created thread. + """ + + payload: Dict[str, Any] = { + "supersteps": [ + { + "updates": [ + { + "values": u["values"], + "command": u.get("command"), + "as_node": u["as_node"], + } + for u in s["updates"] + ] + } + for s in supersteps + ], + } + if thread_id: + payload["thread_id"] = thread_id + if metadata or graph_id: + payload["metadata"] = { + **(metadata or {}), + **({"graph_id": graph_id} if graph_id else {}), + } + if if_exists: + payload["if_exists"] = if_exists + return self.http.post("/threads/state/bulk", json=payload) + def get_history( self, thread_id: str, diff --git a/libs/sdk-py/pyproject.toml b/libs/sdk-py/pyproject.toml index 75e402fee..92e942441 100644 --- a/libs/sdk-py/pyproject.toml +++ b/libs/sdk-py/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langgraph-sdk" -version = "0.1.57" +version = "0.1.58" description = "SDK for interacting with LangGraph API" authors = [] license = "MIT"