From 84446f5ad8f273d282ab72bc16b6982269d661ee Mon Sep 17 00:00:00 2001 From: Luka Aladashvili <115102487+llukito@users.noreply.github.com> Date: Tue, 10 Feb 2026 17:08:39 +0400 Subject: [PATCH 01/41] refactor: replace bare except with BaseException in AsyncQueue (#6765) ## Description Replaced a bare `except:` with `except BaseException:` in `libs/langgraph/langgraph/_internal/_queue.py`. ## Motivation Using a bare `except:` violates PEP 8 (E722). While functionally equivalent to `except BaseException:`, making it explicit improves code readability and satisfies static analysis tools. This ensures that `asyncio.CancelledError` (which inherits from `BaseException`) is still caught and handled correctly by the cancellation logic in the `wait()` method, but without the ambiguity of a bare except. --- libs/langgraph/langgraph/_internal/_queue.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/langgraph/langgraph/_internal/_queue.py b/libs/langgraph/langgraph/_internal/_queue.py index a7e48c486..b2cc02a77 100644 --- a/libs/langgraph/langgraph/_internal/_queue.py +++ b/libs/langgraph/langgraph/_internal/_queue.py @@ -25,7 +25,7 @@ class AsyncQueue(asyncio.Queue): self._getters.append(getter) try: await getter - except: + except BaseException: getter.cancel() # Just in case getter is not done yet. try: # Clean self._getters from canceled getters. From a734f5e6ced3c4488141e7f1101644bfc3293c32 Mon Sep 17 00:00:00 2001 From: William FH <13333726+hinthornw@users.noreply.github.com> Date: Tue, 10 Feb 2026 08:53:52 -0800 Subject: [PATCH 02/41] chore: server runtime type (#6774) Main jtbd here: a) clarify who/how a graph is being accessed and make the factory aware of the `context` where relevant (and make it obvious when it is available) b) make it more clear when you can bypass / defer resources with expensive lifespans (like MCp connections) c) make auth access more type-safe. Gives us room to add other information, like: - langsmith distributed tracing information ---- old Can start doing things like this: ``` def my_graph(runtime: ServerRuntime): if runtime.ensure_user().permissions not in ("foo"): raise ValueError("bar") ``` etc. Points of expected confusion: - You won't have a stream_writer in this context. - This won't be an accessible object within the graph, only the graph factory. For maintainers, related draft PR int he server https://github.com/langchain-ai/langgraph/pull/6774 --- libs/langgraph/uv.lock | 1 + libs/prebuilt/uv.lock | 1 + libs/sdk-py/langgraph_sdk/__init__.py | 2 +- libs/sdk-py/langgraph_sdk/runtime.py | 238 +++++++++ libs/sdk-py/pyproject.toml | 4 + libs/sdk-py/uv.lock | 735 ++++++++++++++++++++++++++ 6 files changed, 980 insertions(+), 1 deletion(-) create mode 100644 libs/sdk-py/langgraph_sdk/runtime.py diff --git a/libs/langgraph/uv.lock b/libs/langgraph/uv.lock index 98e9cbce4..7dd87e65d 100644 --- a/libs/langgraph/uv.lock +++ b/libs/langgraph/uv.lock @@ -1823,6 +1823,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ { name = "codespell" }, + { name = "langgraph", editable = "." }, { name = "mypy", specifier = "==1.19.0" }, { name = "pydantic", specifier = ">=2.12.4" }, { name = "pytest" }, diff --git a/libs/prebuilt/uv.lock b/libs/prebuilt/uv.lock index 84a7fd5e5..2a2f2d66f 100644 --- a/libs/prebuilt/uv.lock +++ b/libs/prebuilt/uv.lock @@ -591,6 +591,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ { name = "codespell" }, + { name = "langgraph", editable = "../langgraph" }, { name = "mypy", specifier = "==1.19.0" }, { name = "pydantic", specifier = ">=2.12.4" }, { name = "pytest" }, diff --git a/libs/sdk-py/langgraph_sdk/__init__.py b/libs/sdk-py/langgraph_sdk/__init__.py index 94fc8454a..c635f7961 100644 --- a/libs/sdk-py/langgraph_sdk/__init__.py +++ b/libs/sdk-py/langgraph_sdk/__init__.py @@ -3,6 +3,6 @@ from langgraph_sdk.client import get_client, get_sync_client from langgraph_sdk.encryption import Encryption from langgraph_sdk.encryption.types import EncryptionContext -__version__ = "0.3.4" +__version__ = "0.3.5" __all__ = ["Auth", "Encryption", "EncryptionContext", "get_client", "get_sync_client"] diff --git a/libs/sdk-py/langgraph_sdk/runtime.py b/libs/sdk-py/langgraph_sdk/runtime.py new file mode 100644 index 000000000..872c4f3de --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/runtime.py @@ -0,0 +1,238 @@ +from __future__ import annotations + +import sys +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, Generic, Literal, TypeVar + +if sys.version_info >= (3, 13): + ContextT = TypeVar("ContextT", default=None) +else: + ContextT = TypeVar("ContextT") + +if sys.version_info >= (3, 12): + from typing import TypeAliasType +else: + from typing_extensions import TypeAliasType + +from langgraph_sdk.auth.types import BaseUser + +if TYPE_CHECKING: + from langgraph.store.base import BaseStore + +__all__ = [ + "AccessContext", + "ServerRuntime", +] + + +AccessContext = Literal[ + "threads.create_run", + "threads.update", + "threads.read", + "assistants.read", +] + + +@dataclass(kw_only=True, slots=True, frozen=True) +class _ServerRuntimeBase(Generic[ContextT]): + """Base for server runtime variants. + + !!! warning "Beta" + This API is in beta and may change in future releases. + """ + + access_context: AccessContext + """Why the graph factory is being called. + + The server accesses graphs in several contexts beyond just executing runs. + For example, it calls the graph factory to retrieve schemas, render the + graph structure, or read state history. This field tells you which + operation triggered the current call. + + In all contexts, the returned graph must have the same topology (nodes, + edges, state schema) as the graph used for execution. Use + `.execution_runtime` to conditionally set up expensive *resources* + (MCP servers, DB connections) without changing the graph structure. + + Write contexts (graph is used to write state): + + - `threads.create_run` (`graph.astream`) — full graph execution + (nodes + edges). `context` is available (use `.execution_runtime` + to narrow). + - `threads.update` (`graph.aupdate_state`) — does NOT execute node + functions or evaluate edges. Only runs the node's channel writers + to apply the provided values to state channels as if the specified + node had returned them. Reducers are applied and channel triggers + are set, so the next `invoke`/`stream` call will evaluate edges + from that node to determine the next step. Does not need access to + external resources, but a different graph topology will apply + writes to the wrong channels. + + Read state contexts (graph used to format the returned + `StateSnapshot`). A different topology may cause `get_state` to + report incorrect pending tasks. Note that `useStream` uses the state + history endpoint to render interrupts and support branching: + + - `threads.read` (`graph.aget_state`, `graph.aget_state_history`) — + the graph structure informs which tasks to include in the prepared + view of the latest checkpoint and how to process subgraphs. + + Introspection contexts (graph structure only, no execution). + A different topology may cause schemas and visualizations to not + match actual execution: + + - `assistants.read` (`graph.aget_graph`, `graph.aget_subgraphs`, + `graph.aget_schemas`) — return the graph definition, subgraph + definitions, and input/output/config schemas. Used for + visualization in the studio UI and to populate schemas for MCP, + A2A, and other protocol integrations. + """ + + user: BaseUser | None = field(default=None) + """The authenticated user, or `None` if no custom auth is configured.""" + + store: BaseStore + """Store for the graph run, enabling persistence and memory.""" + + @property + def execution_runtime(self) -> _ExecutionRuntime[ContextT] | None: + """Narrow to the execution runtime, or `None` if not in an execution context. + + When the server calls the graph factory for `threads.create_run`, the returned + object provides access to `context` (typed by the graph's + `context_schema`). For all other access contexts (introspection, state + reads, state updates), this returns `None`. + + Use this to conditionally set up expensive resources (MCP tool servers, + database connections, etc.) that are only needed during execution: + + ```python + import contextlib + from langgraph_sdk.runtime import ServerRuntime + + @contextlib.asynccontextmanager + async def my_factory(runtime: ServerRuntime[MyCtx]): + if ert := runtime.execution_runtime: + # Only connect to MCP servers when actually executing a run. + # Introspection calls (get_schema, get_graph, ...) skip this. + mcp_tools = await connect_mcp(ert.context.mcp_endpoint) + yield create_agent(model, tools=mcp_tools) + await disconnect_mcp() + else: + yield create_agent(model, tools=[]) + ``` + """ + if isinstance(self, _ExecutionRuntime): + return self + return None + + def ensure_user(self) -> BaseUser: + """Return the authenticated user, or raise if not available. + + When custom auth is configured, `user` is set for all access contexts + (the factory is only called from HTTP handlers where the auth + middleware has already run). This method raises only when no custom + auth is configured. + + Raises: + PermissionError: If no user is authenticated. + """ + if self.user is None: + raise PermissionError( + f"No authenticated user available in access_context='{self.access_context}'. " + "Ensure custom auth is configured for the server." + ) + return self.user + + +@dataclass(kw_only=True, slots=True, frozen=True) +class _ExecutionRuntime(_ServerRuntimeBase[ContextT], Generic[ContextT]): + """Runtime for `threads.create_run` — the graph will be fully executed. + + Access this via `.execution_runtime` on `ServerRuntime`. Do not + construct directly. + + !!! warning "Beta" + This API is in beta and may change in future releases. + """ + + context: ContextT = field(default=None) # type: ignore[assignment] + """The graph run context, typed by the graph's `context_schema`. + + Only available during `threads.create_run`. + """ + + +@dataclass(kw_only=True, slots=True, frozen=True) +class _ReadRuntime(_ServerRuntimeBase[ContextT], Generic[ContextT]): + """Runtime for non-execution access contexts. + + Used for introspection (`assistants.read`), state operations + (`threads.read`), and state updates (`threads.update`). + No `context` is available. + + !!! warning "Beta" + This API is in beta and may change in future releases. + """ + + +ServerRuntime = TypeAliasType( + "ServerRuntime", + _ExecutionRuntime[ContextT] | _ReadRuntime[ContextT], + type_params=(ContextT,), +) +"""Runtime context passed to graph builder factories within the Agent Server. + +Requires version 0.7.30 or later of the agent server. + +The server calls your graph factory in multiple contexts: executing runs, +reading state, fetching schemas, and more. `ServerRuntime` provides +the authenticated user, store, and access context for every call. Use +`.execution_runtime` to narrow to the execution variant and access +`context`. + +Example — conditionally initialize MCP tools only during execution: + +```python +import contextlib +from dataclasses import dataclass + +from langchain.agents import create_agent +from langgraph_sdk.runtime import ServerRuntime +from my_agent import connect_mcp, disconnect_mcp + +@dataclass +class MyCtx: + mcp_endpoint: str + +_readonly_agent = create_agent("anthropic:claude-3-5-haiku", tools=[]) + +@contextlib.asynccontextmanager +async def my_factory(runtime: ServerRuntime[MyCtx]): + if ert := runtime.execution_runtime: + # Only connect to MCP servers for actual runs. + # Schema / graph introspection calls skip this. + user_id = runtime.ensure_user().identity + mcp_tools = await connect_mcp(ert.context.mcp_endpoint, user_id) + yield create_agent("anthropic:claude-3-5-haiku", tools=mcp_tools) + await disconnect_mcp() + else: + yield _readonly_agent +``` + +Example — simple factory that ignores context: + +```python +from langgraph_sdk.runtime import ServerRuntime + +def build_graph(user: BaseUser) -> CompiledGraph: + ... + +async def my_factory(runtime: ServerRuntime) -> CompiledGraph: + # No generic needed if you don't use context. + return build_graph(runtime.ensure_user()) +``` + +!!! warning "Beta" + This API is in beta and may change in future releases. +""" diff --git a/libs/sdk-py/pyproject.toml b/libs/sdk-py/pyproject.toml index 994b09e06..d5cef8b78 100644 --- a/libs/sdk-py/pyproject.toml +++ b/libs/sdk-py/pyproject.toml @@ -39,6 +39,7 @@ lint = [ dev = [ { include-group = "test" }, { include-group = "lint" }, + "langgraph", "pydantic>=2.12.4", ] @@ -52,6 +53,9 @@ asyncio_mode = "auto" [tool.uv] default-groups = ['dev'] +[tool.uv.sources] +langgraph = { path = "../langgraph", editable = true } + [tool.ruff] exclude = ["venv", ".venv", "build", "dist"] [tool.ruff.lint] diff --git a/libs/sdk-py/uv.lock b/libs/sdk-py/uv.lock index df2b266c9..9c764b02b 100644 --- a/libs/sdk-py/uv.lock +++ b/libs/sdk-py/uv.lock @@ -43,6 +43,95 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, ] +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709, upload-time = "2025-10-14T04:40:11.385Z" }, + { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814, upload-time = "2025-10-14T04:40:13.135Z" }, + { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467, upload-time = "2025-10-14T04:40:14.728Z" }, + { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280, upload-time = "2025-10-14T04:40:16.14Z" }, + { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454, upload-time = "2025-10-14T04:40:17.567Z" }, + { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609, upload-time = "2025-10-14T04:40:19.08Z" }, + { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849, upload-time = "2025-10-14T04:40:20.607Z" }, + { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586, upload-time = "2025-10-14T04:40:21.719Z" }, + { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290, upload-time = "2025-10-14T04:40:23.069Z" }, + { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663, upload-time = "2025-10-14T04:40:24.17Z" }, + { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964, upload-time = "2025-10-14T04:40:25.368Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064, upload-time = "2025-10-14T04:40:26.806Z" }, + { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015, upload-time = "2025-10-14T04:40:28.284Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792, upload-time = "2025-10-14T04:40:29.613Z" }, + { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198, upload-time = "2025-10-14T04:40:30.644Z" }, + { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262, upload-time = "2025-10-14T04:40:32.108Z" }, + { url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" }, + { url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" }, + { url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" }, + { url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" }, + { url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" }, + { url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" }, + { url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" }, + { url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" }, + { url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" }, + { url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" }, + { url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" }, + { url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" }, + { url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" }, + { url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" }, + { url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" }, + { url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" }, + { url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" }, + { url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" }, + { url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" }, + { url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" }, + { url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" }, + { url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" }, + { url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" }, + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" }, + { url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" }, + { url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" }, + { url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" }, + { url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" }, + { url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" }, + { url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + [[package]] name = "codespell" version = "2.4.1" @@ -134,6 +223,228 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] +[[package]] +name = "jsonpatch" +version = "1.33" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonpointer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/78/18813351fe5d63acad16aec57f94ec2b70a09e53ca98145589e185423873/jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c", size = 21699, upload-time = "2023-06-26T12:07:29.144Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade", size = 12898, upload-time = "2023-06-16T21:01:28.466Z" }, +] + +[[package]] +name = "jsonpointer" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, +] + +[[package]] +name = "langchain-core" +version = "1.2.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonpatch" }, + { name = "langsmith" }, + { name = "packaging" }, + { name = "pydantic" }, + { name = "pyyaml" }, + { name = "tenacity" }, + { name = "typing-extensions" }, + { name = "uuid-utils" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/60/5dfd49eb4143a3ba72fb93607a71109e56bc92c7144f97eeae103a118e80/langchain_core-1.2.10.tar.gz", hash = "sha256:8c1fa1515b4bf59bf61ff0ff5813dd2b91d4ca1b8bf2ee31c5536364fa4699ae", size = 826391, upload-time = "2026-02-10T14:48:31.679Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/1b/e27c9d03ae431d7b47d2b3289285473d3e724f17c13c0e2409ec158b91e4/langchain_core-1.2.10-py3-none-any.whl", hash = "sha256:fa327dd6a8a596e73a402ec3fa48ea5c4a5f5ac898e983063d1b70b4fddcdf8e", size = 496673, upload-time = "2026-02-10T14:48:29.388Z" }, +] + +[[package]] +name = "langgraph" +version = "1.0.8" +source = { editable = "../langgraph" } +dependencies = [ + { name = "langchain-core" }, + { name = "langgraph-checkpoint" }, + { name = "langgraph-prebuilt" }, + { name = "langgraph-sdk" }, + { name = "pydantic" }, + { name = "xxhash" }, +] + +[package.metadata] +requires-dist = [ + { name = "langchain-core", specifier = ">=0.1" }, + { name = "langgraph-checkpoint", editable = "../checkpoint" }, + { name = "langgraph-prebuilt", editable = "../prebuilt" }, + { name = "langgraph-sdk", editable = "." }, + { name = "pydantic", specifier = ">=2.7.4" }, + { name = "xxhash", specifier = ">=3.5.0" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "httpx" }, + { name = "jupyter" }, + { name = "langchain-core", specifier = ">=1.0.0" }, + { name = "langgraph-checkpoint", editable = "../checkpoint" }, + { name = "langgraph-checkpoint-postgres", editable = "../checkpoint-postgres" }, + { name = "langgraph-checkpoint-sqlite", editable = "../checkpoint-sqlite" }, + { name = "langgraph-cli", marker = "python_full_version < '3.14'", editable = "../cli" }, + { name = "langgraph-cli", extras = ["inmem"], marker = "python_full_version < '3.14'", editable = "../cli" }, + { name = "langgraph-prebuilt", editable = "../prebuilt" }, + { name = "langgraph-sdk", editable = "." }, + { name = "mypy" }, + { name = "psycopg", extras = ["binary"] }, + { name = "py-spy" }, + { name = "pycryptodome" }, + { name = "pyperf" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "pytest-dotenv" }, + { name = "pytest-mock" }, + { name = "pytest-repeat" }, + { name = "pytest-watcher" }, + { name = "pytest-xdist", extras = ["psutil"] }, + { name = "redis" }, + { name = "ruff" }, + { name = "syrupy" }, + { name = "types-requests" }, + { name = "uvloop", specifier = "==0.21.0b1" }, +] +lint = [ + { name = "mypy" }, + { name = "ruff" }, + { name = "types-requests" }, +] +test = [ + { name = "httpx" }, + { name = "langchain-core", specifier = ">=1.0.0" }, + { name = "langgraph-checkpoint", editable = "../checkpoint" }, + { name = "langgraph-checkpoint-postgres", editable = "../checkpoint-postgres" }, + { name = "langgraph-checkpoint-sqlite", editable = "../checkpoint-sqlite" }, + { name = "langgraph-cli", marker = "python_full_version < '3.14'", editable = "../cli" }, + { name = "langgraph-cli", extras = ["inmem"], marker = "python_full_version < '3.14'", editable = "../cli" }, + { name = "langgraph-prebuilt", editable = "../prebuilt" }, + { name = "langgraph-sdk", editable = "." }, + { name = "psycopg", extras = ["binary"] }, + { name = "py-spy" }, + { name = "pycryptodome" }, + { name = "pyperf" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "pytest-dotenv" }, + { name = "pytest-mock" }, + { name = "pytest-repeat" }, + { name = "pytest-watcher" }, + { name = "pytest-xdist", extras = ["psutil"] }, + { name = "redis" }, + { name = "syrupy" }, + { name = "uvloop", specifier = "==0.21.0b1" }, +] + +[[package]] +name = "langgraph-checkpoint" +version = "4.0.0" +source = { editable = "../checkpoint" } +dependencies = [ + { name = "langchain-core" }, + { name = "ormsgpack" }, +] + +[package.metadata] +requires-dist = [ + { name = "langchain-core", specifier = ">=0.2.38" }, + { name = "ormsgpack", specifier = ">=1.12.0" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "codespell" }, + { name = "dataclasses-json" }, + { name = "mypy" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "pandas-stubs", specifier = ">=2.2.2.240807" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-mock" }, + { name = "pytest-watcher" }, + { name = "redis" }, + { name = "ruff" }, +] +lint = [ + { name = "codespell" }, + { name = "mypy" }, + { name = "ruff" }, +] +test = [ + { name = "dataclasses-json" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "pandas-stubs", specifier = ">=2.2.2.240807" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-mock" }, + { name = "pytest-watcher" }, + { name = "redis" }, +] + +[[package]] +name = "langgraph-prebuilt" +version = "1.0.7" +source = { editable = "../prebuilt" } +dependencies = [ + { name = "langchain-core" }, + { name = "langgraph-checkpoint" }, +] + +[package.metadata] +requires-dist = [ + { name = "langchain-core", specifier = ">=1.0.0" }, + { name = "langgraph-checkpoint", editable = "../checkpoint" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "codespell" }, + { name = "langchain-core" }, + { name = "langgraph", editable = "../langgraph" }, + { name = "langgraph-checkpoint", editable = "../checkpoint" }, + { name = "langgraph-checkpoint-postgres", editable = "../checkpoint-postgres" }, + { name = "langgraph-checkpoint-sqlite", editable = "../checkpoint-sqlite" }, + { name = "mypy" }, + { name = "psycopg-binary" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-mock" }, + { name = "pytest-watcher" }, + { name = "ruff" }, + { name = "syrupy" }, +] +lint = [ + { name = "codespell" }, + { name = "mypy" }, + { name = "ruff" }, +] +test = [ + { name = "langchain-core" }, + { name = "langgraph", editable = "../langgraph" }, + { name = "langgraph-checkpoint", editable = "../checkpoint" }, + { name = "langgraph-checkpoint-postgres", editable = "../checkpoint-postgres" }, + { name = "langgraph-checkpoint-sqlite", editable = "../checkpoint-sqlite" }, + { name = "psycopg-binary" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-mock" }, + { name = "pytest-watcher" }, + { name = "syrupy" }, +] + [[package]] name = "langgraph-sdk" source = { editable = "." } @@ -145,6 +456,7 @@ dependencies = [ [package.dev-dependencies] dev = [ { name = "codespell" }, + { name = "langgraph" }, { name = "mypy" }, { name = "pydantic" }, { name = "pytest" }, @@ -178,6 +490,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ { name = "codespell" }, + { name = "langgraph", editable = "../langgraph" }, { name = "mypy", specifier = "==1.19.0" }, { name = "pydantic", specifier = ">=2.12.4" }, { name = "pytest" }, @@ -202,6 +515,26 @@ test = [ { name = "pytest-watch" }, ] +[[package]] +name = "langsmith" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, + { name = "packaging" }, + { name = "pydantic" }, + { name = "requests" }, + { name = "requests-toolbelt" }, + { name = "uuid-utils" }, + { name = "xxhash" }, + { name = "zstandard" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/67/48/3151de6df96e0977b8d319b03905e29db0df6929a85df1d922a030b7e68d/langsmith-0.7.1.tar.gz", hash = "sha256:e3fec2f97f7c5192f192f4873d6a076b8c6469768022323dded07087d8cb70a4", size = 984367, upload-time = "2026-02-10T01:55:24.696Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/87/6f2b008a456b4f5fd0fb1509bb7e1e9368c1a0c9641a535f224a9ddc10f3/langsmith-0.7.1-py3-none-any.whl", hash = "sha256:92cfa54253d35417184c297ad25bfd921d95f15d60a1ca75f14d4e7acd152a29", size = 322515, upload-time = "2026-02-10T01:55:22.531Z" }, +] + [[package]] name = "librt" version = "0.7.8" @@ -411,6 +744,62 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8f/dd/f4fff4a6fe601b4f8f3ba3aa6da8ac33d17d124491a3b804c662a70e1636/orjson-3.11.5-cp314-cp314-win_arm64.whl", hash = "sha256:38b22f476c351f9a1c43e5b07d8b5a02eb24a6ab8e75f700f7d479d4568346a5", size = 126713, upload-time = "2025-12-06T15:55:19.738Z" }, ] +[[package]] +name = "ormsgpack" +version = "1.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/12/0c/f1761e21486942ab9bb6feaebc610fa074f7c5e496e6962dea5873348077/ormsgpack-1.12.2.tar.gz", hash = "sha256:944a2233640273bee67521795a73cf1e959538e0dfb7ac635505010455e53b33", size = 39031, upload-time = "2026-01-18T20:55:28.023Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/fa/a91f70829ebccf6387c4946e0a1a109f6ba0d6a28d65f628bedfad94b890/ormsgpack-1.12.2-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:c1429217f8f4d7fcb053523bbbac6bed5e981af0b85ba616e6df7cce53c19657", size = 378262, upload-time = "2026-01-18T20:55:22.284Z" }, + { url = "https://files.pythonhosted.org/packages/5f/62/3698a9a0c487252b5c6a91926e5654e79e665708ea61f67a8bdeceb022bf/ormsgpack-1.12.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f13034dc6c84a6280c6c33db7ac420253852ea233fc3ee27c8875f8dd651163", size = 203034, upload-time = "2026-01-18T20:55:53.324Z" }, + { url = "https://files.pythonhosted.org/packages/66/3a/f716f64edc4aec2744e817660b317e2f9bb8de372338a95a96198efa1ac1/ormsgpack-1.12.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:59f5da97000c12bc2d50e988bdc8576b21f6ab4e608489879d35b2c07a8ab51a", size = 210538, upload-time = "2026-01-18T20:55:20.097Z" }, + { url = "https://files.pythonhosted.org/packages/72/30/a436be9ce27d693d4e19fa94900028067133779f09fc45776db3f689c822/ormsgpack-1.12.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e4459c3f27066beadb2b81ea48a076a417aafffff7df1d3c11c519190ed44f2", size = 212401, upload-time = "2026-01-18T20:55:46.447Z" }, + { url = "https://files.pythonhosted.org/packages/10/c5/cde98300fd33fee84ca71de4751b19aeeca675f0cf3c0ec4b043f40f3b76/ormsgpack-1.12.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a1c460655d7288407ffa09065e322a7231997c0d62ce914bf3a96ad2dc6dedd", size = 387080, upload-time = "2026-01-18T20:56:00.884Z" }, + { url = "https://files.pythonhosted.org/packages/6a/31/30bf445ef827546747c10889dd254b3d84f92b591300efe4979d792f4c41/ormsgpack-1.12.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:458e4568be13d311ef7d8877275e7ccbe06c0e01b39baaac874caaa0f46d826c", size = 482346, upload-time = "2026-01-18T20:55:39.831Z" }, + { url = "https://files.pythonhosted.org/packages/2e/f5/e1745ddf4fa246c921b5ca253636c4c700ff768d78032f79171289159f6e/ormsgpack-1.12.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8cde5eaa6c6cbc8622db71e4a23de56828e3d876aeb6460ffbcb5b8aff91093b", size = 425178, upload-time = "2026-01-18T20:55:27.106Z" }, + { url = "https://files.pythonhosted.org/packages/8d/a2/e6532ed7716aed03dede8df2d0d0d4150710c2122647d94b474147ccd891/ormsgpack-1.12.2-cp310-cp310-win_amd64.whl", hash = "sha256:dc7a33be14c347893edbb1ceda89afbf14c467d593a5ee92c11de4f1666b4d4f", size = 117183, upload-time = "2026-01-18T20:55:55.52Z" }, + { url = "https://files.pythonhosted.org/packages/4b/08/8b68f24b18e69d92238aa8f258218e6dfeacf4381d9d07ab8df303f524a9/ormsgpack-1.12.2-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:bd5f4bf04c37888e864f08e740c5a573c4017f6fd6e99fa944c5c935fabf2dd9", size = 378266, upload-time = "2026-01-18T20:55:59.876Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/29fc13044ecb7c153523ae0a1972269fcd613650d1fa1a9cec1044c6b666/ormsgpack-1.12.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34d5b28b3570e9fed9a5a76528fc7230c3c76333bc214798958e58e9b79cc18a", size = 203035, upload-time = "2026-01-18T20:55:30.59Z" }, + { url = "https://files.pythonhosted.org/packages/ad/c2/00169fb25dd8f9213f5e8a549dfb73e4d592009ebc85fbbcd3e1dcac575b/ormsgpack-1.12.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3708693412c28f3538fb5a65da93787b6bbab3484f6bc6e935bfb77a62400ae5", size = 210539, upload-time = "2026-01-18T20:55:48.569Z" }, + { url = "https://files.pythonhosted.org/packages/1b/33/543627f323ff3c73091f51d6a20db28a1a33531af30873ea90c5ac95a9b5/ormsgpack-1.12.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43013a3f3e2e902e1d05e72c0f1aeb5bedbb8e09240b51e26792a3c89267e181", size = 212401, upload-time = "2026-01-18T20:56:10.101Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5d/f70e2c3da414f46186659d24745483757bcc9adccb481a6eb93e2b729301/ormsgpack-1.12.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7c8b1667a72cbba74f0ae7ecf3105a5e01304620ed14528b2cb4320679d2869b", size = 387082, upload-time = "2026-01-18T20:56:12.047Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d6/06e8dc920c7903e051f30934d874d4afccc9bb1c09dcaf0bc03a7de4b343/ormsgpack-1.12.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:df6961442140193e517303d0b5d7bc2e20e69a879c2d774316125350c4a76b92", size = 482346, upload-time = "2026-01-18T20:56:05.152Z" }, + { url = "https://files.pythonhosted.org/packages/66/c4/f337ac0905eed9c393ef990c54565cd33644918e0a8031fe48c098c71dbf/ormsgpack-1.12.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c6a4c34ddef109647c769d69be65fa1de7a6022b02ad45546a69b3216573eb4a", size = 425181, upload-time = "2026-01-18T20:55:37.83Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/6d5758fabef3babdf4bbbc453738cc7de9cd3334e4c38dd5737e27b85653/ormsgpack-1.12.2-cp311-cp311-win_amd64.whl", hash = "sha256:73670ed0375ecc303858e3613f407628dd1fca18fe6ac57b7b7ce66cc7bb006c", size = 117182, upload-time = "2026-01-18T20:55:31.472Z" }, + { url = "https://files.pythonhosted.org/packages/c4/57/17a15549233c37e7fd054c48fe9207492e06b026dbd872b826a0b5f833b6/ormsgpack-1.12.2-cp311-cp311-win_arm64.whl", hash = "sha256:c2be829954434e33601ae5da328cccce3266b098927ca7a30246a0baec2ce7bd", size = 111464, upload-time = "2026-01-18T20:55:38.811Z" }, + { url = "https://files.pythonhosted.org/packages/4c/36/16c4b1921c308a92cef3bf6663226ae283395aa0ff6e154f925c32e91ff5/ormsgpack-1.12.2-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7a29d09b64b9694b588ff2f80e9826bdceb3a2b91523c5beae1fab27d5c940e7", size = 378618, upload-time = "2026-01-18T20:55:50.835Z" }, + { url = "https://files.pythonhosted.org/packages/c0/68/468de634079615abf66ed13bb5c34ff71da237213f29294363beeeca5306/ormsgpack-1.12.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b39e629fd2e1c5b2f46f99778450b59454d1f901bc507963168985e79f09c5d", size = 203186, upload-time = "2026-01-18T20:56:11.163Z" }, + { url = "https://files.pythonhosted.org/packages/73/a9/d756e01961442688b7939bacd87ce13bfad7d26ce24f910f6028178b2cc8/ormsgpack-1.12.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:958dcb270d30a7cb633a45ee62b9444433fa571a752d2ca484efdac07480876e", size = 210738, upload-time = "2026-01-18T20:56:09.181Z" }, + { url = "https://files.pythonhosted.org/packages/7b/ba/795b1036888542c9113269a3f5690ab53dd2258c6fb17676ac4bd44fcf94/ormsgpack-1.12.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d379d72b6c5e964851c77cfedfb386e474adee4fd39791c2c5d9efb53505cc", size = 212569, upload-time = "2026-01-18T20:56:06.135Z" }, + { url = "https://files.pythonhosted.org/packages/6c/aa/bff73c57497b9e0cba8837c7e4bcab584b1a6dbc91a5dd5526784a5030c8/ormsgpack-1.12.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8463a3fc5f09832e67bdb0e2fda6d518dc4281b133166146a67f54c08496442e", size = 387166, upload-time = "2026-01-18T20:55:36.738Z" }, + { url = "https://files.pythonhosted.org/packages/d3/cf/f8283cba44bcb7b14f97b6274d449db276b3a86589bdb363169b51bc12de/ormsgpack-1.12.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:eddffb77eff0bad4e67547d67a130604e7e2dfbb7b0cde0796045be4090f35c6", size = 482498, upload-time = "2026-01-18T20:55:29.626Z" }, + { url = "https://files.pythonhosted.org/packages/05/be/71e37b852d723dfcbe952ad04178c030df60d6b78eba26bfd14c9a40575e/ormsgpack-1.12.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fcd55e5f6ba0dbce624942adf9f152062135f991a0126064889f68eb850de0dd", size = 425518, upload-time = "2026-01-18T20:55:49.556Z" }, + { url = "https://files.pythonhosted.org/packages/7a/0c/9803aa883d18c7ef197213cd2cbf73ba76472a11fe100fb7dab2884edf48/ormsgpack-1.12.2-cp312-cp312-win_amd64.whl", hash = "sha256:d024b40828f1dde5654faebd0d824f9cc29ad46891f626272dd5bfd7af2333a4", size = 117462, upload-time = "2026-01-18T20:55:47.726Z" }, + { url = "https://files.pythonhosted.org/packages/c8/9e/029e898298b2cc662f10d7a15652a53e3b525b1e7f07e21fef8536a09bb8/ormsgpack-1.12.2-cp312-cp312-win_arm64.whl", hash = "sha256:da538c542bac7d1c8f3f2a937863dba36f013108ce63e55745941dda4b75dbb6", size = 111559, upload-time = "2026-01-18T20:55:54.273Z" }, + { url = "https://files.pythonhosted.org/packages/eb/29/bb0eba3288c0449efbb013e9c6f58aea79cf5cb9ee1921f8865f04c1a9d7/ormsgpack-1.12.2-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5ea60cb5f210b1cfbad8c002948d73447508e629ec375acb82910e3efa8ff355", size = 378661, upload-time = "2026-01-18T20:55:57.765Z" }, + { url = "https://files.pythonhosted.org/packages/6e/31/5efa31346affdac489acade2926989e019e8ca98129658a183e3add7af5e/ormsgpack-1.12.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3601f19afdbea273ed70b06495e5794606a8b690a568d6c996a90d7255e51c1", size = 203194, upload-time = "2026-01-18T20:56:08.252Z" }, + { url = "https://files.pythonhosted.org/packages/eb/56/d0087278beef833187e0167f8527235ebe6f6ffc2a143e9de12a98b1ce87/ormsgpack-1.12.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:29a9f17a3dac6054c0dce7925e0f4995c727f7c41859adf9b5572180f640d172", size = 210778, upload-time = "2026-01-18T20:55:17.694Z" }, + { url = "https://files.pythonhosted.org/packages/1c/a2/072343e1413d9443e5a252a8eb591c2d5b1bffbe5e7bfc78c069361b92eb/ormsgpack-1.12.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39c1bd2092880e413902910388be8715f70b9f15f20779d44e673033a6146f2d", size = 212592, upload-time = "2026-01-18T20:55:32.747Z" }, + { url = "https://files.pythonhosted.org/packages/a2/8b/a0da3b98a91d41187a63b02dda14267eefc2a74fcb43cc2701066cf1510e/ormsgpack-1.12.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:50b7249244382209877deedeee838aef1542f3d0fc28b8fe71ca9d7e1896a0d7", size = 387164, upload-time = "2026-01-18T20:55:40.853Z" }, + { url = "https://files.pythonhosted.org/packages/19/bb/6d226bc4cf9fc20d8eb1d976d027a3f7c3491e8f08289a2e76abe96a65f3/ormsgpack-1.12.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:5af04800d844451cf102a59c74a841324868d3f1625c296a06cc655c542a6685", size = 482516, upload-time = "2026-01-18T20:55:42.033Z" }, + { url = "https://files.pythonhosted.org/packages/fb/f1/bb2c7223398543dedb3dbf8bb93aaa737b387de61c5feaad6f908841b782/ormsgpack-1.12.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cec70477d4371cd524534cd16472d8b9cc187e0e3043a8790545a9a9b296c258", size = 425539, upload-time = "2026-01-18T20:55:24.727Z" }, + { url = "https://files.pythonhosted.org/packages/7b/e8/0fb45f57a2ada1fed374f7494c8cd55e2f88ccd0ab0a669aa3468716bf5f/ormsgpack-1.12.2-cp313-cp313-win_amd64.whl", hash = "sha256:21f4276caca5c03a818041d637e4019bc84f9d6ca8baa5ea03e5cc8bf56140e9", size = 117459, upload-time = "2026-01-18T20:55:56.876Z" }, + { url = "https://files.pythonhosted.org/packages/7a/d4/0cfeea1e960d550a131001a7f38a5132c7ae3ebde4c82af1f364ccc5d904/ormsgpack-1.12.2-cp313-cp313-win_arm64.whl", hash = "sha256:baca4b6773d20a82e36d6fd25f341064244f9f86a13dead95dd7d7f996f51709", size = 111577, upload-time = "2026-01-18T20:55:43.605Z" }, + { url = "https://files.pythonhosted.org/packages/94/16/24d18851334be09c25e87f74307c84950f18c324a4d3c0b41dabdbf19c29/ormsgpack-1.12.2-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:bc68dd5915f4acf66ff2010ee47c8906dc1cf07399b16f4089f8c71733f6e36c", size = 378717, upload-time = "2026-01-18T20:55:26.164Z" }, + { url = "https://files.pythonhosted.org/packages/b5/a2/88b9b56f83adae8032ac6a6fa7f080c65b3baf9b6b64fd3d37bd202991d4/ormsgpack-1.12.2-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46d084427b4132553940070ad95107266656cb646ea9da4975f85cb1a6676553", size = 203183, upload-time = "2026-01-18T20:55:18.815Z" }, + { url = "https://files.pythonhosted.org/packages/a9/80/43e4555963bf602e5bdc79cbc8debd8b6d5456c00d2504df9775e74b450b/ormsgpack-1.12.2-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c010da16235806cf1d7bc4c96bf286bfa91c686853395a299b3ddb49499a3e13", size = 210814, upload-time = "2026-01-18T20:55:33.973Z" }, + { url = "https://files.pythonhosted.org/packages/78/e1/7cfbf28de8bca6efe7e525b329c31277d1b64ce08dcba723971c241a9d60/ormsgpack-1.12.2-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18867233df592c997154ff942a6503df274b5ac1765215bceba7a231bea2745d", size = 212634, upload-time = "2026-01-18T20:55:28.634Z" }, + { url = "https://files.pythonhosted.org/packages/95/f8/30ae5716e88d792a4e879debee195653c26ddd3964c968594ddef0a3cc7e/ormsgpack-1.12.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b009049086ddc6b8f80c76b3955df1aa22a5fbd7673c525cd63bf91f23122ede", size = 387139, upload-time = "2026-01-18T20:56:02.013Z" }, + { url = "https://files.pythonhosted.org/packages/dc/81/aee5b18a3e3a0e52f718b37ab4b8af6fae0d9d6a65103036a90c2a8ffb5d/ormsgpack-1.12.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:1dcc17d92b6390d4f18f937cf0b99054824a7815818012ddca925d6e01c2e49e", size = 482578, upload-time = "2026-01-18T20:55:35.117Z" }, + { url = "https://files.pythonhosted.org/packages/bd/17/71c9ba472d5d45f7546317f467a5fc941929cd68fb32796ca3d13dcbaec2/ormsgpack-1.12.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f04b5e896d510b07c0ad733d7fce2d44b260c5e6c402d272128f8941984e4285", size = 425539, upload-time = "2026-01-18T20:56:04.009Z" }, + { url = "https://files.pythonhosted.org/packages/2e/a6/ac99cd7fe77e822fed5250ff4b86fa66dd4238937dd178d2299f10b69816/ormsgpack-1.12.2-cp314-cp314-win_amd64.whl", hash = "sha256:ae3aba7eed4ca7cb79fd3436eddd29140f17ea254b91604aa1eb19bfcedb990f", size = 117493, upload-time = "2026-01-18T20:56:07.343Z" }, + { url = "https://files.pythonhosted.org/packages/3a/67/339872846a1ae4592535385a1c1f93614138566d7af094200c9c3b45d1e5/ormsgpack-1.12.2-cp314-cp314-win_arm64.whl", hash = "sha256:118576ea6006893aea811b17429bfc561b4778fad393f5f538c84af70b01260c", size = 111579, upload-time = "2026-01-18T20:55:21.161Z" }, + { url = "https://files.pythonhosted.org/packages/49/c2/6feb972dc87285ad381749d3882d8aecbde9f6ecf908dd717d33d66df095/ormsgpack-1.12.2-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7121b3d355d3858781dc40dafe25a32ff8a8242b9d80c692fd548a4b1f7fd3c8", size = 378721, upload-time = "2026-01-18T20:55:52.12Z" }, + { url = "https://files.pythonhosted.org/packages/a3/9a/900a6b9b413e0f8a471cf07830f9cf65939af039a362204b36bd5b581d8b/ormsgpack-1.12.2-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ee766d2e78251b7a63daf1cddfac36a73562d3ddef68cacfb41b2af64698033", size = 203170, upload-time = "2026-01-18T20:55:44.469Z" }, + { url = "https://files.pythonhosted.org/packages/87/4c/27a95466354606b256f24fad464d7c97ab62bce6cc529dd4673e1179b8fb/ormsgpack-1.12.2-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:292410a7d23de9b40444636b9b8f1e4e4b814af7f1ef476e44887e52a123f09d", size = 212816, upload-time = "2026-01-18T20:55:23.501Z" }, + { url = "https://files.pythonhosted.org/packages/73/cd/29cee6007bddf7a834e6cd6f536754c0535fcb939d384f0f37a38b1cddb8/ormsgpack-1.12.2-cp314-cp314t-win_amd64.whl", hash = "sha256:837dd316584485b72ef451d08dd3e96c4a11d12e4963aedb40e08f89685d8ec2", size = 117232, upload-time = "2026-01-18T20:55:45.448Z" }, +] + [[package]] name = "packaging" version = "25.0" @@ -636,6 +1025,97 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/36/47/ab65fc1d682befc318c439940f81a0de1026048479f732e84fe714cd69c0/pytest-watch-4.2.0.tar.gz", hash = "sha256:06136f03d5b361718b8d0d234042f7b2f203910d8568f63df2f866b547b3d4b9", size = 16340, upload-time = "2018-05-20T19:52:16.194Z" } +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" }, +] + [[package]] name = "ruff" version = "0.14.11" @@ -675,6 +1155,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272, upload-time = "2026-01-18T13:34:09.188Z" }, ] +[[package]] +name = "tenacity" +version = "9.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/c6/ee486fd809e357697ee8a44d3d69222b344920433d3b6666ccd9b374630c/tenacity-9.1.4.tar.gz", hash = "sha256:adb31d4c263f2bd041081ab33b498309a57c77f9acf2db65aadf0898179cf93a", size = 49413, upload-time = "2026-02-07T10:45:33.841Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926, upload-time = "2026-02-07T10:45:32.24Z" }, +] + [[package]] name = "tomli" version = "2.4.0" @@ -775,6 +1264,44 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, ] +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, +] + +[[package]] +name = "uuid-utils" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/7c/3a926e847516e67bc6838634f2e54e24381105b4e80f9338dc35cca0086b/uuid_utils-0.14.0.tar.gz", hash = "sha256:fc5bac21e9933ea6c590433c11aa54aaca599f690c08069e364eb13a12f670b4", size = 22072, upload-time = "2026-01-20T20:37:15.729Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/42/42d003f4a99ddc901eef2fd41acb3694163835e037fb6dde79ad68a72342/uuid_utils-0.14.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:f6695c0bed8b18a904321e115afe73b34444bc8451d0ce3244a1ec3b84deb0e5", size = 601786, upload-time = "2026-01-20T20:37:09.843Z" }, + { url = "https://files.pythonhosted.org/packages/96/e6/775dfb91f74b18f7207e3201eb31ee666d286579990dc69dd50db2d92813/uuid_utils-0.14.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:4f0a730bbf2d8bb2c11b93e1005e91769f2f533fa1125ed1f00fd15b6fcc732b", size = 303943, upload-time = "2026-01-20T20:37:18.767Z" }, + { url = "https://files.pythonhosted.org/packages/17/82/ea5f5e85560b08a1f30cdc65f75e76494dc7aba9773f679e7eaa27370229/uuid_utils-0.14.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40ce3fd1a4fdedae618fc3edc8faf91897012469169d600133470f49fd699ed3", size = 340467, upload-time = "2026-01-20T20:37:11.794Z" }, + { url = "https://files.pythonhosted.org/packages/ca/33/54b06415767f4569882e99b6470c6c8eeb97422686a6d432464f9967fd91/uuid_utils-0.14.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:09ae4a98416a440e78f7d9543d11b11cae4bab538b7ed94ec5da5221481748f2", size = 346333, upload-time = "2026-01-20T20:37:12.818Z" }, + { url = "https://files.pythonhosted.org/packages/cb/10/a6bce636b8f95e65dc84bf4a58ce8205b8e0a2a300a38cdbc83a3f763d27/uuid_utils-0.14.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:971e8c26b90d8ae727e7f2ac3ee23e265971d448b3672882f2eb44828b2b8c3e", size = 470859, upload-time = "2026-01-20T20:37:01.512Z" }, + { url = "https://files.pythonhosted.org/packages/8a/27/84121c51ea72f013f0e03d0886bcdfa96b31c9b83c98300a7bd5cc4fa191/uuid_utils-0.14.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5cde1fa82804a8f9d2907b7aec2009d440062c63f04abbdb825fce717a5e860", size = 341988, upload-time = "2026-01-20T20:37:22.881Z" }, + { url = "https://files.pythonhosted.org/packages/90/a4/01c1c7af5e6a44f20b40183e8dac37d6ed83e7dc9e8df85370a15959b804/uuid_utils-0.14.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c7343862a2359e0bd48a7f3dfb5105877a1728677818bb694d9f40703264a2db", size = 365784, upload-time = "2026-01-20T20:37:10.808Z" }, + { url = "https://files.pythonhosted.org/packages/04/f0/65ee43ec617b8b6b1bf2a5aecd56a069a08cca3d9340c1de86024331bde3/uuid_utils-0.14.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c51e4818fdb08ccec12dc7083a01f49507b4608770a0ab22368001685d59381b", size = 523750, upload-time = "2026-01-20T20:37:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/95/d3/6bf503e3f135a5dfe705a65e6f89f19bccd55ac3fb16cb5d3ec5ba5388b8/uuid_utils-0.14.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:181bbcccb6f93d80a8504b5bd47b311a1c31395139596edbc47b154b0685b533", size = 615818, upload-time = "2026-01-20T20:37:21.816Z" }, + { url = "https://files.pythonhosted.org/packages/df/6c/99937dd78d07f73bba831c8dc9469dfe4696539eba2fc269ae1b92752f9e/uuid_utils-0.14.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:5c8ae96101c3524ba8dbf762b6f05e9e9d896544786c503a727c5bf5cb9af1a7", size = 580831, upload-time = "2026-01-20T20:37:19.691Z" }, + { url = "https://files.pythonhosted.org/packages/44/fa/bbc9e2c25abd09a293b9b097a0d8fc16acd6a92854f0ec080f1ea7ad8bb3/uuid_utils-0.14.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:00ac3c6edfdaff7e1eed041f4800ae09a3361287be780d7610a90fdcde9befdc", size = 546333, upload-time = "2026-01-20T20:37:03.117Z" }, + { url = "https://files.pythonhosted.org/packages/e7/9b/e5e99b324b1b5f0c62882230455786df0bc66f67eff3b452447e703f45d2/uuid_utils-0.14.0-cp39-abi3-win32.whl", hash = "sha256:ec2fd80adf8e0e6589d40699e6f6df94c93edcc16dd999be0438dd007c77b151", size = 177319, upload-time = "2026-01-20T20:37:04.208Z" }, + { url = "https://files.pythonhosted.org/packages/d3/28/2c7d417ea483b6ff7820c948678fdf2ac98899dc7e43bb15852faa95acaf/uuid_utils-0.14.0-cp39-abi3-win_amd64.whl", hash = "sha256:efe881eb43a5504fad922644cb93d725fd8a6a6d949bd5a4b4b7d1a1587c7fd1", size = 182566, upload-time = "2026-01-20T20:37:16.868Z" }, + { url = "https://files.pythonhosted.org/packages/b8/86/49e4bdda28e962fbd7266684171ee29b3d92019116971d58783e51770745/uuid_utils-0.14.0-cp39-abi3-win_arm64.whl", hash = "sha256:32b372b8fd4ebd44d3a219e093fe981af4afdeda2994ee7db208ab065cfcd080", size = 182809, upload-time = "2026-01-20T20:37:05.139Z" }, + { url = "https://files.pythonhosted.org/packages/f1/03/1f1146e32e94d1f260dfabc81e1649102083303fb4ad549775c943425d9a/uuid_utils-0.14.0-pp311-pypy311_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:762e8d67992ac4d2454e24a141a1c82142b5bde10409818c62adbe9924ebc86d", size = 587430, upload-time = "2026-01-20T20:37:24.998Z" }, + { url = "https://files.pythonhosted.org/packages/87/ba/d5a7469362594d885fd9219fe9e851efbe65101d3ef1ef25ea321d7ce841/uuid_utils-0.14.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:40be5bf0b13aa849d9062abc86c198be6a25ff35316ce0b89fc25f3bac6d525e", size = 298106, upload-time = "2026-01-20T20:37:23.896Z" }, + { url = "https://files.pythonhosted.org/packages/8a/11/3dafb2a5502586f59fd49e93f5802cd5face82921b3a0f3abb5f357cb879/uuid_utils-0.14.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:191a90a6f3940d1b7322b6e6cceff4dd533c943659e0a15f788674407856a515", size = 333423, upload-time = "2026-01-20T20:37:17.828Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f2/c8987663f0cdcf4d717a36d85b5db2a5589df0a4e129aa10f16f4380ef48/uuid_utils-0.14.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4aa4525f4ad82f9d9c842f9a3703f1539c1808affbaec07bb1b842f6b8b96aa5", size = 338659, upload-time = "2026-01-20T20:37:14.286Z" }, + { url = "https://files.pythonhosted.org/packages/d1/c8/929d81665d83f0b2ffaecb8e66c3091a50f62c7cb5b65e678bd75a96684e/uuid_utils-0.14.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdbd82ff20147461caefc375551595ecf77ebb384e46267f128aca45a0f2cdfc", size = 467029, upload-time = "2026-01-20T20:37:08.277Z" }, + { url = "https://files.pythonhosted.org/packages/8e/a0/27d7daa1bfed7163f4ccaf52d7d2f4ad7bb1002a85b45077938b91ee584f/uuid_utils-0.14.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eff57e8a5d540006ce73cf0841a643d445afe78ba12e75ac53a95ca2924a56be", size = 333298, upload-time = "2026-01-20T20:37:07.271Z" }, + { url = "https://files.pythonhosted.org/packages/63/d4/acad86ce012b42ce18a12f31ee2aa3cbeeb98664f865f05f68c882945913/uuid_utils-0.14.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3fd9112ca96978361201e669729784f26c71fecc9c13a7f8a07162c31bd4d1e2", size = 359217, upload-time = "2026-01-20T20:36:59.687Z" }, +] + [[package]] name = "watchdog" version = "6.0.0" @@ -806,3 +1333,211 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, ] + +[[package]] +name = "xxhash" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845, upload-time = "2025-10-02T14:33:51.573Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807, upload-time = "2025-10-02T14:33:52.964Z" }, + { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786, upload-time = "2025-10-02T14:33:54.272Z" }, + { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830, upload-time = "2025-10-02T14:33:55.706Z" }, + { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606, upload-time = "2025-10-02T14:33:57.133Z" }, + { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872, upload-time = "2025-10-02T14:33:58.446Z" }, + { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217, upload-time = "2025-10-02T14:33:59.724Z" }, + { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139, upload-time = "2025-10-02T14:34:02.041Z" }, + { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669, upload-time = "2025-10-02T14:34:03.664Z" }, + { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018, upload-time = "2025-10-02T14:34:05.325Z" }, + { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058, upload-time = "2025-10-02T14:34:06.925Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628, upload-time = "2025-10-02T14:34:08.669Z" }, + { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577, upload-time = "2025-10-02T14:34:10.234Z" }, + { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487, upload-time = "2025-10-02T14:34:11.618Z" }, + { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863, upload-time = "2025-10-02T14:34:12.619Z" }, + { url = "https://files.pythonhosted.org/packages/17/d4/cc2f0400e9154df4b9964249da78ebd72f318e35ccc425e9f403c392f22a/xxhash-3.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b47bbd8cf2d72797f3c2772eaaac0ded3d3af26481a26d7d7d41dc2d3c46b04a", size = 32844, upload-time = "2025-10-02T14:34:14.037Z" }, + { url = "https://files.pythonhosted.org/packages/5e/ec/1cc11cd13e26ea8bc3cb4af4eaadd8d46d5014aebb67be3f71fb0b68802a/xxhash-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2b6821e94346f96db75abaa6e255706fb06ebd530899ed76d32cd99f20dc52fa", size = 30809, upload-time = "2025-10-02T14:34:15.484Z" }, + { url = "https://files.pythonhosted.org/packages/04/5f/19fe357ea348d98ca22f456f75a30ac0916b51c753e1f8b2e0e6fb884cce/xxhash-3.6.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d0a9751f71a1a65ce3584e9cae4467651c7e70c9d31017fa57574583a4540248", size = 194665, upload-time = "2025-10-02T14:34:16.541Z" }, + { url = "https://files.pythonhosted.org/packages/90/3b/d1f1a8f5442a5fd8beedae110c5af7604dc37349a8e16519c13c19a9a2de/xxhash-3.6.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b29ee68625ab37b04c0b40c3fafdf24d2f75ccd778333cfb698f65f6c463f62", size = 213550, upload-time = "2025-10-02T14:34:17.878Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ef/3a9b05eb527457d5db13a135a2ae1a26c80fecd624d20f3e8dcc4cb170f3/xxhash-3.6.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6812c25fe0d6c36a46ccb002f40f27ac903bf18af9f6dd8f9669cb4d176ab18f", size = 212384, upload-time = "2025-10-02T14:34:19.182Z" }, + { url = "https://files.pythonhosted.org/packages/0f/18/ccc194ee698c6c623acbf0f8c2969811a8a4b6185af5e824cd27b9e4fd3e/xxhash-3.6.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4ccbff013972390b51a18ef1255ef5ac125c92dc9143b2d1909f59abc765540e", size = 445749, upload-time = "2025-10-02T14:34:20.659Z" }, + { url = "https://files.pythonhosted.org/packages/a5/86/cf2c0321dc3940a7aa73076f4fd677a0fb3e405cb297ead7d864fd90847e/xxhash-3.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:297b7fbf86c82c550e12e8fb71968b3f033d27b874276ba3624ea868c11165a8", size = 193880, upload-time = "2025-10-02T14:34:22.431Z" }, + { url = "https://files.pythonhosted.org/packages/82/fb/96213c8560e6f948a1ecc9a7613f8032b19ee45f747f4fca4eb31bb6d6ed/xxhash-3.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dea26ae1eb293db089798d3973a5fc928a18fdd97cc8801226fae705b02b14b0", size = 210912, upload-time = "2025-10-02T14:34:23.937Z" }, + { url = "https://files.pythonhosted.org/packages/40/aa/4395e669b0606a096d6788f40dbdf2b819d6773aa290c19e6e83cbfc312f/xxhash-3.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7a0b169aafb98f4284f73635a8e93f0735f9cbde17bd5ec332480484241aaa77", size = 198654, upload-time = "2025-10-02T14:34:25.644Z" }, + { url = "https://files.pythonhosted.org/packages/67/74/b044fcd6b3d89e9b1b665924d85d3f400636c23590226feb1eb09e1176ce/xxhash-3.6.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:08d45aef063a4531b785cd72de4887766d01dc8f362a515693df349fdb825e0c", size = 210867, upload-time = "2025-10-02T14:34:27.203Z" }, + { url = "https://files.pythonhosted.org/packages/bc/fd/3ce73bf753b08cb19daee1eb14aa0d7fe331f8da9c02dd95316ddfe5275e/xxhash-3.6.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:929142361a48ee07f09121fe9e96a84950e8d4df3bb298ca5d88061969f34d7b", size = 414012, upload-time = "2025-10-02T14:34:28.409Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b3/5a4241309217c5c876f156b10778f3ab3af7ba7e3259e6d5f5c7d0129eb2/xxhash-3.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:51312c768403d8540487dbbfb557454cfc55589bbde6424456951f7fcd4facb3", size = 191409, upload-time = "2025-10-02T14:34:29.696Z" }, + { url = "https://files.pythonhosted.org/packages/c0/01/99bfbc15fb9abb9a72b088c1d95219fc4782b7d01fc835bd5744d66dd0b8/xxhash-3.6.0-cp311-cp311-win32.whl", hash = "sha256:d1927a69feddc24c987b337ce81ac15c4720955b667fe9b588e02254b80446fd", size = 30574, upload-time = "2025-10-02T14:34:31.028Z" }, + { url = "https://files.pythonhosted.org/packages/65/79/9d24d7f53819fe301b231044ea362ce64e86c74f6e8c8e51320de248b3e5/xxhash-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:26734cdc2d4ffe449b41d186bbeac416f704a482ed835d375a5c0cb02bc63fef", size = 31481, upload-time = "2025-10-02T14:34:32.062Z" }, + { url = "https://files.pythonhosted.org/packages/30/4e/15cd0e3e8772071344eab2961ce83f6e485111fed8beb491a3f1ce100270/xxhash-3.6.0-cp311-cp311-win_arm64.whl", hash = "sha256:d72f67ef8bf36e05f5b6c65e8524f265bd61071471cd4cf1d36743ebeeeb06b7", size = 27861, upload-time = "2025-10-02T14:34:33.555Z" }, + { url = "https://files.pythonhosted.org/packages/9a/07/d9412f3d7d462347e4511181dea65e47e0d0e16e26fbee2ea86a2aefb657/xxhash-3.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:01362c4331775398e7bb34e3ab403bc9ee9f7c497bc7dee6272114055277dd3c", size = 32744, upload-time = "2025-10-02T14:34:34.622Z" }, + { url = "https://files.pythonhosted.org/packages/79/35/0429ee11d035fc33abe32dca1b2b69e8c18d236547b9a9b72c1929189b9a/xxhash-3.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7b2df81a23f8cb99656378e72501b2cb41b1827c0f5a86f87d6b06b69f9f204", size = 30816, upload-time = "2025-10-02T14:34:36.043Z" }, + { url = "https://files.pythonhosted.org/packages/b7/f2/57eb99aa0f7d98624c0932c5b9a170e1806406cdbcdb510546634a1359e0/xxhash-3.6.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dc94790144e66b14f67b10ac8ed75b39ca47536bf8800eb7c24b50271ea0c490", size = 194035, upload-time = "2025-10-02T14:34:37.354Z" }, + { url = "https://files.pythonhosted.org/packages/4c/ed/6224ba353690d73af7a3f1c7cdb1fc1b002e38f783cb991ae338e1eb3d79/xxhash-3.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93f107c673bccf0d592cdba077dedaf52fe7f42dcd7676eba1f6d6f0c3efffd2", size = 212914, upload-time = "2025-10-02T14:34:38.6Z" }, + { url = "https://files.pythonhosted.org/packages/38/86/fb6b6130d8dd6b8942cc17ab4d90e223653a89aa32ad2776f8af7064ed13/xxhash-3.6.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aa5ee3444c25b69813663c9f8067dcfaa2e126dc55e8dddf40f4d1c25d7effa", size = 212163, upload-time = "2025-10-02T14:34:39.872Z" }, + { url = "https://files.pythonhosted.org/packages/ee/dc/e84875682b0593e884ad73b2d40767b5790d417bde603cceb6878901d647/xxhash-3.6.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7f99123f0e1194fa59cc69ad46dbae2e07becec5df50a0509a808f90a0f03f0", size = 445411, upload-time = "2025-10-02T14:34:41.569Z" }, + { url = "https://files.pythonhosted.org/packages/11/4f/426f91b96701ec2f37bb2b8cec664eff4f658a11f3fa9d94f0a887ea6d2b/xxhash-3.6.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49e03e6fe2cac4a1bc64952dd250cf0dbc5ef4ebb7b8d96bce82e2de163c82a2", size = 193883, upload-time = "2025-10-02T14:34:43.249Z" }, + { url = "https://files.pythonhosted.org/packages/53/5a/ddbb83eee8e28b778eacfc5a85c969673e4023cdeedcfcef61f36731610b/xxhash-3.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bd17fede52a17a4f9a7bc4472a5867cb0b160deeb431795c0e4abe158bc784e9", size = 210392, upload-time = "2025-10-02T14:34:45.042Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c2/ff69efd07c8c074ccdf0a4f36fcdd3d27363665bcdf4ba399abebe643465/xxhash-3.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6fb5f5476bef678f69db04f2bd1efbed3030d2aba305b0fc1773645f187d6a4e", size = 197898, upload-time = "2025-10-02T14:34:46.302Z" }, + { url = "https://files.pythonhosted.org/packages/58/ca/faa05ac19b3b622c7c9317ac3e23954187516298a091eb02c976d0d3dd45/xxhash-3.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:843b52f6d88071f87eba1631b684fcb4b2068cd2180a0224122fe4ef011a9374", size = 210655, upload-time = "2025-10-02T14:34:47.571Z" }, + { url = "https://files.pythonhosted.org/packages/d4/7a/06aa7482345480cc0cb597f5c875b11a82c3953f534394f620b0be2f700c/xxhash-3.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7d14a6cfaf03b1b6f5f9790f76880601ccc7896aff7ab9cd8978a939c1eb7e0d", size = 414001, upload-time = "2025-10-02T14:34:49.273Z" }, + { url = "https://files.pythonhosted.org/packages/23/07/63ffb386cd47029aa2916b3d2f454e6cc5b9f5c5ada3790377d5430084e7/xxhash-3.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:418daf3db71e1413cfe211c2f9a528456936645c17f46b5204705581a45390ae", size = 191431, upload-time = "2025-10-02T14:34:50.798Z" }, + { url = "https://files.pythonhosted.org/packages/0f/93/14fde614cadb4ddf5e7cebf8918b7e8fac5ae7861c1875964f17e678205c/xxhash-3.6.0-cp312-cp312-win32.whl", hash = "sha256:50fc255f39428a27299c20e280d6193d8b63b8ef8028995323bf834a026b4fbb", size = 30617, upload-time = "2025-10-02T14:34:51.954Z" }, + { url = "https://files.pythonhosted.org/packages/13/5d/0d125536cbe7565a83d06e43783389ecae0c0f2ed037b48ede185de477c0/xxhash-3.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:c0f2ab8c715630565ab8991b536ecded9416d615538be8ecddce43ccf26cbc7c", size = 31534, upload-time = "2025-10-02T14:34:53.276Z" }, + { url = "https://files.pythonhosted.org/packages/54/85/6ec269b0952ec7e36ba019125982cf11d91256a778c7c3f98a4c5043d283/xxhash-3.6.0-cp312-cp312-win_arm64.whl", hash = "sha256:eae5c13f3bc455a3bbb68bdc513912dc7356de7e2280363ea235f71f54064829", size = 27876, upload-time = "2025-10-02T14:34:54.371Z" }, + { url = "https://files.pythonhosted.org/packages/33/76/35d05267ac82f53ae9b0e554da7c5e281ee61f3cad44c743f0fcd354f211/xxhash-3.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:599e64ba7f67472481ceb6ee80fa3bd828fd61ba59fb11475572cc5ee52b89ec", size = 32738, upload-time = "2025-10-02T14:34:55.839Z" }, + { url = "https://files.pythonhosted.org/packages/31/a8/3fbce1cd96534a95e35d5120637bf29b0d7f5d8fa2f6374e31b4156dd419/xxhash-3.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7d8b8aaa30fca4f16f0c84a5c8d7ddee0e25250ec2796c973775373257dde8f1", size = 30821, upload-time = "2025-10-02T14:34:57.219Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ea/d387530ca7ecfa183cb358027f1833297c6ac6098223fd14f9782cd0015c/xxhash-3.6.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d597acf8506d6e7101a4a44a5e428977a51c0fadbbfd3c39650cca9253f6e5a6", size = 194127, upload-time = "2025-10-02T14:34:59.21Z" }, + { url = "https://files.pythonhosted.org/packages/ba/0c/71435dcb99874b09a43b8d7c54071e600a7481e42b3e3ce1eb5226a5711a/xxhash-3.6.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:858dc935963a33bc33490128edc1c12b0c14d9c7ebaa4e387a7869ecc4f3e263", size = 212975, upload-time = "2025-10-02T14:35:00.816Z" }, + { url = "https://files.pythonhosted.org/packages/84/7a/c2b3d071e4bb4a90b7057228a99b10d51744878f4a8a6dd643c8bd897620/xxhash-3.6.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba284920194615cb8edf73bf52236ce2e1664ccd4a38fdb543506413529cc546", size = 212241, upload-time = "2025-10-02T14:35:02.207Z" }, + { url = "https://files.pythonhosted.org/packages/81/5f/640b6eac0128e215f177df99eadcd0f1b7c42c274ab6a394a05059694c5a/xxhash-3.6.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b54219177f6c6674d5378bd862c6aedf64725f70dd29c472eaae154df1a2e89", size = 445471, upload-time = "2025-10-02T14:35:03.61Z" }, + { url = "https://files.pythonhosted.org/packages/5e/1e/3c3d3ef071b051cc3abbe3721ffb8365033a172613c04af2da89d5548a87/xxhash-3.6.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42c36dd7dbad2f5238950c377fcbf6811b1cdb1c444fab447960030cea60504d", size = 193936, upload-time = "2025-10-02T14:35:05.013Z" }, + { url = "https://files.pythonhosted.org/packages/2c/bd/4a5f68381939219abfe1c22a9e3a5854a4f6f6f3c4983a87d255f21f2e5d/xxhash-3.6.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f22927652cba98c44639ffdc7aaf35828dccf679b10b31c4ad72a5b530a18eb7", size = 210440, upload-time = "2025-10-02T14:35:06.239Z" }, + { url = "https://files.pythonhosted.org/packages/eb/37/b80fe3d5cfb9faff01a02121a0f4d565eb7237e9e5fc66e73017e74dcd36/xxhash-3.6.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b45fad44d9c5c119e9c6fbf2e1c656a46dc68e280275007bbfd3d572b21426db", size = 197990, upload-time = "2025-10-02T14:35:07.735Z" }, + { url = "https://files.pythonhosted.org/packages/d7/fd/2c0a00c97b9e18f72e1f240ad4e8f8a90fd9d408289ba9c7c495ed7dc05c/xxhash-3.6.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:6f2580ffab1a8b68ef2b901cde7e55fa8da5e4be0977c68f78fc80f3c143de42", size = 210689, upload-time = "2025-10-02T14:35:09.438Z" }, + { url = "https://files.pythonhosted.org/packages/93/86/5dd8076a926b9a95db3206aba20d89a7fc14dd5aac16e5c4de4b56033140/xxhash-3.6.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40c391dd3cd041ebc3ffe6f2c862f402e306eb571422e0aa918d8070ba31da11", size = 414068, upload-time = "2025-10-02T14:35:11.162Z" }, + { url = "https://files.pythonhosted.org/packages/af/3c/0bb129170ee8f3650f08e993baee550a09593462a5cddd8e44d0011102b1/xxhash-3.6.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f205badabde7aafd1a31e8ca2a3e5a763107a71c397c4481d6a804eb5063d8bd", size = 191495, upload-time = "2025-10-02T14:35:12.971Z" }, + { url = "https://files.pythonhosted.org/packages/e9/3a/6797e0114c21d1725e2577508e24006fd7ff1d8c0c502d3b52e45c1771d8/xxhash-3.6.0-cp313-cp313-win32.whl", hash = "sha256:2577b276e060b73b73a53042ea5bd5203d3e6347ce0d09f98500f418a9fcf799", size = 30620, upload-time = "2025-10-02T14:35:14.129Z" }, + { url = "https://files.pythonhosted.org/packages/86/15/9bc32671e9a38b413a76d24722a2bf8784a132c043063a8f5152d390b0f9/xxhash-3.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:757320d45d2fbcce8f30c42a6b2f47862967aea7bf458b9625b4bbe7ee390392", size = 31542, upload-time = "2025-10-02T14:35:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/39/c5/cc01e4f6188656e56112d6a8e0dfe298a16934b8c47a247236549a3f7695/xxhash-3.6.0-cp313-cp313-win_arm64.whl", hash = "sha256:457b8f85dec5825eed7b69c11ae86834a018b8e3df5e77783c999663da2f96d6", size = 27880, upload-time = "2025-10-02T14:35:16.315Z" }, + { url = "https://files.pythonhosted.org/packages/f3/30/25e5321c8732759e930c555176d37e24ab84365482d257c3b16362235212/xxhash-3.6.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a42e633d75cdad6d625434e3468126c73f13f7584545a9cf34e883aa1710e702", size = 32956, upload-time = "2025-10-02T14:35:17.413Z" }, + { url = "https://files.pythonhosted.org/packages/9f/3c/0573299560d7d9f8ab1838f1efc021a280b5ae5ae2e849034ef3dee18810/xxhash-3.6.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:568a6d743219e717b07b4e03b0a828ce593833e498c3b64752e0f5df6bfe84db", size = 31072, upload-time = "2025-10-02T14:35:18.844Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1c/52d83a06e417cd9d4137722693424885cc9878249beb3a7c829e74bf7ce9/xxhash-3.6.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bec91b562d8012dae276af8025a55811b875baace6af510412a5e58e3121bc54", size = 196409, upload-time = "2025-10-02T14:35:20.31Z" }, + { url = "https://files.pythonhosted.org/packages/e3/8e/c6d158d12a79bbd0b878f8355432075fc82759e356ab5a111463422a239b/xxhash-3.6.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78e7f2f4c521c30ad5e786fdd6bae89d47a32672a80195467b5de0480aa97b1f", size = 215736, upload-time = "2025-10-02T14:35:21.616Z" }, + { url = "https://files.pythonhosted.org/packages/bc/68/c4c80614716345d55071a396cf03d06e34b5f4917a467faf43083c995155/xxhash-3.6.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3ed0df1b11a79856df5ffcab572cbd6b9627034c1c748c5566fa79df9048a7c5", size = 214833, upload-time = "2025-10-02T14:35:23.32Z" }, + { url = "https://files.pythonhosted.org/packages/7e/e9/ae27c8ffec8b953efa84c7c4a6c6802c263d587b9fc0d6e7cea64e08c3af/xxhash-3.6.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0e4edbfc7d420925b0dd5e792478ed393d6e75ff8fc219a6546fb446b6a417b1", size = 448348, upload-time = "2025-10-02T14:35:25.111Z" }, + { url = "https://files.pythonhosted.org/packages/d7/6b/33e21afb1b5b3f46b74b6bd1913639066af218d704cc0941404ca717fc57/xxhash-3.6.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fba27a198363a7ef87f8c0f6b171ec36b674fe9053742c58dd7e3201c1ab30ee", size = 196070, upload-time = "2025-10-02T14:35:26.586Z" }, + { url = "https://files.pythonhosted.org/packages/96/b6/fcabd337bc5fa624e7203aa0fa7d0c49eed22f72e93229431752bddc83d9/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:794fe9145fe60191c6532fa95063765529770edcdd67b3d537793e8004cabbfd", size = 212907, upload-time = "2025-10-02T14:35:28.087Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d3/9ee6160e644d660fcf176c5825e61411c7f62648728f69c79ba237250143/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:6105ef7e62b5ac73a837778efc331a591d8442f8ef5c7e102376506cb4ae2729", size = 200839, upload-time = "2025-10-02T14:35:29.857Z" }, + { url = "https://files.pythonhosted.org/packages/0d/98/e8de5baa5109394baf5118f5e72ab21a86387c4f89b0e77ef3e2f6b0327b/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f01375c0e55395b814a679b3eea205db7919ac2af213f4a6682e01220e5fe292", size = 213304, upload-time = "2025-10-02T14:35:31.222Z" }, + { url = "https://files.pythonhosted.org/packages/7b/1d/71056535dec5c3177eeb53e38e3d367dd1d16e024e63b1cee208d572a033/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:d706dca2d24d834a4661619dcacf51a75c16d65985718d6a7d73c1eeeb903ddf", size = 416930, upload-time = "2025-10-02T14:35:32.517Z" }, + { url = "https://files.pythonhosted.org/packages/dc/6c/5cbde9de2cd967c322e651c65c543700b19e7ae3e0aae8ece3469bf9683d/xxhash-3.6.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5f059d9faeacd49c0215d66f4056e1326c80503f51a1532ca336a385edadd033", size = 193787, upload-time = "2025-10-02T14:35:33.827Z" }, + { url = "https://files.pythonhosted.org/packages/19/fa/0172e350361d61febcea941b0cc541d6e6c8d65d153e85f850a7b256ff8a/xxhash-3.6.0-cp313-cp313t-win32.whl", hash = "sha256:1244460adc3a9be84731d72b8e80625788e5815b68da3da8b83f78115a40a7ec", size = 30916, upload-time = "2025-10-02T14:35:35.107Z" }, + { url = "https://files.pythonhosted.org/packages/ad/e6/e8cf858a2b19d6d45820f072eff1bea413910592ff17157cabc5f1227a16/xxhash-3.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b1e420ef35c503869c4064f4a2f2b08ad6431ab7b229a05cce39d74268bca6b8", size = 31799, upload-time = "2025-10-02T14:35:36.165Z" }, + { url = "https://files.pythonhosted.org/packages/56/15/064b197e855bfb7b343210e82490ae672f8bc7cdf3ddb02e92f64304ee8a/xxhash-3.6.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ec44b73a4220623235f67a996c862049f375df3b1052d9899f40a6382c32d746", size = 28044, upload-time = "2025-10-02T14:35:37.195Z" }, + { url = "https://files.pythonhosted.org/packages/7e/5e/0138bc4484ea9b897864d59fce9be9086030825bc778b76cb5a33a906d37/xxhash-3.6.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a40a3d35b204b7cc7643cbcf8c9976d818cb47befcfac8bbefec8038ac363f3e", size = 32754, upload-time = "2025-10-02T14:35:38.245Z" }, + { url = "https://files.pythonhosted.org/packages/18/d7/5dac2eb2ec75fd771957a13e5dda560efb2176d5203f39502a5fc571f899/xxhash-3.6.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a54844be970d3fc22630b32d515e79a90d0a3ddb2644d8d7402e3c4c8da61405", size = 30846, upload-time = "2025-10-02T14:35:39.6Z" }, + { url = "https://files.pythonhosted.org/packages/fe/71/8bc5be2bb00deb5682e92e8da955ebe5fa982da13a69da5a40a4c8db12fb/xxhash-3.6.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:016e9190af8f0a4e3741343777710e3d5717427f175adfdc3e72508f59e2a7f3", size = 194343, upload-time = "2025-10-02T14:35:40.69Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3b/52badfb2aecec2c377ddf1ae75f55db3ba2d321c5e164f14461c90837ef3/xxhash-3.6.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f6f72232f849eb9d0141e2ebe2677ece15adfd0fa599bc058aad83c714bb2c6", size = 213074, upload-time = "2025-10-02T14:35:42.29Z" }, + { url = "https://files.pythonhosted.org/packages/a2/2b/ae46b4e9b92e537fa30d03dbc19cdae57ed407e9c26d163895e968e3de85/xxhash-3.6.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:63275a8aba7865e44b1813d2177e0f5ea7eadad3dd063a21f7cf9afdc7054063", size = 212388, upload-time = "2025-10-02T14:35:43.929Z" }, + { url = "https://files.pythonhosted.org/packages/f5/80/49f88d3afc724b4ac7fbd664c8452d6db51b49915be48c6982659e0e7942/xxhash-3.6.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cd01fa2aa00d8b017c97eb46b9a794fbdca53fc14f845f5a328c71254b0abb7", size = 445614, upload-time = "2025-10-02T14:35:45.216Z" }, + { url = "https://files.pythonhosted.org/packages/ed/ba/603ce3961e339413543d8cd44f21f2c80e2a7c5cfe692a7b1f2cccf58f3c/xxhash-3.6.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0226aa89035b62b6a86d3c68df4d7c1f47a342b8683da2b60cedcddb46c4d95b", size = 194024, upload-time = "2025-10-02T14:35:46.959Z" }, + { url = "https://files.pythonhosted.org/packages/78/d1/8e225ff7113bf81545cfdcd79eef124a7b7064a0bba53605ff39590b95c2/xxhash-3.6.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c6e193e9f56e4ca4923c61238cdaced324f0feac782544eb4c6d55ad5cc99ddd", size = 210541, upload-time = "2025-10-02T14:35:48.301Z" }, + { url = "https://files.pythonhosted.org/packages/6f/58/0f89d149f0bad89def1a8dd38feb50ccdeb643d9797ec84707091d4cb494/xxhash-3.6.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9176dcaddf4ca963d4deb93866d739a343c01c969231dbe21680e13a5d1a5bf0", size = 198305, upload-time = "2025-10-02T14:35:49.584Z" }, + { url = "https://files.pythonhosted.org/packages/11/38/5eab81580703c4df93feb5f32ff8fa7fe1e2c51c1f183ee4e48d4bb9d3d7/xxhash-3.6.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c1ce4009c97a752e682b897aa99aef84191077a9433eb237774689f14f8ec152", size = 210848, upload-time = "2025-10-02T14:35:50.877Z" }, + { url = "https://files.pythonhosted.org/packages/5e/6b/953dc4b05c3ce678abca756416e4c130d2382f877a9c30a20d08ee6a77c0/xxhash-3.6.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:8cb2f4f679b01513b7adbb9b1b2f0f9cdc31b70007eaf9d59d0878809f385b11", size = 414142, upload-time = "2025-10-02T14:35:52.15Z" }, + { url = "https://files.pythonhosted.org/packages/08/a9/238ec0d4e81a10eb5026d4a6972677cbc898ba6c8b9dbaec12ae001b1b35/xxhash-3.6.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:653a91d7c2ab54a92c19ccf43508b6a555440b9be1bc8be553376778be7f20b5", size = 191547, upload-time = "2025-10-02T14:35:53.547Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ee/3cf8589e06c2164ac77c3bf0aa127012801128f1feebf2a079272da5737c/xxhash-3.6.0-cp314-cp314-win32.whl", hash = "sha256:a756fe893389483ee8c394d06b5ab765d96e68fbbfe6fde7aa17e11f5720559f", size = 31214, upload-time = "2025-10-02T14:35:54.746Z" }, + { url = "https://files.pythonhosted.org/packages/02/5d/a19552fbc6ad4cb54ff953c3908bbc095f4a921bc569433d791f755186f1/xxhash-3.6.0-cp314-cp314-win_amd64.whl", hash = "sha256:39be8e4e142550ef69629c9cd71b88c90e9a5db703fecbcf265546d9536ca4ad", size = 32290, upload-time = "2025-10-02T14:35:55.791Z" }, + { url = "https://files.pythonhosted.org/packages/b1/11/dafa0643bc30442c887b55baf8e73353a344ee89c1901b5a5c54a6c17d39/xxhash-3.6.0-cp314-cp314-win_arm64.whl", hash = "sha256:25915e6000338999236f1eb68a02a32c3275ac338628a7eaa5a269c401995679", size = 28795, upload-time = "2025-10-02T14:35:57.162Z" }, + { url = "https://files.pythonhosted.org/packages/2c/db/0e99732ed7f64182aef4a6fb145e1a295558deec2a746265dcdec12d191e/xxhash-3.6.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c5294f596a9017ca5a3e3f8884c00b91ab2ad2933cf288f4923c3fd4346cf3d4", size = 32955, upload-time = "2025-10-02T14:35:58.267Z" }, + { url = "https://files.pythonhosted.org/packages/55/f4/2a7c3c68e564a099becfa44bb3d398810cc0ff6749b0d3cb8ccb93f23c14/xxhash-3.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1cf9dcc4ab9cff01dfbba78544297a3a01dafd60f3bde4e2bfd016cf7e4ddc67", size = 31072, upload-time = "2025-10-02T14:35:59.382Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d9/72a29cddc7250e8a5819dad5d466facb5dc4c802ce120645630149127e73/xxhash-3.6.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:01262da8798422d0685f7cef03b2bd3f4f46511b02830861df548d7def4402ad", size = 196579, upload-time = "2025-10-02T14:36:00.838Z" }, + { url = "https://files.pythonhosted.org/packages/63/93/b21590e1e381040e2ca305a884d89e1c345b347404f7780f07f2cdd47ef4/xxhash-3.6.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:51a73fb7cb3a3ead9f7a8b583ffd9b8038e277cdb8cb87cf890e88b3456afa0b", size = 215854, upload-time = "2025-10-02T14:36:02.207Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b8/edab8a7d4fa14e924b29be877d54155dcbd8b80be85ea00d2be3413a9ed4/xxhash-3.6.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b9c6df83594f7df8f7f708ce5ebeacfc69f72c9fbaaababf6cf4758eaada0c9b", size = 214965, upload-time = "2025-10-02T14:36:03.507Z" }, + { url = "https://files.pythonhosted.org/packages/27/67/dfa980ac7f0d509d54ea0d5a486d2bb4b80c3f1bb22b66e6a05d3efaf6c0/xxhash-3.6.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:627f0af069b0ea56f312fd5189001c24578868643203bca1abbc2c52d3a6f3ca", size = 448484, upload-time = "2025-10-02T14:36:04.828Z" }, + { url = "https://files.pythonhosted.org/packages/8c/63/8ffc2cc97e811c0ca5d00ab36604b3ea6f4254f20b7bc658ca825ce6c954/xxhash-3.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa912c62f842dfd013c5f21a642c9c10cd9f4c4e943e0af83618b4a404d9091a", size = 196162, upload-time = "2025-10-02T14:36:06.182Z" }, + { url = "https://files.pythonhosted.org/packages/4b/77/07f0e7a3edd11a6097e990f6e5b815b6592459cb16dae990d967693e6ea9/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b465afd7909db30168ab62afe40b2fcf79eedc0b89a6c0ab3123515dc0df8b99", size = 213007, upload-time = "2025-10-02T14:36:07.733Z" }, + { url = "https://files.pythonhosted.org/packages/ae/d8/bc5fa0d152837117eb0bef6f83f956c509332ce133c91c63ce07ee7c4873/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:a881851cf38b0a70e7c4d3ce81fc7afd86fbc2a024f4cfb2a97cf49ce04b75d3", size = 200956, upload-time = "2025-10-02T14:36:09.106Z" }, + { url = "https://files.pythonhosted.org/packages/26/a5/d749334130de9411783873e9b98ecc46688dad5db64ca6e04b02acc8b473/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9b3222c686a919a0f3253cfc12bb118b8b103506612253b5baeaac10d8027cf6", size = 213401, upload-time = "2025-10-02T14:36:10.585Z" }, + { url = "https://files.pythonhosted.org/packages/89/72/abed959c956a4bfc72b58c0384bb7940663c678127538634d896b1195c10/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:c5aa639bc113e9286137cec8fadc20e9cd732b2cc385c0b7fa673b84fc1f2a93", size = 417083, upload-time = "2025-10-02T14:36:12.276Z" }, + { url = "https://files.pythonhosted.org/packages/0c/b3/62fd2b586283b7d7d665fb98e266decadf31f058f1cf6c478741f68af0cb/xxhash-3.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5c1343d49ac102799905e115aee590183c3921d475356cb24b4de29a4bc56518", size = 193913, upload-time = "2025-10-02T14:36:14.025Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/c19c42c5b3f5a4aad748a6d5b4f23df3bed7ee5445accc65a0fb3ff03953/xxhash-3.6.0-cp314-cp314t-win32.whl", hash = "sha256:5851f033c3030dd95c086b4a36a2683c2ff4a799b23af60977188b057e467119", size = 31586, upload-time = "2025-10-02T14:36:15.603Z" }, + { url = "https://files.pythonhosted.org/packages/03/d6/4cc450345be9924fd5dc8c590ceda1db5b43a0a889587b0ae81a95511360/xxhash-3.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0444e7967dac37569052d2409b00a8860c2135cff05502df4da80267d384849f", size = 32526, upload-time = "2025-10-02T14:36:16.708Z" }, + { url = "https://files.pythonhosted.org/packages/0f/c9/7243eb3f9eaabd1a88a5a5acadf06df2d83b100c62684b7425c6a11bcaa8/xxhash-3.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:bb79b1e63f6fd84ec778a4b1916dfe0a7c3fdb986c06addd5db3a0d413819d95", size = 28898, upload-time = "2025-10-02T14:36:17.843Z" }, + { url = "https://files.pythonhosted.org/packages/93/1e/8aec23647a34a249f62e2398c42955acd9b4c6ed5cf08cbea94dc46f78d2/xxhash-3.6.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0f7b7e2ec26c1666ad5fc9dbfa426a6a3367ceaf79db5dd76264659d509d73b0", size = 30662, upload-time = "2025-10-02T14:37:01.743Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0b/b14510b38ba91caf43006209db846a696ceea6a847a0c9ba0a5b1adc53d6/xxhash-3.6.0-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5dc1e14d14fa0f5789ec29a7062004b5933964bb9b02aae6622b8f530dc40296", size = 41056, upload-time = "2025-10-02T14:37:02.879Z" }, + { url = "https://files.pythonhosted.org/packages/50/55/15a7b8a56590e66ccd374bbfa3f9ffc45b810886c8c3b614e3f90bd2367c/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:881b47fc47e051b37d94d13e7455131054b56749b91b508b0907eb07900d1c13", size = 36251, upload-time = "2025-10-02T14:37:04.44Z" }, + { url = "https://files.pythonhosted.org/packages/62/b2/5ac99a041a29e58e95f907876b04f7067a0242cb85b5f39e726153981503/xxhash-3.6.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6dc31591899f5e5666f04cc2e529e69b4072827085c1ef15294d91a004bc1bd", size = 32481, upload-time = "2025-10-02T14:37:05.869Z" }, + { url = "https://files.pythonhosted.org/packages/7b/d9/8d95e906764a386a3d3b596f3c68bb63687dfca806373509f51ce8eea81f/xxhash-3.6.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:15e0dac10eb9309508bfc41f7f9deaa7755c69e35af835db9cb10751adebc35d", size = 31565, upload-time = "2025-10-02T14:37:06.966Z" }, +] + +[[package]] +name = "zstandard" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513, upload-time = "2025-09-14T22:15:54.002Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/7a/28efd1d371f1acd037ac64ed1c5e2b41514a6cc937dd6ab6a13ab9f0702f/zstandard-0.25.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e59fdc271772f6686e01e1b3b74537259800f57e24280be3f29c8a0deb1904dd", size = 795256, upload-time = "2025-09-14T22:15:56.415Z" }, + { url = "https://files.pythonhosted.org/packages/96/34/ef34ef77f1ee38fc8e4f9775217a613b452916e633c4f1d98f31db52c4a5/zstandard-0.25.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4d441506e9b372386a5271c64125f72d5df6d2a8e8a2a45a0ae09b03cb781ef7", size = 640565, upload-time = "2025-09-14T22:15:58.177Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1b/4fdb2c12eb58f31f28c4d28e8dc36611dd7205df8452e63f52fb6261d13e/zstandard-0.25.0-cp310-cp310-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:ab85470ab54c2cb96e176f40342d9ed41e58ca5733be6a893b730e7af9c40550", size = 5345306, upload-time = "2025-09-14T22:16:00.165Z" }, + { url = "https://files.pythonhosted.org/packages/73/28/a44bdece01bca027b079f0e00be3b6bd89a4df180071da59a3dd7381665b/zstandard-0.25.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e05ab82ea7753354bb054b92e2f288afb750e6b439ff6ca78af52939ebbc476d", size = 5055561, upload-time = "2025-09-14T22:16:02.22Z" }, + { url = "https://files.pythonhosted.org/packages/e9/74/68341185a4f32b274e0fc3410d5ad0750497e1acc20bd0f5b5f64ce17785/zstandard-0.25.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:78228d8a6a1c177a96b94f7e2e8d012c55f9c760761980da16ae7546a15a8e9b", size = 5402214, upload-time = "2025-09-14T22:16:04.109Z" }, + { url = "https://files.pythonhosted.org/packages/8b/67/f92e64e748fd6aaffe01e2b75a083c0c4fd27abe1c8747fee4555fcee7dd/zstandard-0.25.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:2b6bd67528ee8b5c5f10255735abc21aa106931f0dbaf297c7be0c886353c3d0", size = 5449703, upload-time = "2025-09-14T22:16:06.312Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e5/6d36f92a197c3c17729a2125e29c169f460538a7d939a27eaaa6dcfcba8e/zstandard-0.25.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4b6d83057e713ff235a12e73916b6d356e3084fd3d14ced499d84240f3eecee0", size = 5556583, upload-time = "2025-09-14T22:16:08.457Z" }, + { url = "https://files.pythonhosted.org/packages/d7/83/41939e60d8d7ebfe2b747be022d0806953799140a702b90ffe214d557638/zstandard-0.25.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9174f4ed06f790a6869b41cba05b43eeb9a35f8993c4422ab853b705e8112bbd", size = 5045332, upload-time = "2025-09-14T22:16:10.444Z" }, + { url = "https://files.pythonhosted.org/packages/b3/87/d3ee185e3d1aa0133399893697ae91f221fda79deb61adbe998a7235c43f/zstandard-0.25.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:25f8f3cd45087d089aef5ba3848cd9efe3ad41163d3400862fb42f81a3a46701", size = 5572283, upload-time = "2025-09-14T22:16:12.128Z" }, + { url = "https://files.pythonhosted.org/packages/0a/1d/58635ae6104df96671076ac7d4ae7816838ce7debd94aecf83e30b7121b0/zstandard-0.25.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3756b3e9da9b83da1796f8809dd57cb024f838b9eeafde28f3cb472012797ac1", size = 4959754, upload-time = "2025-09-14T22:16:14.225Z" }, + { url = "https://files.pythonhosted.org/packages/75/d6/57e9cb0a9983e9a229dd8fd2e6e96593ef2aa82a3907188436f22b111ccd/zstandard-0.25.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:81dad8d145d8fd981b2962b686b2241d3a1ea07733e76a2f15435dfb7fb60150", size = 5266477, upload-time = "2025-09-14T22:16:16.343Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a9/ee891e5edf33a6ebce0a028726f0bbd8567effe20fe3d5808c42323e8542/zstandard-0.25.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a5a419712cf88862a45a23def0ae063686db3d324cec7edbe40509d1a79a0aab", size = 5440914, upload-time = "2025-09-14T22:16:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/58/08/a8522c28c08031a9521f27abc6f78dbdee7312a7463dd2cfc658b813323b/zstandard-0.25.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e7360eae90809efd19b886e59a09dad07da4ca9ba096752e61a2e03c8aca188e", size = 5819847, upload-time = "2025-09-14T22:16:20.559Z" }, + { url = "https://files.pythonhosted.org/packages/6f/11/4c91411805c3f7b6f31c60e78ce347ca48f6f16d552fc659af6ec3b73202/zstandard-0.25.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:75ffc32a569fb049499e63ce68c743155477610532da1eb38e7f24bf7cd29e74", size = 5363131, upload-time = "2025-09-14T22:16:22.206Z" }, + { url = "https://files.pythonhosted.org/packages/ef/d6/8c4bd38a3b24c4c7676a7a3d8de85d6ee7a983602a734b9f9cdefb04a5d6/zstandard-0.25.0-cp310-cp310-win32.whl", hash = "sha256:106281ae350e494f4ac8a80470e66d1fe27e497052c8d9c3b95dc4cf1ade81aa", size = 436469, upload-time = "2025-09-14T22:16:25.002Z" }, + { url = "https://files.pythonhosted.org/packages/93/90/96d50ad417a8ace5f841b3228e93d1bb13e6ad356737f42e2dde30d8bd68/zstandard-0.25.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea9d54cc3d8064260114a0bbf3479fc4a98b21dffc89b3459edd506b69262f6e", size = 506100, upload-time = "2025-09-14T22:16:23.569Z" }, + { url = "https://files.pythonhosted.org/packages/2a/83/c3ca27c363d104980f1c9cee1101cc8ba724ac8c28a033ede6aab89585b1/zstandard-0.25.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:933b65d7680ea337180733cf9e87293cc5500cc0eb3fc8769f4d3c88d724ec5c", size = 795254, upload-time = "2025-09-14T22:16:26.137Z" }, + { url = "https://files.pythonhosted.org/packages/ac/4d/e66465c5411a7cf4866aeadc7d108081d8ceba9bc7abe6b14aa21c671ec3/zstandard-0.25.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3f79487c687b1fc69f19e487cd949bf3aae653d181dfb5fde3bf6d18894706f", size = 640559, upload-time = "2025-09-14T22:16:27.973Z" }, + { url = "https://files.pythonhosted.org/packages/12/56/354fe655905f290d3b147b33fe946b0f27e791e4b50a5f004c802cb3eb7b/zstandard-0.25.0-cp311-cp311-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:0bbc9a0c65ce0eea3c34a691e3c4b6889f5f3909ba4822ab385fab9057099431", size = 5348020, upload-time = "2025-09-14T22:16:29.523Z" }, + { url = "https://files.pythonhosted.org/packages/3b/13/2b7ed68bd85e69a2069bcc72141d378f22cae5a0f3b353a2c8f50ef30c1b/zstandard-0.25.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:01582723b3ccd6939ab7b3a78622c573799d5d8737b534b86d0e06ac18dbde4a", size = 5058126, upload-time = "2025-09-14T22:16:31.811Z" }, + { url = "https://files.pythonhosted.org/packages/c9/dd/fdaf0674f4b10d92cb120ccff58bbb6626bf8368f00ebfd2a41ba4a0dc99/zstandard-0.25.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5f1ad7bf88535edcf30038f6919abe087f606f62c00a87d7e33e7fc57cb69fcc", size = 5405390, upload-time = "2025-09-14T22:16:33.486Z" }, + { url = "https://files.pythonhosted.org/packages/0f/67/354d1555575bc2490435f90d67ca4dd65238ff2f119f30f72d5cde09c2ad/zstandard-0.25.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:06acb75eebeedb77b69048031282737717a63e71e4ae3f77cc0c3b9508320df6", size = 5452914, upload-time = "2025-09-14T22:16:35.277Z" }, + { url = "https://files.pythonhosted.org/packages/bb/1f/e9cfd801a3f9190bf3e759c422bbfd2247db9d7f3d54a56ecde70137791a/zstandard-0.25.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9300d02ea7c6506f00e627e287e0492a5eb0371ec1670ae852fefffa6164b072", size = 5559635, upload-time = "2025-09-14T22:16:37.141Z" }, + { url = "https://files.pythonhosted.org/packages/21/88/5ba550f797ca953a52d708c8e4f380959e7e3280af029e38fbf47b55916e/zstandard-0.25.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfd06b1c5584b657a2892a6014c2f4c20e0db0208c159148fa78c65f7e0b0277", size = 5048277, upload-time = "2025-09-14T22:16:38.807Z" }, + { url = "https://files.pythonhosted.org/packages/46/c0/ca3e533b4fa03112facbe7fbe7779cb1ebec215688e5df576fe5429172e0/zstandard-0.25.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f373da2c1757bb7f1acaf09369cdc1d51d84131e50d5fa9863982fd626466313", size = 5574377, upload-time = "2025-09-14T22:16:40.523Z" }, + { url = "https://files.pythonhosted.org/packages/12/9b/3fb626390113f272abd0799fd677ea33d5fc3ec185e62e6be534493c4b60/zstandard-0.25.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c0e5a65158a7946e7a7affa6418878ef97ab66636f13353b8502d7ea03c8097", size = 4961493, upload-time = "2025-09-14T22:16:43.3Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d3/23094a6b6a4b1343b27ae68249daa17ae0651fcfec9ed4de09d14b940285/zstandard-0.25.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c8e167d5adf59476fa3e37bee730890e389410c354771a62e3c076c86f9f7778", size = 5269018, upload-time = "2025-09-14T22:16:45.292Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a7/bb5a0c1c0f3f4b5e9d5b55198e39de91e04ba7c205cc46fcb0f95f0383c1/zstandard-0.25.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:98750a309eb2f020da61e727de7d7ba3c57c97cf6213f6f6277bb7fb42a8e065", size = 5443672, upload-time = "2025-09-14T22:16:47.076Z" }, + { url = "https://files.pythonhosted.org/packages/27/22/503347aa08d073993f25109c36c8d9f029c7d5949198050962cb568dfa5e/zstandard-0.25.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22a086cff1b6ceca18a8dd6096ec631e430e93a8e70a9ca5efa7561a00f826fa", size = 5822753, upload-time = "2025-09-14T22:16:49.316Z" }, + { url = "https://files.pythonhosted.org/packages/e2/be/94267dc6ee64f0f8ba2b2ae7c7a2df934a816baaa7291db9e1aa77394c3c/zstandard-0.25.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:72d35d7aa0bba323965da807a462b0966c91608ef3a48ba761678cb20ce5d8b7", size = 5366047, upload-time = "2025-09-14T22:16:51.328Z" }, + { url = "https://files.pythonhosted.org/packages/7b/a3/732893eab0a3a7aecff8b99052fecf9f605cf0fb5fb6d0290e36beee47a4/zstandard-0.25.0-cp311-cp311-win32.whl", hash = "sha256:f5aeea11ded7320a84dcdd62a3d95b5186834224a9e55b92ccae35d21a8b63d4", size = 436484, upload-time = "2025-09-14T22:16:55.005Z" }, + { url = "https://files.pythonhosted.org/packages/43/a3/c6155f5c1cce691cb80dfd38627046e50af3ee9ddc5d0b45b9b063bfb8c9/zstandard-0.25.0-cp311-cp311-win_amd64.whl", hash = "sha256:daab68faadb847063d0c56f361a289c4f268706b598afbf9ad113cbe5c38b6b2", size = 506183, upload-time = "2025-09-14T22:16:52.753Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3e/8945ab86a0820cc0e0cdbf38086a92868a9172020fdab8a03ac19662b0e5/zstandard-0.25.0-cp311-cp311-win_arm64.whl", hash = "sha256:22a06c5df3751bb7dc67406f5374734ccee8ed37fc5981bf1ad7041831fa1137", size = 462533, upload-time = "2025-09-14T22:16:53.878Z" }, + { url = "https://files.pythonhosted.org/packages/82/fc/f26eb6ef91ae723a03e16eddb198abcfce2bc5a42e224d44cc8b6765e57e/zstandard-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b3c3a3ab9daa3eed242d6ecceead93aebbb8f5f84318d82cee643e019c4b73b", size = 795738, upload-time = "2025-09-14T22:16:56.237Z" }, + { url = "https://files.pythonhosted.org/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:913cbd31a400febff93b564a23e17c3ed2d56c064006f54efec210d586171c00", size = 640436, upload-time = "2025-09-14T22:16:57.774Z" }, + { url = "https://files.pythonhosted.org/packages/53/6c/288c3f0bd9fcfe9ca41e2c2fbfd17b2097f6af57b62a81161941f09afa76/zstandard-0.25.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:011d388c76b11a0c165374ce660ce2c8efa8e5d87f34996aa80f9c0816698b64", size = 5343019, upload-time = "2025-09-14T22:16:59.302Z" }, + { url = "https://files.pythonhosted.org/packages/1e/15/efef5a2f204a64bdb5571e6161d49f7ef0fffdbca953a615efbec045f60f/zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dffecc361d079bb48d7caef5d673c88c8988d3d33fb74ab95b7ee6da42652ea", size = 5063012, upload-time = "2025-09-14T22:17:01.156Z" }, + { url = "https://files.pythonhosted.org/packages/b7/37/a6ce629ffdb43959e92e87ebdaeebb5ac81c944b6a75c9c47e300f85abdf/zstandard-0.25.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7149623bba7fdf7e7f24312953bcf73cae103db8cae49f8154dd1eadc8a29ecb", size = 5394148, upload-time = "2025-09-14T22:17:03.091Z" }, + { url = "https://files.pythonhosted.org/packages/e3/79/2bf870b3abeb5c070fe2d670a5a8d1057a8270f125ef7676d29ea900f496/zstandard-0.25.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6a573a35693e03cf1d67799fd01b50ff578515a8aeadd4595d2a7fa9f3ec002a", size = 5451652, upload-time = "2025-09-14T22:17:04.979Z" }, + { url = "https://files.pythonhosted.org/packages/53/60/7be26e610767316c028a2cbedb9a3beabdbe33e2182c373f71a1c0b88f36/zstandard-0.25.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5a56ba0db2d244117ed744dfa8f6f5b366e14148e00de44723413b2f3938a902", size = 5546993, upload-time = "2025-09-14T22:17:06.781Z" }, + { url = "https://files.pythonhosted.org/packages/85/c7/3483ad9ff0662623f3648479b0380d2de5510abf00990468c286c6b04017/zstandard-0.25.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:10ef2a79ab8e2974e2075fb984e5b9806c64134810fac21576f0668e7ea19f8f", size = 5046806, upload-time = "2025-09-14T22:17:08.415Z" }, + { url = "https://files.pythonhosted.org/packages/08/b3/206883dd25b8d1591a1caa44b54c2aad84badccf2f1de9e2d60a446f9a25/zstandard-0.25.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aaf21ba8fb76d102b696781bddaa0954b782536446083ae3fdaa6f16b25a1c4b", size = 5576659, upload-time = "2025-09-14T22:17:10.164Z" }, + { url = "https://files.pythonhosted.org/packages/9d/31/76c0779101453e6c117b0ff22565865c54f48f8bd807df2b00c2c404b8e0/zstandard-0.25.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1869da9571d5e94a85a5e8d57e4e8807b175c9e4a6294e3b66fa4efb074d90f6", size = 4953933, upload-time = "2025-09-14T22:17:11.857Z" }, + { url = "https://files.pythonhosted.org/packages/18/e1/97680c664a1bf9a247a280a053d98e251424af51f1b196c6d52f117c9720/zstandard-0.25.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:809c5bcb2c67cd0ed81e9229d227d4ca28f82d0f778fc5fea624a9def3963f91", size = 5268008, upload-time = "2025-09-14T22:17:13.627Z" }, + { url = "https://files.pythonhosted.org/packages/1e/73/316e4010de585ac798e154e88fd81bb16afc5c5cb1a72eeb16dd37e8024a/zstandard-0.25.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f27662e4f7dbf9f9c12391cb37b4c4c3cb90ffbd3b1fb9284dadbbb8935fa708", size = 5433517, upload-time = "2025-09-14T22:17:16.103Z" }, + { url = "https://files.pythonhosted.org/packages/5b/60/dd0f8cfa8129c5a0ce3ea6b7f70be5b33d2618013a161e1ff26c2b39787c/zstandard-0.25.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99c0c846e6e61718715a3c9437ccc625de26593fea60189567f0118dc9db7512", size = 5814292, upload-time = "2025-09-14T22:17:17.827Z" }, + { url = "https://files.pythonhosted.org/packages/fc/5f/75aafd4b9d11b5407b641b8e41a57864097663699f23e9ad4dbb91dc6bfe/zstandard-0.25.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:474d2596a2dbc241a556e965fb76002c1ce655445e4e3bf38e5477d413165ffa", size = 5360237, upload-time = "2025-09-14T22:17:19.954Z" }, + { url = "https://files.pythonhosted.org/packages/ff/8d/0309daffea4fcac7981021dbf21cdb2e3427a9e76bafbcdbdf5392ff99a4/zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd", size = 436922, upload-time = "2025-09-14T22:17:24.398Z" }, + { url = "https://files.pythonhosted.org/packages/79/3b/fa54d9015f945330510cb5d0b0501e8253c127cca7ebe8ba46a965df18c5/zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01", size = 506276, upload-time = "2025-09-14T22:17:21.429Z" }, + { url = "https://files.pythonhosted.org/packages/ea/6b/8b51697e5319b1f9ac71087b0af9a40d8a6288ff8025c36486e0c12abcc4/zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9", size = 462679, upload-time = "2025-09-14T22:17:23.147Z" }, + { url = "https://files.pythonhosted.org/packages/35/0b/8df9c4ad06af91d39e94fa96cc010a24ac4ef1378d3efab9223cc8593d40/zstandard-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec996f12524f88e151c339688c3897194821d7f03081ab35d31d1e12ec975e94", size = 795735, upload-time = "2025-09-14T22:17:26.042Z" }, + { url = "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a1a4ae2dec3993a32247995bdfe367fc3266da832d82f8438c8570f989753de1", size = 640440, upload-time = "2025-09-14T22:17:27.366Z" }, + { url = "https://files.pythonhosted.org/packages/d9/14/933d27204c2bd404229c69f445862454dcc101cd69ef8c6068f15aaec12c/zstandard-0.25.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:e96594a5537722fdfb79951672a2a63aec5ebfb823e7560586f7484819f2a08f", size = 5343070, upload-time = "2025-09-14T22:17:28.896Z" }, + { url = "https://files.pythonhosted.org/packages/6d/db/ddb11011826ed7db9d0e485d13df79b58586bfdec56e5c84a928a9a78c1c/zstandard-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bfc4e20784722098822e3eee42b8e576b379ed72cca4a7cb856ae733e62192ea", size = 5063001, upload-time = "2025-09-14T22:17:31.044Z" }, + { url = "https://files.pythonhosted.org/packages/db/00/87466ea3f99599d02a5238498b87bf84a6348290c19571051839ca943777/zstandard-0.25.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:457ed498fc58cdc12fc48f7950e02740d4f7ae9493dd4ab2168a47c93c31298e", size = 5394120, upload-time = "2025-09-14T22:17:32.711Z" }, + { url = "https://files.pythonhosted.org/packages/2b/95/fc5531d9c618a679a20ff6c29e2b3ef1d1f4ad66c5e161ae6ff847d102a9/zstandard-0.25.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fd7a5004eb1980d3cefe26b2685bcb0b17989901a70a1040d1ac86f1d898c551", size = 5451230, upload-time = "2025-09-14T22:17:34.41Z" }, + { url = "https://files.pythonhosted.org/packages/63/4b/e3678b4e776db00f9f7b2fe58e547e8928ef32727d7a1ff01dea010f3f13/zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e735494da3db08694d26480f1493ad2cf86e99bdd53e8e9771b2752a5c0246a", size = 5547173, upload-time = "2025-09-14T22:17:36.084Z" }, + { url = "https://files.pythonhosted.org/packages/4e/d5/ba05ed95c6b8ec30bd468dfeab20589f2cf709b5c940483e31d991f2ca58/zstandard-0.25.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3a39c94ad7866160a4a46d772e43311a743c316942037671beb264e395bdd611", size = 5046736, upload-time = "2025-09-14T22:17:37.891Z" }, + { url = "https://files.pythonhosted.org/packages/50/d5/870aa06b3a76c73eced65c044b92286a3c4e00554005ff51962deef28e28/zstandard-0.25.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:172de1f06947577d3a3005416977cce6168f2261284c02080e7ad0185faeced3", size = 5576368, upload-time = "2025-09-14T22:17:40.206Z" }, + { url = "https://files.pythonhosted.org/packages/5d/35/398dc2ffc89d304d59bc12f0fdd931b4ce455bddf7038a0a67733a25f550/zstandard-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c83b0188c852a47cd13ef3bf9209fb0a77fa5374958b8c53aaa699398c6bd7b", size = 4954022, upload-time = "2025-09-14T22:17:41.879Z" }, + { url = "https://files.pythonhosted.org/packages/9a/5c/36ba1e5507d56d2213202ec2b05e8541734af5f2ce378c5d1ceaf4d88dc4/zstandard-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1673b7199bbe763365b81a4f3252b8e80f44c9e323fc42940dc8843bfeaf9851", size = 5267889, upload-time = "2025-09-14T22:17:43.577Z" }, + { url = "https://files.pythonhosted.org/packages/70/e8/2ec6b6fb7358b2ec0113ae202647ca7c0e9d15b61c005ae5225ad0995df5/zstandard-0.25.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0be7622c37c183406f3dbf0cba104118eb16a4ea7359eeb5752f0794882fc250", size = 5433952, upload-time = "2025-09-14T22:17:45.271Z" }, + { url = "https://files.pythonhosted.org/packages/7b/01/b5f4d4dbc59ef193e870495c6f1275f5b2928e01ff5a81fecb22a06e22fb/zstandard-0.25.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f5e4c2a23ca271c218ac025bd7d635597048b366d6f31f420aaeb715239fc98", size = 5814054, upload-time = "2025-09-14T22:17:47.08Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e5/fbd822d5c6f427cf158316d012c5a12f233473c2f9c5fe5ab1ae5d21f3d8/zstandard-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f187a0bb61b35119d1926aee039524d1f93aaf38a9916b8c4b78ac8514a0aaf", size = 5360113, upload-time = "2025-09-14T22:17:48.893Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e0/69a553d2047f9a2c7347caa225bb3a63b6d7704ad74610cb7823baa08ed7/zstandard-0.25.0-cp313-cp313-win32.whl", hash = "sha256:7030defa83eef3e51ff26f0b7bfb229f0204b66fe18e04359ce3474ac33cbc09", size = 436936, upload-time = "2025-09-14T22:17:52.658Z" }, + { url = "https://files.pythonhosted.org/packages/d9/82/b9c06c870f3bd8767c201f1edbdf9e8dc34be5b0fbc5682c4f80fe948475/zstandard-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:1f830a0dac88719af0ae43b8b2d6aef487d437036468ef3c2ea59c51f9d55fd5", size = 506232, upload-time = "2025-09-14T22:17:50.402Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/60c3c01243bb81d381c9916e2a6d9e149ab8627c0c7d7abb2d73384b3c0c/zstandard-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:85304a43f4d513f5464ceb938aa02c1e78c2943b29f44a750b48b25ac999a049", size = 462671, upload-time = "2025-09-14T22:17:51.533Z" }, + { url = "https://files.pythonhosted.org/packages/3d/5c/f8923b595b55fe49e30612987ad8bf053aef555c14f05bb659dd5dbe3e8a/zstandard-0.25.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e29f0cf06974c899b2c188ef7f783607dbef36da4c242eb6c82dcd8b512855e3", size = 795887, upload-time = "2025-09-14T22:17:54.198Z" }, + { url = "https://files.pythonhosted.org/packages/8d/09/d0a2a14fc3439c5f874042dca72a79c70a532090b7ba0003be73fee37ae2/zstandard-0.25.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:05df5136bc5a011f33cd25bc9f506e7426c0c9b3f9954f056831ce68f3b6689f", size = 640658, upload-time = "2025-09-14T22:17:55.423Z" }, + { url = "https://files.pythonhosted.org/packages/5d/7c/8b6b71b1ddd517f68ffb55e10834388d4f793c49c6b83effaaa05785b0b4/zstandard-0.25.0-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:f604efd28f239cc21b3adb53eb061e2a205dc164be408e553b41ba2ffe0ca15c", size = 5379849, upload-time = "2025-09-14T22:17:57.372Z" }, + { url = "https://files.pythonhosted.org/packages/a4/86/a48e56320d0a17189ab7a42645387334fba2200e904ee47fc5a26c1fd8ca/zstandard-0.25.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223415140608d0f0da010499eaa8ccdb9af210a543fac54bce15babbcfc78439", size = 5058095, upload-time = "2025-09-14T22:17:59.498Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ad/eb659984ee2c0a779f9d06dbfe45e2dc39d99ff40a319895df2d3d9a48e5/zstandard-0.25.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e54296a283f3ab5a26fc9b8b5d4978ea0532f37b231644f367aa588930aa043", size = 5551751, upload-time = "2025-09-14T22:18:01.618Z" }, + { url = "https://files.pythonhosted.org/packages/61/b3/b637faea43677eb7bd42ab204dfb7053bd5c4582bfe6b1baefa80ac0c47b/zstandard-0.25.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ca54090275939dc8ec5dea2d2afb400e0f83444b2fc24e07df7fdef677110859", size = 6364818, upload-time = "2025-09-14T22:18:03.769Z" }, + { url = "https://files.pythonhosted.org/packages/31/dc/cc50210e11e465c975462439a492516a73300ab8caa8f5e0902544fd748b/zstandard-0.25.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e09bb6252b6476d8d56100e8147b803befa9a12cea144bbe629dd508800d1ad0", size = 5560402, upload-time = "2025-09-14T22:18:05.954Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ae/56523ae9c142f0c08efd5e868a6da613ae76614eca1305259c3bf6a0ed43/zstandard-0.25.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a9ec8c642d1ec73287ae3e726792dd86c96f5681eb8df274a757bf62b750eae7", size = 4955108, upload-time = "2025-09-14T22:18:07.68Z" }, + { url = "https://files.pythonhosted.org/packages/98/cf/c899f2d6df0840d5e384cf4c4121458c72802e8bda19691f3b16619f51e9/zstandard-0.25.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a4089a10e598eae6393756b036e0f419e8c1d60f44a831520f9af41c14216cf2", size = 5269248, upload-time = "2025-09-14T22:18:09.753Z" }, + { url = "https://files.pythonhosted.org/packages/1b/c0/59e912a531d91e1c192d3085fc0f6fb2852753c301a812d856d857ea03c6/zstandard-0.25.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f67e8f1a324a900e75b5e28ffb152bcac9fbed1cc7b43f99cd90f395c4375344", size = 5430330, upload-time = "2025-09-14T22:18:11.966Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/7e31db1240de2df22a58e2ea9a93fc6e38cc29353e660c0272b6735d6669/zstandard-0.25.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9654dbc012d8b06fc3d19cc825af3f7bf8ae242226df5f83936cb39f5fdc846c", size = 5811123, upload-time = "2025-09-14T22:18:13.907Z" }, + { url = "https://files.pythonhosted.org/packages/f6/49/fac46df5ad353d50535e118d6983069df68ca5908d4d65b8c466150a4ff1/zstandard-0.25.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4203ce3b31aec23012d3a4cf4a2ed64d12fea5269c49aed5e4c3611b938e4088", size = 5359591, upload-time = "2025-09-14T22:18:16.465Z" }, + { url = "https://files.pythonhosted.org/packages/c2/38/f249a2050ad1eea0bb364046153942e34abba95dd5520af199aed86fbb49/zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12", size = 444513, upload-time = "2025-09-14T22:18:20.61Z" }, + { url = "https://files.pythonhosted.org/packages/3a/43/241f9615bcf8ba8903b3f0432da069e857fc4fd1783bd26183db53c4804b/zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2", size = 516118, upload-time = "2025-09-14T22:18:17.849Z" }, + { url = "https://files.pythonhosted.org/packages/f0/ef/da163ce2450ed4febf6467d77ccb4cd52c4c30ab45624bad26ca0a27260c/zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d", size = 476940, upload-time = "2025-09-14T22:18:19.088Z" }, +] From f9870bc9aefeb271927ffd5ad558b22e416793ef Mon Sep 17 00:00:00 2001 From: William FH <13333726+hinthornw@users.noreply.github.com> Date: Tue, 10 Feb 2026 15:11:24 -0800 Subject: [PATCH 03/41] chore: Drop support for bullseye builds (#6779) It's EOL for debian. --- libs/cli/langgraph_cli/__init__.py | 2 +- libs/cli/langgraph_cli/config.py | 7 +++++- libs/cli/langgraph_cli/schemas.py | 4 ++-- libs/cli/schemas/schema.json | 5 ++--- libs/cli/schemas/schema.v0.json | 5 ++--- libs/cli/tests/unit_tests/test_config.py | 27 +++++++++++++++++------- 6 files changed, 32 insertions(+), 18 deletions(-) diff --git a/libs/cli/langgraph_cli/__init__.py b/libs/cli/langgraph_cli/__init__.py index 9b084a609..4b2ce7df3 100644 --- a/libs/cli/langgraph_cli/__init__.py +++ b/libs/cli/langgraph_cli/__init__.py @@ -1 +1 @@ -__version__ = "0.4.12" +__version__ = "0.4.13" diff --git a/libs/cli/langgraph_cli/config.py b/libs/cli/langgraph_cli/config.py index 393f54f6d..c21402eea 100644 --- a/libs/cli/langgraph_cli/config.py +++ b/libs/cli/langgraph_cli/config.py @@ -210,10 +210,15 @@ def validate_config(config: Config) -> Config: # Validate image_distro config if image_distro := config.get("image_distro"): + if image_distro == "bullseye": + raise click.UsageError( + "Bullseye images were deprecated in version 0.4.13. " + "Please use 'bookworm' or 'debian' instead." + ) if image_distro not in Distros.__args__: raise click.UsageError( f"Invalid image_distro: '{image_distro}'. " - "Must be one of 'debian', 'bullseye', or 'bookworm'." + "Must be one of 'debian', 'wolfi', or 'bookworm'." ) if pip_installer := config.get("pip_installer"): diff --git a/libs/cli/langgraph_cli/schemas.py b/libs/cli/langgraph_cli/schemas.py index fb517becd..8b460e6ee 100644 --- a/libs/cli/langgraph_cli/schemas.py +++ b/libs/cli/langgraph_cli/schemas.py @@ -1,6 +1,6 @@ from typing import Any, Literal, TypedDict -Distros = Literal["debian", "wolfi", "bullseye", "bookworm"] +Distros = Literal["debian", "wolfi", "bookworm"] MiddlewareOrders = Literal["auth_first", "middleware_first"] @@ -559,7 +559,7 @@ class Config(TypedDict, total=False): image_distro: Distros | None """Optional. Linux distribution for the base image. - Must be one of 'wolfi', 'debian', 'bullseye', or 'bookworm'. + Must be one of 'wolfi', 'debian', or 'bookworm'. If omitted, defaults to 'debian' ('latest'). """ diff --git a/libs/cli/schemas/schema.json b/libs/cli/schemas/schema.json index e4f31bb4d..c9b774861 100644 --- a/libs/cli/schemas/schema.json +++ b/libs/cli/schemas/schema.json @@ -147,7 +147,6 @@ { "enum": [ "bookworm", - "bullseye", "debian", "wolfi" ] @@ -156,7 +155,7 @@ "type": "null" } ], - "description": "Optional. Linux distribution for the base image.\n\nMust be one of 'wolfi', 'debian', 'bullseye', or 'bookworm'.\nIf omitted, defaults to 'debian' ('latest').\n" + "description": "Optional. Linux distribution for the base image.\n\nMust be one of 'wolfi', 'debian', or 'bookworm'.\nIf omitted, defaults to 'debian' ('latest').\n" }, "keep_pkg_tools": { "anyOf": [ @@ -370,7 +369,7 @@ "type": "null" } ], - "description": "Optional. Linux distribution for the base image.\n\nMust be one of 'wolfi', 'debian', 'bullseye', or 'bookworm'.\nIf omitted, defaults to 'debian' ('latest').\n" + "description": "Optional. Linux distribution for the base image.\n\nMust be one of 'wolfi', 'debian', or 'bookworm'.\nIf omitted, defaults to 'debian' ('latest').\n" }, "keep_pkg_tools": { "anyOf": [ diff --git a/libs/cli/schemas/schema.v0.json b/libs/cli/schemas/schema.v0.json index e4f31bb4d..c9b774861 100644 --- a/libs/cli/schemas/schema.v0.json +++ b/libs/cli/schemas/schema.v0.json @@ -147,7 +147,6 @@ { "enum": [ "bookworm", - "bullseye", "debian", "wolfi" ] @@ -156,7 +155,7 @@ "type": "null" } ], - "description": "Optional. Linux distribution for the base image.\n\nMust be one of 'wolfi', 'debian', 'bullseye', or 'bookworm'.\nIf omitted, defaults to 'debian' ('latest').\n" + "description": "Optional. Linux distribution for the base image.\n\nMust be one of 'wolfi', 'debian', or 'bookworm'.\nIf omitted, defaults to 'debian' ('latest').\n" }, "keep_pkg_tools": { "anyOf": [ @@ -370,7 +369,7 @@ "type": "null" } ], - "description": "Optional. Linux distribution for the base image.\n\nMust be one of 'wolfi', 'debian', 'bullseye', or 'bookworm'.\nIf omitted, defaults to 'debian' ('latest').\n" + "description": "Optional. Linux distribution for the base image.\n\nMust be one of 'wolfi', 'debian', or 'bookworm'.\nIf omitted, defaults to 'debian' ('latest').\n" }, "keep_pkg_tools": { "anyOf": [ diff --git a/libs/cli/tests/unit_tests/test_config.py b/libs/cli/tests/unit_tests/test_config.py index 566ba272f..eecc887ed 100644 --- a/libs/cli/tests/unit_tests/test_config.py +++ b/libs/cli/tests/unit_tests/test_config.py @@ -120,14 +120,14 @@ def test_validate_config(): validate_config({"python_version": "3.10"}) assert "Minimum required version" in str(exc_info.value) - config = validate_config( - { - "python_version": "3.11-bullseye", - "dependencies": ["."], - "graphs": {"agent": "./agent.py:graph"}, - } - ) - assert config["python_version"] == "3.11-bullseye" + with pytest.raises(click.UsageError, match="Bullseye images were deprecated"): + validate_config( + { + "python_version": "3.11-bullseye", + "dependencies": ["."], + "graphs": {"agent": "./agent.py:graph"}, + } + ) config = validate_config( { @@ -181,6 +181,17 @@ def test_validate_config_image_distro(): ) assert config["image_distro"] == "debian" + # Bullseye should raise deprecation error + with pytest.raises(click.UsageError, match="Bullseye images were deprecated"): + validate_config( + { + "python_version": "3.11", + "dependencies": ["."], + "graphs": {"agent": "./agent.py:graph"}, + "image_distro": "bullseye", + } + ) + # Invalid image_distro values should raise error with pytest.raises(click.UsageError) as exc_info: validate_config( From f5e56e200d373e0036fb8e6c4a334c07c478f2e4 Mon Sep 17 00:00:00 2001 From: William FH <13333726+hinthornw@users.noreply.github.com> Date: Wed, 11 Feb 2026 19:00:48 -0800 Subject: [PATCH 04/41] feat(cli): add keep_latest prune strategy to ThreadTTLConfig (#6784) ## Summary - Add `"keep_latest"` to `ThreadTTLConfig.strategy` to match langgraph-api support for pruning old checkpoints while retaining the thread and its latest state - Add `sweep_limit` to `ThreadTTLConfig` where the API actually reads it (was previously a no-op on `CheckpointerConfig`) - Regenerate `schema.json` / `schema.v0.json` ## Test plan - [x] `make format && make lint` passes - [x] `make test` passes (85/85) --------- Co-authored-by: Claude Opus 4.6 --- .github/scripts/run_langgraph_cli_test.py | 4 +-- .github/workflows/_integration_test.yml | 4 +-- .../deps/additional_deps/pyproject.toml | 2 +- .../graph_prerelease_reqs/pyproject.toml | 2 +- libs/cli/langgraph_cli/config.py | 5 ++++ libs/cli/langgraph_cli/schemas.py | 16 +++++------ libs/cli/schemas/schema.json | 27 ++++++++++--------- libs/cli/schemas/schema.v0.json | 27 ++++++++++--------- 8 files changed, 47 insertions(+), 40 deletions(-) diff --git a/.github/scripts/run_langgraph_cli_test.py b/.github/scripts/run_langgraph_cli_test.py index cdead9c6d..e296ba7d5 100644 --- a/.github/scripts/run_langgraph_cli_test.py +++ b/.github/scripts/run_langgraph_cli_test.py @@ -63,7 +63,7 @@ def test(config: pathlib.Path, port: int, tag: str, verbose: bool): try: sys.stderr.write("\n== docker compose ps ==\n") runner.run( - subp_exec(*compose_cmd, *args, "ps", input=stdin, verbose=False) + subp_exec(*compose_cmd, *args, "ps", input=stdin, verbose=True) ) except Exception: pass @@ -76,7 +76,7 @@ def test(config: pathlib.Path, port: int, tag: str, verbose: bool): "logs", "langgraph-api", input=stdin, - verbose=False, + verbose=True, ) ) except Exception: diff --git a/.github/workflows/_integration_test.yml b/.github/workflows/_integration_test.yml index 3be88dae0..352f58511 100644 --- a/.github/workflows/_integration_test.yml +++ b/.github/workflows/_integration_test.yml @@ -96,8 +96,8 @@ jobs: timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-h echo "Finished starting up langgraph-test-h" LANGGRAPH_VERSION=$(docker run --rm --entrypoint "" langgraph-test-h python -c "import sys; from importlib.metadata import version; v = version('langgraph'); print(v);") - if [ "$LANGGRAPH_VERSION" != "1.0.2" ]; then - echo "LANGGRAPH_VERSION != 1.0.2; $LANGGRAPH_VERSION" + if [ "$LANGGRAPH_VERSION" != "1.0.8" ]; then + echo "LANGGRAPH_VERSION != 1.0.8; $LANGGRAPH_VERSION" exit 1 fi LANGCHAIN_OPENAI_VERSION=$(docker run --rm --entrypoint "" langgraph-test-h python -c "import sys; from importlib.metadata import version; v = version('langchain-openai'); print(v);") diff --git a/libs/cli/examples/graph_prerelease_reqs/deps/additional_deps/pyproject.toml b/libs/cli/examples/graph_prerelease_reqs/deps/additional_deps/pyproject.toml index c68fdf561..4df335816 100644 --- a/libs/cli/examples/graph_prerelease_reqs/deps/additional_deps/pyproject.toml +++ b/libs/cli/examples/graph_prerelease_reqs/deps/additional_deps/pyproject.toml @@ -5,5 +5,5 @@ description = "Test for prerelease stuff" readme = "README.md" requires-python = ">=3.10" dependencies = [ - "langgraph==1.0.2" + "langgraph==1.0.8" ] \ No newline at end of file diff --git a/libs/cli/examples/graph_prerelease_reqs/pyproject.toml b/libs/cli/examples/graph_prerelease_reqs/pyproject.toml index b0c1ab59a..a548185d0 100644 --- a/libs/cli/examples/graph_prerelease_reqs/pyproject.toml +++ b/libs/cli/examples/graph_prerelease_reqs/pyproject.toml @@ -7,7 +7,7 @@ requires-python = ">=3.10" dependencies = [ "langchain-openai==1.0.0a2", "langchain-anthropic==1.0.0a5", - "langgraph==1.0.2" + "langgraph==1.0.8" ] [tool.uv] diff --git a/libs/cli/langgraph_cli/config.py b/libs/cli/langgraph_cli/config.py index c21402eea..0e80b1e33 100644 --- a/libs/cli/langgraph_cli/config.py +++ b/libs/cli/langgraph_cli/config.py @@ -196,6 +196,11 @@ def validate_config(config: Config) -> Config: f"Python version {pyversion} is not supported. " f"Minimum required version is {MIN_PYTHON_VERSION}." ) + if "bullseye" in pyversion: + raise click.UsageError( + "Bullseye images were deprecated in version 0.4.13. " + "Please use 'bookworm' or 'debian' instead." + ) if not config["dependencies"]: raise click.UsageError( diff --git a/libs/cli/langgraph_cli/schemas.py b/libs/cli/langgraph_cli/schemas.py index 8b460e6ee..e87692dc1 100644 --- a/libs/cli/langgraph_cli/schemas.py +++ b/libs/cli/langgraph_cli/schemas.py @@ -107,17 +107,19 @@ class StoreConfig(TypedDict, total=False): class ThreadTTLConfig(TypedDict, total=False): """Configure a default TTL for checkpointed data within threads.""" - strategy: Literal["delete"] - """Strategy to use for deleting checkpointed data. - - Choices: - - "delete": Delete all checkpoints for a thread after TTL expires. + strategy: Literal["delete", "keep_latest"] + """Action taken when a thread exceeds its TTL. + + - "delete": Remove the thread and all its data entirely. + - "keep_latest": Prune old checkpoints but keep the thread and its latest state. """ default_ttl: float | None """Default TTL (time-to-live) in minutes for checkpointed data.""" sweep_interval_minutes: int | None """Interval in minutes between sweep iterations. If omitted, a default interval will be used (typically ~ 5 minutes).""" + sweep_limit: int | None + """Maximum number of threads to process per sweep iteration. Defaults to 1000.""" class SerdeConfig(TypedDict, total=False): @@ -173,14 +175,12 @@ class CheckpointerConfig(TypedDict, total=False): """ serde: SerdeConfig | None """Optional. Defines the serde configuration. - + If provided, the checkpointer will apply serde settings according to the configuration. If omitted, no serde behavior is configured. This configuration requires server version 0.5 or later to take effect. """ - sweep_limit: int | None - """Maximum number of threads to process per sweep iteration. Defaults to 1000.""" class SecurityConfig(TypedDict, total=False): diff --git a/libs/cli/schemas/schema.json b/libs/cli/schemas/schema.json index c9b774861..2d0a9eba8 100644 --- a/libs/cli/schemas/schema.json +++ b/libs/cli/schemas/schema.json @@ -553,17 +553,6 @@ ], "description": "Optional. Defines the serde configuration.\n\nIf provided, the checkpointer will apply serde settings according to the configuration.\nIf omitted, no serde behavior is configured.\n\nThis configuration requires server version 0.5 or later to take effect.\n" }, - "sweep_limit": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Maximum number of threads to process per sweep iteration. Defaults to 1000." - }, "ttl": { "anyOf": [ { @@ -628,9 +617,10 @@ }, "strategy": { "enum": [ - "delete" + "delete", + "keep_latest" ], - "description": "Strategy to use for deleting checkpointed data.\n" + "description": "Action taken when a thread exceeds its TTL.\n\n" }, "sweep_interval_minutes": { "anyOf": [ @@ -642,6 +632,17 @@ } ], "description": "Interval in minutes between sweep iterations.\nIf omitted, a default interval will be used (typically ~ 5 minutes)." + }, + "sweep_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Maximum number of threads to process per sweep iteration. Defaults to 1000." } }, "required": [] diff --git a/libs/cli/schemas/schema.v0.json b/libs/cli/schemas/schema.v0.json index c9b774861..2d0a9eba8 100644 --- a/libs/cli/schemas/schema.v0.json +++ b/libs/cli/schemas/schema.v0.json @@ -553,17 +553,6 @@ ], "description": "Optional. Defines the serde configuration.\n\nIf provided, the checkpointer will apply serde settings according to the configuration.\nIf omitted, no serde behavior is configured.\n\nThis configuration requires server version 0.5 or later to take effect.\n" }, - "sweep_limit": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "description": "Maximum number of threads to process per sweep iteration. Defaults to 1000." - }, "ttl": { "anyOf": [ { @@ -628,9 +617,10 @@ }, "strategy": { "enum": [ - "delete" + "delete", + "keep_latest" ], - "description": "Strategy to use for deleting checkpointed data.\n" + "description": "Action taken when a thread exceeds its TTL.\n\n" }, "sweep_interval_minutes": { "anyOf": [ @@ -642,6 +632,17 @@ } ], "description": "Interval in minutes between sweep iterations.\nIf omitted, a default interval will be used (typically ~ 5 minutes)." + }, + "sweep_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Maximum number of threads to process per sweep iteration. Defaults to 1000." } }, "required": [] From 9f0ae94f27af04cd1b2d413db960b383f7a365c9 Mon Sep 17 00:00:00 2001 From: William FH <13333726+hinthornw@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:22:59 -0800 Subject: [PATCH 05/41] chore: Re-organize client files. (#6787) Additional guidelines: - Make sure optional dependencies are imported within a function. - Please do not add dependencies to `pyproject.toml` files (even optional ones) unless they are **required** for unit tests. - Most PRs should not touch more than one package. - Changes should be backwards compatible. --------- Co-authored-by: Claude Opus 4.6 --- libs/sdk-py/langgraph_sdk/_async/__init__.py | 20 + .../sdk-py/langgraph_sdk/_async/assistants.py | 722 ++ libs/sdk-py/langgraph_sdk/_async/client.py | 178 + libs/sdk-py/langgraph_sdk/_async/cron.py | 452 ++ libs/sdk-py/langgraph_sdk/_async/http.py | 305 + libs/sdk-py/langgraph_sdk/_async/runs.py | 1017 +++ libs/sdk-py/langgraph_sdk/_async/store.py | 313 + libs/sdk-py/langgraph_sdk/_async/threads.py | 671 ++ libs/sdk-py/langgraph_sdk/_shared/__init__.py | 1 + libs/sdk-py/langgraph_sdk/_shared/types.py | 10 + .../sdk-py/langgraph_sdk/_shared/utilities.py | 131 + libs/sdk-py/langgraph_sdk/_sync/__init__.py | 20 + libs/sdk-py/langgraph_sdk/_sync/assistants.py | 718 ++ libs/sdk-py/langgraph_sdk/_sync/client.py | 127 + libs/sdk-py/langgraph_sdk/_sync/cron.py | 439 + libs/sdk-py/langgraph_sdk/_sync/http.py | 296 + libs/sdk-py/langgraph_sdk/_sync/runs.py | 999 +++ libs/sdk-py/langgraph_sdk/_sync/store.py | 313 + libs/sdk-py/langgraph_sdk/_sync/threads.py | 654 ++ libs/sdk-py/langgraph_sdk/client.py | 7125 +---------------- libs/sdk-py/tests/test_client_exports.py | 91 + 21 files changed, 7521 insertions(+), 7081 deletions(-) create mode 100644 libs/sdk-py/langgraph_sdk/_async/__init__.py create mode 100644 libs/sdk-py/langgraph_sdk/_async/assistants.py create mode 100644 libs/sdk-py/langgraph_sdk/_async/client.py create mode 100644 libs/sdk-py/langgraph_sdk/_async/cron.py create mode 100644 libs/sdk-py/langgraph_sdk/_async/http.py create mode 100644 libs/sdk-py/langgraph_sdk/_async/runs.py create mode 100644 libs/sdk-py/langgraph_sdk/_async/store.py create mode 100644 libs/sdk-py/langgraph_sdk/_async/threads.py create mode 100644 libs/sdk-py/langgraph_sdk/_shared/__init__.py create mode 100644 libs/sdk-py/langgraph_sdk/_shared/types.py create mode 100644 libs/sdk-py/langgraph_sdk/_shared/utilities.py create mode 100644 libs/sdk-py/langgraph_sdk/_sync/__init__.py create mode 100644 libs/sdk-py/langgraph_sdk/_sync/assistants.py create mode 100644 libs/sdk-py/langgraph_sdk/_sync/client.py create mode 100644 libs/sdk-py/langgraph_sdk/_sync/cron.py create mode 100644 libs/sdk-py/langgraph_sdk/_sync/http.py create mode 100644 libs/sdk-py/langgraph_sdk/_sync/runs.py create mode 100644 libs/sdk-py/langgraph_sdk/_sync/store.py create mode 100644 libs/sdk-py/langgraph_sdk/_sync/threads.py create mode 100644 libs/sdk-py/tests/test_client_exports.py diff --git a/libs/sdk-py/langgraph_sdk/_async/__init__.py b/libs/sdk-py/langgraph_sdk/_async/__init__.py new file mode 100644 index 000000000..16bf0e4ff --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_async/__init__.py @@ -0,0 +1,20 @@ +"""Async client exports.""" + +from langgraph_sdk._async.assistants import AssistantsClient +from langgraph_sdk._async.client import LangGraphClient, get_client +from langgraph_sdk._async.cron import CronClient +from langgraph_sdk._async.http import HttpClient +from langgraph_sdk._async.runs import RunsClient +from langgraph_sdk._async.store import StoreClient +from langgraph_sdk._async.threads import ThreadsClient + +__all__ = [ + "AssistantsClient", + "CronClient", + "HttpClient", + "LangGraphClient", + "RunsClient", + "StoreClient", + "ThreadsClient", + "get_client", +] diff --git a/libs/sdk-py/langgraph_sdk/_async/assistants.py b/libs/sdk-py/langgraph_sdk/_async/assistants.py new file mode 100644 index 000000000..447535252 --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_async/assistants.py @@ -0,0 +1,722 @@ +"""Async client for managing assistants in LangGraph.""" + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, Literal, cast, overload + +import httpx + +from langgraph_sdk._async.http import HttpClient +from langgraph_sdk.schema import ( + Assistant, + AssistantSelectField, + AssistantSortBy, + AssistantsSearchResponse, + AssistantVersion, + Config, + Context, + GraphSchema, + Json, + OnConflictBehavior, + QueryParamTypes, + SortOrder, + Subgraphs, +) + + +class AssistantsClient: + """Client for managing assistants in LangGraph. + + This class provides methods to interact with assistants, + which are versioned configurations of your graph. + + ???+ example "Example" + + ```python + client = get_client(url="http://localhost:2024") + assistant = await client.assistants.get("assistant_id_123") + ``` + """ + + def __init__(self, http: HttpClient) -> None: + self.http = http + + async def get( + self, + assistant_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Assistant: + """Get an assistant by ID. + + Args: + assistant_id: The ID of the assistant to get. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + Assistant: Assistant Object. + + ???+ example "Example Usage" + + ```python + assistant = await client.assistants.get( + assistant_id="my_assistant_id" + ) + print(assistant) + ``` + + ```shell + ---------------------------------------------------- + + { + 'assistant_id': 'my_assistant_id', + 'graph_id': 'agent', + 'created_at': '2024-06-25T17:10:33.109781+00:00', + 'updated_at': '2024-06-25T17:10:33.109781+00:00', + 'config': {}, + 'metadata': {'created_by': 'system'}, + 'version': 1, + 'name': 'my_assistant' + } + ``` + """ + return await self.http.get( + f"/assistants/{assistant_id}", headers=headers, params=params + ) + + async def get_graph( + self, + assistant_id: str, + *, + xray: int | bool = False, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> dict[str, list[dict[str, Any]]]: + """Get the graph of an assistant by ID. + + Args: + assistant_id: The ID of the assistant to get the graph of. + xray: Include graph representation of subgraphs. If an integer value is provided, only subgraphs with a depth less than or equal to the value will be included. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + Graph: The graph information for the assistant in JSON format. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + graph_info = await client.assistants.get_graph( + assistant_id="my_assistant_id" + ) + print(graph_info) + ``` + + ```shell + + -------------------------------------------------------------------------------------------------------------------------- + + { + 'nodes': + [ + {'id': '__start__', 'type': 'schema', 'data': '__start__'}, + {'id': '__end__', 'type': 'schema', 'data': '__end__'}, + {'id': 'agent','type': 'runnable','data': {'id': ['langgraph', 'utils', 'RunnableCallable'],'name': 'agent'}}, + ], + 'edges': + [ + {'source': '__start__', 'target': 'agent'}, + {'source': 'agent','target': '__end__'} + ] + } + ``` + + + """ + query_params = {"xray": xray} + if params: + query_params.update(params) + + return await self.http.get( + f"/assistants/{assistant_id}/graph", params=query_params, headers=headers + ) + + async def get_schemas( + self, + assistant_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> GraphSchema: + """Get the schemas of an assistant by ID. + + Args: + assistant_id: The ID of the assistant to get the schema of. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + GraphSchema: The graph schema for the assistant. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + schema = await client.assistants.get_schemas( + assistant_id="my_assistant_id" + ) + print(schema) + ``` + + ```shell + + ---------------------------------------------------------------------------------------------------------------------------- + + { + 'graph_id': 'agent', + 'state_schema': + { + 'title': 'LangGraphInput', + '$ref': '#/definitions/AgentState', + 'definitions': + { + 'BaseMessage': + { + 'title': 'BaseMessage', + 'description': 'Base abstract Message class. Messages are the inputs and outputs of ChatModels.', + 'type': 'object', + 'properties': + { + 'content': + { + 'title': 'Content', + 'anyOf': [ + {'type': 'string'}, + {'type': 'array','items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}} + ] + }, + 'additional_kwargs': + { + 'title': 'Additional Kwargs', + 'type': 'object' + }, + 'response_metadata': + { + 'title': 'Response Metadata', + 'type': 'object' + }, + 'type': + { + 'title': 'Type', + 'type': 'string' + }, + 'name': + { + 'title': 'Name', + 'type': 'string' + }, + 'id': + { + 'title': 'Id', + 'type': 'string' + } + }, + 'required': ['content', 'type'] + }, + 'AgentState': + { + 'title': 'AgentState', + 'type': 'object', + 'properties': + { + 'messages': + { + 'title': 'Messages', + 'type': 'array', + 'items': {'$ref': '#/definitions/BaseMessage'} + } + }, + 'required': ['messages'] + } + } + }, + 'context_schema': + { + 'title': 'Context', + 'type': 'object', + 'properties': + { + 'model_name': + { + 'title': 'Model Name', + 'enum': ['anthropic', 'openai'], + 'type': 'string' + } + } + } + } + ``` + + """ + return await self.http.get( + f"/assistants/{assistant_id}/schemas", headers=headers, params=params + ) + + async def get_subgraphs( + self, + assistant_id: str, + namespace: str | None = None, + recurse: bool = False, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Subgraphs: + """Get the schemas of an assistant by ID. + + Args: + assistant_id: The ID of the assistant to get the schema of. + namespace: Optional namespace to filter by. + recurse: Whether to recursively get subgraphs. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + Subgraphs: The graph schema for the assistant. + + """ + get_params = {"recurse": recurse} + if params: + get_params = {**get_params, **params} + if namespace is not None: + return await self.http.get( + f"/assistants/{assistant_id}/subgraphs/{namespace}", + params=get_params, + headers=headers, + ) + else: + return await self.http.get( + f"/assistants/{assistant_id}/subgraphs", + params=get_params, + headers=headers, + ) + + async def create( + self, + graph_id: str | None, + config: Config | None = None, + *, + context: Context | None = None, + metadata: Json = None, + assistant_id: str | None = None, + if_exists: OnConflictBehavior | None = None, + name: str | None = None, + headers: Mapping[str, str] | None = None, + description: str | None = None, + params: QueryParamTypes | None = None, + ) -> Assistant: + """Create a new assistant. + + Useful when graph is configurable and you want to create different assistants based on different configurations. + + Args: + graph_id: The ID of the graph the assistant should use. The graph ID is normally set in your langgraph.json configuration. + config: Configuration to use for the graph. + metadata: Metadata to add to assistant. + context: Static context to add to the assistant. + !!! version-added "Added in version 0.6.0" + assistant_id: Assistant ID to use, will default to a random UUID if not provided. + if_exists: How to handle duplicate creation. Defaults to 'raise' under the hood. + Must be either 'raise' (raise error if duplicate), or 'do_nothing' (return existing assistant). + name: The name of the assistant. Defaults to 'Untitled' under the hood. + headers: Optional custom headers to include with the request. + description: Optional description of the assistant. + The description field is available for langgraph-api server version>=0.0.45 + params: Optional query parameters to include with the request. + + Returns: + Assistant: The created assistant. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + assistant = await client.assistants.create( + graph_id="agent", + context={"model_name": "openai"}, + metadata={"number":1}, + assistant_id="my-assistant-id", + if_exists="do_nothing", + name="my_name" + ) + ``` + """ + payload: dict[str, Any] = { + "graph_id": graph_id, + } + if config: + payload["config"] = config + if context: + payload["context"] = context + if metadata: + payload["metadata"] = metadata + if assistant_id: + payload["assistant_id"] = assistant_id + if if_exists: + payload["if_exists"] = if_exists + if name: + payload["name"] = name + if description: + payload["description"] = description + return await self.http.post( + "/assistants", json=payload, headers=headers, params=params + ) + + async def update( + self, + assistant_id: str, + *, + graph_id: str | None = None, + config: Config | None = None, + context: Context | None = None, + metadata: Json = None, + name: str | None = None, + headers: Mapping[str, str] | None = None, + description: str | None = None, + params: QueryParamTypes | None = None, + ) -> Assistant: + """Update an assistant. + + Use this to point to a different graph, update the configuration, or change the metadata of an assistant. + + Args: + assistant_id: Assistant to update. + graph_id: The ID of the graph the assistant should use. + The graph ID is normally set in your langgraph.json configuration. If `None`, assistant will keep pointing to same graph. + config: Configuration to use for the graph. + context: Static context to add to the assistant. + !!! version-added "Added in version 0.6.0" + metadata: Metadata to merge with existing assistant metadata. + name: The new name for the assistant. + headers: Optional custom headers to include with the request. + description: Optional description of the assistant. + The description field is available for langgraph-api server version>=0.0.45 + params: Optional query parameters to include with the request. + + Returns: + The updated assistant. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + assistant = await client.assistants.update( + assistant_id='e280dad7-8618-443f-87f1-8e41841c180f', + graph_id="other-graph", + context={"model_name": "anthropic"}, + metadata={"number":2} + ) + ``` + + """ + payload: dict[str, Any] = {} + if graph_id: + payload["graph_id"] = graph_id + if config: + payload["config"] = config + if context: + payload["context"] = context + if metadata: + payload["metadata"] = metadata + if name: + payload["name"] = name + if description: + payload["description"] = description + return await self.http.patch( + f"/assistants/{assistant_id}", + json=payload, + headers=headers, + params=params, + ) + + async def delete( + self, + assistant_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Delete an assistant. + + Args: + assistant_id: The assistant ID to delete. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + await client.assistants.delete( + assistant_id="my_assistant_id" + ) + ``` + + """ + await self.http.delete( + f"/assistants/{assistant_id}", headers=headers, params=params + ) + + @overload + async def search( + self, + *, + metadata: Json = None, + graph_id: str | None = None, + name: str | None = None, + limit: int = 10, + offset: int = 0, + sort_by: AssistantSortBy | None = None, + sort_order: SortOrder | None = None, + select: list[AssistantSelectField] | None = None, + response_format: Literal["object"], + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> AssistantsSearchResponse: ... + + @overload + async def search( + self, + *, + metadata: Json = None, + graph_id: str | None = None, + name: str | None = None, + limit: int = 10, + offset: int = 0, + sort_by: AssistantSortBy | None = None, + sort_order: SortOrder | None = None, + select: list[AssistantSelectField] | None = None, + response_format: Literal["array"] = "array", + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> list[Assistant]: ... + + async def search( + self, + *, + metadata: Json = None, + graph_id: str | None = None, + name: str | None = None, + limit: int = 10, + offset: int = 0, + sort_by: AssistantSortBy | None = None, + sort_order: SortOrder | None = None, + select: list[AssistantSelectField] | None = None, + response_format: Literal["array", "object"] = "array", + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> AssistantsSearchResponse | list[Assistant]: + """Search for assistants. + + Args: + metadata: Metadata to filter by. Exact match filter for each KV pair. + graph_id: The ID of the graph to filter by. + The graph ID is normally set in your langgraph.json configuration. + name: The name of the assistant to filter by. + The filtering logic will match assistants where 'name' is a substring (case insensitive) of the assistant name. + limit: The maximum number of results to return. + offset: The number of results to skip. + sort_by: The field to sort by. + sort_order: The order to sort by. + select: Specific assistant fields to include in the response. + response_format: Controls the response shape. Use `"array"` (default) + to return a bare list of assistants, or `"object"` to return + a mapping containing assistants plus pagination metadata. + Defaults to "array", though this default will be changed to "object" in a future release. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + A list of assistants (when `response_format="array"`) or a mapping + with the assistants and the next pagination cursor (when + `response_format="object"`). + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + response = await client.assistants.search( + metadata = {"name":"my_name"}, + graph_id="my_graph_id", + limit=5, + offset=5, + response_format="object" + ) + next_cursor = response["next"] + assistants = response["assistants"] + ``` + """ + if response_format not in ("array", "object"): + raise ValueError( + f"response_format must be 'array' or 'object', got {response_format!r}" + ) + payload: dict[str, Any] = { + "limit": limit, + "offset": offset, + } + if metadata: + payload["metadata"] = metadata + if graph_id: + payload["graph_id"] = graph_id + if name: + payload["name"] = name + if sort_by: + payload["sort_by"] = sort_by + if sort_order: + payload["sort_order"] = sort_order + if select: + payload["select"] = select + next_cursor: str | None = None + + def capture_pagination(response: httpx.Response) -> None: + nonlocal next_cursor + next_cursor = response.headers.get("X-Pagination-Next") + + assistants = cast( + list[Assistant], + await self.http.post( + "/assistants/search", + json=payload, + headers=headers, + params=params, + on_response=capture_pagination if response_format == "object" else None, + ), + ) + if response_format == "object": + return {"assistants": assistants, "next": next_cursor} + return assistants + + async def count( + self, + *, + metadata: Json = None, + graph_id: str | None = None, + name: str | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> int: + """Count assistants matching filters. + + Args: + metadata: Metadata to filter by. Exact match for each key/value. + graph_id: Optional graph id to filter by. + name: Optional name to filter by. + The filtering logic will match assistants where 'name' is a substring (case insensitive) of the assistant name. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + int: Number of assistants matching the criteria. + """ + payload: dict[str, Any] = {} + if metadata: + payload["metadata"] = metadata + if graph_id: + payload["graph_id"] = graph_id + if name: + payload["name"] = name + return await self.http.post( + "/assistants/count", json=payload, headers=headers, params=params + ) + + async def get_versions( + self, + assistant_id: str, + metadata: Json = None, + limit: int = 10, + offset: int = 0, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> list[AssistantVersion]: + """List all versions of an assistant. + + Args: + assistant_id: The assistant ID to get versions for. + metadata: Metadata to filter versions by. Exact match filter for each KV pair. + limit: The maximum number of versions to return. + offset: The number of versions to skip. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + A list of assistant versions. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + assistant_versions = await client.assistants.get_versions( + assistant_id="my_assistant_id" + ) + ``` + """ + + payload: dict[str, Any] = { + "limit": limit, + "offset": offset, + } + if metadata: + payload["metadata"] = metadata + return await self.http.post( + f"/assistants/{assistant_id}/versions", + json=payload, + headers=headers, + params=params, + ) + + async def set_latest( + self, + assistant_id: str, + version: int, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Assistant: + """Change the version of an assistant. + + Args: + assistant_id: The assistant ID to delete. + version: The version to change to. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + Assistant Object. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + new_version_assistant = await client.assistants.set_latest( + assistant_id="my_assistant_id", + version=3 + ) + ``` + + """ + + payload: dict[str, Any] = {"version": version} + + return await self.http.post( + f"/assistants/{assistant_id}/latest", + json=payload, + headers=headers, + params=params, + ) diff --git a/libs/sdk-py/langgraph_sdk/_async/client.py b/libs/sdk-py/langgraph_sdk/_async/client.py new file mode 100644 index 000000000..5d7e494da --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_async/client.py @@ -0,0 +1,178 @@ +"""Async LangGraph client.""" + +from __future__ import annotations + +import logging +import os +from collections.abc import Mapping +from types import TracebackType + +import httpx + +from langgraph_sdk._async.assistants import AssistantsClient +from langgraph_sdk._async.cron import CronClient +from langgraph_sdk._async.http import HttpClient +from langgraph_sdk._async.runs import RunsClient +from langgraph_sdk._async.store import StoreClient +from langgraph_sdk._async.threads import ThreadsClient +from langgraph_sdk._shared.types import TimeoutTypes +from langgraph_sdk._shared.utilities import ( + NOT_PROVIDED, + _get_headers, + _registered_transports, + get_asgi_transport, +) + +logger = logging.getLogger(__name__) + + +def get_client( + *, + url: str | None = None, + api_key: str | None = NOT_PROVIDED, + headers: Mapping[str, str] | None = None, + timeout: TimeoutTypes | None = None, +) -> LangGraphClient: + """Create and configure a LangGraphClient. + + The client provides programmatic access to LangSmith Deployment. It supports + both remote servers and local in-process connections (when running inside a LangGraph server). + + Args: + url: + Base URL of the LangGraph API. + - If `None`, the client first attempts an in-process connection via ASGI transport. + If that fails, it defers registration until after app initialization. This + only works if the client is used from within the Agent server. + api_key: + API key for authentication. Can be: + - A string: use this exact API key + - `None`: explicitly skip loading from environment variables + - Not provided (default): auto-load from environment in this order: + 1. `LANGGRAPH_API_KEY` + 2. `LANGSMITH_API_KEY` + 3. `LANGCHAIN_API_KEY` + headers: + Additional HTTP headers to include in requests. Merged with authentication headers. + timeout: + HTTP timeout configuration. May be: + - `httpx.Timeout` instance + - float (total seconds) + - tuple `(connect, read, write, pool)` in seconds + Defaults: connect=5, read=300, write=300, pool=5. + + Returns: + LangGraphClient: + A top-level client exposing sub-clients for assistants, threads, + runs, and cron operations. + + ???+ example "Connect to a remote server:" + + ```python + from langgraph_sdk import get_client + + # get top-level LangGraphClient + client = get_client(url="http://localhost:8123") + + # example usage: client..() + assistants = await client.assistants.get(assistant_id="some_uuid") + ``` + + ???+ example "Connect in-process to a running LangGraph server:" + + ```python + from langgraph_sdk import get_client + + client = get_client(url=None) + + async def my_node(...): + subagent_result = await client.runs.wait( + thread_id=None, + assistant_id="agent", + input={"messages": [{"role": "user", "content": "Foo"}]}, + ) + ``` + + ???+ example "Skip auto-loading API key from environment:" + + ```python + from langgraph_sdk import get_client + + # Don't load API key from environment variables + client = get_client( + url="http://localhost:8123", + api_key=None + ) + ``` + """ + + transport: httpx.AsyncBaseTransport | None = None + if url is None: + url = "http://api" + if os.environ.get("__LANGGRAPH_DEFER_LOOPBACK_TRANSPORT") == "true": + transport = get_asgi_transport()(app=None, root_path="/noauth") + _registered_transports.append(transport) + else: + try: + from langgraph_api.server import app # type: ignore + + transport = get_asgi_transport()(app, root_path="/noauth") + except Exception: + logger.debug( + "Failed to connect to in-process LangGraph server. Deferring configuration.", + exc_info=True, + ) + transport = get_asgi_transport()(app=None, root_path="/noauth") + _registered_transports.append(transport) + + if transport is None: + transport = httpx.AsyncHTTPTransport(retries=5) + client = httpx.AsyncClient( + base_url=url, + transport=transport, + timeout=( + httpx.Timeout(timeout) # type: ignore[arg-type] + if timeout is not None + else httpx.Timeout(connect=5, read=300, write=300, pool=5) + ), + headers=_get_headers(api_key, headers), + ) + return LangGraphClient(client) + + +class LangGraphClient: + """Top-level client for LangGraph API. + + Attributes: + assistants: Manages versioned configuration for your graphs. + threads: Handles (potentially) multi-turn interactions, such as conversational threads. + runs: Controls individual invocations of the graph. + crons: Manages scheduled operations. + store: Interfaces with persistent, shared data storage. + """ + + def __init__(self, client: httpx.AsyncClient) -> None: + self.http = HttpClient(client) + self.assistants = AssistantsClient(self.http) + self.threads = ThreadsClient(self.http) + self.runs = RunsClient(self.http) + self.crons = CronClient(self.http) + self.store = StoreClient(self.http) + + async def __aenter__(self) -> LangGraphClient: + """Enter the async context manager.""" + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + """Exit the async context manager.""" + await self.aclose() + + async def aclose(self) -> None: + """Close the underlying HTTP client.""" + if hasattr(self, "http"): + await self.http.client.aclose() diff --git a/libs/sdk-py/langgraph_sdk/_async/cron.py b/libs/sdk-py/langgraph_sdk/_async/cron.py new file mode 100644 index 000000000..808980366 --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_async/cron.py @@ -0,0 +1,452 @@ +"""Async client for managing recurrent runs (cron jobs) in LangGraph.""" + +from __future__ import annotations + +from collections.abc import Mapping +from datetime import datetime +from typing import Any + +from langgraph_sdk._async.http import HttpClient +from langgraph_sdk.schema import ( + All, + Config, + Context, + Cron, + CronSelectField, + CronSortBy, + Input, + OnCompletionBehavior, + QueryParamTypes, + Run, + SortOrder, +) + + +class CronClient: + """Client for managing recurrent runs (cron jobs) in LangGraph. + + A run is a single invocation of an assistant with optional input, config, and context. + This client allows scheduling recurring runs to occur automatically. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024")) + cron_job = await client.crons.create_for_thread( + thread_id="thread_123", + assistant_id="asst_456", + schedule="0 9 * * *", + input={"message": "Daily update"} + ) + ``` + + !!! note "Feature Availability" + + The crons client functionality is not supported on all licenses. + Please check the relevant license documentation for the most up-to-date + details on feature availability. + """ + + def __init__(self, http_client: HttpClient) -> None: + self.http = http_client + + async def create_for_thread( + self, + thread_id: str, + assistant_id: str, + *, + schedule: str, + input: Input | None = None, + metadata: Mapping[str, Any] | None = None, + config: Config | None = None, + context: Context | None = None, + checkpoint_during: bool | None = None, + interrupt_before: All | list[str] | None = None, + interrupt_after: All | list[str] | None = None, + webhook: str | None = None, + multitask_strategy: str | None = None, + end_time: datetime | None = None, + enabled: bool | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Run: + """Create a cron job for a thread. + + Args: + thread_id: the thread ID to run the cron job on. + assistant_id: The assistant ID or graph name to use for the cron job. + If using graph name, will default to first assistant created from that graph. + schedule: The cron schedule to execute this job on. + Schedules are interpreted in UTC. + input: The input to the graph. + metadata: Metadata to assign to the cron job runs. + config: The configuration for the assistant. + context: Static context to add to the assistant. + !!! version-added "Added in version 0.6.0" + checkpoint_during: Whether to checkpoint during the run (or only at the end/interruption). + interrupt_before: Nodes to interrupt immediately before they get executed. + + interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. + + webhook: Webhook to call after LangGraph API call is done. + multitask_strategy: Multitask strategy to use. + Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. + end_time: The time to stop running the cron job. If not provided, the cron job will run indefinitely. + enabled: Whether the cron job is enabled or not. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + The cron run. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + cron_run = await client.crons.create_for_thread( + thread_id="my-thread-id", + assistant_id="agent", + schedule="27 15 * * *", + input={"messages": [{"role": "user", "content": "hello!"}]}, + metadata={"name":"my_run"}, + context={"model_name": "openai"}, + interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], + interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], + webhook="https://my.fake.webhook.com", + multitask_strategy="interrupt", + enabled=True, + ) + ``` + """ + payload = { + "schedule": schedule, + "input": input, + "config": config, + "metadata": metadata, + "context": context, + "assistant_id": assistant_id, + "checkpoint_during": checkpoint_during, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "webhook": webhook, + "end_time": end_time.isoformat() if end_time else None, + "enabled": enabled, + } + if multitask_strategy: + payload["multitask_strategy"] = multitask_strategy + payload = {k: v for k, v in payload.items() if v is not None} + return await self.http.post( + f"/threads/{thread_id}/runs/crons", + json=payload, + headers=headers, + params=params, + ) + + async def create( + self, + assistant_id: str, + *, + schedule: str, + input: Input | None = None, + metadata: Mapping[str, Any] | None = None, + config: Config | None = None, + context: Context | None = None, + checkpoint_during: bool | None = None, + interrupt_before: All | list[str] | None = None, + interrupt_after: All | list[str] | None = None, + webhook: str | None = None, + on_run_completed: OnCompletionBehavior | None = None, + multitask_strategy: str | None = None, + end_time: datetime | None = None, + enabled: bool | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Run: + """Create a cron run. + + Args: + assistant_id: The assistant ID or graph name to use for the cron job. + If using graph name, will default to first assistant created from that graph. + schedule: The cron schedule to execute this job on. + Schedules are interpreted in UTC. + input: The input to the graph. + metadata: Metadata to assign to the cron job runs. + config: The configuration for the assistant. + context: Static context to add to the assistant. + !!! version-added "Added in version 0.6.0" + checkpoint_during: Whether to checkpoint during the run (or only at the end/interruption). + interrupt_before: Nodes to interrupt immediately before they get executed. + interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. + webhook: Webhook to call after LangGraph API call is done. + on_run_completed: What to do with the thread after the run completes. + Must be one of 'delete' (default) or 'keep'. 'delete' removes the thread + after execution. 'keep' creates a new thread for each execution but does not + clean them up. Clients are responsible for cleaning up kept threads. + multitask_strategy: Multitask strategy to use. + Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. + end_time: The time to stop running the cron job. If not provided, the cron job will run indefinitely. + enabled: Whether the cron job is enabled or not. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + The cron run. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + cron_run = client.crons.create( + assistant_id="agent", + schedule="27 15 * * *", + input={"messages": [{"role": "user", "content": "hello!"}]}, + metadata={"name":"my_run"}, + context={"model_name": "openai"}, + interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], + interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], + webhook="https://my.fake.webhook.com", + multitask_strategy="interrupt", + enabled=True, + ) + ``` + + """ + payload = { + "schedule": schedule, + "input": input, + "config": config, + "metadata": metadata, + "context": context, + "assistant_id": assistant_id, + "checkpoint_during": checkpoint_during, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "webhook": webhook, + "on_run_completed": on_run_completed, + "end_time": end_time.isoformat() if end_time else None, + "enabled": enabled, + } + if multitask_strategy: + payload["multitask_strategy"] = multitask_strategy + payload = {k: v for k, v in payload.items() if v is not None} + return await self.http.post( + "/runs/crons", json=payload, headers=headers, params=params + ) + + async def delete( + self, + cron_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Delete a cron. + + Args: + cron_id: The cron ID to delete. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + await client.crons.delete( + cron_id="cron_to_delete" + ) + ``` + + """ + await self.http.delete(f"/runs/crons/{cron_id}", headers=headers, params=params) + + async def update( + self, + cron_id: str, + *, + schedule: str | None = None, + end_time: datetime | None = None, + input: Input | None = None, + metadata: Mapping[str, Any] | None = None, + config: Config | None = None, + context: Context | None = None, + webhook: str | None = None, + interrupt_before: All | list[str] | None = None, + interrupt_after: All | list[str] | None = None, + on_run_completed: OnCompletionBehavior | None = None, + enabled: bool | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Cron: + """Update a cron job by ID. + + Args: + cron_id: The cron ID to update. + schedule: The cron schedule to execute this job on. + Schedules are interpreted in UTC. + end_time: The end date to stop running the cron. + input: The input to the graph. + metadata: Metadata to assign to the cron job runs. + config: The configuration for the assistant. + context: Static context added to the assistant. + webhook: Webhook to call after LangGraph API call is done. + interrupt_before: Nodes to interrupt immediately before they get executed. + interrupt_after: Nodes to interrupt immediately after they get executed. + on_run_completed: What to do with the thread after the run completes. + Must be one of 'delete' or 'keep'. 'delete' removes the thread + after execution. 'keep' creates a new thread for each execution but does not + clean them up. + enabled: Enable or disable the cron job. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + The updated cron job. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + updated_cron = await client.crons.update( + cron_id="1ef3cefa-4c09-6926-96d0-3dc97fd5e39b", + schedule="0 10 * * *", + enabled=False, + ) + ``` + + """ + payload = { + "schedule": schedule, + "end_time": end_time.isoformat() if end_time else None, + "input": input, + "metadata": metadata, + "config": config, + "context": context, + "webhook": webhook, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "on_run_completed": on_run_completed, + "enabled": enabled, + } + payload = {k: v for k, v in payload.items() if v is not None} + return await self.http.patch( + f"/runs/crons/{cron_id}", + json=payload, + headers=headers, + params=params, + ) + + async def search( + self, + *, + assistant_id: str | None = None, + thread_id: str | None = None, + enabled: bool | None = None, + limit: int = 10, + offset: int = 0, + sort_by: CronSortBy | None = None, + sort_order: SortOrder | None = None, + select: list[CronSelectField] | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> list[Cron]: + """Get a list of cron jobs. + + Args: + assistant_id: The assistant ID or graph name to search for. + thread_id: the thread ID to search for. + enabled: The enabled status to search for. + limit: The maximum number of results to return. + offset: The number of results to skip. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + The list of cron jobs returned by the search, + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + cron_jobs = await client.crons.search( + assistant_id="my_assistant_id", + thread_id="my_thread_id", + enabled=True, + limit=5, + offset=5, + ) + print(cron_jobs) + ``` + ```shell + + ---------------------------------------------------------- + + [ + { + 'cron_id': '1ef3cefa-4c09-6926-96d0-3dc97fd5e39b', + 'assistant_id': 'my_assistant_id', + 'thread_id': 'my_thread_id', + 'user_id': None, + 'payload': + { + 'input': {'start_time': ''}, + 'schedule': '4 * * * *', + 'assistant_id': 'my_assistant_id' + }, + 'schedule': '4 * * * *', + 'next_run_date': '2024-07-25T17:04:00+00:00', + 'end_time': None, + 'created_at': '2024-07-08T06:02:23.073257+00:00', + 'updated_at': '2024-07-08T06:02:23.073257+00:00' + } + ] + ``` + + """ + payload = { + "assistant_id": assistant_id, + "thread_id": thread_id, + "enabled": enabled, + "limit": limit, + "offset": offset, + } + if sort_by: + payload["sort_by"] = sort_by + if sort_order: + payload["sort_order"] = sort_order + if select: + payload["select"] = select + payload = {k: v for k, v in payload.items() if v is not None} + return await self.http.post( + "/runs/crons/search", json=payload, headers=headers, params=params + ) + + async def count( + self, + *, + assistant_id: str | None = None, + thread_id: str | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> int: + """Count cron jobs matching filters. + + Args: + assistant_id: Assistant ID to filter by. + thread_id: Thread ID to filter by. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + int: Number of crons matching the criteria. + """ + payload: dict[str, Any] = {} + if assistant_id: + payload["assistant_id"] = assistant_id + if thread_id: + payload["thread_id"] = thread_id + return await self.http.post( + "/runs/crons/count", json=payload, headers=headers, params=params + ) diff --git a/libs/sdk-py/langgraph_sdk/_async/http.py b/libs/sdk-py/langgraph_sdk/_async/http.py new file mode 100644 index 000000000..48e224be0 --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_async/http.py @@ -0,0 +1,305 @@ +"""HTTP client for async operations.""" + +from __future__ import annotations + +import asyncio +import logging +import sys +import warnings +from collections.abc import AsyncIterator, Callable, Mapping +from typing import Any, cast + +import httpx +import orjson + +from langgraph_sdk._shared.utilities import _orjson_default +from langgraph_sdk.errors import _araise_for_status_typed +from langgraph_sdk.schema import QueryParamTypes, StreamPart +from langgraph_sdk.sse import SSEDecoder, aiter_lines_raw + +logger = logging.getLogger(__name__) + + +class HttpClient: + """Handle async requests to the LangGraph API. + + Adds additional error messaging & content handling above the + provided httpx client. + + Attributes: + client (httpx.AsyncClient): Underlying HTTPX async client. + """ + + def __init__(self, client: httpx.AsyncClient) -> None: + self.client = client + + async def get( + self, + path: str, + *, + params: QueryParamTypes | None = None, + headers: Mapping[str, str] | None = None, + on_response: Callable[[httpx.Response], None] | None = None, + ) -> Any: + """Send a `GET` request.""" + r = await self.client.get(path, params=params, headers=headers) + if on_response: + on_response(r) + await _araise_for_status_typed(r) + return await _adecode_json(r) + + async def post( + self, + path: str, + *, + json: dict[str, Any] | list | None, + params: QueryParamTypes | None = None, + headers: Mapping[str, str] | None = None, + on_response: Callable[[httpx.Response], None] | None = None, + ) -> Any: + """Send a `POST` request.""" + if json is not None: + request_headers, content = await _aencode_json(json) + else: + request_headers, content = {}, b"" + # Merge headers, with runtime headers taking precedence + if headers: + request_headers.update(headers) + r = await self.client.post( + path, headers=request_headers, content=content, params=params + ) + if on_response: + on_response(r) + await _araise_for_status_typed(r) + return await _adecode_json(r) + + async def put( + self, + path: str, + *, + json: dict, + params: QueryParamTypes | None = None, + headers: Mapping[str, str] | None = None, + on_response: Callable[[httpx.Response], None] | None = None, + ) -> Any: + """Send a `PUT` request.""" + request_headers, content = await _aencode_json(json) + if headers: + request_headers.update(headers) + r = await self.client.put( + path, headers=request_headers, content=content, params=params + ) + if on_response: + on_response(r) + await _araise_for_status_typed(r) + return await _adecode_json(r) + + async def patch( + self, + path: str, + *, + json: dict, + params: QueryParamTypes | None = None, + headers: Mapping[str, str] | None = None, + on_response: Callable[[httpx.Response], None] | None = None, + ) -> Any: + """Send a `PATCH` request.""" + request_headers, content = await _aencode_json(json) + if headers: + request_headers.update(headers) + r = await self.client.patch( + path, headers=request_headers, content=content, params=params + ) + if on_response: + on_response(r) + await _araise_for_status_typed(r) + return await _adecode_json(r) + + async def delete( + self, + path: str, + *, + json: Any | None = None, + params: QueryParamTypes | None = None, + headers: Mapping[str, str] | None = None, + on_response: Callable[[httpx.Response], None] | None = None, + ) -> None: + """Send a `DELETE` request.""" + r = await self.client.request( + "DELETE", path, json=json, params=params, headers=headers + ) + if on_response: + on_response(r) + await _araise_for_status_typed(r) + + async def request_reconnect( + self, + path: str, + method: str, + *, + json: dict[str, Any] | None = None, + params: QueryParamTypes | None = None, + headers: Mapping[str, str] | None = None, + on_response: Callable[[httpx.Response], None] | None = None, + reconnect_limit: int = 5, + ) -> Any: + """Send a request that automatically reconnects to Location header.""" + request_headers, content = await _aencode_json(json) + if headers: + request_headers.update(headers) + async with self.client.stream( + method, path, headers=request_headers, content=content, params=params + ) as r: + if on_response: + on_response(r) + try: + r.raise_for_status() + except httpx.HTTPStatusError as e: + body = (await r.aread()).decode() + if sys.version_info >= (3, 11): + e.add_note(body) + else: + logger.error(f"Error from langgraph-api: {body}", exc_info=e) + raise e + loc = r.headers.get("location") + if reconnect_limit <= 0 or not loc: + return await _adecode_json(r) + try: + return await _adecode_json(r) + except httpx.HTTPError: + warnings.warn( + f"Request failed, attempting reconnect to Location: {loc}", + stacklevel=2, + ) + await r.aclose() + return await self.request_reconnect( + loc, + "GET", + headers=request_headers, + # don't pass on_response so it's only called once + reconnect_limit=reconnect_limit - 1, + ) + + async def stream( + self, + path: str, + method: str, + *, + json: dict[str, Any] | None = None, + params: QueryParamTypes | None = None, + headers: Mapping[str, str] | None = None, + on_response: Callable[[httpx.Response], None] | None = None, + ) -> AsyncIterator[StreamPart]: + """Stream results using SSE.""" + request_headers, content = await _aencode_json(json) + request_headers["Accept"] = "text/event-stream" + request_headers["Cache-Control"] = "no-store" + # Add runtime headers with precedence + if headers: + request_headers.update(headers) + + reconnect_headers = { + key: value + for key, value in request_headers.items() + if key.lower() not in {"content-length", "content-type"} + } + + last_event_id: str | None = None + reconnect_path: str | None = None + reconnect_attempts = 0 + max_reconnect_attempts = 5 + + while True: + current_headers = dict( + request_headers if reconnect_path is None else reconnect_headers + ) + if last_event_id is not None: + current_headers["Last-Event-ID"] = last_event_id + + current_method = method if reconnect_path is None else "GET" + current_content = content if reconnect_path is None else None + current_params = params if reconnect_path is None else None + + retry = False + async with self.client.stream( + current_method, + reconnect_path or path, + headers=current_headers, + content=current_content, + params=current_params, + ) as res: + if reconnect_path is None and on_response: + on_response(res) + # check status + await _araise_for_status_typed(res) + # check content type + content_type = res.headers.get("content-type", "").partition(";")[0] + if "text/event-stream" not in content_type: + raise httpx.TransportError( + "Expected response header Content-Type to contain 'text/event-stream', " + f"got {content_type!r}" + ) + + reconnect_location = res.headers.get("location") + if reconnect_location: + reconnect_path = reconnect_location + + # parse SSE + decoder = SSEDecoder() + try: + async for line in aiter_lines_raw(res): + sse = decoder.decode(line=cast("bytes", line).rstrip(b"\n")) + if sse is not None: + if decoder.last_event_id is not None: + last_event_id = decoder.last_event_id + if sse.event or sse.data is not None: + yield sse + except httpx.HTTPError: + # httpx.TransportError inherits from HTTPError, so transient + # disconnects during streaming land here. + if reconnect_path is None: + raise + retry = True + else: + if sse := decoder.decode(b""): + if decoder.last_event_id is not None: + last_event_id = decoder.last_event_id + if sse.event or sse.data is not None: + # decoder.decode(b"") flushes the in-flight event and may + # return an empty placeholder when there is no pending + # message. Skip these no-op events so the stream doesn't + # emit a trailing blank item after reconnects. + yield sse + if retry: + reconnect_attempts += 1 + if reconnect_attempts > max_reconnect_attempts: + raise httpx.TransportError( + "Exceeded maximum SSE reconnection attempts" + ) + continue + break + + +async def _aencode_json(json: Any) -> tuple[dict[str, str], bytes | None]: + if json is None: + return {}, None + body = await asyncio.get_running_loop().run_in_executor( + None, + orjson.dumps, + json, + _orjson_default, + orjson.OPT_SERIALIZE_NUMPY | orjson.OPT_NON_STR_KEYS, + ) + content_length = str(len(body)) + content_type = "application/json" + headers = {"Content-Length": content_length, "Content-Type": content_type} + return headers, body + + +async def _adecode_json(r: httpx.Response) -> Any: + body = await r.aread() + return ( + await asyncio.get_running_loop().run_in_executor(None, orjson.loads, body) + if body + else None + ) diff --git a/libs/sdk-py/langgraph_sdk/_async/runs.py b/libs/sdk-py/langgraph_sdk/_async/runs.py new file mode 100644 index 000000000..1b02c2555 --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_async/runs.py @@ -0,0 +1,1017 @@ +"""Async client for managing runs in LangGraph.""" + +from __future__ import annotations + +import warnings +from collections.abc import AsyncIterator, Callable, Mapping, Sequence +from typing import Any, overload + +import httpx + +from langgraph_sdk._async.http import HttpClient +from langgraph_sdk._shared.utilities import _get_run_metadata_from_response +from langgraph_sdk.schema import ( + All, + CancelAction, + Checkpoint, + Command, + Config, + Context, + DisconnectMode, + Durability, + IfNotExists, + Input, + MultitaskStrategy, + OnCompletionBehavior, + QueryParamTypes, + Run, + RunCreate, + RunCreateMetadata, + RunSelectField, + RunStatus, + StreamMode, + StreamPart, +) + + +class RunsClient: + """Client for managing runs in LangGraph. + + A run is a single assistant invocation with optional input, config, context, and metadata. + This client manages runs, which can be stateful (on threads) or stateless. + + ???+ example "Example" + + ```python + client = get_client(url="http://localhost:2024") + run = await client.runs.create(assistant_id="asst_123", thread_id="thread_456", input={"query": "Hello"}) + ``` + """ + + def __init__(self, http: HttpClient) -> None: + self.http = http + + @overload + def stream( + self, + thread_id: str, + assistant_id: str, + *, + input: Input | None = None, + 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, + checkpoint: Checkpoint | None = None, + checkpoint_id: str | None = None, + checkpoint_during: bool | None = None, + interrupt_before: All | Sequence[str] | None = None, + interrupt_after: All | Sequence[str] | None = None, + feedback_keys: Sequence[str] | None = None, + on_disconnect: DisconnectMode | None = None, + webhook: str | None = None, + multitask_strategy: MultitaskStrategy | None = None, + if_not_exists: IfNotExists | None = None, + after_seconds: int | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + ) -> AsyncIterator[StreamPart]: ... + + @overload + def stream( + self, + thread_id: None, + assistant_id: str, + *, + input: Input | None = None, + 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, + checkpoint_during: bool | None = None, + interrupt_before: All | Sequence[str] | None = None, + interrupt_after: All | Sequence[str] | None = None, + feedback_keys: Sequence[str] | None = None, + on_disconnect: DisconnectMode | None = None, + on_completion: OnCompletionBehavior | None = None, + if_not_exists: IfNotExists | None = None, + webhook: str | None = None, + after_seconds: int | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + ) -> AsyncIterator[StreamPart]: ... + + def stream( + self, + thread_id: str | None, + assistant_id: str, + *, + input: Input | None = None, + 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, + checkpoint: Checkpoint | None = None, + checkpoint_id: str | None = None, + checkpoint_during: bool | None = None, # deprecated + interrupt_before: All | Sequence[str] | None = None, + interrupt_after: All | Sequence[str] | None = None, + feedback_keys: Sequence[str] | None = None, + on_disconnect: DisconnectMode | None = None, + on_completion: OnCompletionBehavior | None = None, + webhook: str | None = None, + multitask_strategy: MultitaskStrategy | None = None, + if_not_exists: IfNotExists | None = None, + after_seconds: int | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + durability: Durability | None = None, + ) -> AsyncIterator[StreamPart]: + """Create a run and stream the results. + + Args: + thread_id: the thread ID to assign to the thread. + If `None` will create a stateless run. + assistant_id: The assistant ID or graph name to stream from. + If using graph name, will default to first assistant created from that graph. + input: The input to the graph. + command: A command to execute. Cannot be combined with input. + stream_mode: The stream mode(s) to use. + stream_subgraphs: Whether to stream output from subgraphs. + stream_resumable: Whether the stream is considered resumable. + If true, the stream can be resumed and replayed in its entirety even after disconnection. + metadata: Metadata to assign to the run. + config: The configuration for the assistant. + context: Static context to add to the assistant. + !!! version-added "Added in version 0.6.0" + checkpoint: The checkpoint to resume from. + checkpoint_during: (deprecated) Whether to checkpoint during the run (or only at the end/interruption). + interrupt_before: Nodes to interrupt immediately before they get executed. + interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. + feedback_keys: Feedback keys to assign to run. + on_disconnect: The disconnect mode to use. + Must be one of 'cancel' or 'continue'. + on_completion: Whether to delete or keep the thread created for a stateless run. + Must be one of 'delete' or 'keep'. + webhook: Webhook to call after LangGraph API call is done. + multitask_strategy: Multitask strategy to use. + Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. + if_not_exists: How to handle missing thread. Defaults to 'reject'. + Must be either 'reject' (raise error if missing), or 'create' (create new thread). + after_seconds: The number of seconds to wait before starting the run. + Use to schedule future runs. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + on_run_created: Callback when a run is created. + durability: The durability to use for the run. Values are "sync", "async", or "exit". + "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 + + Returns: + Asynchronous iterator of stream results. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024) + async for chunk in client.runs.stream( + thread_id=None, + assistant_id="agent", + input={"messages": [{"role": "user", "content": "how are you?"}]}, + stream_mode=["values","debug"], + metadata={"name":"my_run"}, + context={"model_name": "anthropic"}, + interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], + interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], + feedback_keys=["my_feedback_key_1","my_feedback_key_2"], + webhook="https://my.fake.webhook.com", + multitask_strategy="interrupt" + ): + print(chunk) + ``` + + ```shell + + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + + 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) + ``` + + """ + if checkpoint_during is not None: + warnings.warn( + "`checkpoint_during` is deprecated and will be removed in a future version. Use `durability` instead.", + DeprecationWarning, + stacklevel=2, + ) + + payload = { + "input": input, + "command": ( + {k: v for k, v in command.items() if v is not None} if command else None + ), + "config": config, + "context": context, + "metadata": metadata, + "stream_mode": stream_mode, + "stream_subgraphs": stream_subgraphs, + "stream_resumable": stream_resumable, + "assistant_id": assistant_id, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "feedback_keys": feedback_keys, + "webhook": webhook, + "checkpoint": checkpoint, + "checkpoint_id": checkpoint_id, + "checkpoint_during": checkpoint_during, + "multitask_strategy": multitask_strategy, + "if_not_exists": if_not_exists, + "on_disconnect": on_disconnect, + "on_completion": on_completion, + "after_seconds": after_seconds, + "durability": durability, + } + endpoint = ( + f"/threads/{thread_id}/runs/stream" + if thread_id is not None + else "/runs/stream" + ) + + def on_response(res: httpx.Response): + """Callback function to handle the response.""" + if on_run_created and (metadata := _get_run_metadata_from_response(res)): + on_run_created(metadata) + + return self.http.stream( + endpoint, + "POST", + json={k: v for k, v in payload.items() if v is not None}, + params=params, + headers=headers, + on_response=on_response if on_run_created else None, + ) + + @overload + async def create( + self, + thread_id: None, + assistant_id: str, + *, + input: Input | None = None, + command: Command | None = None, + stream_mode: StreamMode | Sequence[StreamMode] = "values", + stream_subgraphs: bool = False, + stream_resumable: bool = False, + metadata: Mapping[str, Any] | None = None, + checkpoint_during: bool | None = None, + config: Config | None = None, + context: Context | None = None, + interrupt_before: All | Sequence[str] | None = None, + interrupt_after: All | Sequence[str] | None = None, + webhook: str | None = None, + on_completion: OnCompletionBehavior | None = None, + if_not_exists: IfNotExists | None = None, + after_seconds: int | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + ) -> Run: ... + + @overload + async def create( + self, + thread_id: str, + assistant_id: str, + *, + input: Input | None = None, + 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, + checkpoint: Checkpoint | None = None, + checkpoint_id: str | None = None, + checkpoint_during: bool | None = None, + interrupt_before: All | Sequence[str] | None = None, + interrupt_after: All | Sequence[str] | None = None, + webhook: str | None = None, + multitask_strategy: MultitaskStrategy | None = None, + if_not_exists: IfNotExists | None = None, + after_seconds: int | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + ) -> Run: ... + + async def create( + self, + thread_id: str | None, + assistant_id: str, + *, + input: Input | None = None, + 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, + checkpoint: Checkpoint | None = None, + checkpoint_id: str | None = None, + checkpoint_during: bool | None = None, # deprecated + interrupt_before: All | Sequence[str] | None = None, + interrupt_after: All | Sequence[str] | None = None, + webhook: str | None = None, + multitask_strategy: MultitaskStrategy | None = None, + if_not_exists: IfNotExists | None = None, + on_completion: OnCompletionBehavior | None = None, + after_seconds: int | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + durability: Durability | None = None, + ) -> Run: + """Create a background run. + + Args: + thread_id: the thread ID to assign to the thread. + If `None` will create a stateless run. + assistant_id: The assistant ID or graph name to stream from. + If using graph name, will default to first assistant created from that graph. + input: The input to the graph. + command: A command to execute. Cannot be combined with input. + stream_mode: The stream mode(s) to use. + stream_subgraphs: Whether to stream output from subgraphs. + stream_resumable: Whether the stream is considered resumable. + If true, the stream can be resumed and replayed in its entirety even after disconnection. + metadata: Metadata to assign to the run. + config: The configuration for the assistant. + context: Static context to add to the assistant. + !!! version-added "Added in version 0.6.0" + checkpoint: The checkpoint to resume from. + checkpoint_during: (deprecated) Whether to checkpoint during the run (or only at the end/interruption). + interrupt_before: Nodes to interrupt immediately before they get executed. + interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. + webhook: Webhook to call after LangGraph API call is done. + multitask_strategy: Multitask strategy to use. + Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. + on_completion: Whether to delete or keep the thread created for a stateless run. + Must be one of 'delete' or 'keep'. + if_not_exists: How to handle missing thread. Defaults to 'reject'. + Must be either 'reject' (raise error if missing), or 'create' (create new thread). + after_seconds: The number of seconds to wait before starting the run. + Use to schedule future runs. + headers: Optional custom headers to include with the request. + on_run_created: Optional callback to call when a run is created. + durability: The durability to use for the run. Values are "sync", "async", or "exit". + "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 + + Returns: + The created background run. + + ???+ example "Example Usage" + + ```python + + background_run = await client.runs.create( + thread_id="my_thread_id", + assistant_id="my_assistant_id", + input={"messages": [{"role": "user", "content": "hello!"}]}, + metadata={"name":"my_run"}, + context={"model_name": "openai"}, + interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], + interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], + webhook="https://my.fake.webhook.com", + multitask_strategy="interrupt" + ) + print(background_run) + ``` + + ```shell + -------------------------------------------------------------------------------- + + { + 'run_id': 'my_run_id', + 'thread_id': 'my_thread_id', + 'assistant_id': 'my_assistant_id', + 'created_at': '2024-07-25T15:35:42.598503+00:00', + 'updated_at': '2024-07-25T15:35:42.598503+00:00', + 'metadata': {}, + 'status': 'pending', + 'kwargs': + { + 'input': + { + 'messages': [ + { + 'role': 'user', + 'content': 'how are you?' + } + ] + }, + 'config': + { + 'metadata': + { + 'created_by': 'system' + }, + 'configurable': + { + 'run_id': 'my_run_id', + 'user_id': None, + 'graph_id': 'agent', + 'thread_id': 'my_thread_id', + 'checkpoint_id': None, + 'assistant_id': 'my_assistant_id' + }, + }, + 'context': + { + 'model_name': 'openai' + } + 'webhook': "https://my.fake.webhook.com", + 'temporary': False, + 'stream_mode': ['values'], + 'feedback_keys': None, + 'interrupt_after': ["node_to_stop_after_1","node_to_stop_after_2"], + 'interrupt_before': ["node_to_stop_before_1","node_to_stop_before_2"] + }, + 'multitask_strategy': 'interrupt' + } + ``` + """ + if checkpoint_during is not None: + warnings.warn( + "`checkpoint_during` is deprecated and will be removed in a future version. Use `durability` instead.", + DeprecationWarning, + stacklevel=2, + ) + payload = { + "input": input, + "command": ( + {k: v for k, v in command.items() if v is not None} if command else None + ), + "stream_mode": stream_mode, + "stream_subgraphs": stream_subgraphs, + "stream_resumable": stream_resumable, + "config": config, + "context": context, + "metadata": metadata, + "assistant_id": assistant_id, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "webhook": webhook, + "checkpoint": checkpoint, + "checkpoint_id": checkpoint_id, + "checkpoint_during": checkpoint_during, + "multitask_strategy": multitask_strategy, + "if_not_exists": if_not_exists, + "on_completion": on_completion, + "after_seconds": after_seconds, + "durability": durability, + } + payload = {k: v for k, v in payload.items() if v is not None} + + def on_response(res: httpx.Response): + """Callback function to handle the response.""" + if on_run_created and (metadata := _get_run_metadata_from_response(res)): + on_run_created(metadata) + + return await self.http.post( + f"/threads/{thread_id}/runs" if thread_id else "/runs", + json=payload, + params=params, + headers=headers, + on_response=on_response if on_run_created else None, + ) + + async def create_batch( + self, + payloads: list[RunCreate], + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> list[Run]: + """Create a batch of stateless background runs.""" + + def filter_payload(payload: RunCreate): + return {k: v for k, v in payload.items() if v is not None} + + filtered = [filter_payload(payload) for payload in payloads] + return await self.http.post( + "/runs/batch", json=filtered, headers=headers, params=params + ) + + @overload + async def wait( + self, + thread_id: str, + assistant_id: str, + *, + input: Input | None = None, + command: Command | None = None, + metadata: Mapping[str, Any] | None = None, + config: Config | None = None, + context: Context | None = None, + checkpoint: Checkpoint | None = None, + checkpoint_id: str | None = None, + checkpoint_during: bool | None = None, + interrupt_before: All | Sequence[str] | None = None, + interrupt_after: All | Sequence[str] | None = None, + webhook: str | None = None, + on_disconnect: DisconnectMode | None = None, + multitask_strategy: MultitaskStrategy | None = None, + if_not_exists: IfNotExists | None = None, + after_seconds: int | None = None, + raise_error: bool = True, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + ) -> list[dict] | dict[str, Any]: ... + + @overload + async def wait( + self, + thread_id: None, + assistant_id: str, + *, + input: Input | None = None, + command: Command | None = None, + 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, + webhook: str | None = None, + on_disconnect: DisconnectMode | None = None, + on_completion: OnCompletionBehavior | None = None, + if_not_exists: IfNotExists | None = None, + after_seconds: int | None = None, + raise_error: bool = True, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + ) -> list[dict] | dict[str, Any]: ... + + async def wait( + self, + thread_id: str | None, + assistant_id: str, + *, + input: Input | None = None, + command: Command | None = None, + metadata: Mapping[str, Any] | None = None, + config: Config | None = None, + context: Context | None = None, + checkpoint: Checkpoint | None = None, + checkpoint_id: str | None = None, + checkpoint_during: bool | None = None, # deprecated + interrupt_before: All | Sequence[str] | None = None, + interrupt_after: All | Sequence[str] | None = None, + webhook: str | None = None, + on_disconnect: DisconnectMode | None = None, + on_completion: OnCompletionBehavior | None = None, + multitask_strategy: MultitaskStrategy | None = None, + if_not_exists: IfNotExists | None = None, + after_seconds: int | None = None, + raise_error: bool = True, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + durability: Durability | None = None, + ) -> list[dict] | dict[str, Any]: + """Create a run, wait until it finishes and return the final state. + + Args: + thread_id: the thread ID to create the run on. + If `None` will create a stateless run. + assistant_id: The assistant ID or graph name to run. + If using graph name, will default to first assistant created from that graph. + input: The input to the graph. + command: A command to execute. Cannot be combined with input. + metadata: Metadata to assign to the run. + config: The configuration for the assistant. + context: Static context to add to the assistant. + !!! version-added "Added in version 0.6.0" + checkpoint: The checkpoint to resume from. + checkpoint_during: (deprecated) Whether to checkpoint during the run (or only at the end/interruption). + interrupt_before: Nodes to interrupt immediately before they get executed. + interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. + webhook: Webhook to call after LangGraph API call is done. + on_disconnect: The disconnect mode to use. + Must be one of 'cancel' or 'continue'. + on_completion: Whether to delete or keep the thread created for a stateless run. + Must be one of 'delete' or 'keep'. + multitask_strategy: Multitask strategy to use. + Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. + if_not_exists: How to handle missing thread. Defaults to 'reject'. + Must be either 'reject' (raise error if missing), or 'create' (create new thread). + after_seconds: The number of seconds to wait before starting the run. + Use to schedule future runs. + headers: Optional custom headers to include with the request. + on_run_created: Optional callback to call when a run is created. + durability: The durability to use for the run. Values are "sync", "async", or "exit". + "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 + + Returns: + The output of the run. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + final_state_of_run = await client.runs.wait( + thread_id=None, + assistant_id="agent", + input={"messages": [{"role": "user", "content": "how are you?"}]}, + metadata={"name":"my_run"}, + context={"model_name": "anthropic"}, + interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], + interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], + webhook="https://my.fake.webhook.com", + multitask_strategy="interrupt" + ) + print(final_state_of_run) + ``` + + ```shell + ------------------------------------------------------------------------------------------------------------------------------------------- + + { + 'messages': [ + { + 'content': 'how are you?', + 'additional_kwargs': {}, + 'response_metadata': {}, + 'type': 'human', + 'name': None, + 'id': 'f51a862c-62fe-4866-863b-b0863e8ad78a', + '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-bf1cd3c6-768f-4c16-b62d-ba6f17ad8b36', + 'example': False, + 'tool_calls': [], + 'invalid_tool_calls': [], + 'usage_metadata': None + } + ] + } + ``` + + """ + if checkpoint_during is not None: + warnings.warn( + "`checkpoint_during` is deprecated and will be removed in a future version. Use `durability` instead.", + DeprecationWarning, + stacklevel=2, + ) + payload = { + "input": input, + "command": ( + {k: v for k, v in command.items() if v is not None} if command else None + ), + "config": config, + "context": context, + "metadata": metadata, + "assistant_id": assistant_id, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "webhook": webhook, + "checkpoint": checkpoint, + "checkpoint_id": checkpoint_id, + "multitask_strategy": multitask_strategy, + "checkpoint_during": checkpoint_during, + "if_not_exists": if_not_exists, + "on_disconnect": on_disconnect, + "on_completion": on_completion, + "after_seconds": after_seconds, + "durability": durability, + } + endpoint = ( + f"/threads/{thread_id}/runs/wait" if thread_id is not None else "/runs/wait" + ) + + def on_response(res: httpx.Response): + """Callback function to handle the response.""" + if on_run_created and (metadata := _get_run_metadata_from_response(res)): + on_run_created(metadata) + + response = await self.http.request_reconnect( + endpoint, + "POST", + json={k: v for k, v in payload.items() if v is not None}, + params=params, + 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 + + async def list( + self, + thread_id: str, + *, + limit: int = 10, + offset: int = 0, + status: RunStatus | None = None, + select: list[RunSelectField] | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> list[Run]: + """List runs. + + Args: + thread_id: The thread ID to list runs for. + limit: The maximum number of results to return. + offset: The number of results to skip. + status: The status of the run to filter by. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + The runs for the thread. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + await client.runs.list( + thread_id="thread_id", + limit=5, + offset=5, + ) + ``` + + """ + query_params: dict[str, Any] = { + "limit": limit, + "offset": offset, + } + if status is not None: + query_params["status"] = status + if select: + query_params["select"] = select + if params: + query_params.update(params) + return await self.http.get( + f"/threads/{thread_id}/runs", params=query_params, headers=headers + ) + + async def get( + self, + thread_id: str, + run_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Run: + """Get a run. + + Args: + thread_id: The thread ID to get. + run_id: The run ID to get. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `Run` object. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + run = await client.runs.get( + thread_id="thread_id_to_delete", + run_id="run_id_to_delete", + ) + ``` + + """ + + return await self.http.get( + f"/threads/{thread_id}/runs/{run_id}", headers=headers, params=params + ) + + async def cancel( + self, + thread_id: str, + run_id: str, + *, + wait: bool = False, + action: CancelAction = "interrupt", + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Get a run. + + Args: + thread_id: The thread ID to cancel. + run_id: The run ID to cancel. + wait: Whether to wait until run has completed. + action: Action to take when cancelling the run. Possible values + are `interrupt` or `rollback`. Default is `interrupt`. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + await client.runs.cancel( + thread_id="thread_id_to_cancel", + run_id="run_id_to_cancel", + wait=True, + action="interrupt" + ) + ``` + + """ + query_params = { + "wait": 1 if wait else 0, + "action": action, + } + if params: + query_params.update(params) + if wait: + return await self.http.request_reconnect( + f"/threads/{thread_id}/runs/{run_id}/cancel", + "POST", + params=query_params, + headers=headers, + ) + else: + return await self.http.post( + f"/threads/{thread_id}/runs/{run_id}/cancel", + json=None, + params=query_params, + headers=headers, + ) + + async def join( + self, + thread_id: str, + run_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> dict: + """Block until a run is done. Returns the final state of the thread. + + Args: + thread_id: The thread ID to join. + run_id: The run ID to join. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + result =await client.runs.join( + thread_id="thread_id_to_join", + run_id="run_id_to_join" + ) + ``` + + """ + return await self.http.request_reconnect( + f"/threads/{thread_id}/runs/{run_id}/join", + "GET", + headers=headers, + params=params, + ) + + def join_stream( + self, + thread_id: str, + run_id: str, + *, + cancel_on_disconnect: bool = False, + stream_mode: StreamMode | Sequence[StreamMode] | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + last_event_id: str | None = None, + ) -> AsyncIterator[StreamPart]: + """Stream output from a run in real-time, until the run is done. + Output is not buffered, so any output produced before this call will + not be received here. + + Args: + thread_id: The thread ID to join. + run_id: The run ID to join. + cancel_on_disconnect: Whether to cancel the run when the stream is disconnected. + stream_mode: The stream mode(s) to use. Must be a subset of the stream modes passed + when creating the run. Background runs default to having the union of all + stream modes. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + last_event_id: The last event ID to use for the stream. + + Returns: + The stream of parts. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + async for part in client.runs.join_stream( + thread_id="thread_id_to_join", + run_id="run_id_to_join", + stream_mode=["values", "debug"] + ): + print(part) + ``` + + """ + query_params = { + "cancel_on_disconnect": cancel_on_disconnect, + "stream_mode": stream_mode, + } + if params: + query_params.update(params) + return self.http.stream( + f"/threads/{thread_id}/runs/{run_id}/stream", + "GET", + params=query_params, + headers={ + **({"Last-Event-ID": last_event_id} if last_event_id else {}), + **(headers or {}), + } + or None, + ) + + async def delete( + self, + thread_id: str, + run_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Delete a run. + + Args: + thread_id: The thread ID to delete. + run_id: The run ID to delete. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + await client.runs.delete( + thread_id="thread_id_to_delete", + run_id="run_id_to_delete" + ) + ``` + + """ + await self.http.delete( + f"/threads/{thread_id}/runs/{run_id}", headers=headers, params=params + ) diff --git a/libs/sdk-py/langgraph_sdk/_async/store.py b/libs/sdk-py/langgraph_sdk/_async/store.py new file mode 100644 index 000000000..e24967047 --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_async/store.py @@ -0,0 +1,313 @@ +"""Async Store client for LangGraph SDK.""" + +from __future__ import annotations + +from collections.abc import Mapping, Sequence +from typing import Any, Literal + +from langgraph_sdk._async.http import HttpClient +from langgraph_sdk._shared.utilities import _provided_vals +from langgraph_sdk.schema import ( + Item, + ListNamespaceResponse, + QueryParamTypes, + SearchItemsResponse, +) + + +class StoreClient: + """Client for interacting with the graph's shared storage. + + The Store provides a key-value storage system for persisting data across graph executions, + allowing for stateful operations and data sharing across threads. + + ???+ example "Example" + + ```python + client = get_client(url="http://localhost:2024") + await client.store.put_item(["users", "user123"], "mem-123451342", {"name": "Alice", "score": 100}) + ``` + """ + + def __init__(self, http: HttpClient) -> None: + self.http = http + + async def put_item( + self, + namespace: Sequence[str], + /, + key: str, + value: Mapping[str, Any], + index: Literal[False] | list[str] | None = None, + ttl: int | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Store or update an item. + + Args: + namespace: A list of strings representing the namespace path. + key: The unique identifier for the item within the namespace. + value: A dictionary containing the item's data. + index: Controls search indexing - None (use defaults), False (disable), or list of field paths to index. + ttl: Optional time-to-live in minutes for the item, or None for no expiration. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + await client.store.put_item( + ["documents", "user123"], + key="item456", + value={"title": "My Document", "content": "Hello World"} + ) + ``` + """ + for label in namespace: + if "." in label: + raise ValueError( + f"Invalid namespace label '{label}'. Namespace labels cannot contain periods ('.')." + ) + payload = { + "namespace": namespace, + "key": key, + "value": value, + "index": index, + "ttl": ttl, + } + await self.http.put( + "/store/items", json=_provided_vals(payload), headers=headers, params=params + ) + + async def get_item( + self, + namespace: Sequence[str], + /, + key: str, + *, + refresh_ttl: bool | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Item: + """Retrieve a single item. + + Args: + key: The unique identifier for the item. + namespace: Optional list of strings representing the namespace path. + refresh_ttl: Whether to refresh the TTL on this read operation. If `None`, uses the store's default behavior. + + Returns: + Item: The retrieved item. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + item = await client.store.get_item( + ["documents", "user123"], + key="item456", + ) + print(item) + ``` + ```shell + + ---------------------------------------------------------------- + + { + 'namespace': ['documents', 'user123'], + 'key': 'item456', + 'value': {'title': 'My Document', 'content': 'Hello World'}, + 'created_at': '2024-07-30T12:00:00Z', + 'updated_at': '2024-07-30T12:00:00Z' + } + ``` + """ + for label in namespace: + if "." in label: + raise ValueError( + f"Invalid namespace label '{label}'. Namespace labels cannot contain periods ('.')." + ) + get_params = {"namespace": ".".join(namespace), "key": key} + if refresh_ttl is not None: + get_params["refresh_ttl"] = refresh_ttl + if params: + get_params = {**get_params, **params} + return await self.http.get("/store/items", params=get_params, headers=headers) + + async def delete_item( + self, + namespace: Sequence[str], + /, + key: str, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Delete an item. + + Args: + key: The unique identifier for the item. + namespace: Optional list of strings representing the namespace path. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + await client.store.delete_item( + ["documents", "user123"], + key="item456", + ) + ``` + """ + await self.http.delete( + "/store/items", + json={"namespace": namespace, "key": key}, + headers=headers, + params=params, + ) + + async def search_items( + self, + namespace_prefix: Sequence[str], + /, + filter: Mapping[str, Any] | None = None, + limit: int = 10, + offset: int = 0, + query: str | None = None, + refresh_ttl: bool | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> SearchItemsResponse: + """Search for items within a namespace prefix. + + Args: + namespace_prefix: List of strings representing the namespace prefix. + filter: Optional dictionary of key-value pairs to filter results. + limit: Maximum number of items to return (default is 10). + offset: Number of items to skip before returning results (default is 0). + query: Optional query for natural language search. + refresh_ttl: Whether to refresh the TTL on items returned by this search. If `None`, uses the store's default behavior. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + A list of items matching the search criteria. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + items = await client.store.search_items( + ["documents"], + filter={"author": "John Doe"}, + limit=5, + offset=0 + ) + print(items) + ``` + ```shell + + ---------------------------------------------------------------- + + { + "items": [ + { + "namespace": ["documents", "user123"], + "key": "item789", + "value": { + "title": "Another Document", + "author": "John Doe" + }, + "created_at": "2024-07-30T12:00:00Z", + "updated_at": "2024-07-30T12:00:00Z" + }, + # ... additional items ... + ] + } + ``` + """ + payload = { + "namespace_prefix": namespace_prefix, + "filter": filter, + "limit": limit, + "offset": offset, + "query": query, + "refresh_ttl": refresh_ttl, + } + + return await self.http.post( + "/store/items/search", + json=_provided_vals(payload), + headers=headers, + params=params, + ) + + async def list_namespaces( + self, + prefix: list[str] | None = None, + suffix: list[str] | None = None, + max_depth: int | None = None, + limit: int = 100, + offset: int = 0, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> ListNamespaceResponse: + """List namespaces with optional match conditions. + + Args: + prefix: Optional list of strings representing the prefix to filter namespaces. + suffix: Optional list of strings representing the suffix to filter namespaces. + max_depth: Optional integer specifying the maximum depth of namespaces to return. + limit: Maximum number of namespaces to return (default is 100). + offset: Number of namespaces to skip before returning results (default is 0). + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + A list of namespaces matching the criteria. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + namespaces = await client.store.list_namespaces( + prefix=["documents"], + max_depth=3, + limit=10, + offset=0 + ) + print(namespaces) + + ---------------------------------------------------------------- + + [ + ["documents", "user123", "reports"], + ["documents", "user456", "invoices"], + ... + ] + ``` + """ + payload = { + "prefix": prefix, + "suffix": suffix, + "max_depth": max_depth, + "limit": limit, + "offset": offset, + } + return await self.http.post( + "/store/namespaces", + json=_provided_vals(payload), + headers=headers, + params=params, + ) diff --git a/libs/sdk-py/langgraph_sdk/_async/threads.py b/libs/sdk-py/langgraph_sdk/_async/threads.py new file mode 100644 index 000000000..d7081cd83 --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_async/threads.py @@ -0,0 +1,671 @@ +"""Async client for managing threads in LangGraph.""" + +from __future__ import annotations + +from collections.abc import AsyncIterator, Mapping, Sequence +from typing import Any + +from langgraph_sdk._async.http import HttpClient +from langgraph_sdk.schema import ( + Checkpoint, + Json, + OnConflictBehavior, + QueryParamTypes, + SortOrder, + StreamPart, + Thread, + ThreadSelectField, + ThreadSortBy, + ThreadState, + ThreadStatus, + ThreadStreamMode, + ThreadUpdateStateResponse, +) + + +class ThreadsClient: + """Client for managing threads in LangGraph. + + A thread maintains the state of a graph across multiple interactions/invocations (aka runs). + It accumulates and persists the graph's state, allowing for continuity between separate + invocations of the graph. + + ???+ example "Example" + + ```python + client = get_client(url="http://localhost:2024")) + new_thread = await client.threads.create(metadata={"user_id": "123"}) + ``` + """ + + def __init__(self, http: HttpClient) -> None: + self.http = http + + async def get( + self, + thread_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Thread: + """Get a thread by ID. + + Args: + thread_id: The ID of the thread to get. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + Thread object. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + thread = await client.threads.get( + thread_id="my_thread_id" + ) + print(thread) + ``` + + ```shell + ----------------------------------------------------- + + { + 'thread_id': 'my_thread_id', + 'created_at': '2024-07-18T18:35:15.540834+00:00', + 'updated_at': '2024-07-18T18:35:15.540834+00:00', + 'metadata': {'graph_id': 'agent'} + } + ``` + + """ + + return await self.http.get( + f"/threads/{thread_id}", headers=headers, params=params + ) + + async def create( + self, + *, + metadata: Json = None, + thread_id: str | None = None, + if_exists: OnConflictBehavior | None = None, + supersteps: Sequence[dict[str, Sequence[dict[str, Any]]]] | None = None, + graph_id: str | None = None, + ttl: int | Mapping[str, Any] | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Thread: + """Create a new thread. + + Args: + metadata: Metadata to add to thread. + thread_id: ID of thread. + If `None`, ID will be a randomly generated UUID. + if_exists: How to handle duplicate creation. Defaults to 'raise' under the hood. + Must be either 'raise' (raise error if duplicate), or 'do_nothing' (return existing thread). + supersteps: Apply a list of supersteps when creating a thread, each containing a sequence of updates. + Each update has `values` or `command` and `as_node`. Used for copying a thread between deployments. + graph_id: Optional graph ID to associate with the thread. + ttl: Optional time-to-live in minutes for the thread. You can pass an + integer (minutes) or a mapping with keys `ttl` and optional + `strategy` (defaults to "delete"). + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + The created thread. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + thread = await client.threads.create( + metadata={"number":1}, + thread_id="my-thread-id", + if_exists="raise" + ) + ``` + """ + payload: dict[str, Any] = {} + 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 + if supersteps: + payload["supersteps"] = [ + { + "updates": [ + { + "values": u["values"], + "command": u.get("command"), + "as_node": u["as_node"], + } + for u in s["updates"] + ] + } + for s in supersteps + ] + if ttl is not None: + if isinstance(ttl, (int, float)): + payload["ttl"] = {"ttl": ttl, "strategy": "delete"} + else: + payload["ttl"] = ttl + + return await self.http.post( + "/threads", json=payload, headers=headers, params=params + ) + + async def update( + self, + thread_id: str, + *, + metadata: Mapping[str, Any], + ttl: int | Mapping[str, Any] | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Thread: + """Update a thread. + + Args: + thread_id: ID of thread to update. + metadata: Metadata to merge with existing thread metadata. + ttl: Optional time-to-live in minutes for the thread. You can pass an + integer (minutes) or a mapping with keys `ttl` and optional + `strategy` (defaults to "delete"). + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + The created thread. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + thread = await client.threads.update( + thread_id="my-thread-id", + metadata={"number":1}, + ttl=43_200, + ) + ``` + """ + payload: dict[str, Any] = {"metadata": metadata} + if ttl is not None: + if isinstance(ttl, (int, float)): + payload["ttl"] = {"ttl": ttl, "strategy": "delete"} + else: + payload["ttl"] = ttl + return await self.http.patch( + f"/threads/{thread_id}", + json=payload, + headers=headers, + params=params, + ) + + async def delete( + self, + thread_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Delete a thread. + + Args: + thread_id: The ID of the thread to delete. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost2024) + await client.threads.delete( + thread_id="my_thread_id" + ) + ``` + + """ + await self.http.delete(f"/threads/{thread_id}", headers=headers, params=params) + + async def search( + self, + *, + metadata: Json = None, + values: Json = None, + ids: Sequence[str] | None = None, + status: ThreadStatus | None = None, + limit: int = 10, + offset: int = 0, + sort_by: ThreadSortBy | None = None, + sort_order: SortOrder | None = None, + select: list[ThreadSelectField] | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> list[Thread]: + """Search for threads. + + Args: + metadata: Thread metadata to filter on. + values: State values to filter on. + ids: List of thread IDs to filter by. + status: Thread status to filter on. + Must be one of 'idle', 'busy', 'interrupted' or 'error'. + limit: Limit on number of threads to return. + offset: Offset in threads table to start search from. + sort_by: Sort by field. + sort_order: Sort order. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + List of the threads matching the search parameters. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + threads = await client.threads.search( + metadata={"number":1}, + status="interrupted", + limit=15, + offset=5 + ) + ``` + + """ + payload: dict[str, Any] = { + "limit": limit, + "offset": offset, + } + if metadata: + payload["metadata"] = metadata + if values: + payload["values"] = values + if ids: + payload["ids"] = ids + if status: + payload["status"] = status + if sort_by: + payload["sort_by"] = sort_by + if sort_order: + payload["sort_order"] = sort_order + if select: + payload["select"] = select + return await self.http.post( + "/threads/search", + json=payload, + headers=headers, + params=params, + ) + + async def count( + self, + *, + metadata: Json = None, + values: Json = None, + status: ThreadStatus | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> int: + """Count threads matching filters. + + Args: + metadata: Thread metadata to filter on. + values: State values to filter on. + status: Thread status to filter on. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + int: Number of threads matching the criteria. + """ + payload: dict[str, Any] = {} + if metadata: + payload["metadata"] = metadata + if values: + payload["values"] = values + if status: + payload["status"] = status + return await self.http.post( + "/threads/count", json=payload, headers=headers, params=params + ) + + async def copy( + self, + thread_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Copy a thread. + + Args: + thread_id: The ID of the thread to copy. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024) + await client.threads.copy( + thread_id="my_thread_id" + ) + ``` + + """ + return await self.http.post( + f"/threads/{thread_id}/copy", json=None, headers=headers, params=params + ) + + async def get_state( + self, + thread_id: str, + checkpoint: Checkpoint | None = None, + checkpoint_id: str | None = None, # deprecated + *, + subgraphs: bool = False, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> ThreadState: + """Get the state of a thread. + + Args: + thread_id: The ID of the thread to get the state of. + checkpoint: The checkpoint to get the state of. + checkpoint_id: (deprecated) The checkpoint ID to get the state of. + subgraphs: Include subgraphs states. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + The thread of the state. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024) + thread_state = await client.threads.get_state( + thread_id="my_thread_id", + checkpoint_id="my_checkpoint_id" + ) + print(thread_state) + ``` + + ```shell + ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + { + 'values': { + '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 + } + ] + }, + 'next': [], + 'checkpoint': + { + 'thread_id': 'e2496803-ecd5-4e0c-a779-3226296181c2', + 'checkpoint_ns': '', + 'checkpoint_id': '1ef4a9b8-e6fb-67b1-8001-abd5184439d1' + } + 'metadata': + { + 'step': 1, + 'run_id': '1ef4a9b8-d7da-679a-a45a-872054341df2', + 'source': 'loop', + 'writes': + { + 'agent': + { + 'messages': [ + { + 'id': 'run-159b782c-b679-4830-83c6-cef87798fe8b', + 'name': None, + 'type': 'ai', + 'content': "I'm doing well, thanks for asking! I'm an AI assistant created by Anthropic to be helpful, honest, and harmless.", + 'example': False, + 'tool_calls': [], + 'usage_metadata': None, + 'additional_kwargs': {}, + 'response_metadata': {}, + 'invalid_tool_calls': [] + } + ] + } + }, + 'user_id': None, + 'graph_id': 'agent', + 'thread_id': 'e2496803-ecd5-4e0c-a779-3226296181c2', + 'created_by': 'system', + 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, + 'created_at': '2024-07-25T15:35:44.184703+00:00', + 'parent_config': + { + 'thread_id': 'e2496803-ecd5-4e0c-a779-3226296181c2', + 'checkpoint_ns': '', + 'checkpoint_id': '1ef4a9b8-d80d-6fa7-8000-9300467fad0f' + } + } + ``` + """ + if checkpoint: + return await self.http.post( + f"/threads/{thread_id}/state/checkpoint", + json={"checkpoint": checkpoint, "subgraphs": subgraphs}, + headers=headers, + params=params, + ) + elif checkpoint_id: + get_params = {"subgraphs": subgraphs} + if params: + get_params = {**get_params, **params} + return await self.http.get( + f"/threads/{thread_id}/state/{checkpoint_id}", + params=get_params, + headers=headers, + ) + else: + get_params = {"subgraphs": subgraphs} + if params: + get_params = {**get_params, **params} + return await self.http.get( + f"/threads/{thread_id}/state", + params=get_params, + headers=headers, + ) + + async def update_state( + self, + thread_id: str, + values: dict[str, Any] | Sequence[dict] | None, + *, + as_node: str | None = None, + checkpoint: Checkpoint | None = None, + checkpoint_id: str | None = None, # deprecated + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> ThreadUpdateStateResponse: + """Update the state of 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. + checkpoint_id: (deprecated) The checkpoint ID to update the state of. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + Response after updating a thread's state. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024) + response = await client.threads.update_state( + thread_id="my_thread_id", + values={"messages":[{"role": "user", "content": "hello!"}]}, + as_node="my_node", + ) + print(response) + ``` + ```shell + + ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + { + 'checkpoint': { + 'thread_id': 'e2496803-ecd5-4e0c-a779-3226296181c2', + 'checkpoint_ns': '', + 'checkpoint_id': '1ef4a9b8-e6fb-67b1-8001-abd5184439d1', + 'checkpoint_map': {} + } + } + ``` + """ + payload: dict[str, Any] = { + "values": values, + } + if checkpoint_id: + payload["checkpoint_id"] = checkpoint_id + if checkpoint: + payload["checkpoint"] = checkpoint + if as_node: + payload["as_node"] = as_node + return await self.http.post( + f"/threads/{thread_id}/state", json=payload, headers=headers, params=params + ) + + async def get_history( + self, + thread_id: str, + *, + limit: int = 10, + before: str | Checkpoint | None = None, + metadata: Mapping[str, Any] | None = None, + checkpoint: Checkpoint | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> list[ThreadState]: + """Get the state history of a thread. + + Args: + thread_id: The ID of the thread to get the state history for. + checkpoint: Return states for this subgraph. If empty defaults to root. + limit: The maximum number of states to return. + before: Return states before this checkpoint. + metadata: Filter states by metadata key-value pairs. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + The state history of the thread. + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024) + thread_state = await client.threads.get_history( + thread_id="my_thread_id", + limit=5, + ) + ``` + + """ + payload: dict[str, Any] = { + "limit": limit, + } + if before: + payload["before"] = before + if metadata: + payload["metadata"] = metadata + if checkpoint: + payload["checkpoint"] = checkpoint + return await self.http.post( + f"/threads/{thread_id}/history", + json=payload, + headers=headers, + params=params, + ) + + async def join_stream( + self, + thread_id: str, + *, + last_event_id: str | None = None, + stream_mode: ThreadStreamMode | Sequence[ThreadStreamMode] = "run_modes", + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> AsyncIterator[StreamPart]: + """Get a stream of events for a thread. + + Args: + thread_id: The ID of the thread to get the stream for. + last_event_id: The ID of the last event to get. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + An iterator of stream parts. + + ???+ example "Example Usage" + + ```python + + for chunk in client.threads.join_stream( + thread_id="my_thread_id", + last_event_id="my_event_id", + ): + print(chunk) + ``` + + """ + query_params = { + "stream_mode": stream_mode, + } + if params: + query_params.update(params) + return self.http.stream( + f"/threads/{thread_id}/stream", + "GET", + headers={ + **({"Last-Event-ID": last_event_id} if last_event_id else {}), + **(headers or {}), + }, + params=query_params, + ) diff --git a/libs/sdk-py/langgraph_sdk/_shared/__init__.py b/libs/sdk-py/langgraph_sdk/_shared/__init__.py new file mode 100644 index 000000000..5783ce0c2 --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_shared/__init__.py @@ -0,0 +1 @@ +"""Shared utilities for async and sync clients.""" diff --git a/libs/sdk-py/langgraph_sdk/_shared/types.py b/libs/sdk-py/langgraph_sdk/_shared/types.py new file mode 100644 index 000000000..073b1380a --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_shared/types.py @@ -0,0 +1,10 @@ +"""Type aliases and constants.""" + +from __future__ import annotations + +TimeoutTypes = ( + None + | float + | tuple[float | None, float | None] + | tuple[float | None, float | None, float | None, float | None] +) diff --git a/libs/sdk-py/langgraph_sdk/_shared/utilities.py b/libs/sdk-py/langgraph_sdk/_shared/utilities.py new file mode 100644 index 000000000..02f28fd9a --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_shared/utilities.py @@ -0,0 +1,131 @@ +"""Shared utility functions for async and sync clients.""" + +from __future__ import annotations + +import functools +import os +import re +from collections.abc import Mapping +from typing import Any, cast + +import httpx + +import langgraph_sdk +from langgraph_sdk.schema import RunCreateMetadata + +RESERVED_HEADERS = ("x-api-key",) + +NOT_PROVIDED = cast(None, object()) + + +def _get_api_key(api_key: str | None = NOT_PROVIDED) -> str | None: + """Get the API key from the environment. + Precedence: + 1. explicit string argument + 2. LANGGRAPH_API_KEY (if api_key not provided) + 3. LANGSMITH_API_KEY (if api_key not provided) + 4. LANGCHAIN_API_KEY (if api_key not provided) + + Args: + api_key: The API key to use. Can be: + - A string: use this exact API key + - None: explicitly skip loading from environment + - NOT_PROVIDED (default): auto-load from environment variables + """ + if isinstance(api_key, str): + return api_key + if api_key is NOT_PROVIDED: + # api_key is not explicitly provided, try to load from environment + for prefix in ["LANGGRAPH", "LANGSMITH", "LANGCHAIN"]: + if env := os.getenv(f"{prefix}_API_KEY"): + return env.strip().strip('"').strip("'") + # api_key is explicitly None, don't load from environment + return None + + +def _get_headers( + api_key: str | None, + custom_headers: Mapping[str, str] | None, +) -> dict[str, str]: + """Combine api_key and custom user-provided headers.""" + custom_headers = custom_headers or {} + for header in RESERVED_HEADERS: + if header in custom_headers: + raise ValueError(f"Cannot set reserved header '{header}'") + + headers = { + "User-Agent": f"langgraph-sdk-py/{langgraph_sdk.__version__}", + **custom_headers, + } + resolved_api_key = _get_api_key(api_key) + if resolved_api_key: + headers["x-api-key"] = resolved_api_key + + return headers + + +def _orjson_default(obj: Any) -> Any: + is_class = isinstance(obj, type) + if hasattr(obj, "model_dump") and callable(obj.model_dump): + if is_class: + raise TypeError( + f"Cannot JSON-serialize type object: {obj!r}. Did you mean to pass an instance of the object instead?" + f"\nReceived type: {obj!r}" + ) + return obj.model_dump() + elif hasattr(obj, "dict") and callable(obj.dict): + if is_class: + raise TypeError( + f"Cannot JSON-serialize type object: {obj!r}. Did you mean to pass an instance of the object instead?" + f"\nReceived type: {obj!r}" + ) + return obj.dict() + elif isinstance(obj, (set, frozenset)): + return list(obj) + else: + raise TypeError(f"Object of type {type(obj)} is not JSON serializable") + + +# Compiled regex pattern for extracting run metadata from Content-Location header +_RUN_METADATA_PATTERN = re.compile( + r"(\/threads\/(?P.+))?\/runs\/(?P.+)" +) + + +def _get_run_metadata_from_response( + response: httpx.Response, +) -> RunCreateMetadata | None: + """Extract run metadata from the response headers.""" + if (content_location := response.headers.get("Content-Location")) and ( + match := _RUN_METADATA_PATTERN.search(content_location) + ): + return RunCreateMetadata( + run_id=match.group("run_id"), + thread_id=match.group("thread_id") or None, + ) + + return None + + +def _provided_vals(d: Mapping[str, Any]) -> dict[str, Any]: + return {k: v for k, v in d.items() if v is not None} + + +_registered_transports: list[httpx.ASGITransport] = [] + + +# Do not move; this is used in the server. +def configure_loopback_transports(app: Any) -> None: + for transport in _registered_transports: + transport.app = app + + +@functools.lru_cache(maxsize=1) +def get_asgi_transport() -> type[httpx.ASGITransport]: + try: + from langgraph_api import asgi_transport # type: ignore[unresolved-import] + + return asgi_transport.ASGITransport + except ImportError: + # Older versions of the server + return httpx.ASGITransport diff --git a/libs/sdk-py/langgraph_sdk/_sync/__init__.py b/libs/sdk-py/langgraph_sdk/_sync/__init__.py new file mode 100644 index 000000000..1ab36bf80 --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_sync/__init__.py @@ -0,0 +1,20 @@ +"""Sync client exports.""" + +from langgraph_sdk._sync.assistants import SyncAssistantsClient +from langgraph_sdk._sync.client import SyncLangGraphClient, get_sync_client +from langgraph_sdk._sync.cron import SyncCronClient +from langgraph_sdk._sync.http import SyncHttpClient +from langgraph_sdk._sync.runs import SyncRunsClient +from langgraph_sdk._sync.store import SyncStoreClient +from langgraph_sdk._sync.threads import SyncThreadsClient + +__all__ = [ + "SyncAssistantsClient", + "SyncCronClient", + "SyncHttpClient", + "SyncLangGraphClient", + "SyncRunsClient", + "SyncStoreClient", + "SyncThreadsClient", + "get_sync_client", +] diff --git a/libs/sdk-py/langgraph_sdk/_sync/assistants.py b/libs/sdk-py/langgraph_sdk/_sync/assistants.py new file mode 100644 index 000000000..0f5dec393 --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_sync/assistants.py @@ -0,0 +1,718 @@ +"""Synchronous client for managing assistants in LangGraph.""" + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, Literal, cast, overload + +import httpx + +from langgraph_sdk._sync.http import SyncHttpClient +from langgraph_sdk.schema import ( + Assistant, + AssistantSelectField, + AssistantSortBy, + AssistantsSearchResponse, + AssistantVersion, + Config, + Context, + GraphSchema, + Json, + OnConflictBehavior, + QueryParamTypes, + SortOrder, + Subgraphs, +) + + +class SyncAssistantsClient: + """Client for managing assistants in LangGraph synchronously. + + This class provides methods to interact with assistants, which are versioned configurations of your graph. + + ???+ example "Example" + + ```python + client = get_sync_client(url="http://localhost:2024") + assistant = client.assistants.get("assistant_id_123") + ``` + """ + + def __init__(self, http: SyncHttpClient) -> None: + self.http = http + + def get( + self, + assistant_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Assistant: + """Get an assistant by ID. + + Args: + assistant_id: The ID of the assistant to get OR the name of the graph (to use the default assistant). + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `Assistant` Object. + + ???+ example "Example Usage" + + ```python + assistant = client.assistants.get( + assistant_id="my_assistant_id" + ) + print(assistant) + ``` + + ```shell + ---------------------------------------------------- + + { + 'assistant_id': 'my_assistant_id', + 'graph_id': 'agent', + 'created_at': '2024-06-25T17:10:33.109781+00:00', + 'updated_at': '2024-06-25T17:10:33.109781+00:00', + 'config': {}, + 'context': {}, + 'metadata': {'created_by': 'system'} + } + ``` + + """ + return self.http.get( + f"/assistants/{assistant_id}", headers=headers, params=params + ) + + def get_graph( + self, + assistant_id: str, + *, + xray: int | bool = False, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> dict[str, list[dict[str, Any]]]: + """Get the graph of an assistant by ID. + + Args: + assistant_id: The ID of the assistant to get the graph of. + xray: Include graph representation of subgraphs. If an integer value is provided, only subgraphs with a depth less than or equal to the value will be included. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + The graph information for the assistant in JSON format. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + graph_info = client.assistants.get_graph( + assistant_id="my_assistant_id" + ) + print(graph_info) + + -------------------------------------------------------------------------------------------------------------------------- + + { + 'nodes': + [ + {'id': '__start__', 'type': 'schema', 'data': '__start__'}, + {'id': '__end__', 'type': 'schema', 'data': '__end__'}, + {'id': 'agent','type': 'runnable','data': {'id': ['langgraph', 'utils', 'RunnableCallable'],'name': 'agent'}}, + ], + 'edges': + [ + {'source': '__start__', 'target': 'agent'}, + {'source': 'agent','target': '__end__'} + ] + } + ``` + + """ + query_params = {"xray": xray} + if params: + query_params.update(params) + return self.http.get( + f"/assistants/{assistant_id}/graph", params=query_params, headers=headers + ) + + def get_schemas( + self, + assistant_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> GraphSchema: + """Get the schemas of an assistant by ID. + + Args: + assistant_id: The ID of the assistant to get the schema of. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + GraphSchema: The graph schema for the assistant. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + schema = client.assistants.get_schemas( + assistant_id="my_assistant_id" + ) + print(schema) + ``` + ```shell + ---------------------------------------------------------------------------------------------------------------------------- + + { + 'graph_id': 'agent', + 'state_schema': + { + 'title': 'LangGraphInput', + '$ref': '#/definitions/AgentState', + 'definitions': + { + 'BaseMessage': + { + 'title': 'BaseMessage', + 'description': 'Base abstract Message class. Messages are the inputs and outputs of ChatModels.', + 'type': 'object', + 'properties': + { + 'content': + { + 'title': 'Content', + 'anyOf': [ + {'type': 'string'}, + {'type': 'array','items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}} + ] + }, + 'additional_kwargs': + { + 'title': 'Additional Kwargs', + 'type': 'object' + }, + 'response_metadata': + { + 'title': 'Response Metadata', + 'type': 'object' + }, + 'type': + { + 'title': 'Type', + 'type': 'string' + }, + 'name': + { + 'title': 'Name', + 'type': 'string' + }, + 'id': + { + 'title': 'Id', + 'type': 'string' + } + }, + 'required': ['content', 'type'] + }, + 'AgentState': + { + 'title': 'AgentState', + 'type': 'object', + 'properties': + { + 'messages': + { + 'title': 'Messages', + 'type': 'array', + 'items': {'$ref': '#/definitions/BaseMessage'} + } + }, + 'required': ['messages'] + } + } + }, + 'config_schema': + { + 'title': 'Configurable', + 'type': 'object', + 'properties': + { + 'model_name': + { + 'title': 'Model Name', + 'enum': ['anthropic', 'openai'], + 'type': 'string' + } + } + }, + 'context_schema': + { + 'title': 'Context', + 'type': 'object', + 'properties': + { + 'model_name': + { + 'title': 'Model Name', + 'enum': ['anthropic', 'openai'], + 'type': 'string' + } + } + } + } + ``` + + """ + return self.http.get( + f"/assistants/{assistant_id}/schemas", headers=headers, params=params + ) + + def get_subgraphs( + self, + assistant_id: str, + namespace: str | None = None, + recurse: bool = False, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Subgraphs: + """Get the schemas of an assistant by ID. + + Args: + assistant_id: The ID of the assistant to get the schema of. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + Subgraphs: The graph schema for the assistant. + + """ + get_params = {"recurse": recurse} + if params: + get_params = {**get_params, **params} + if namespace is not None: + return self.http.get( + f"/assistants/{assistant_id}/subgraphs/{namespace}", + params=get_params, + headers=headers, + ) + else: + return self.http.get( + f"/assistants/{assistant_id}/subgraphs", + params=get_params, + headers=headers, + ) + + def create( + self, + graph_id: str | None, + config: Config | None = None, + *, + context: Context | None = None, + metadata: Json = None, + assistant_id: str | None = None, + if_exists: OnConflictBehavior | None = None, + name: str | None = None, + headers: Mapping[str, str] | None = None, + description: str | None = None, + params: QueryParamTypes | None = None, + ) -> Assistant: + """Create a new assistant. + + Useful when graph is configurable and you want to create different assistants based on different configurations. + + Args: + graph_id: The ID of the graph the assistant should use. The graph ID is normally set in your langgraph.json configuration. + config: Configuration to use for the graph. + context: Static context to add to the assistant. + !!! version-added "Added in version 0.6.0" + metadata: Metadata to add to assistant. + assistant_id: Assistant ID to use, will default to a random UUID if not provided. + if_exists: How to handle duplicate creation. Defaults to 'raise' under the hood. + Must be either 'raise' (raise error if duplicate), or 'do_nothing' (return existing assistant). + name: The name of the assistant. Defaults to 'Untitled' under the hood. + headers: Optional custom headers to include with the request. + description: Optional description of the assistant. + The description field is available for langgraph-api server version>=0.0.45 + params: Optional query parameters to include with the request. + + Returns: + The created assistant. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + assistant = client.assistants.create( + graph_id="agent", + context={"model_name": "openai"}, + metadata={"number":1}, + assistant_id="my-assistant-id", + if_exists="do_nothing", + name="my_name" + ) + ``` + """ + payload: dict[str, Any] = { + "graph_id": graph_id, + } + if config: + payload["config"] = config + if context: + payload["context"] = context + if metadata: + payload["metadata"] = metadata + if assistant_id: + payload["assistant_id"] = assistant_id + if if_exists: + payload["if_exists"] = if_exists + if name: + payload["name"] = name + if description: + payload["description"] = description + return self.http.post( + "/assistants", json=payload, headers=headers, params=params + ) + + def update( + self, + assistant_id: str, + *, + graph_id: str | None = None, + config: Config | None = None, + context: Context | None = None, + metadata: Json = None, + name: str | None = None, + headers: Mapping[str, str] | None = None, + description: str | None = None, + params: QueryParamTypes | None = None, + ) -> Assistant: + """Update an assistant. + + Use this to point to a different graph, update the configuration, or change the metadata of an assistant. + + Args: + assistant_id: Assistant to update. + graph_id: The ID of the graph the assistant should use. + The graph ID is normally set in your langgraph.json configuration. If `None`, assistant will keep pointing to same graph. + config: Configuration to use for the graph. + context: Static context to add to the assistant. + !!! version-added "Added in version 0.6.0" + metadata: Metadata to merge with existing assistant metadata. + name: The new name for the assistant. + headers: Optional custom headers to include with the request. + description: Optional description of the assistant. + The description field is available for langgraph-api server version>=0.0.45 + + Returns: + The updated assistant. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + assistant = client.assistants.update( + assistant_id='e280dad7-8618-443f-87f1-8e41841c180f', + graph_id="other-graph", + context={"model_name": "anthropic"}, + metadata={"number":2} + ) + ``` + """ + payload: dict[str, Any] = {} + if graph_id: + payload["graph_id"] = graph_id + if config: + payload["config"] = config + if context: + payload["context"] = context + if metadata: + payload["metadata"] = metadata + if name: + payload["name"] = name + if description: + payload["description"] = description + return self.http.patch( + f"/assistants/{assistant_id}", + json=payload, + headers=headers, + params=params, + ) + + def delete( + self, + assistant_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Delete an assistant. + + Args: + assistant_id: The assistant ID to delete. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + client.assistants.delete( + assistant_id="my_assistant_id" + ) + ``` + + """ + self.http.delete(f"/assistants/{assistant_id}", headers=headers, params=params) + + @overload + def search( + self, + *, + metadata: Json = None, + graph_id: str | None = None, + name: str | None = None, + limit: int = 10, + offset: int = 0, + sort_by: AssistantSortBy | None = None, + sort_order: SortOrder | None = None, + select: list[AssistantSelectField] | None = None, + response_format: Literal["object"], + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> AssistantsSearchResponse: ... + + @overload + def search( + self, + *, + metadata: Json = None, + graph_id: str | None = None, + name: str | None = None, + limit: int = 10, + offset: int = 0, + sort_by: AssistantSortBy | None = None, + sort_order: SortOrder | None = None, + select: list[AssistantSelectField] | None = None, + response_format: Literal["array"] = "array", + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> list[Assistant]: ... + + def search( + self, + *, + metadata: Json = None, + graph_id: str | None = None, + name: str | None = None, + limit: int = 10, + offset: int = 0, + sort_by: AssistantSortBy | None = None, + sort_order: SortOrder | None = None, + select: list[AssistantSelectField] | None = None, + response_format: Literal["array", "object"] = "array", + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> AssistantsSearchResponse | list[Assistant]: + """Search for assistants. + + Args: + metadata: Metadata to filter by. Exact match filter for each KV pair. + graph_id: The ID of the graph to filter by. + The graph ID is normally set in your langgraph.json configuration. + name: The name of the assistant to filter by. + The filtering logic will match assistants where 'name' is a substring (case insensitive) of the assistant name. + limit: The maximum number of results to return. + offset: The number of results to skip. + sort_by: The field to sort by. + sort_order: The order to sort by. + select: Specific assistant fields to include in the response. + response_format: Controls the response shape. Use `"array"` (default) + to return a bare list of assistants, or `"object"` to return + a mapping containing assistants plus pagination metadata. + Defaults to "array", though this default will be changed to "object" in a future release. + headers: Optional custom headers to include with the request. + + Returns: + A list of assistants (when `response_format="array"`) or a mapping + with the assistants and the next pagination cursor (when + `response_format="object"`). + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + response = client.assistants.search( + metadata = {"name":"my_name"}, + graph_id="my_graph_id", + limit=5, + offset=5, + response_format="object", + ) + assistants = response["assistants"] + next_cursor = response["next"] + ``` + """ + if response_format not in ("array", "object"): + raise ValueError("response_format must be 'array' or 'object'") + payload: dict[str, Any] = { + "limit": limit, + "offset": offset, + } + if metadata: + payload["metadata"] = metadata + if graph_id: + payload["graph_id"] = graph_id + if name: + payload["name"] = name + if sort_by: + payload["sort_by"] = sort_by + if sort_order: + payload["sort_order"] = sort_order + if select: + payload["select"] = select + next_cursor: str | None = None + + def capture_pagination(response: httpx.Response) -> None: + nonlocal next_cursor + next_cursor = response.headers.get("X-Pagination-Next") + + assistants = cast( + list[Assistant], + self.http.post( + "/assistants/search", + json=payload, + headers=headers, + params=params, + on_response=capture_pagination if response_format == "object" else None, + ), + ) + if response_format == "object": + return {"assistants": assistants, "next": next_cursor} + return assistants + + def count( + self, + *, + metadata: Json = None, + graph_id: str | None = None, + name: str | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> int: + """Count assistants matching filters. + + Args: + metadata: Metadata to filter by. Exact match for each key/value. + graph_id: Optional graph id to filter by. + name: Optional name to filter by. + The filtering logic will match assistants where 'name' is a substring (case insensitive) of the assistant name. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + int: Number of assistants matching the criteria. + """ + payload: dict[str, Any] = {} + if metadata: + payload["metadata"] = metadata + if graph_id: + payload["graph_id"] = graph_id + if name: + payload["name"] = name + return self.http.post( + "/assistants/count", json=payload, headers=headers, params=params + ) + + def get_versions( + self, + assistant_id: str, + metadata: Json = None, + limit: int = 10, + offset: int = 0, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> list[AssistantVersion]: + """List all versions of an assistant. + + Args: + assistant_id: The assistant ID to get versions for. + metadata: Metadata to filter versions by. Exact match filter for each KV pair. + limit: The maximum number of versions to return. + offset: The number of versions to skip. + headers: Optional custom headers to include with the request. + + Returns: + A list of assistants. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + assistant_versions = client.assistants.get_versions( + assistant_id="my_assistant_id" + ) + ``` + + """ + + payload: dict[str, Any] = { + "limit": limit, + "offset": offset, + } + if metadata: + payload["metadata"] = metadata + return self.http.post( + f"/assistants/{assistant_id}/versions", + json=payload, + headers=headers, + params=params, + ) + + def set_latest( + self, + assistant_id: str, + version: int, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Assistant: + """Change the version of an assistant. + + Args: + assistant_id: The assistant ID to delete. + version: The version to change to. + headers: Optional custom headers to include with the request. + + Returns: + `Assistant` Object. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + new_version_assistant = client.assistants.set_latest( + assistant_id="my_assistant_id", + version=3 + ) + ``` + + """ + + payload: dict[str, Any] = {"version": version} + + return self.http.post( + f"/assistants/{assistant_id}/latest", + json=payload, + headers=headers, + params=params, + ) diff --git a/libs/sdk-py/langgraph_sdk/_sync/client.py b/libs/sdk-py/langgraph_sdk/_sync/client.py new file mode 100644 index 000000000..1a0d641e2 --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_sync/client.py @@ -0,0 +1,127 @@ +"""Sync LangGraph client.""" + +from __future__ import annotations + +from collections.abc import Mapping +from types import TracebackType + +import httpx + +from langgraph_sdk._shared.types import TimeoutTypes +from langgraph_sdk._shared.utilities import NOT_PROVIDED, _get_headers +from langgraph_sdk._sync.assistants import SyncAssistantsClient +from langgraph_sdk._sync.cron import SyncCronClient +from langgraph_sdk._sync.http import SyncHttpClient +from langgraph_sdk._sync.runs import SyncRunsClient +from langgraph_sdk._sync.store import SyncStoreClient +from langgraph_sdk._sync.threads import SyncThreadsClient + + +def get_sync_client( + *, + url: str | None = None, + api_key: str | None = NOT_PROVIDED, + headers: Mapping[str, str] | None = None, + timeout: TimeoutTypes | None = None, +) -> SyncLangGraphClient: + """Get a synchronous LangGraphClient instance. + + Args: + url: The URL of the LangGraph API. + api_key: API key for authentication. Can be: + - A string: use this exact API key + - `None`: explicitly skip loading from environment variables + - Not provided (default): auto-load from environment in this order: + 1. `LANGGRAPH_API_KEY` + 2. `LANGSMITH_API_KEY` + 3. `LANGCHAIN_API_KEY` + headers: Optional custom headers + timeout: Optional timeout configuration for the HTTP client. + Accepts an httpx.Timeout instance, a float (seconds), or a tuple of timeouts. + Tuple format is (connect, read, write, pool) + If not provided, defaults to connect=5s, read=300s, write=300s, and pool=5s. + Returns: + SyncLangGraphClient: The top-level synchronous client for accessing AssistantsClient, + ThreadsClient, RunsClient, and CronClient. + + ???+ example "Example" + + ```python + from langgraph_sdk import get_sync_client + + # get top-level synchronous LangGraphClient + client = get_sync_client(url="http://localhost:8123") + + # example usage: client..() + assistant = client.assistants.get(assistant_id="some_uuid") + ``` + + ???+ example "Skip auto-loading API key from environment:" + + ```python + from langgraph_sdk import get_sync_client + + # Don't load API key from environment variables + client = get_sync_client( + url="http://localhost:8123", + api_key=None + ) + ``` + """ + + if url is None: + url = "http://localhost:8123" + + transport = httpx.HTTPTransport(retries=5) + client = httpx.Client( + base_url=url, + transport=transport, + timeout=( + httpx.Timeout(timeout) # type: ignore[arg-type] + if timeout is not None + else httpx.Timeout(connect=5, read=300, write=300, pool=5) + ), + headers=_get_headers(api_key, headers), + ) + return SyncLangGraphClient(client) + + +class SyncLangGraphClient: + """Synchronous client for interacting with the LangGraph API. + + This class provides synchronous access to LangGraph API endpoints for managing + assistants, threads, runs, cron jobs, and data storage. + + ???+ example "Example" + + ```python + client = get_sync_client(url="http://localhost:2024") + assistant = client.assistants.get("asst_123") + ``` + """ + + def __init__(self, client: httpx.Client) -> None: + self.http = SyncHttpClient(client) + self.assistants = SyncAssistantsClient(self.http) + self.threads = SyncThreadsClient(self.http) + self.runs = SyncRunsClient(self.http) + self.crons = SyncCronClient(self.http) + self.store = SyncStoreClient(self.http) + + def __enter__(self) -> SyncLangGraphClient: + """Enter the sync context manager.""" + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + """Exit the sync context manager.""" + self.close() + + def close(self) -> None: + """Close the underlying HTTP client.""" + if hasattr(self, "http"): + self.http.client.close() diff --git a/libs/sdk-py/langgraph_sdk/_sync/cron.py b/libs/sdk-py/langgraph_sdk/_sync/cron.py new file mode 100644 index 000000000..b335a15ef --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_sync/cron.py @@ -0,0 +1,439 @@ +"""Synchronous cron client for LangGraph SDK.""" + +from __future__ import annotations + +from collections.abc import Mapping +from datetime import datetime +from typing import Any + +from langgraph_sdk._sync.http import SyncHttpClient +from langgraph_sdk.schema import ( + All, + Config, + Context, + Cron, + CronSelectField, + CronSortBy, + Input, + OnCompletionBehavior, + QueryParamTypes, + Run, + SortOrder, +) + + +class SyncCronClient: + """Synchronous client for managing cron jobs in LangGraph. + + This class provides methods to create and manage scheduled tasks (cron jobs) for automated graph executions. + + ???+ example "Example" + + ```python + client = get_sync_client(url="http://localhost:8123") + cron_job = client.crons.create_for_thread(thread_id="thread_123", assistant_id="asst_456", schedule="0 * * * *") + ``` + + !!! note "Feature Availability" + + The crons client functionality is not supported on all licenses. + Please check the relevant license documentation for the most up-to-date + details on feature availability. + """ + + def __init__(self, http_client: SyncHttpClient) -> None: + self.http = http_client + + def create_for_thread( + self, + thread_id: str, + assistant_id: str, + *, + schedule: str, + input: Input | None = None, + metadata: Mapping[str, Any] | None = None, + config: Config | None = None, + context: Context | None = None, + checkpoint_during: bool | None = None, + interrupt_before: All | list[str] | None = None, + interrupt_after: All | list[str] | None = None, + webhook: str | None = None, + multitask_strategy: str | None = None, + end_time: datetime | None = None, + enabled: bool | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Run: + """Create a cron job for a thread. + + Args: + thread_id: the thread ID to run the cron job on. + assistant_id: The assistant ID or graph name to use for the cron job. + If using graph name, will default to first assistant created from that graph. + schedule: The cron schedule to execute this job on. + Schedules are interpreted in UTC. + input: The input to the graph. + metadata: Metadata to assign to the cron job runs. + config: The configuration for the assistant. + context: Static context to add to the assistant. + !!! version-added "Added in version 0.6.0" + checkpoint_during: Whether to checkpoint during the run (or only at the end/interruption). + interrupt_before: Nodes to interrupt immediately before they get executed. + interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. + webhook: Webhook to call after LangGraph API call is done. + multitask_strategy: Multitask strategy to use. + Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. + end_time: The time to stop running the cron job. If not provided, the cron job will run indefinitely. + enabled: Whether the cron job is enabled. By default, it is considered enabled. + headers: Optional custom headers to include with the request. + + Returns: + The cron `Run`. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:8123") + cron_run = client.crons.create_for_thread( + thread_id="my-thread-id", + assistant_id="agent", + schedule="27 15 * * *", + input={"messages": [{"role": "user", "content": "hello!"}]}, + metadata={"name":"my_run"}, + context={"model_name": "openai"}, + interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], + interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], + webhook="https://my.fake.webhook.com", + multitask_strategy="interrupt", + enabled=True + ) + ``` + """ + payload = { + "schedule": schedule, + "input": input, + "config": config, + "metadata": metadata, + "context": context, + "assistant_id": assistant_id, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "checkpoint_during": checkpoint_during, + "webhook": webhook, + "multitask_strategy": multitask_strategy, + "end_time": end_time.isoformat() if end_time else None, + "enabled": enabled, + } + payload = {k: v for k, v in payload.items() if v is not None} + return self.http.post( + f"/threads/{thread_id}/runs/crons", + json=payload, + headers=headers, + params=params, + ) + + def create( + self, + assistant_id: str, + *, + schedule: str, + input: Input | None = None, + metadata: Mapping[str, Any] | None = None, + config: Config | None = None, + context: Context | None = None, + checkpoint_during: bool | None = None, + interrupt_before: All | list[str] | None = None, + interrupt_after: All | list[str] | None = None, + webhook: str | None = None, + on_run_completed: OnCompletionBehavior | None = None, + multitask_strategy: str | None = None, + end_time: datetime | None = None, + enabled: bool | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Run: + """Create a cron run. + + Args: + assistant_id: The assistant ID or graph name to use for the cron job. + If using graph name, will default to first assistant created from that graph. + schedule: The cron schedule to execute this job on. + Schedules are interpreted in UTC. + input: The input to the graph. + metadata: Metadata to assign to the cron job runs. + config: The configuration for the assistant. + context: Static context to add to the assistant. + !!! version-added "Added in version 0.6.0" + checkpoint_during: Whether to checkpoint during the run (or only at the end/interruption). + interrupt_before: Nodes to interrupt immediately before they get executed. + interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. + webhook: Webhook to call after LangGraph API call is done. + on_run_completed: What to do with the thread after the run completes. + Must be one of 'delete' (default) or 'keep'. 'delete' removes the thread + after execution. 'keep' creates a new thread for each execution but does not + clean them up. Clients are responsible for cleaning up kept threads. + multitask_strategy: Multitask strategy to use. + Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. + end_time: The time to stop running the cron job. If not provided, the cron job will run indefinitely. + enabled: Whether the cron job is enabled. By default, it is considered enabled. + headers: Optional custom headers to include with the request. + + Returns: + The cron `Run`. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:8123") + cron_run = client.crons.create( + assistant_id="agent", + schedule="27 15 * * *", + input={"messages": [{"role": "user", "content": "hello!"}]}, + metadata={"name":"my_run"}, + context={"model_name": "openai"}, + checkpoint_during=True, + interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], + interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], + webhook="https://my.fake.webhook.com", + multitask_strategy="interrupt", + enabled=True + ) + ``` + + """ + payload = { + "schedule": schedule, + "input": input, + "config": config, + "metadata": metadata, + "context": context, + "assistant_id": assistant_id, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "webhook": webhook, + "checkpoint_during": checkpoint_during, + "on_run_completed": on_run_completed, + "multitask_strategy": multitask_strategy, + "end_time": end_time.isoformat() if end_time else None, + "enabled": enabled, + } + payload = {k: v for k, v in payload.items() if v is not None} + return self.http.post( + "/runs/crons", json=payload, headers=headers, params=params + ) + + def delete( + self, + cron_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Delete a cron. + + Args: + cron_id: The cron ID to delete. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:8123") + client.crons.delete( + cron_id="cron_to_delete" + ) + ``` + + """ + self.http.delete(f"/runs/crons/{cron_id}", headers=headers, params=params) + + def update( + self, + cron_id: str, + *, + schedule: str | None = None, + end_time: datetime | None = None, + input: Input | None = None, + metadata: Mapping[str, Any] | None = None, + config: Config | None = None, + context: Context | None = None, + webhook: str | None = None, + interrupt_before: All | list[str] | None = None, + interrupt_after: All | list[str] | None = None, + on_run_completed: OnCompletionBehavior | None = None, + enabled: bool | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Cron: + """Update a cron job by ID. + + Args: + cron_id: The cron ID to update. + schedule: The cron schedule to execute this job on. + Schedules are interpreted in UTC. + end_time: The end date to stop running the cron. + input: The input to the graph. + metadata: Metadata to assign to the cron job runs. + config: The configuration for the assistant. + context: Static context added to the assistant. + webhook: Webhook to call after LangGraph API call is done. + interrupt_before: Nodes to interrupt immediately before they get executed. + interrupt_after: Nodes to interrupt immediately after they get executed. + on_run_completed: What to do with the thread after the run completes. + Must be one of 'delete' or 'keep'. 'delete' removes the thread + after execution. 'keep' creates a new thread for each execution but does not + clean them up. + enabled: Enable or disable the cron job. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + The updated cron job. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:8123") + updated_cron = client.crons.update( + cron_id="1ef3cefa-4c09-6926-96d0-3dc97fd5e39b", + schedule="0 10 * * *", + enabled=False, + ) + ``` + + """ + payload = { + "schedule": schedule, + "end_time": end_time.isoformat() if end_time else None, + "input": input, + "metadata": metadata, + "config": config, + "context": context, + "webhook": webhook, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "on_run_completed": on_run_completed, + "enabled": enabled, + } + payload = {k: v for k, v in payload.items() if v is not None} + return self.http.patch( + f"/runs/crons/{cron_id}", + json=payload, + headers=headers, + params=params, + ) + + def search( + self, + *, + assistant_id: str | None = None, + thread_id: str | None = None, + enabled: bool | None = None, + limit: int = 10, + offset: int = 0, + sort_by: CronSortBy | None = None, + sort_order: SortOrder | None = None, + select: list[CronSelectField] | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> list[Cron]: + """Get a list of cron jobs. + + Args: + assistant_id: The assistant ID or graph name to search for. + thread_id: the thread ID to search for. + enabled: Whether the cron job is enabled. + limit: The maximum number of results to return. + offset: The number of results to skip. + headers: Optional custom headers to include with the request. + + Returns: + The list of cron jobs returned by the search, + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:8123") + cron_jobs = client.crons.search( + assistant_id="my_assistant_id", + thread_id="my_thread_id", + enabled=True, + limit=5, + offset=5, + ) + print(cron_jobs) + ``` + + ```shell + ---------------------------------------------------------- + + [ + { + 'cron_id': '1ef3cefa-4c09-6926-96d0-3dc97fd5e39b', + 'assistant_id': 'my_assistant_id', + 'thread_id': 'my_thread_id', + 'user_id': None, + 'payload': + { + 'input': {'start_time': ''}, + 'schedule': '4 * * * *', + 'assistant_id': 'my_assistant_id' + }, + 'schedule': '4 * * * *', + 'next_run_date': '2024-07-25T17:04:00+00:00', + 'end_time': None, + 'created_at': '2024-07-08T06:02:23.073257+00:00', + 'updated_at': '2024-07-08T06:02:23.073257+00:00' + } + ] + ``` + """ + payload = { + "assistant_id": assistant_id, + "thread_id": thread_id, + "enabled": enabled, + "limit": limit, + "offset": offset, + } + if sort_by: + payload["sort_by"] = sort_by + if sort_order: + payload["sort_order"] = sort_order + if select: + payload["select"] = select + payload = {k: v for k, v in payload.items() if v is not None} + return self.http.post( + "/runs/crons/search", json=payload, headers=headers, params=params + ) + + def count( + self, + *, + assistant_id: str | None = None, + thread_id: str | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> int: + """Count cron jobs matching filters. + + Args: + assistant_id: Assistant ID to filter by. + thread_id: Thread ID to filter by. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + int: Number of crons matching the criteria. + """ + payload: dict[str, Any] = {} + if assistant_id: + payload["assistant_id"] = assistant_id + if thread_id: + payload["thread_id"] = thread_id + return self.http.post( + "/runs/crons/count", json=payload, headers=headers, params=params + ) diff --git a/libs/sdk-py/langgraph_sdk/_sync/http.py b/libs/sdk-py/langgraph_sdk/_sync/http.py new file mode 100644 index 000000000..dccba518f --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_sync/http.py @@ -0,0 +1,296 @@ +"""Synchronous HTTP client for LangGraph API.""" + +from __future__ import annotations + +import logging +import sys +import warnings +from collections.abc import Callable, Iterator, Mapping +from typing import Any, cast + +import httpx +import orjson + +from langgraph_sdk._shared.utilities import _orjson_default +from langgraph_sdk.errors import _raise_for_status_typed +from langgraph_sdk.schema import QueryParamTypes, StreamPart +from langgraph_sdk.sse import SSEDecoder, iter_lines_raw + +logger = logging.getLogger(__name__) + + +class SyncHttpClient: + """Handle synchronous requests to the LangGraph API. + + Provides error messaging and content handling enhancements above the + underlying httpx client, mirroring the interface of [HttpClient](#HttpClient) + but for sync usage. + + Attributes: + client (httpx.Client): Underlying HTTPX sync client. + """ + + def __init__(self, client: httpx.Client) -> None: + self.client = client + + def get( + self, + path: str, + *, + params: QueryParamTypes | None = None, + headers: Mapping[str, str] | None = None, + on_response: Callable[[httpx.Response], None] | None = None, + ) -> Any: + """Send a `GET` request.""" + r = self.client.get(path, params=params, headers=headers) + if on_response: + on_response(r) + _raise_for_status_typed(r) + return _decode_json(r) + + def post( + self, + path: str, + *, + json: dict[str, Any] | list | None, + params: QueryParamTypes | None = None, + headers: Mapping[str, str] | None = None, + on_response: Callable[[httpx.Response], None] | None = None, + ) -> Any: + """Send a `POST` request.""" + if json is not None: + request_headers, content = _encode_json(json) + else: + request_headers, content = {}, b"" + if headers: + request_headers.update(headers) + r = self.client.post( + path, headers=request_headers, content=content, params=params + ) + if on_response: + on_response(r) + _raise_for_status_typed(r) + return _decode_json(r) + + def put( + self, + path: str, + *, + json: dict, + params: QueryParamTypes | None = None, + headers: Mapping[str, str] | None = None, + on_response: Callable[[httpx.Response], None] | None = None, + ) -> Any: + """Send a `PUT` request.""" + request_headers, content = _encode_json(json) + if headers: + request_headers.update(headers) + + r = self.client.put( + path, headers=request_headers, content=content, params=params + ) + if on_response: + on_response(r) + _raise_for_status_typed(r) + return _decode_json(r) + + def patch( + self, + path: str, + *, + json: dict, + params: QueryParamTypes | None = None, + headers: Mapping[str, str] | None = None, + on_response: Callable[[httpx.Response], None] | None = None, + ) -> Any: + """Send a `PATCH` request.""" + request_headers, content = _encode_json(json) + if headers: + request_headers.update(headers) + r = self.client.patch( + path, headers=request_headers, content=content, params=params + ) + if on_response: + on_response(r) + _raise_for_status_typed(r) + return _decode_json(r) + + def delete( + self, + path: str, + *, + json: Any | None = None, + params: QueryParamTypes | None = None, + headers: Mapping[str, str] | None = None, + on_response: Callable[[httpx.Response], None] | None = None, + ) -> None: + """Send a `DELETE` request.""" + r = self.client.request( + "DELETE", path, json=json, params=params, headers=headers + ) + if on_response: + on_response(r) + _raise_for_status_typed(r) + + def request_reconnect( + self, + path: str, + method: str, + *, + json: dict[str, Any] | None = None, + params: QueryParamTypes | None = None, + headers: Mapping[str, str] | None = None, + on_response: Callable[[httpx.Response], None] | None = None, + reconnect_limit: int = 5, + ) -> Any: + """Send a request that automatically reconnects to Location header.""" + request_headers, content = _encode_json(json) + if headers: + request_headers.update(headers) + with self.client.stream( + method, path, headers=request_headers, content=content, params=params + ) as r: + if on_response: + on_response(r) + try: + r.raise_for_status() + except httpx.HTTPStatusError as e: + body = r.read().decode() + if sys.version_info >= (3, 11): + e.add_note(body) + else: + logger.error(f"Error from langgraph-api: {body}", exc_info=e) + raise e + loc = r.headers.get("location") + if reconnect_limit <= 0 or not loc: + return _decode_json(r) + try: + return _decode_json(r) + except httpx.HTTPError: + warnings.warn( + f"Request failed, attempting reconnect to Location: {loc}", + stacklevel=2, + ) + r.close() + return self.request_reconnect( + loc, + "GET", + headers=request_headers, + # don't pass on_response so it's only called once + reconnect_limit=reconnect_limit - 1, + ) + + def stream( + self, + path: str, + method: str, + *, + json: dict[str, Any] | None = None, + params: QueryParamTypes | None = None, + headers: Mapping[str, str] | None = None, + on_response: Callable[[httpx.Response], None] | None = None, + ) -> Iterator[StreamPart]: + """Stream the results of a request using SSE.""" + if json is not None: + request_headers, content = _encode_json(json) + else: + request_headers, content = {}, None + request_headers["Accept"] = "text/event-stream" + request_headers["Cache-Control"] = "no-store" + if headers: + request_headers.update(headers) + + reconnect_headers = { + key: value + for key, value in request_headers.items() + if key.lower() not in {"content-length", "content-type"} + } + + last_event_id: str | None = None + reconnect_path: str | None = None + reconnect_attempts = 0 + max_reconnect_attempts = 5 + + while True: + current_headers = dict( + request_headers if reconnect_path is None else reconnect_headers + ) + if last_event_id is not None: + current_headers["Last-Event-ID"] = last_event_id + + current_method = method if reconnect_path is None else "GET" + current_content = content if reconnect_path is None else None + current_params = params if reconnect_path is None else None + + retry = False + with self.client.stream( + current_method, + reconnect_path or path, + headers=current_headers, + content=current_content, + params=current_params, + ) as res: + if reconnect_path is None and on_response: + on_response(res) + # check status + _raise_for_status_typed(res) + # check content type + content_type = res.headers.get("content-type", "").partition(";")[0] + if "text/event-stream" not in content_type: + raise httpx.TransportError( + "Expected response header Content-Type to contain 'text/event-stream', " + f"got {content_type!r}" + ) + + reconnect_location = res.headers.get("location") + if reconnect_location: + reconnect_path = reconnect_location + + decoder = SSEDecoder() + try: + for line in iter_lines_raw(res): + sse = decoder.decode(cast(bytes, line).rstrip(b"\n")) + if sse is not None: + if decoder.last_event_id is not None: + last_event_id = decoder.last_event_id + if sse.event or sse.data is not None: + yield sse + except httpx.HTTPError: + # httpx.TransportError inherits from HTTPError, so transient + # disconnects during streaming land here. + if reconnect_path is None: + raise + retry = True + else: + if sse := decoder.decode(b""): + if decoder.last_event_id is not None: + last_event_id = decoder.last_event_id + if sse.event or sse.data is not None: + # See async stream implementation for rationale on + # skipping empty flush events. + yield sse + if retry: + reconnect_attempts += 1 + if reconnect_attempts > max_reconnect_attempts: + raise httpx.TransportError( + "Exceeded maximum SSE reconnection attempts" + ) + continue + break + + +def _encode_json(json: Any) -> tuple[dict[str, str], bytes]: + body = orjson.dumps( + json, + _orjson_default, + orjson.OPT_SERIALIZE_NUMPY | orjson.OPT_NON_STR_KEYS, + ) + content_length = str(len(body)) + content_type = "application/json" + headers = {"Content-Length": content_length, "Content-Type": content_type} + return headers, body + + +def _decode_json(r: httpx.Response) -> Any: + body = r.read() + return orjson.loads(body) if body else None diff --git a/libs/sdk-py/langgraph_sdk/_sync/runs.py b/libs/sdk-py/langgraph_sdk/_sync/runs.py new file mode 100644 index 000000000..ab6e1943f --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_sync/runs.py @@ -0,0 +1,999 @@ +"""Synchronous client for managing runs in LangGraph.""" + +from __future__ import annotations + +import warnings +from collections.abc import Callable, Iterator, Mapping, Sequence +from typing import Any, overload + +import httpx + +from langgraph_sdk._shared.utilities import _get_run_metadata_from_response +from langgraph_sdk._sync.http import SyncHttpClient +from langgraph_sdk.schema import ( + All, + CancelAction, + Checkpoint, + Command, + Config, + Context, + DisconnectMode, + Durability, + IfNotExists, + Input, + MultitaskStrategy, + OnCompletionBehavior, + QueryParamTypes, + Run, + RunCreate, + RunCreateMetadata, + RunSelectField, + RunStatus, + StreamMode, + StreamPart, +) + + +class SyncRunsClient: + """Synchronous client for managing runs in LangGraph. + + This class provides methods to create, retrieve, and manage runs, which represent + individual executions of graphs. + + ???+ example "Example" + + ```python + client = get_sync_client(url="http://localhost:2024") + run = client.runs.create(thread_id="thread_123", assistant_id="asst_456") + ``` + """ + + def __init__(self, http: SyncHttpClient) -> None: + self.http = http + + @overload + def stream( + self, + thread_id: str, + assistant_id: str, + *, + input: Input | None = None, + command: Command | None = None, + stream_mode: StreamMode | Sequence[StreamMode] = "values", + stream_subgraphs: bool = False, + metadata: Mapping[str, Any] | None = None, + config: Config | None = None, + context: Context | None = None, + checkpoint: Checkpoint | None = None, + checkpoint_id: str | None = None, + checkpoint_during: bool | None = None, + interrupt_before: All | Sequence[str] | None = None, + interrupt_after: All | Sequence[str] | None = None, + feedback_keys: Sequence[str] | None = None, + on_disconnect: DisconnectMode | None = None, + webhook: str | None = None, + multitask_strategy: MultitaskStrategy | None = None, + if_not_exists: IfNotExists | None = None, + after_seconds: int | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + ) -> Iterator[StreamPart]: ... + + @overload + def stream( + self, + thread_id: None, + assistant_id: str, + *, + input: Input | None = None, + 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, + checkpoint_during: bool | None = None, + interrupt_before: All | Sequence[str] | None = None, + interrupt_after: All | Sequence[str] | None = None, + feedback_keys: Sequence[str] | None = None, + on_disconnect: DisconnectMode | None = None, + on_completion: OnCompletionBehavior | None = None, + if_not_exists: IfNotExists | None = None, + webhook: str | None = None, + after_seconds: int | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + ) -> Iterator[StreamPart]: ... + + def stream( + self, + thread_id: str | None, + assistant_id: str, + *, + input: Input | None = None, + 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, + checkpoint: Checkpoint | None = None, + checkpoint_id: str | None = None, + checkpoint_during: bool | None = None, # deprecated + interrupt_before: All | Sequence[str] | None = None, + interrupt_after: All | Sequence[str] | None = None, + feedback_keys: Sequence[str] | None = None, + on_disconnect: DisconnectMode | None = None, + on_completion: OnCompletionBehavior | None = None, + webhook: str | None = None, + multitask_strategy: MultitaskStrategy | None = None, + if_not_exists: IfNotExists | None = None, + after_seconds: int | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + durability: Durability | None = None, + ) -> Iterator[StreamPart]: + """Create a run and stream the results. + + Args: + thread_id: the thread ID to assign to the thread. + If `None` will create a stateless run. + assistant_id: The assistant ID or graph name to stream from. + If using graph name, will default to first assistant created from that graph. + input: The input to the graph. + command: The command to execute. + stream_mode: The stream mode(s) to use. + stream_subgraphs: Whether to stream output from subgraphs. + stream_resumable: Whether the stream is considered resumable. + If true, the stream can be resumed and replayed in its entirety even after disconnection. + metadata: Metadata to assign to the run. + config: The configuration for the assistant. + context: Static context to add to the assistant. + !!! version-added "Added in version 0.6.0" + checkpoint: The checkpoint to resume from. + checkpoint_during: (deprecated) Whether to checkpoint during the run (or only at the end/interruption). + interrupt_before: Nodes to interrupt immediately before they get executed. + interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. + feedback_keys: Feedback keys to assign to run. + on_disconnect: The disconnect mode to use. + Must be one of 'cancel' or 'continue'. + on_completion: Whether to delete or keep the thread created for a stateless run. + Must be one of 'delete' or 'keep'. + webhook: Webhook to call after LangGraph API call is done. + multitask_strategy: Multitask strategy to use. + Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. + if_not_exists: How to handle missing thread. Defaults to 'reject'. + Must be either 'reject' (raise error if missing), or 'create' (create new thread). + after_seconds: The number of seconds to wait before starting the run. + Use to schedule future runs. + headers: Optional custom headers to include with the request. + on_run_created: Optional callback to call when a run is created. + durability: The durability to use for the run. Values are "sync", "async", or "exit". + "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 + + + Returns: + Iterator of stream results. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + async for chunk in client.runs.stream( + thread_id=None, + assistant_id="agent", + input={"messages": [{"role": "user", "content": "how are you?"}]}, + stream_mode=["values","debug"], + metadata={"name":"my_run"}, + context={"model_name": "anthropic"}, + interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], + interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], + feedback_keys=["my_feedback_key_1","my_feedback_key_2"], + webhook="https://my.fake.webhook.com", + multitask_strategy="interrupt" + ): + print(chunk) + ``` + ```shell + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + + 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) + ``` + """ + if checkpoint_during is not None: + warnings.warn( + "`checkpoint_during` is deprecated and will be removed in a future version. Use `durability` instead.", + DeprecationWarning, + stacklevel=2, + ) + payload = { + "input": input, + "command": ( + {k: v for k, v in command.items() if v is not None} if command else None + ), + "config": config, + "context": context, + "metadata": metadata, + "stream_mode": stream_mode, + "stream_subgraphs": stream_subgraphs, + "stream_resumable": stream_resumable, + "assistant_id": assistant_id, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "feedback_keys": feedback_keys, + "webhook": webhook, + "checkpoint": checkpoint, + "checkpoint_id": checkpoint_id, + "checkpoint_during": checkpoint_during, + "multitask_strategy": multitask_strategy, + "if_not_exists": if_not_exists, + "on_disconnect": on_disconnect, + "on_completion": on_completion, + "after_seconds": after_seconds, + "durability": durability, + } + endpoint = ( + f"/threads/{thread_id}/runs/stream" + if thread_id is not None + else "/runs/stream" + ) + + def on_response(res: httpx.Response): + """Callback function to handle the response.""" + if on_run_created and (metadata := _get_run_metadata_from_response(res)): + on_run_created(metadata) + + return self.http.stream( + endpoint, + "POST", + json={k: v for k, v in payload.items() if v is not None}, + params=params, + headers=headers, + on_response=on_response if on_run_created else None, + ) + + @overload + def create( + self, + thread_id: None, + assistant_id: str, + *, + input: Input | None = None, + 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, + checkpoint_during: bool | None = None, + interrupt_before: All | Sequence[str] | None = None, + interrupt_after: All | Sequence[str] | None = None, + webhook: str | None = None, + on_completion: OnCompletionBehavior | None = None, + if_not_exists: IfNotExists | None = None, + after_seconds: int | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + ) -> Run: ... + + @overload + def create( + self, + thread_id: str, + assistant_id: str, + *, + input: Input | None = None, + 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, + checkpoint: Checkpoint | None = None, + checkpoint_id: str | None = None, + checkpoint_during: bool | None = None, + interrupt_before: All | Sequence[str] | None = None, + interrupt_after: All | Sequence[str] | None = None, + webhook: str | None = None, + multitask_strategy: MultitaskStrategy | None = None, + if_not_exists: IfNotExists | None = None, + after_seconds: int | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + ) -> Run: ... + + def create( + self, + thread_id: str | None, + assistant_id: str, + *, + input: Input | None = None, + 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, + checkpoint: Checkpoint | None = None, + checkpoint_id: str | None = None, + checkpoint_during: bool | None = None, # deprecated + interrupt_before: All | Sequence[str] | None = None, + interrupt_after: All | Sequence[str] | None = None, + webhook: str | None = None, + multitask_strategy: MultitaskStrategy | None = None, + if_not_exists: IfNotExists | None = None, + on_completion: OnCompletionBehavior | None = None, + after_seconds: int | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + durability: Durability | None = None, + ) -> Run: + """Create a background run. + + Args: + thread_id: the thread ID to assign to the thread. + If `None` will create a stateless run. + assistant_id: The assistant ID or graph name to stream from. + If using graph name, will default to first assistant created from that graph. + input: The input to the graph. + command: The command to execute. + stream_mode: The stream mode(s) to use. + stream_subgraphs: Whether to stream output from subgraphs. + stream_resumable: Whether the stream is considered resumable. + If true, the stream can be resumed and replayed in its entirety even after disconnection. + metadata: Metadata to assign to the run. + config: The configuration for the assistant. + context: Static context to add to the assistant. + !!! version-added "Added in version 0.6.0" + checkpoint: The checkpoint to resume from. + checkpoint_during: (deprecated) Whether to checkpoint during the run (or only at the end/interruption). + interrupt_before: Nodes to interrupt immediately before they get executed. + interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. + webhook: Webhook to call after LangGraph API call is done. + multitask_strategy: Multitask strategy to use. + Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. + on_completion: Whether to delete or keep the thread created for a stateless run. + Must be one of 'delete' or 'keep'. + if_not_exists: How to handle missing thread. Defaults to 'reject'. + Must be either 'reject' (raise error if missing), or 'create' (create new thread). + after_seconds: The number of seconds to wait before starting the run. + Use to schedule future runs. + headers: Optional custom headers to include with the request. + on_run_created: Optional callback to call when a run is created. + durability: The durability to use for the run. Values are "sync", "async", or "exit". + "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 + + Returns: + The created background `Run`. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + background_run = client.runs.create( + thread_id="my_thread_id", + assistant_id="my_assistant_id", + input={"messages": [{"role": "user", "content": "hello!"}]}, + metadata={"name":"my_run"}, + context={"model_name": "openai"}, + interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], + interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], + webhook="https://my.fake.webhook.com", + multitask_strategy="interrupt" + ) + print(background_run) + ``` + + ```shell + -------------------------------------------------------------------------------- + + { + 'run_id': 'my_run_id', + 'thread_id': 'my_thread_id', + 'assistant_id': 'my_assistant_id', + 'created_at': '2024-07-25T15:35:42.598503+00:00', + 'updated_at': '2024-07-25T15:35:42.598503+00:00', + 'metadata': {}, + 'status': 'pending', + 'kwargs': + { + 'input': + { + 'messages': [ + { + 'role': 'user', + 'content': 'how are you?' + } + ] + }, + 'config': + { + 'metadata': + { + 'created_by': 'system' + }, + 'configurable': + { + 'run_id': 'my_run_id', + 'user_id': None, + 'graph_id': 'agent', + 'thread_id': 'my_thread_id', + 'checkpoint_id': None, + 'assistant_id': 'my_assistant_id' + } + }, + 'context': + { + 'model_name': 'openai' + }, + 'webhook': "https://my.fake.webhook.com", + 'temporary': False, + 'stream_mode': ['values'], + 'feedback_keys': None, + 'interrupt_after': ["node_to_stop_after_1","node_to_stop_after_2"], + 'interrupt_before': ["node_to_stop_before_1","node_to_stop_before_2"] + }, + 'multitask_strategy': 'interrupt' + } + ``` + """ + if checkpoint_during is not None: + warnings.warn( + "`checkpoint_during` is deprecated and will be removed in a future version. Use `durability` instead.", + DeprecationWarning, + stacklevel=2, + ) + payload = { + "input": input, + "command": ( + {k: v for k, v in command.items() if v is not None} if command else None + ), + "stream_mode": stream_mode, + "stream_subgraphs": stream_subgraphs, + "stream_resumable": stream_resumable, + "config": config, + "context": context, + "metadata": metadata, + "assistant_id": assistant_id, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "webhook": webhook, + "checkpoint": checkpoint, + "checkpoint_id": checkpoint_id, + "checkpoint_during": checkpoint_during, + "multitask_strategy": multitask_strategy, + "if_not_exists": if_not_exists, + "on_completion": on_completion, + "after_seconds": after_seconds, + "durability": durability, + } + payload = {k: v for k, v in payload.items() if v is not None} + + def on_response(res: httpx.Response): + """Callback function to handle the response.""" + if on_run_created and (metadata := _get_run_metadata_from_response(res)): + on_run_created(metadata) + + return self.http.post( + f"/threads/{thread_id}/runs" if thread_id else "/runs", + json=payload, + params=params, + headers=headers, + on_response=on_response if on_run_created else None, + ) + + def create_batch( + self, + payloads: list[RunCreate], + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> list[Run]: + """Create a batch of stateless background runs.""" + + def filter_payload(payload: RunCreate): + return {k: v for k, v in payload.items() if v is not None} + + filtered = [filter_payload(payload) for payload in payloads] + return self.http.post( + "/runs/batch", json=filtered, headers=headers, params=params + ) + + @overload + def wait( + self, + thread_id: str, + assistant_id: str, + *, + input: Input | None = None, + command: Command | None = None, + metadata: Mapping[str, Any] | None = None, + config: Config | None = None, + context: Context | None = None, + checkpoint: Checkpoint | None = None, + checkpoint_id: str | None = None, + checkpoint_during: bool | None = None, + interrupt_before: All | Sequence[str] | None = None, + interrupt_after: All | Sequence[str] | None = None, + webhook: str | None = None, + on_disconnect: DisconnectMode | None = None, + multitask_strategy: MultitaskStrategy | None = None, + if_not_exists: IfNotExists | None = None, + after_seconds: int | None = None, + raise_error: bool = True, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + ) -> list[dict] | dict[str, Any]: ... + + @overload + def wait( + self, + thread_id: None, + assistant_id: str, + *, + input: Input | None = None, + command: Command | None = None, + 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, + webhook: str | None = None, + on_disconnect: DisconnectMode | None = None, + on_completion: OnCompletionBehavior | None = None, + if_not_exists: IfNotExists | None = None, + after_seconds: int | None = None, + raise_error: bool = True, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + ) -> list[dict] | dict[str, Any]: ... + + def wait( + self, + thread_id: str | None, + assistant_id: str, + *, + input: Input | None = None, + command: Command | None = None, + metadata: Mapping[str, Any] | None = None, + config: Config | None = None, + context: Context | None = None, + checkpoint_during: bool | None = None, # deprecated + checkpoint: Checkpoint | None = None, + checkpoint_id: str | None = None, + interrupt_before: All | Sequence[str] | None = None, + interrupt_after: All | Sequence[str] | None = None, + webhook: str | None = None, + on_disconnect: DisconnectMode | None = None, + on_completion: OnCompletionBehavior | None = None, + multitask_strategy: MultitaskStrategy | None = None, + if_not_exists: IfNotExists | None = None, + after_seconds: int | None = None, + raise_error: bool = True, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + on_run_created: Callable[[RunCreateMetadata], None] | None = None, + durability: Durability | None = None, + ) -> list[dict] | dict[str, Any]: + """Create a run, wait until it finishes and return the final state. + + Args: + thread_id: the thread ID to create the run on. + If `None` will create a stateless run. + assistant_id: The assistant ID or graph name to run. + If using graph name, will default to first assistant created from that graph. + input: The input to the graph. + command: The command to execute. + metadata: Metadata to assign to the run. + config: The configuration for the assistant. + context: Static context to add to the assistant. + !!! version-added "Added in version 0.6.0" + checkpoint: The checkpoint to resume from. + checkpoint_during: (deprecated) Whether to checkpoint during the run (or only at the end/interruption). + interrupt_before: Nodes to interrupt immediately before they get executed. + interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. + webhook: Webhook to call after LangGraph API call is done. + on_disconnect: The disconnect mode to use. + Must be one of 'cancel' or 'continue'. + on_completion: Whether to delete or keep the thread created for a stateless run. + Must be one of 'delete' or 'keep'. + multitask_strategy: Multitask strategy to use. + Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. + if_not_exists: How to handle missing thread. Defaults to 'reject'. + Must be either 'reject' (raise error if missing), or 'create' (create new thread). + after_seconds: The number of seconds to wait before starting the run. + Use to schedule future runs. + raise_error: Whether to raise an error if the run fails. + headers: Optional custom headers to include with the request. + on_run_created: Optional callback to call when a run is created. + durability: The durability to use for the run. Values are "sync", "async", or "exit". + "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 + + Returns: + The output of the `Run`. + + ???+ example "Example Usage" + + ```python + + final_state_of_run = client.runs.wait( + thread_id=None, + assistant_id="agent", + input={"messages": [{"role": "user", "content": "how are you?"}]}, + metadata={"name":"my_run"}, + context={"model_name": "anthropic"}, + interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], + interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], + webhook="https://my.fake.webhook.com", + multitask_strategy="interrupt" + ) + print(final_state_of_run) + ``` + + ```shell + + ------------------------------------------------------------------------------------------------------------------------------------------- + + { + 'messages': [ + { + 'content': 'how are you?', + 'additional_kwargs': {}, + 'response_metadata': {}, + 'type': 'human', + 'name': None, + 'id': 'f51a862c-62fe-4866-863b-b0863e8ad78a', + '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-bf1cd3c6-768f-4c16-b62d-ba6f17ad8b36', + 'example': False, + 'tool_calls': [], + 'invalid_tool_calls': [], + 'usage_metadata': None + } + ] + } + ``` + + """ + if checkpoint_during is not None: + warnings.warn( + "`checkpoint_during` is deprecated and will be removed in a future version. Use `durability` instead.", + DeprecationWarning, + stacklevel=2, + ) + payload = { + "input": input, + "command": ( + {k: v for k, v in command.items() if v is not None} if command else None + ), + "config": config, + "context": context, + "metadata": metadata, + "assistant_id": assistant_id, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "webhook": webhook, + "checkpoint": checkpoint, + "checkpoint_id": checkpoint_id, + "multitask_strategy": multitask_strategy, + "if_not_exists": if_not_exists, + "on_disconnect": on_disconnect, + "checkpoint_during": checkpoint_during, + "on_completion": on_completion, + "after_seconds": after_seconds, + "raise_error": raise_error, + "durability": durability, + } + + def on_response(res: httpx.Response): + """Callback function to handle the response.""" + if on_run_created and (metadata := _get_run_metadata_from_response(res)): + on_run_created(metadata) + + endpoint = ( + f"/threads/{thread_id}/runs/wait" if thread_id is not None else "/runs/wait" + ) + return self.http.request_reconnect( + endpoint, + "POST", + json={k: v for k, v in payload.items() if v is not None}, + params=params, + headers=headers, + on_response=on_response if on_run_created else None, + ) + + def list( + self, + thread_id: str, + *, + limit: int = 10, + offset: int = 0, + status: RunStatus | None = None, + select: list[RunSelectField] | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> list[Run]: + """List runs. + + Args: + thread_id: The thread ID to list runs for. + limit: The maximum number of results to return. + offset: The number of results to skip. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + The runs for the thread. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + client.runs.list( + thread_id="thread_id", + limit=5, + offset=5, + ) + ``` + + """ + query_params: dict[str, Any] = {"limit": limit, "offset": offset} + if status is not None: + query_params["status"] = status + if select: + query_params["select"] = select + if params: + query_params.update(params) + return self.http.get( + f"/threads/{thread_id}/runs", params=query_params, headers=headers + ) + + def get( + self, + thread_id: str, + run_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Run: + """Get a run. + + Args: + thread_id: The thread ID to get. + run_id: The run ID to get. + headers: Optional custom headers to include with the request. + + Returns: + `Run` object. + + ???+ example "Example Usage" + + ```python + + run = client.runs.get( + thread_id="thread_id_to_delete", + run_id="run_id_to_delete", + ) + ``` + """ + + return self.http.get( + f"/threads/{thread_id}/runs/{run_id}", headers=headers, params=params + ) + + def cancel( + self, + thread_id: str, + run_id: str, + *, + wait: bool = False, + action: CancelAction = "interrupt", + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Get a run. + + Args: + thread_id: The thread ID to cancel. + run_id: The run ID to cancel. + wait: Whether to wait until run has completed. + action: Action to take when cancelling the run. Possible values + are `interrupt` or `rollback`. Default is `interrupt`. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + client.runs.cancel( + thread_id="thread_id_to_cancel", + run_id="run_id_to_cancel", + wait=True, + action="interrupt" + ) + ``` + + """ + query_params = { + "wait": 1 if wait else 0, + "action": action, + } + if params: + query_params.update(params) + if wait: + return self.http.request_reconnect( + f"/threads/{thread_id}/runs/{run_id}/cancel", + "POST", + json=None, + params=query_params, + headers=headers, + ) + return self.http.post( + f"/threads/{thread_id}/runs/{run_id}/cancel", + json=None, + params=query_params, + headers=headers, + ) + + def join( + self, + thread_id: str, + run_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> dict: + """Block until a run is done. Returns the final state of the thread. + + Args: + thread_id: The thread ID to join. + run_id: The run ID to join. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + client.runs.join( + thread_id="thread_id_to_join", + run_id="run_id_to_join" + ) + ``` + + """ + return self.http.request_reconnect( + f"/threads/{thread_id}/runs/{run_id}/join", + "GET", + headers=headers, + params=params, + ) + + def join_stream( + self, + thread_id: str, + run_id: str, + *, + cancel_on_disconnect: bool = False, + stream_mode: StreamMode | Sequence[StreamMode] | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + last_event_id: str | None = None, + ) -> Iterator[StreamPart]: + """Stream output from a run in real-time, until the run is done. + Output is not buffered, so any output produced before this call will + not be received here. + + Args: + thread_id: The thread ID to join. + run_id: The run ID to join. + stream_mode: The stream mode(s) to use. Must be a subset of the stream modes passed + when creating the run. Background runs default to having the union of all + stream modes. + cancel_on_disconnect: Whether to cancel the run when the stream is disconnected. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + last_event_id: The last event ID to use for the stream. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + client.runs.join_stream( + thread_id="thread_id_to_join", + run_id="run_id_to_join", + stream_mode=["values", "debug"] + ) + ``` + + """ + query_params = { + "stream_mode": stream_mode, + "cancel_on_disconnect": cancel_on_disconnect, + } + if params: + query_params.update(params) + return self.http.stream( + f"/threads/{thread_id}/runs/{run_id}/stream", + "GET", + params=query_params, + headers={ + **({"Last-Event-ID": last_event_id} if last_event_id else {}), + **(headers or {}), + } + or None, + ) + + def delete( + self, + thread_id: str, + run_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Delete a run. + + Args: + thread_id: The thread ID to delete. + run_id: The run ID to delete. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + client.runs.delete( + thread_id="thread_id_to_delete", + run_id="run_id_to_delete" + ) + ``` + + """ + self.http.delete( + f"/threads/{thread_id}/runs/{run_id}", headers=headers, params=params + ) diff --git a/libs/sdk-py/langgraph_sdk/_sync/store.py b/libs/sdk-py/langgraph_sdk/_sync/store.py new file mode 100644 index 000000000..ae9bf4134 --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_sync/store.py @@ -0,0 +1,313 @@ +"""Synchronous store client for LangGraph SDK.""" + +from __future__ import annotations + +from collections.abc import Mapping, Sequence +from typing import Any, Literal + +from langgraph_sdk._shared.utilities import _provided_vals +from langgraph_sdk._sync.http import SyncHttpClient +from langgraph_sdk.schema import ( + Item, + ListNamespaceResponse, + QueryParamTypes, + SearchItemsResponse, +) + + +class SyncStoreClient: + """A client for synchronous operations on a key-value store. + + Provides methods to interact with a remote key-value store, allowing + storage and retrieval of items within namespaced hierarchies. + + ???+ example "Example" + + ```python + client = get_sync_client(url="http://localhost:2024")) + client.store.put_item(["users", "profiles"], "user123", {"name": "Alice", "age": 30}) + ``` + """ + + def __init__(self, http: SyncHttpClient) -> None: + self.http = http + + def put_item( + self, + namespace: Sequence[str], + /, + key: str, + value: Mapping[str, Any], + index: Literal[False] | list[str] | None = None, + ttl: int | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Store or update an item. + + Args: + namespace: A list of strings representing the namespace path. + key: The unique identifier for the item within the namespace. + value: A dictionary containing the item's data. + index: Controls search indexing - None (use defaults), False (disable), or list of field paths to index. + ttl: Optional time-to-live in minutes for the item, or None for no expiration. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:8123") + client.store.put_item( + ["documents", "user123"], + key="item456", + value={"title": "My Document", "content": "Hello World"} + ) + ``` + """ + for label in namespace: + if "." in label: + raise ValueError( + f"Invalid namespace label '{label}'. Namespace labels cannot contain periods ('.')." + ) + payload = { + "namespace": namespace, + "key": key, + "value": value, + "index": index, + "ttl": ttl, + } + self.http.put( + "/store/items", json=_provided_vals(payload), headers=headers, params=params + ) + + def get_item( + self, + namespace: Sequence[str], + /, + key: str, + *, + refresh_ttl: bool | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Item: + """Retrieve a single item. + + Args: + key: The unique identifier for the item. + namespace: Optional list of strings representing the namespace path. + refresh_ttl: Whether to refresh the TTL on this read operation. If `None`, uses the store's default behavior. + headers: Optional custom headers to include with the request. + + Returns: + The retrieved item. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:8123") + item = client.store.get_item( + ["documents", "user123"], + key="item456", + ) + print(item) + ``` + + ```shell + ---------------------------------------------------------------- + + { + 'namespace': ['documents', 'user123'], + 'key': 'item456', + 'value': {'title': 'My Document', 'content': 'Hello World'}, + 'created_at': '2024-07-30T12:00:00Z', + 'updated_at': '2024-07-30T12:00:00Z' + } + ``` + """ + for label in namespace: + if "." in label: + raise ValueError( + f"Invalid namespace label '{label}'. Namespace labels cannot contain periods ('.')." + ) + + query_params = {"key": key, "namespace": ".".join(namespace)} + if refresh_ttl is not None: + query_params["refresh_ttl"] = refresh_ttl + if params: + query_params.update(params) + return self.http.get("/store/items", params=query_params, headers=headers) + + def delete_item( + self, + namespace: Sequence[str], + /, + key: str, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Delete an item. + + Args: + key: The unique identifier for the item. + namespace: Optional list of strings representing the namespace path. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:8123") + client.store.delete_item( + ["documents", "user123"], + key="item456", + ) + ``` + """ + self.http.delete( + "/store/items", + json={"key": key, "namespace": namespace}, + headers=headers, + params=params, + ) + + def search_items( + self, + namespace_prefix: Sequence[str], + /, + filter: Mapping[str, Any] | None = None, + limit: int = 10, + offset: int = 0, + query: str | None = None, + refresh_ttl: bool | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> SearchItemsResponse: + """Search for items within a namespace prefix. + + Args: + namespace_prefix: List of strings representing the namespace prefix. + filter: Optional dictionary of key-value pairs to filter results. + limit: Maximum number of items to return (default is 10). + offset: Number of items to skip before returning results (default is 0). + query: Optional query for natural language search. + refresh_ttl: Whether to refresh the TTL on items returned by this search. If `None`, uses the store's default behavior. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + A list of items matching the search criteria. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:8123") + items = client.store.search_items( + ["documents"], + filter={"author": "John Doe"}, + limit=5, + offset=0 + ) + print(items) + ``` + ```shell + ---------------------------------------------------------------- + + { + "items": [ + { + "namespace": ["documents", "user123"], + "key": "item789", + "value": { + "title": "Another Document", + "author": "John Doe" + }, + "created_at": "2024-07-30T12:00:00Z", + "updated_at": "2024-07-30T12:00:00Z" + }, + # ... additional items ... + ] + } + ``` + """ + payload = { + "namespace_prefix": namespace_prefix, + "filter": filter, + "limit": limit, + "offset": offset, + "query": query, + "refresh_ttl": refresh_ttl, + } + return self.http.post( + "/store/items/search", + json=_provided_vals(payload), + headers=headers, + params=params, + ) + + def list_namespaces( + self, + prefix: list[str] | None = None, + suffix: list[str] | None = None, + max_depth: int | None = None, + limit: int = 100, + offset: int = 0, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> ListNamespaceResponse: + """List namespaces with optional match conditions. + + Args: + prefix: Optional list of strings representing the prefix to filter namespaces. + suffix: Optional list of strings representing the suffix to filter namespaces. + max_depth: Optional integer specifying the maximum depth of namespaces to return. + limit: Maximum number of namespaces to return (default is 100). + offset: Number of namespaces to skip before returning results (default is 0). + headers: Optional custom headers to include with the request. + + Returns: + A list of namespaces matching the criteria. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:8123") + namespaces = client.store.list_namespaces( + prefix=["documents"], + max_depth=3, + limit=10, + offset=0 + ) + print(namespaces) + ``` + + ```shell + ---------------------------------------------------------------- + + [ + ["documents", "user123", "reports"], + ["documents", "user456", "invoices"], + ... + ] + ``` + """ + payload = { + "prefix": prefix, + "suffix": suffix, + "max_depth": max_depth, + "limit": limit, + "offset": offset, + } + return self.http.post( + "/store/namespaces", + json=_provided_vals(payload), + headers=headers, + params=params, + ) diff --git a/libs/sdk-py/langgraph_sdk/_sync/threads.py b/libs/sdk-py/langgraph_sdk/_sync/threads.py new file mode 100644 index 000000000..1086da193 --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/_sync/threads.py @@ -0,0 +1,654 @@ +"""Synchronous client for managing threads in LangGraph.""" + +from __future__ import annotations + +from collections.abc import Iterator, Mapping, Sequence +from typing import Any + +from langgraph_sdk._sync.http import SyncHttpClient +from langgraph_sdk.schema import ( + Checkpoint, + Json, + OnConflictBehavior, + QueryParamTypes, + SortOrder, + StreamPart, + Thread, + ThreadSelectField, + ThreadSortBy, + ThreadState, + ThreadStatus, + ThreadStreamMode, + ThreadUpdateStateResponse, +) + + +class SyncThreadsClient: + """Synchronous client for managing threads in LangGraph. + + This class provides methods to create, retrieve, and manage threads, + which represent conversations or stateful interactions. + + ???+ example "Example" + + ```python + client = get_sync_client(url="http://localhost:2024") + thread = client.threads.create(metadata={"user_id": "123"}) + ``` + """ + + def __init__(self, http: SyncHttpClient) -> None: + self.http = http + + def get( + self, + thread_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Thread: + """Get a thread by ID. + + Args: + thread_id: The ID of the thread to get. + headers: Optional custom headers to include with the request. + + Returns: + `Thread` object. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + thread = client.threads.get( + thread_id="my_thread_id" + ) + print(thread) + ``` + ```shell + ----------------------------------------------------- + + { + 'thread_id': 'my_thread_id', + 'created_at': '2024-07-18T18:35:15.540834+00:00', + 'updated_at': '2024-07-18T18:35:15.540834+00:00', + 'metadata': {'graph_id': 'agent'} + } + ``` + + """ + + return self.http.get(f"/threads/{thread_id}", headers=headers, params=params) + + def create( + self, + *, + metadata: Json = None, + thread_id: str | None = None, + if_exists: OnConflictBehavior | None = None, + supersteps: Sequence[dict[str, Sequence[dict[str, Any]]]] | None = None, + graph_id: str | None = None, + ttl: int | Mapping[str, Any] | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Thread: + """Create a new thread. + + Args: + metadata: Metadata to add to thread. + thread_id: ID of thread. + If `None`, ID will be a randomly generated UUID. + if_exists: How to handle duplicate creation. Defaults to 'raise' under the hood. + Must be either 'raise' (raise error if duplicate), or 'do_nothing' (return existing thread). + supersteps: Apply a list of supersteps when creating a thread, each containing a sequence of updates. + Each update has `values` or `command` and `as_node`. Used for copying a thread between deployments. + graph_id: Optional graph ID to associate with the thread. + ttl: Optional time-to-live in minutes for the thread. You can pass an + integer (minutes) or a mapping with keys `ttl` and optional + `strategy` (defaults to "delete"). + headers: Optional custom headers to include with the request. + + Returns: + The created `Thread`. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + thread = client.threads.create( + metadata={"number":1}, + thread_id="my-thread-id", + if_exists="raise" + ) + ``` + ) + """ + payload: dict[str, Any] = {} + 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 + if supersteps: + payload["supersteps"] = [ + { + "updates": [ + { + "values": u["values"], + "command": u.get("command"), + "as_node": u["as_node"], + } + for u in s["updates"] + ] + } + for s in supersteps + ] + if ttl is not None: + if isinstance(ttl, (int, float)): + payload["ttl"] = {"ttl": ttl, "strategy": "delete"} + else: + payload["ttl"] = ttl + + return self.http.post("/threads", json=payload, headers=headers, params=params) + + def update( + self, + thread_id: str, + *, + metadata: Mapping[str, Any], + ttl: int | Mapping[str, Any] | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Thread: + """Update a thread. + + Args: + thread_id: ID of thread to update. + metadata: Metadata to merge with existing thread metadata. + ttl: Optional time-to-live in minutes for the thread. You can pass an + integer (minutes) or a mapping with keys `ttl` and optional + `strategy` (defaults to "delete"). + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + The created `Thread`. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + thread = client.threads.update( + thread_id="my-thread-id", + metadata={"number":1}, + ttl=43_200, + ) + ``` + """ + payload: dict[str, Any] = {"metadata": metadata} + if ttl is not None: + if isinstance(ttl, (int, float)): + payload["ttl"] = {"ttl": ttl, "strategy": "delete"} + else: + payload["ttl"] = ttl + return self.http.patch( + f"/threads/{thread_id}", + json=payload, + headers=headers, + params=params, + ) + + def delete( + self, + thread_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Delete a thread. + + Args: + thread_id: The ID of the thread to delete. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client.threads.delete( + thread_id="my_thread_id" + ) + ``` + + """ + self.http.delete(f"/threads/{thread_id}", headers=headers, params=params) + + def search( + self, + *, + metadata: Json = None, + values: Json = None, + ids: Sequence[str] | None = None, + status: ThreadStatus | None = None, + limit: int = 10, + offset: int = 0, + sort_by: ThreadSortBy | None = None, + sort_order: SortOrder | None = None, + select: list[ThreadSelectField] | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> list[Thread]: + """Search for threads. + + Args: + metadata: Thread metadata to filter on. + values: State values to filter on. + ids: List of thread IDs to filter by. + status: Thread status to filter on. + Must be one of 'idle', 'busy', 'interrupted' or 'error'. + limit: Limit on number of threads to return. + offset: Offset in threads table to start search from. + headers: Optional custom headers to include with the request. + + Returns: + List of the threads matching the search parameters. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + threads = client.threads.search( + metadata={"number":1}, + status="interrupted", + limit=15, + offset=5 + ) + ``` + """ + payload: dict[str, Any] = { + "limit": limit, + "offset": offset, + } + if metadata: + payload["metadata"] = metadata + if values: + payload["values"] = values + if ids: + payload["ids"] = ids + if status: + payload["status"] = status + if sort_by: + payload["sort_by"] = sort_by + if sort_order: + payload["sort_order"] = sort_order + if select: + payload["select"] = select + return self.http.post( + "/threads/search", json=payload, headers=headers, params=params + ) + + def count( + self, + *, + metadata: Json = None, + values: Json = None, + status: ThreadStatus | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> int: + """Count threads matching filters. + + Args: + metadata: Thread metadata to filter on. + values: State values to filter on. + status: Thread status to filter on. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + int: Number of threads matching the criteria. + """ + payload: dict[str, Any] = {} + if metadata: + payload["metadata"] = metadata + if values: + payload["values"] = values + if status: + payload["status"] = status + return self.http.post( + "/threads/count", json=payload, headers=headers, params=params + ) + + def copy( + self, + thread_id: str, + *, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Copy a thread. + + Args: + thread_id: The ID of the thread to copy. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + client.threads.copy( + thread_id="my_thread_id" + ) + ``` + + """ + return self.http.post( + f"/threads/{thread_id}/copy", json=None, headers=headers, params=params + ) + + def get_state( + self, + thread_id: str, + checkpoint: Checkpoint | None = None, + checkpoint_id: str | None = None, # deprecated + *, + subgraphs: bool = False, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> ThreadState: + """Get the state of a thread. + + Args: + thread_id: The ID of the thread to get the state of. + checkpoint: The checkpoint to get the state of. + subgraphs: Include subgraphs states. + headers: Optional custom headers to include with the request. + + Returns: + The thread of the state. + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + thread_state = client.threads.get_state( + thread_id="my_thread_id", + checkpoint_id="my_checkpoint_id" + ) + print(thread_state) + ``` + + ```shell + ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + { + 'values': { + '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 + } + ] + }, + 'next': [], + 'checkpoint': + { + 'thread_id': 'e2496803-ecd5-4e0c-a779-3226296181c2', + 'checkpoint_ns': '', + 'checkpoint_id': '1ef4a9b8-e6fb-67b1-8001-abd5184439d1' + } + 'metadata': + { + 'step': 1, + 'run_id': '1ef4a9b8-d7da-679a-a45a-872054341df2', + 'source': 'loop', + 'writes': + { + 'agent': + { + 'messages': [ + { + 'id': 'run-159b782c-b679-4830-83c6-cef87798fe8b', + 'name': None, + 'type': 'ai', + 'content': "I'm doing well, thanks for asking! I'm an AI assistant created by Anthropic to be helpful, honest, and harmless.", + 'example': False, + 'tool_calls': [], + 'usage_metadata': None, + 'additional_kwargs': {}, + 'response_metadata': {}, + 'invalid_tool_calls': [] + } + ] + } + }, + 'user_id': None, + 'graph_id': 'agent', + 'thread_id': 'e2496803-ecd5-4e0c-a779-3226296181c2', + 'created_by': 'system', + 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, + 'created_at': '2024-07-25T15:35:44.184703+00:00', + 'parent_config': + { + 'thread_id': 'e2496803-ecd5-4e0c-a779-3226296181c2', + 'checkpoint_ns': '', + 'checkpoint_id': '1ef4a9b8-d80d-6fa7-8000-9300467fad0f' + } + } + ``` + + """ + if checkpoint: + return self.http.post( + f"/threads/{thread_id}/state/checkpoint", + json={"checkpoint": checkpoint, "subgraphs": subgraphs}, + headers=headers, + params=params, + ) + elif checkpoint_id: + get_params = {"subgraphs": subgraphs} + if params: + get_params = {**get_params, **params} + return self.http.get( + f"/threads/{thread_id}/state/{checkpoint_id}", + params=get_params, + headers=headers, + ) + else: + get_params = {"subgraphs": subgraphs} + if params: + get_params = {**get_params, **params} + return self.http.get( + f"/threads/{thread_id}/state", + params=get_params, + headers=headers, + ) + + def update_state( + self, + thread_id: str, + values: dict[str, Any] | Sequence[dict] | None, + *, + as_node: str | None = None, + checkpoint: Checkpoint | None = None, + checkpoint_id: str | None = None, # deprecated + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> ThreadUpdateStateResponse: + """Update the state of 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. + headers: Optional custom headers to include with the request. + + Returns: + Response after updating a thread's state. + + ???+ example "Example Usage" + + ```python + + response = await 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': {} + } + } + ``` + + """ + payload: dict[str, Any] = { + "values": values, + } + if checkpoint_id: + payload["checkpoint_id"] = checkpoint_id + if checkpoint: + payload["checkpoint"] = checkpoint + if as_node: + payload["as_node"] = as_node + return self.http.post( + f"/threads/{thread_id}/state", json=payload, headers=headers, params=params + ) + + def get_history( + self, + thread_id: str, + *, + limit: int = 10, + before: str | Checkpoint | None = None, + metadata: Mapping[str, Any] | None = None, + checkpoint: Checkpoint | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> list[ThreadState]: + """Get the state history of a thread. + + Args: + thread_id: The ID of the thread to get the state history for. + checkpoint: Return states for this subgraph. If empty defaults to root. + limit: The maximum number of states to return. + before: Return states before this checkpoint. + metadata: Filter states by metadata key-value pairs. + headers: Optional custom headers to include with the request. + + Returns: + The state history of the `Thread`. + + ???+ example "Example Usage" + + ```python + + thread_state = client.threads.get_history( + thread_id="my_thread_id", + limit=5, + before="my_timestamp", + metadata={"name":"my_name"} + ) + ``` + + """ + payload: dict[str, Any] = { + "limit": limit, + } + if before: + payload["before"] = before + if metadata: + payload["metadata"] = metadata + if checkpoint: + payload["checkpoint"] = checkpoint + return self.http.post( + f"/threads/{thread_id}/history", + json=payload, + headers=headers, + params=params, + ) + + def join_stream( + self, + thread_id: str, + *, + stream_mode: ThreadStreamMode | Sequence[ThreadStreamMode] = "run_modes", + last_event_id: str | None = None, + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> Iterator[StreamPart]: + """Get a stream of events for a thread. + + Args: + thread_id: The ID of the thread to get the stream for. + last_event_id: The ID of the last event to get. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + An iterator of stream parts. + + ???+ example "Example Usage" + + ```python + + for chunk in client.threads.join_stream( + thread_id="my_thread_id", + last_event_id="my_event_id", + stream_mode="run_modes", + ): + print(chunk) + ``` + + """ + query_params = { + "stream_mode": stream_mode, + } + if params: + query_params.update(params) + return self.http.stream( + f"/threads/{thread_id}/stream", + "GET", + headers={ + **({"Last-Event-ID": last_event_id} if last_event_id else {}), + **(headers or {}), + }, + params=query_params, + ) diff --git a/libs/sdk-py/langgraph_sdk/client.py b/libs/sdk-py/langgraph_sdk/client.py index a0b0a3263..f9ce571e8 100644 --- a/libs/sdk-py/langgraph_sdk/client.py +++ b/libs/sdk-py/langgraph_sdk/client.py @@ -9,7084 +9,47 @@ Store. from __future__ import annotations -import asyncio -import functools -import logging -import os -import re -import sys -import warnings -from collections.abc import AsyncIterator, Callable, Iterator, Mapping, Sequence -from datetime import datetime -from types import TracebackType -from typing import ( - Any, - Literal, - cast, - overload, -) - -import httpx -import orjson - -import langgraph_sdk -from langgraph_sdk.errors import _araise_for_status_typed, _raise_for_status_typed -from langgraph_sdk.schema import ( - All, - Assistant, - AssistantSelectField, - AssistantSortBy, - AssistantsSearchResponse, - AssistantVersion, - CancelAction, - Checkpoint, - Command, - Config, - Context, - Cron, - CronSelectField, - CronSortBy, - DisconnectMode, - Durability, - GraphSchema, - IfNotExists, - Input, - Item, - Json, - ListNamespaceResponse, - MultitaskStrategy, - OnCompletionBehavior, - OnConflictBehavior, - QueryParamTypes, - Run, - RunCreate, - RunCreateMetadata, - RunSelectField, - RunStatus, - SearchItemsResponse, - SortOrder, - StreamMode, - StreamPart, - Subgraphs, - Thread, - ThreadSelectField, - ThreadSortBy, - ThreadState, - ThreadStatus, - ThreadStreamMode, - ThreadUpdateStateResponse, -) -from langgraph_sdk.sse import SSEDecoder, aiter_lines_raw, iter_lines_raw - -logger = logging.getLogger(__name__) - - -RESERVED_HEADERS = ("x-api-key",) - -NOT_PROVIDED = cast(None, object()) - - -def _get_api_key(api_key: str | None = NOT_PROVIDED) -> str | None: - """Get the API key from the environment. - Precedence: - 1. explicit string argument - 2. LANGGRAPH_API_KEY (if api_key not provided) - 3. LANGSMITH_API_KEY (if api_key not provided) - 4. LANGCHAIN_API_KEY (if api_key not provided) - - Args: - api_key: The API key to use. Can be: - - A string: use this exact API key - - None: explicitly skip loading from environment - - NOT_PROVIDED (default): auto-load from environment variables - """ - if isinstance(api_key, str): - return api_key - if api_key is NOT_PROVIDED: - # api_key is not explicitly provided, try to load from environment - for prefix in ["LANGGRAPH", "LANGSMITH", "LANGCHAIN"]: - if env := os.getenv(f"{prefix}_API_KEY"): - return env.strip().strip('"').strip("'") - # api_key is explicitly None, don't load from environment - return None - - -def _get_headers( - api_key: str | None, - custom_headers: Mapping[str, str] | None, -) -> dict[str, str]: - """Combine api_key and custom user-provided headers.""" - custom_headers = custom_headers or {} - for header in RESERVED_HEADERS: - if header in custom_headers: - raise ValueError(f"Cannot set reserved header '{header}'") - - headers = { - "User-Agent": f"langgraph-sdk-py/{langgraph_sdk.__version__}", - **custom_headers, - } - resolved_api_key = _get_api_key(api_key) - if resolved_api_key: - headers["x-api-key"] = resolved_api_key - - return headers - - -def _orjson_default(obj: Any) -> Any: - is_class = isinstance(obj, type) - if hasattr(obj, "model_dump") and callable(obj.model_dump): - if is_class: - raise TypeError( - f"Cannot JSON-serialize type object: {obj!r}. Did you mean to pass an instance of the object instead?" - f"\nReceived type: {obj!r}" - ) - return obj.model_dump() - elif hasattr(obj, "dict") and callable(obj.dict): - if is_class: - raise TypeError( - f"Cannot JSON-serialize type object: {obj!r}. Did you mean to pass an instance of the object instead?" - f"\nReceived type: {obj!r}" - ) - return obj.dict() - elif isinstance(obj, (set, frozenset)): - return list(obj) - else: - raise TypeError(f"Object of type {type(obj)} is not JSON serializable") - - -# Compiled regex pattern for extracting run metadata from Content-Location header -_RUN_METADATA_PATTERN = re.compile( - r"(\/threads\/(?P.+))?\/runs\/(?P.+)" -) - - -def _get_run_metadata_from_response( - response: httpx.Response, -) -> RunCreateMetadata | None: - """Extract run metadata from the response headers.""" - if (content_location := response.headers.get("Content-Location")) and ( - match := _RUN_METADATA_PATTERN.search(content_location) - ): - return RunCreateMetadata( - run_id=match.group("run_id"), - thread_id=match.group("thread_id") or None, - ) - - return None - - -def get_client( - *, - url: str | None = None, - api_key: str | None = NOT_PROVIDED, - headers: Mapping[str, str] | None = None, - timeout: TimeoutTypes | None = None, -) -> LangGraphClient: - """Create and configure a LangGraphClient. - - The client provides programmatic access to LangSmith Deployment. It supports - both remote servers and local in-process connections (when running inside a LangGraph server). - - Args: - url: - Base URL of the LangGraph API. - - If `None`, the client first attempts an in-process connection via ASGI transport. - If that fails, it defers registration until after app initialization. This - only works if the client is used from within the Agent server. - api_key: - API key for authentication. Can be: - - A string: use this exact API key - - `None`: explicitly skip loading from environment variables - - Not provided (default): auto-load from environment in this order: - 1. `LANGGRAPH_API_KEY` - 2. `LANGSMITH_API_KEY` - 3. `LANGCHAIN_API_KEY` - headers: - Additional HTTP headers to include in requests. Merged with authentication headers. - timeout: - HTTP timeout configuration. May be: - - `httpx.Timeout` instance - - float (total seconds) - - tuple `(connect, read, write, pool)` in seconds - Defaults: connect=5, read=300, write=300, pool=5. - - Returns: - LangGraphClient: - A top-level client exposing sub-clients for assistants, threads, - runs, and cron operations. - - ???+ example "Connect to a remote server:" - - ```python - from langgraph_sdk import get_client - - # get top-level LangGraphClient - client = get_client(url="http://localhost:8123") - - # example usage: client..() - assistants = await client.assistants.get(assistant_id="some_uuid") - ``` - - ???+ example "Connect in-process to a running LangGraph server:" - - ```python - from langgraph_sdk import get_client - - client = get_client(url=None) - - async def my_node(...): - subagent_result = await client.runs.wait( - thread_id=None, - assistant_id="agent", - input={"messages": [{"role": "user", "content": "Foo"}]}, - ) - ``` - - ???+ example "Skip auto-loading API key from environment:" - - ```python - from langgraph_sdk import get_client - - # Don't load API key from environment variables - client = get_client( - url="http://localhost:8123", - api_key=None - ) - ``` - """ - - transport: httpx.AsyncBaseTransport | None = None - if url is None: - url = "http://api" - if os.environ.get("__LANGGRAPH_DEFER_LOOPBACK_TRANSPORT") == "true": - transport = get_asgi_transport()(app=None, root_path="/noauth") - _registered_transports.append(transport) - else: - try: - from langgraph_api.server import app # type: ignore - - transport = get_asgi_transport()(app, root_path="/noauth") - except Exception: - logger.debug( - "Failed to connect to in-process LangGraph server. Deferring configuration.", - exc_info=True, - ) - transport = get_asgi_transport()(app=None, root_path="/noauth") - _registered_transports.append(transport) - - if transport is None: - transport = httpx.AsyncHTTPTransport(retries=5) - client = httpx.AsyncClient( - base_url=url, - transport=transport, - timeout=( - httpx.Timeout(timeout) # ty: ignore[invalid-argument-type] - if timeout is not None - else httpx.Timeout(connect=5, read=300, write=300, pool=5) - ), - headers=_get_headers(api_key, headers), - ) - return LangGraphClient(client) - - -class LangGraphClient: - """Top-level client for LangGraph API. - - Attributes: - assistants: Manages versioned configuration for your graphs. - threads: Handles (potentially) multi-turn interactions, such as conversational threads. - runs: Controls individual invocations of the graph. - crons: Manages scheduled operations. - store: Interfaces with persistent, shared data storage. - """ - - def __init__(self, client: httpx.AsyncClient) -> None: - self.http = HttpClient(client) - self.assistants = AssistantsClient(self.http) - self.threads = ThreadsClient(self.http) - self.runs = RunsClient(self.http) - self.crons = CronClient(self.http) - self.store = StoreClient(self.http) - - async def __aenter__(self) -> LangGraphClient: - """Enter the async context manager.""" - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - """Exit the async context manager.""" - await self.aclose() - - async def aclose(self) -> None: - """Close the underlying HTTP client.""" - if hasattr(self, "http"): - await self.http.client.aclose() - - -class HttpClient: - """Handle async requests to the LangGraph API. - - Adds additional error messaging & content handling above the - provided httpx client. - - Attributes: - client (httpx.AsyncClient): Underlying HTTPX async client. - """ - - def __init__(self, client: httpx.AsyncClient) -> None: - self.client = client - - async def get( - self, - path: str, - *, - params: QueryParamTypes | None = None, - headers: Mapping[str, str] | None = None, - on_response: Callable[[httpx.Response], None] | None = None, - ) -> Any: - """Send a `GET` request.""" - r = await self.client.get(path, params=params, headers=headers) - if on_response: - on_response(r) - await _araise_for_status_typed(r) - return await _adecode_json(r) - - async def post( - self, - path: str, - *, - json: dict[str, Any] | list | None, - params: QueryParamTypes | None = None, - headers: Mapping[str, str] | None = None, - on_response: Callable[[httpx.Response], None] | None = None, - ) -> Any: - """Send a `POST` request.""" - if json is not None: - request_headers, content = await _aencode_json(json) - else: - request_headers, content = {}, b"" - # Merge headers, with runtime headers taking precedence - if headers: - request_headers.update(headers) - r = await self.client.post( - path, headers=request_headers, content=content, params=params - ) - if on_response: - on_response(r) - await _araise_for_status_typed(r) - return await _adecode_json(r) - - async def put( - self, - path: str, - *, - json: dict, - params: QueryParamTypes | None = None, - headers: Mapping[str, str] | None = None, - on_response: Callable[[httpx.Response], None] | None = None, - ) -> Any: - """Send a `PUT` request.""" - request_headers, content = await _aencode_json(json) - if headers: - request_headers.update(headers) - r = await self.client.put( - path, headers=request_headers, content=content, params=params - ) - if on_response: - on_response(r) - await _araise_for_status_typed(r) - return await _adecode_json(r) - - async def patch( - self, - path: str, - *, - json: dict, - params: QueryParamTypes | None = None, - headers: Mapping[str, str] | None = None, - on_response: Callable[[httpx.Response], None] | None = None, - ) -> Any: - """Send a `PATCH` request.""" - request_headers, content = await _aencode_json(json) - if headers: - request_headers.update(headers) - r = await self.client.patch( - path, headers=request_headers, content=content, params=params - ) - if on_response: - on_response(r) - await _araise_for_status_typed(r) - return await _adecode_json(r) - - async def delete( - self, - path: str, - *, - json: Any | None = None, - params: QueryParamTypes | None = None, - headers: Mapping[str, str] | None = None, - on_response: Callable[[httpx.Response], None] | None = None, - ) -> None: - """Send a `DELETE` request.""" - r = await self.client.request( - "DELETE", path, json=json, params=params, headers=headers - ) - if on_response: - on_response(r) - await _araise_for_status_typed(r) - - async def request_reconnect( - self, - path: str, - method: str, - *, - json: dict[str, Any] | None = None, - params: QueryParamTypes | None = None, - headers: Mapping[str, str] | None = None, - on_response: Callable[[httpx.Response], None] | None = None, - reconnect_limit: int = 5, - ) -> Any: - """Send a request that automatically reconnects to Location header.""" - request_headers, content = await _aencode_json(json) - if headers: - request_headers.update(headers) - async with self.client.stream( - method, path, headers=request_headers, content=content, params=params - ) as r: - if on_response: - on_response(r) - try: - r.raise_for_status() - except httpx.HTTPStatusError as e: - body = (await r.aread()).decode() - if sys.version_info >= (3, 11): - e.add_note(body) - else: - logger.error(f"Error from langgraph-api: {body}", exc_info=e) - raise e - loc = r.headers.get("location") - if reconnect_limit <= 0 or not loc: - return await _adecode_json(r) - try: - return await _adecode_json(r) - except httpx.HTTPError: - warnings.warn( - f"Request failed, attempting reconnect to Location: {loc}", - stacklevel=2, - ) - await r.aclose() - return await self.request_reconnect( - loc, - "GET", - headers=request_headers, - # don't pass on_response so it's only called once - reconnect_limit=reconnect_limit - 1, - ) - - async def stream( - self, - path: str, - method: str, - *, - json: dict[str, Any] | None = None, - params: QueryParamTypes | None = None, - headers: Mapping[str, str] | None = None, - on_response: Callable[[httpx.Response], None] | None = None, - ) -> AsyncIterator[StreamPart]: - """Stream results using SSE.""" - request_headers, content = await _aencode_json(json) - request_headers["Accept"] = "text/event-stream" - request_headers["Cache-Control"] = "no-store" - # Add runtime headers with precedence - if headers: - request_headers.update(headers) - - reconnect_headers = { - key: value - for key, value in request_headers.items() - if key.lower() not in {"content-length", "content-type"} - } - - last_event_id: str | None = None - reconnect_path: str | None = None - reconnect_attempts = 0 - max_reconnect_attempts = 5 - - while True: - current_headers = dict( - request_headers if reconnect_path is None else reconnect_headers - ) - if last_event_id is not None: - current_headers["Last-Event-ID"] = last_event_id - - current_method = method if reconnect_path is None else "GET" - current_content = content if reconnect_path is None else None - current_params = params if reconnect_path is None else None - - retry = False - async with self.client.stream( - current_method, - reconnect_path or path, - headers=current_headers, - content=current_content, - params=current_params, - ) as res: - if reconnect_path is None and on_response: - on_response(res) - # check status - await _araise_for_status_typed(res) - # check content type - content_type = res.headers.get("content-type", "").partition(";")[0] - if "text/event-stream" not in content_type: - raise httpx.TransportError( - "Expected response header Content-Type to contain 'text/event-stream', " - f"got {content_type!r}" - ) - - reconnect_location = res.headers.get("location") - if reconnect_location: - reconnect_path = reconnect_location - - # parse SSE - decoder = SSEDecoder() - try: - async for line in aiter_lines_raw(res): - sse = decoder.decode(line=cast("bytes", line).rstrip(b"\n")) - if sse is not None: - if decoder.last_event_id is not None: - last_event_id = decoder.last_event_id - if sse.event or sse.data is not None: - yield sse - except httpx.HTTPError: - # httpx.TransportError inherits from HTTPError, so transient - # disconnects during streaming land here. - if reconnect_path is None: - raise - retry = True - else: - if sse := decoder.decode(b""): - if decoder.last_event_id is not None: - last_event_id = decoder.last_event_id - if sse.event or sse.data is not None: - # decoder.decode(b"") flushes the in-flight event and may - # return an empty placeholder when there is no pending - # message. Skip these no-op events so the stream doesn't - # emit a trailing blank item after reconnects. - yield sse - if retry: - reconnect_attempts += 1 - if reconnect_attempts > max_reconnect_attempts: - raise httpx.TransportError( - "Exceeded maximum SSE reconnection attempts" - ) - continue - break - - -async def _aencode_json(json: Any) -> tuple[dict[str, str], bytes | None]: - if json is None: - return {}, None - body = await asyncio.get_running_loop().run_in_executor( - None, - orjson.dumps, - json, - _orjson_default, - orjson.OPT_SERIALIZE_NUMPY | orjson.OPT_NON_STR_KEYS, - ) - content_length = str(len(body)) - content_type = "application/json" - headers = {"Content-Length": content_length, "Content-Type": content_type} - return headers, body - - -async def _adecode_json(r: httpx.Response) -> Any: - body = await r.aread() - return ( - await asyncio.get_running_loop().run_in_executor(None, orjson.loads, body) - if body - else None - ) - - -class AssistantsClient: - """Client for managing assistants in LangGraph. - - This class provides methods to interact with assistants, - which are versioned configurations of your graph. - - ???+ example "Example" - - ```python - client = get_client(url="http://localhost:2024") - assistant = await client.assistants.get("assistant_id_123") - ``` - """ - - def __init__(self, http: HttpClient) -> None: - self.http = http - - async def get( - self, - assistant_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Assistant: - """Get an assistant by ID. - - Args: - assistant_id: The ID of the assistant to get. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - Assistant: Assistant Object. - - ???+ example "Example Usage" - - ```python - assistant = await client.assistants.get( - assistant_id="my_assistant_id" - ) - print(assistant) - ``` - - ```shell - ---------------------------------------------------- - - { - 'assistant_id': 'my_assistant_id', - 'graph_id': 'agent', - 'created_at': '2024-06-25T17:10:33.109781+00:00', - 'updated_at': '2024-06-25T17:10:33.109781+00:00', - 'config': {}, - 'metadata': {'created_by': 'system'}, - 'version': 1, - 'name': 'my_assistant' - } - ``` - """ - return await self.http.get( - f"/assistants/{assistant_id}", headers=headers, params=params - ) - - async def get_graph( - self, - assistant_id: str, - *, - xray: int | bool = False, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> dict[str, list[dict[str, Any]]]: - """Get the graph of an assistant by ID. - - Args: - assistant_id: The ID of the assistant to get the graph of. - xray: Include graph representation of subgraphs. If an integer value is provided, only subgraphs with a depth less than or equal to the value will be included. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - Graph: The graph information for the assistant in JSON format. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - graph_info = await client.assistants.get_graph( - assistant_id="my_assistant_id" - ) - print(graph_info) - ``` - - ```shell - - -------------------------------------------------------------------------------------------------------------------------- - - { - 'nodes': - [ - {'id': '__start__', 'type': 'schema', 'data': '__start__'}, - {'id': '__end__', 'type': 'schema', 'data': '__end__'}, - {'id': 'agent','type': 'runnable','data': {'id': ['langgraph', 'utils', 'RunnableCallable'],'name': 'agent'}}, - ], - 'edges': - [ - {'source': '__start__', 'target': 'agent'}, - {'source': 'agent','target': '__end__'} - ] - } - ``` - - - """ - query_params = {"xray": xray} - if params: - query_params.update(params) - - return await self.http.get( - f"/assistants/{assistant_id}/graph", params=query_params, headers=headers - ) - - async def get_schemas( - self, - assistant_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> GraphSchema: - """Get the schemas of an assistant by ID. - - Args: - assistant_id: The ID of the assistant to get the schema of. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - GraphSchema: The graph schema for the assistant. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - schema = await client.assistants.get_schemas( - assistant_id="my_assistant_id" - ) - print(schema) - ``` - - ```shell - - ---------------------------------------------------------------------------------------------------------------------------- - - { - 'graph_id': 'agent', - 'state_schema': - { - 'title': 'LangGraphInput', - '$ref': '#/definitions/AgentState', - 'definitions': - { - 'BaseMessage': - { - 'title': 'BaseMessage', - 'description': 'Base abstract Message class. Messages are the inputs and outputs of ChatModels.', - 'type': 'object', - 'properties': - { - 'content': - { - 'title': 'Content', - 'anyOf': [ - {'type': 'string'}, - {'type': 'array','items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}} - ] - }, - 'additional_kwargs': - { - 'title': 'Additional Kwargs', - 'type': 'object' - }, - 'response_metadata': - { - 'title': 'Response Metadata', - 'type': 'object' - }, - 'type': - { - 'title': 'Type', - 'type': 'string' - }, - 'name': - { - 'title': 'Name', - 'type': 'string' - }, - 'id': - { - 'title': 'Id', - 'type': 'string' - } - }, - 'required': ['content', 'type'] - }, - 'AgentState': - { - 'title': 'AgentState', - 'type': 'object', - 'properties': - { - 'messages': - { - 'title': 'Messages', - 'type': 'array', - 'items': {'$ref': '#/definitions/BaseMessage'} - } - }, - 'required': ['messages'] - } - } - }, - 'context_schema': - { - 'title': 'Context', - 'type': 'object', - 'properties': - { - 'model_name': - { - 'title': 'Model Name', - 'enum': ['anthropic', 'openai'], - 'type': 'string' - } - } - } - } - ``` - - """ - return await self.http.get( - f"/assistants/{assistant_id}/schemas", headers=headers, params=params - ) - - async def get_subgraphs( - self, - assistant_id: str, - namespace: str | None = None, - recurse: bool = False, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Subgraphs: - """Get the schemas of an assistant by ID. - - Args: - assistant_id: The ID of the assistant to get the schema of. - namespace: Optional namespace to filter by. - recurse: Whether to recursively get subgraphs. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - Subgraphs: The graph schema for the assistant. - - """ - get_params = {"recurse": recurse} - if params: - get_params = {**get_params, **params} - if namespace is not None: - return await self.http.get( - f"/assistants/{assistant_id}/subgraphs/{namespace}", - params=get_params, - headers=headers, - ) - else: - return await self.http.get( - f"/assistants/{assistant_id}/subgraphs", - params=get_params, - headers=headers, - ) - - async def create( - self, - graph_id: str | None, - config: Config | None = None, - *, - context: Context | None = None, - metadata: Json = None, - assistant_id: str | None = None, - if_exists: OnConflictBehavior | None = None, - name: str | None = None, - headers: Mapping[str, str] | None = None, - description: str | None = None, - params: QueryParamTypes | None = None, - ) -> Assistant: - """Create a new assistant. - - Useful when graph is configurable and you want to create different assistants based on different configurations. - - Args: - graph_id: The ID of the graph the assistant should use. The graph ID is normally set in your langgraph.json configuration. - config: Configuration to use for the graph. - metadata: Metadata to add to assistant. - context: Static context to add to the assistant. - !!! version-added "Added in version 0.6.0" - assistant_id: Assistant ID to use, will default to a random UUID if not provided. - if_exists: How to handle duplicate creation. Defaults to 'raise' under the hood. - Must be either 'raise' (raise error if duplicate), or 'do_nothing' (return existing assistant). - name: The name of the assistant. Defaults to 'Untitled' under the hood. - headers: Optional custom headers to include with the request. - description: Optional description of the assistant. - The description field is available for langgraph-api server version>=0.0.45 - params: Optional query parameters to include with the request. - - Returns: - Assistant: The created assistant. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - assistant = await client.assistants.create( - graph_id="agent", - context={"model_name": "openai"}, - metadata={"number":1}, - assistant_id="my-assistant-id", - if_exists="do_nothing", - name="my_name" - ) - ``` - """ - payload: dict[str, Any] = { - "graph_id": graph_id, - } - if config: - payload["config"] = config - if context: - payload["context"] = context - if metadata: - payload["metadata"] = metadata - if assistant_id: - payload["assistant_id"] = assistant_id - if if_exists: - payload["if_exists"] = if_exists - if name: - payload["name"] = name - if description: - payload["description"] = description - return await self.http.post( - "/assistants", json=payload, headers=headers, params=params - ) - - async def update( - self, - assistant_id: str, - *, - graph_id: str | None = None, - config: Config | None = None, - context: Context | None = None, - metadata: Json = None, - name: str | None = None, - headers: Mapping[str, str] | None = None, - description: str | None = None, - params: QueryParamTypes | None = None, - ) -> Assistant: - """Update an assistant. - - Use this to point to a different graph, update the configuration, or change the metadata of an assistant. - - Args: - assistant_id: Assistant to update. - graph_id: The ID of the graph the assistant should use. - The graph ID is normally set in your langgraph.json configuration. If `None`, assistant will keep pointing to same graph. - config: Configuration to use for the graph. - context: Static context to add to the assistant. - !!! version-added "Added in version 0.6.0" - metadata: Metadata to merge with existing assistant metadata. - name: The new name for the assistant. - headers: Optional custom headers to include with the request. - description: Optional description of the assistant. - The description field is available for langgraph-api server version>=0.0.45 - params: Optional query parameters to include with the request. - - Returns: - The updated assistant. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - assistant = await client.assistants.update( - assistant_id='e280dad7-8618-443f-87f1-8e41841c180f', - graph_id="other-graph", - context={"model_name": "anthropic"}, - metadata={"number":2} - ) - ``` - - """ - payload: dict[str, Any] = {} - if graph_id: - payload["graph_id"] = graph_id - if config: - payload["config"] = config - if context: - payload["context"] = context - if metadata: - payload["metadata"] = metadata - if name: - payload["name"] = name - if description: - payload["description"] = description - return await self.http.patch( - f"/assistants/{assistant_id}", - json=payload, - headers=headers, - params=params, - ) - - async def delete( - self, - assistant_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> None: - """Delete an assistant. - - Args: - assistant_id: The assistant ID to delete. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - await client.assistants.delete( - assistant_id="my_assistant_id" - ) - ``` - - """ - await self.http.delete( - f"/assistants/{assistant_id}", headers=headers, params=params - ) - - @overload - async def search( - self, - *, - metadata: Json = None, - graph_id: str | None = None, - name: str | None = None, - limit: int = 10, - offset: int = 0, - sort_by: AssistantSortBy | None = None, - sort_order: SortOrder | None = None, - select: list[AssistantSelectField] | None = None, - response_format: Literal["object"], - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> AssistantsSearchResponse: ... - - @overload - async def search( - self, - *, - metadata: Json = None, - graph_id: str | None = None, - name: str | None = None, - limit: int = 10, - offset: int = 0, - sort_by: AssistantSortBy | None = None, - sort_order: SortOrder | None = None, - select: list[AssistantSelectField] | None = None, - response_format: Literal["array"] = "array", - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> list[Assistant]: ... - - async def search( - self, - *, - metadata: Json = None, - graph_id: str | None = None, - name: str | None = None, - limit: int = 10, - offset: int = 0, - sort_by: AssistantSortBy | None = None, - sort_order: SortOrder | None = None, - select: list[AssistantSelectField] | None = None, - response_format: Literal["array", "object"] = "array", - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> AssistantsSearchResponse | list[Assistant]: - """Search for assistants. - - Args: - metadata: Metadata to filter by. Exact match filter for each KV pair. - graph_id: The ID of the graph to filter by. - The graph ID is normally set in your langgraph.json configuration. - name: The name of the assistant to filter by. - The filtering logic will match assistants where 'name' is a substring (case insensitive) of the assistant name. - limit: The maximum number of results to return. - offset: The number of results to skip. - sort_by: The field to sort by. - sort_order: The order to sort by. - select: Specific assistant fields to include in the response. - response_format: Controls the response shape. Use ``"array"`` (default) - to return a bare list of assistants, or ``"object"`` to return - a mapping containing assistants plus pagination metadata. - Defaults to "array", though this default will be changed to "object" in a future release. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - A list of assistants (when ``response_format=\"array\"``) or a mapping - with the assistants and the next pagination cursor (when - ``response_format=\"object\"``). - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - response = await client.assistants.search( - metadata = {"name":"my_name"}, - graph_id="my_graph_id", - limit=5, - offset=5, - response_format="object" - ) - next_cursor = response["next"] - assistants = response["assistants"] - ``` - """ - if response_format not in ("array", "object"): - raise ValueError( - f"response_format must be 'array' or 'object', got {response_format!r}" - ) - payload: dict[str, Any] = { - "limit": limit, - "offset": offset, - } - if metadata: - payload["metadata"] = metadata - if graph_id: - payload["graph_id"] = graph_id - if name: - payload["name"] = name - if sort_by: - payload["sort_by"] = sort_by - if sort_order: - payload["sort_order"] = sort_order - if select: - payload["select"] = select - next_cursor: str | None = None - - def capture_pagination(response: httpx.Response) -> None: - nonlocal next_cursor - next_cursor = response.headers.get("X-Pagination-Next") - - assistants = cast( - list[Assistant], - await self.http.post( - "/assistants/search", - json=payload, - headers=headers, - params=params, - on_response=capture_pagination if response_format == "object" else None, - ), - ) - if response_format == "object": - return {"assistants": assistants, "next": next_cursor} - return assistants - - async def count( - self, - *, - metadata: Json = None, - graph_id: str | None = None, - name: str | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> int: - """Count assistants matching filters. - - Args: - metadata: Metadata to filter by. Exact match for each key/value. - graph_id: Optional graph id to filter by. - name: Optional name to filter by. - The filtering logic will match assistants where 'name' is a substring (case insensitive) of the assistant name. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - int: Number of assistants matching the criteria. - """ - payload: dict[str, Any] = {} - if metadata: - payload["metadata"] = metadata - if graph_id: - payload["graph_id"] = graph_id - if name: - payload["name"] = name - return await self.http.post( - "/assistants/count", json=payload, headers=headers, params=params - ) - - async def get_versions( - self, - assistant_id: str, - metadata: Json = None, - limit: int = 10, - offset: int = 0, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> list[AssistantVersion]: - """List all versions of an assistant. - - Args: - assistant_id: The assistant ID to get versions for. - metadata: Metadata to filter versions by. Exact match filter for each KV pair. - limit: The maximum number of versions to return. - offset: The number of versions to skip. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - A list of assistant versions. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - assistant_versions = await client.assistants.get_versions( - assistant_id="my_assistant_id" - ) - ``` - """ - - payload: dict[str, Any] = { - "limit": limit, - "offset": offset, - } - if metadata: - payload["metadata"] = metadata - return await self.http.post( - f"/assistants/{assistant_id}/versions", - json=payload, - headers=headers, - params=params, - ) - - async def set_latest( - self, - assistant_id: str, - version: int, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Assistant: - """Change the version of an assistant. - - Args: - assistant_id: The assistant ID to delete. - version: The version to change to. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - Assistant Object. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - new_version_assistant = await client.assistants.set_latest( - assistant_id="my_assistant_id", - version=3 - ) - ``` - - """ - - payload: dict[str, Any] = {"version": version} - - return await self.http.post( - f"/assistants/{assistant_id}/latest", - json=payload, - headers=headers, - params=params, - ) - - -class ThreadsClient: - """Client for managing threads in LangGraph. - - A thread maintains the state of a graph across multiple interactions/invocations (aka runs). - It accumulates and persists the graph's state, allowing for continuity between separate - invocations of the graph. - - ???+ example "Example" - - ```python - client = get_client(url="http://localhost:2024")) - new_thread = await client.threads.create(metadata={"user_id": "123"}) - ``` - """ - - def __init__(self, http: HttpClient) -> None: - self.http = http - - async def get( - self, - thread_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Thread: - """Get a thread by ID. - - Args: - thread_id: The ID of the thread to get. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - Thread object. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - thread = await client.threads.get( - thread_id="my_thread_id" - ) - print(thread) - ``` - - ```shell - ----------------------------------------------------- - - { - 'thread_id': 'my_thread_id', - 'created_at': '2024-07-18T18:35:15.540834+00:00', - 'updated_at': '2024-07-18T18:35:15.540834+00:00', - 'metadata': {'graph_id': 'agent'} - } - ``` - - """ - - return await self.http.get( - f"/threads/{thread_id}", headers=headers, params=params - ) - - async def create( - self, - *, - metadata: Json = None, - thread_id: str | None = None, - if_exists: OnConflictBehavior | None = None, - supersteps: Sequence[dict[str, Sequence[dict[str, Any]]]] | None = None, - graph_id: str | None = None, - ttl: int | Mapping[str, Any] | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Thread: - """Create a new thread. - - Args: - metadata: Metadata to add to thread. - thread_id: ID of thread. - If `None`, ID will be a randomly generated UUID. - if_exists: How to handle duplicate creation. Defaults to 'raise' under the hood. - Must be either 'raise' (raise error if duplicate), or 'do_nothing' (return existing thread). - supersteps: Apply a list of supersteps when creating a thread, each containing a sequence of updates. - Each update has `values` or `command` and `as_node`. Used for copying a thread between deployments. - graph_id: Optional graph ID to associate with the thread. - ttl: Optional time-to-live in minutes for the thread. You can pass an - integer (minutes) or a mapping with keys `ttl` and optional - `strategy` (defaults to "delete"). - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - The created thread. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - thread = await client.threads.create( - metadata={"number":1}, - thread_id="my-thread-id", - if_exists="raise" - ) - ``` - """ - payload: dict[str, Any] = {} - 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 - if supersteps: - payload["supersteps"] = [ - { - "updates": [ - { - "values": u["values"], - "command": u.get("command"), - "as_node": u["as_node"], - } - for u in s["updates"] - ] - } - for s in supersteps - ] - if ttl is not None: - if isinstance(ttl, (int, float)): - payload["ttl"] = {"ttl": ttl, "strategy": "delete"} - else: - payload["ttl"] = ttl - - return await self.http.post( - "/threads", json=payload, headers=headers, params=params - ) - - async def update( - self, - thread_id: str, - *, - metadata: Mapping[str, Any], - ttl: int | Mapping[str, Any] | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Thread: - """Update a thread. - - Args: - thread_id: ID of thread to update. - metadata: Metadata to merge with existing thread metadata. - ttl: Optional time-to-live in minutes for the thread. You can pass an - integer (minutes) or a mapping with keys `ttl` and optional - `strategy` (defaults to "delete"). - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - The created thread. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - thread = await client.threads.update( - thread_id="my-thread-id", - metadata={"number":1}, - ttl=43_200, - ) - ``` - """ - payload: dict[str, Any] = {"metadata": metadata} - if ttl is not None: - if isinstance(ttl, (int, float)): - payload["ttl"] = {"ttl": ttl, "strategy": "delete"} - else: - payload["ttl"] = ttl - return await self.http.patch( - f"/threads/{thread_id}", - json=payload, - headers=headers, - params=params, - ) - - async def delete( - self, - thread_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> None: - """Delete a thread. - - Args: - thread_id: The ID of the thread to delete. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost2024) - await client.threads.delete( - thread_id="my_thread_id" - ) - ``` - - """ - await self.http.delete(f"/threads/{thread_id}", headers=headers, params=params) - - async def search( - self, - *, - metadata: Json = None, - values: Json = None, - ids: Sequence[str] | None = None, - status: ThreadStatus | None = None, - limit: int = 10, - offset: int = 0, - sort_by: ThreadSortBy | None = None, - sort_order: SortOrder | None = None, - select: list[ThreadSelectField] | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> list[Thread]: - """Search for threads. - - Args: - metadata: Thread metadata to filter on. - values: State values to filter on. - ids: List of thread IDs to filter by. - status: Thread status to filter on. - Must be one of 'idle', 'busy', 'interrupted' or 'error'. - limit: Limit on number of threads to return. - offset: Offset in threads table to start search from. - sort_by: Sort by field. - sort_order: Sort order. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - List of the threads matching the search parameters. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - threads = await client.threads.search( - metadata={"number":1}, - status="interrupted", - limit=15, - offset=5 - ) - ``` - - """ - payload: dict[str, Any] = { - "limit": limit, - "offset": offset, - } - if metadata: - payload["metadata"] = metadata - if values: - payload["values"] = values - if ids: - payload["ids"] = ids - if status: - payload["status"] = status - if sort_by: - payload["sort_by"] = sort_by - if sort_order: - payload["sort_order"] = sort_order - if select: - payload["select"] = select - return await self.http.post( - "/threads/search", - json=payload, - headers=headers, - params=params, - ) - - async def count( - self, - *, - metadata: Json = None, - values: Json = None, - status: ThreadStatus | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> int: - """Count threads matching filters. - - Args: - metadata: Thread metadata to filter on. - values: State values to filter on. - status: Thread status to filter on. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - int: Number of threads matching the criteria. - """ - payload: dict[str, Any] = {} - if metadata: - payload["metadata"] = metadata - if values: - payload["values"] = values - if status: - payload["status"] = status - return await self.http.post( - "/threads/count", json=payload, headers=headers, params=params - ) - - async def copy( - self, - thread_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> None: - """Copy a thread. - - Args: - thread_id: The ID of the thread to copy. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024) - await client.threads.copy( - thread_id="my_thread_id" - ) - ``` - - """ - return await self.http.post( - f"/threads/{thread_id}/copy", json=None, headers=headers, params=params - ) - - async def get_state( - self, - thread_id: str, - checkpoint: Checkpoint | None = None, - checkpoint_id: str | None = None, # deprecated - *, - subgraphs: bool = False, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> ThreadState: - """Get the state of a thread. - - Args: - thread_id: The ID of the thread to get the state of. - checkpoint: The checkpoint to get the state of. - checkpoint_id: (deprecated) The checkpoint ID to get the state of. - subgraphs: Include subgraphs states. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - The thread of the state. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024) - thread_state = await client.threads.get_state( - thread_id="my_thread_id", - checkpoint_id="my_checkpoint_id" - ) - print(thread_state) - ``` - - ```shell - ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- - - { - 'values': { - '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 - } - ] - }, - 'next': [], - 'checkpoint': - { - 'thread_id': 'e2496803-ecd5-4e0c-a779-3226296181c2', - 'checkpoint_ns': '', - 'checkpoint_id': '1ef4a9b8-e6fb-67b1-8001-abd5184439d1' - } - 'metadata': - { - 'step': 1, - 'run_id': '1ef4a9b8-d7da-679a-a45a-872054341df2', - 'source': 'loop', - 'writes': - { - 'agent': - { - 'messages': [ - { - 'id': 'run-159b782c-b679-4830-83c6-cef87798fe8b', - 'name': None, - 'type': 'ai', - 'content': "I'm doing well, thanks for asking! I'm an AI assistant created by Anthropic to be helpful, honest, and harmless.", - 'example': False, - 'tool_calls': [], - 'usage_metadata': None, - 'additional_kwargs': {}, - 'response_metadata': {}, - 'invalid_tool_calls': [] - } - ] - } - }, - 'user_id': None, - 'graph_id': 'agent', - 'thread_id': 'e2496803-ecd5-4e0c-a779-3226296181c2', - 'created_by': 'system', - 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, - 'created_at': '2024-07-25T15:35:44.184703+00:00', - 'parent_config': - { - 'thread_id': 'e2496803-ecd5-4e0c-a779-3226296181c2', - 'checkpoint_ns': '', - 'checkpoint_id': '1ef4a9b8-d80d-6fa7-8000-9300467fad0f' - } - } - ``` - """ - if checkpoint: - return await self.http.post( - f"/threads/{thread_id}/state/checkpoint", - json={"checkpoint": checkpoint, "subgraphs": subgraphs}, - headers=headers, - params=params, - ) - elif checkpoint_id: - get_params = {"subgraphs": subgraphs} - if params: - get_params = {**get_params, **params} - return await self.http.get( - f"/threads/{thread_id}/state/{checkpoint_id}", - params=get_params, - headers=headers, - ) - else: - get_params = {"subgraphs": subgraphs} - if params: - get_params = {**get_params, **params} - return await self.http.get( - f"/threads/{thread_id}/state", - params=get_params, - headers=headers, - ) - - async def update_state( - self, - thread_id: str, - values: dict[str, Any] | Sequence[dict] | None, - *, - as_node: str | None = None, - checkpoint: Checkpoint | None = None, - checkpoint_id: str | None = None, # deprecated - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> ThreadUpdateStateResponse: - """Update the state of 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. - checkpoint_id: (deprecated) The checkpoint ID to update the state of. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - Response after updating a thread's state. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024) - response = await client.threads.update_state( - thread_id="my_thread_id", - values={"messages":[{"role": "user", "content": "hello!"}]}, - as_node="my_node", - ) - print(response) - ``` - ```shell - - ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- - - { - 'checkpoint': { - 'thread_id': 'e2496803-ecd5-4e0c-a779-3226296181c2', - 'checkpoint_ns': '', - 'checkpoint_id': '1ef4a9b8-e6fb-67b1-8001-abd5184439d1', - 'checkpoint_map': {} - } - } - ``` - """ - payload: dict[str, Any] = { - "values": values, - } - if checkpoint_id: - payload["checkpoint_id"] = checkpoint_id - if checkpoint: - payload["checkpoint"] = checkpoint - if as_node: - payload["as_node"] = as_node - return await self.http.post( - f"/threads/{thread_id}/state", json=payload, headers=headers, params=params - ) - - async def get_history( - self, - thread_id: str, - *, - limit: int = 10, - before: str | Checkpoint | None = None, - metadata: Mapping[str, Any] | None = None, - checkpoint: Checkpoint | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> list[ThreadState]: - """Get the state history of a thread. - - Args: - thread_id: The ID of the thread to get the state history for. - checkpoint: Return states for this subgraph. If empty defaults to root. - limit: The maximum number of states to return. - before: Return states before this checkpoint. - metadata: Filter states by metadata key-value pairs. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - The state history of the thread. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024) - thread_state = await client.threads.get_history( - thread_id="my_thread_id", - limit=5, - ) - ``` - - """ - payload: dict[str, Any] = { - "limit": limit, - } - if before: - payload["before"] = before - if metadata: - payload["metadata"] = metadata - if checkpoint: - payload["checkpoint"] = checkpoint - return await self.http.post( - f"/threads/{thread_id}/history", - json=payload, - headers=headers, - params=params, - ) - - async def join_stream( - self, - thread_id: str, - *, - last_event_id: str | None = None, - stream_mode: ThreadStreamMode | Sequence[ThreadStreamMode] = "run_modes", - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> AsyncIterator[StreamPart]: - """Get a stream of events for a thread. - - Args: - thread_id: The ID of the thread to get the stream for. - last_event_id: The ID of the last event to get. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - An iterator of stream parts. - - ???+ example "Example Usage" - - ```python - - for chunk in client.threads.join_stream( - thread_id="my_thread_id", - last_event_id="my_event_id", - ): - print(chunk) - ``` - - """ - query_params = { - "stream_mode": stream_mode, - } - if params: - query_params.update(params) - return self.http.stream( - f"/threads/{thread_id}/stream", - "GET", - headers={ - **({"Last-Event-ID": last_event_id} if last_event_id else {}), - **(headers or {}), - }, - params=query_params, - ) - - -class RunsClient: - """Client for managing runs in LangGraph. - - A run is a single assistant invocation with optional input, config, context, and metadata. - This client manages runs, which can be stateful (on threads) or stateless. - - ???+ example "Example" - - ```python - client = get_client(url="http://localhost:2024") - run = await client.runs.create(assistant_id="asst_123", thread_id="thread_456", input={"query": "Hello"}) - ``` - """ - - def __init__(self, http: HttpClient) -> None: - self.http = http - - @overload - def stream( - self, - thread_id: str, - assistant_id: str, - *, - input: Input | None = None, - 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, - checkpoint: Checkpoint | None = None, - checkpoint_id: str | None = None, - checkpoint_during: bool | None = None, - interrupt_before: All | Sequence[str] | None = None, - interrupt_after: All | Sequence[str] | None = None, - feedback_keys: Sequence[str] | None = None, - on_disconnect: DisconnectMode | None = None, - webhook: str | None = None, - multitask_strategy: MultitaskStrategy | None = None, - if_not_exists: IfNotExists | None = None, - after_seconds: int | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - ) -> AsyncIterator[StreamPart]: ... - - @overload - def stream( - self, - thread_id: None, - assistant_id: str, - *, - input: Input | None = None, - 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, - checkpoint_during: bool | None = None, - interrupt_before: All | Sequence[str] | None = None, - interrupt_after: All | Sequence[str] | None = None, - feedback_keys: Sequence[str] | None = None, - on_disconnect: DisconnectMode | None = None, - on_completion: OnCompletionBehavior | None = None, - if_not_exists: IfNotExists | None = None, - webhook: str | None = None, - after_seconds: int | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - ) -> AsyncIterator[StreamPart]: ... - - def stream( - self, - thread_id: str | None, - assistant_id: str, - *, - input: Input | None = None, - 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, - checkpoint: Checkpoint | None = None, - checkpoint_id: str | None = None, - checkpoint_during: bool | None = None, # deprecated - interrupt_before: All | Sequence[str] | None = None, - interrupt_after: All | Sequence[str] | None = None, - feedback_keys: Sequence[str] | None = None, - on_disconnect: DisconnectMode | None = None, - on_completion: OnCompletionBehavior | None = None, - webhook: str | None = None, - multitask_strategy: MultitaskStrategy | None = None, - if_not_exists: IfNotExists | None = None, - after_seconds: int | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - durability: Durability | None = None, - ) -> AsyncIterator[StreamPart]: - """Create a run and stream the results. - - Args: - thread_id: the thread ID to assign to the thread. - If `None` will create a stateless run. - assistant_id: The assistant ID or graph name to stream from. - If using graph name, will default to first assistant created from that graph. - input: The input to the graph. - command: A command to execute. Cannot be combined with input. - stream_mode: The stream mode(s) to use. - stream_subgraphs: Whether to stream output from subgraphs. - stream_resumable: Whether the stream is considered resumable. - If true, the stream can be resumed and replayed in its entirety even after disconnection. - metadata: Metadata to assign to the run. - config: The configuration for the assistant. - context: Static context to add to the assistant. - !!! version-added "Added in version 0.6.0" - checkpoint: The checkpoint to resume from. - checkpoint_during: (deprecated) Whether to checkpoint during the run (or only at the end/interruption). - interrupt_before: Nodes to interrupt immediately before they get executed. - interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. - feedback_keys: Feedback keys to assign to run. - on_disconnect: The disconnect mode to use. - Must be one of 'cancel' or 'continue'. - on_completion: Whether to delete or keep the thread created for a stateless run. - Must be one of 'delete' or 'keep'. - webhook: Webhook to call after LangGraph API call is done. - multitask_strategy: Multitask strategy to use. - Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. - if_not_exists: How to handle missing thread. Defaults to 'reject'. - Must be either 'reject' (raise error if missing), or 'create' (create new thread). - after_seconds: The number of seconds to wait before starting the run. - Use to schedule future runs. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - on_run_created: Callback when a run is created. - durability: The durability to use for the run. Values are "sync", "async", or "exit". - "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 - - Returns: - Asynchronous iterator of stream results. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024) - async for chunk in client.runs.stream( - thread_id=None, - assistant_id="agent", - input={"messages": [{"role": "user", "content": "how are you?"}]}, - stream_mode=["values","debug"], - metadata={"name":"my_run"}, - context={"model_name": "anthropic"}, - interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], - interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], - feedback_keys=["my_feedback_key_1","my_feedback_key_2"], - webhook="https://my.fake.webhook.com", - multitask_strategy="interrupt" - ): - print(chunk) - ``` - - ```shell - - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - - 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) - ``` - - """ - if checkpoint_during is not None: - warnings.warn( - "`checkpoint_during` is deprecated and will be removed in a future version. Use `durability` instead.", - DeprecationWarning, - stacklevel=2, - ) - - payload = { - "input": input, - "command": ( - {k: v for k, v in command.items() if v is not None} if command else None - ), - "config": config, - "context": context, - "metadata": metadata, - "stream_mode": stream_mode, - "stream_subgraphs": stream_subgraphs, - "stream_resumable": stream_resumable, - "assistant_id": assistant_id, - "interrupt_before": interrupt_before, - "interrupt_after": interrupt_after, - "feedback_keys": feedback_keys, - "webhook": webhook, - "checkpoint": checkpoint, - "checkpoint_id": checkpoint_id, - "checkpoint_during": checkpoint_during, - "multitask_strategy": multitask_strategy, - "if_not_exists": if_not_exists, - "on_disconnect": on_disconnect, - "on_completion": on_completion, - "after_seconds": after_seconds, - "durability": durability, - } - endpoint = ( - f"/threads/{thread_id}/runs/stream" - if thread_id is not None - else "/runs/stream" - ) - - def on_response(res: httpx.Response): - """Callback function to handle the response.""" - if on_run_created and (metadata := _get_run_metadata_from_response(res)): - on_run_created(metadata) - - return self.http.stream( - endpoint, - "POST", - json={k: v for k, v in payload.items() if v is not None}, - params=params, - headers=headers, - on_response=on_response if on_run_created else None, - ) - - @overload - async def create( - self, - thread_id: None, - assistant_id: str, - *, - input: Input | None = None, - command: Command | None = None, - stream_mode: StreamMode | Sequence[StreamMode] = "values", - stream_subgraphs: bool = False, - stream_resumable: bool = False, - metadata: Mapping[str, Any] | None = None, - checkpoint_during: bool | None = None, - config: Config | None = None, - context: Context | None = None, - interrupt_before: All | Sequence[str] | None = None, - interrupt_after: All | Sequence[str] | None = None, - webhook: str | None = None, - on_completion: OnCompletionBehavior | None = None, - if_not_exists: IfNotExists | None = None, - after_seconds: int | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - ) -> Run: ... - - @overload - async def create( - self, - thread_id: str, - assistant_id: str, - *, - input: Input | None = None, - 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, - checkpoint: Checkpoint | None = None, - checkpoint_id: str | None = None, - checkpoint_during: bool | None = None, - interrupt_before: All | Sequence[str] | None = None, - interrupt_after: All | Sequence[str] | None = None, - webhook: str | None = None, - multitask_strategy: MultitaskStrategy | None = None, - if_not_exists: IfNotExists | None = None, - after_seconds: int | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - ) -> Run: ... - - async def create( - self, - thread_id: str | None, - assistant_id: str, - *, - input: Input | None = None, - 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, - checkpoint: Checkpoint | None = None, - checkpoint_id: str | None = None, - checkpoint_during: bool | None = None, # deprecated - interrupt_before: All | Sequence[str] | None = None, - interrupt_after: All | Sequence[str] | None = None, - webhook: str | None = None, - multitask_strategy: MultitaskStrategy | None = None, - if_not_exists: IfNotExists | None = None, - on_completion: OnCompletionBehavior | None = None, - after_seconds: int | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - durability: Durability | None = None, - ) -> Run: - """Create a background run. - - Args: - thread_id: the thread ID to assign to the thread. - If `None` will create a stateless run. - assistant_id: The assistant ID or graph name to stream from. - If using graph name, will default to first assistant created from that graph. - input: The input to the graph. - command: A command to execute. Cannot be combined with input. - stream_mode: The stream mode(s) to use. - stream_subgraphs: Whether to stream output from subgraphs. - stream_resumable: Whether the stream is considered resumable. - If true, the stream can be resumed and replayed in its entirety even after disconnection. - metadata: Metadata to assign to the run. - config: The configuration for the assistant. - context: Static context to add to the assistant. - !!! version-added "Added in version 0.6.0" - checkpoint: The checkpoint to resume from. - checkpoint_during: (deprecated) Whether to checkpoint during the run (or only at the end/interruption). - interrupt_before: Nodes to interrupt immediately before they get executed. - interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. - webhook: Webhook to call after LangGraph API call is done. - multitask_strategy: Multitask strategy to use. - Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. - on_completion: Whether to delete or keep the thread created for a stateless run. - Must be one of 'delete' or 'keep'. - if_not_exists: How to handle missing thread. Defaults to 'reject'. - Must be either 'reject' (raise error if missing), or 'create' (create new thread). - after_seconds: The number of seconds to wait before starting the run. - Use to schedule future runs. - headers: Optional custom headers to include with the request. - on_run_created: Optional callback to call when a run is created. - durability: The durability to use for the run. Values are "sync", "async", or "exit". - "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 - - Returns: - The created background run. - - ???+ example "Example Usage" - - ```python - - background_run = await client.runs.create( - thread_id="my_thread_id", - assistant_id="my_assistant_id", - input={"messages": [{"role": "user", "content": "hello!"}]}, - metadata={"name":"my_run"}, - context={"model_name": "openai"}, - interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], - interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], - webhook="https://my.fake.webhook.com", - multitask_strategy="interrupt" - ) - print(background_run) - ``` - - ```shell - -------------------------------------------------------------------------------- - - { - 'run_id': 'my_run_id', - 'thread_id': 'my_thread_id', - 'assistant_id': 'my_assistant_id', - 'created_at': '2024-07-25T15:35:42.598503+00:00', - 'updated_at': '2024-07-25T15:35:42.598503+00:00', - 'metadata': {}, - 'status': 'pending', - 'kwargs': - { - 'input': - { - 'messages': [ - { - 'role': 'user', - 'content': 'how are you?' - } - ] - }, - 'config': - { - 'metadata': - { - 'created_by': 'system' - }, - 'configurable': - { - 'run_id': 'my_run_id', - 'user_id': None, - 'graph_id': 'agent', - 'thread_id': 'my_thread_id', - 'checkpoint_id': None, - 'assistant_id': 'my_assistant_id' - }, - }, - 'context': - { - 'model_name': 'openai' - } - 'webhook': "https://my.fake.webhook.com", - 'temporary': False, - 'stream_mode': ['values'], - 'feedback_keys': None, - 'interrupt_after': ["node_to_stop_after_1","node_to_stop_after_2"], - 'interrupt_before': ["node_to_stop_before_1","node_to_stop_before_2"] - }, - 'multitask_strategy': 'interrupt' - } - ``` - """ - if checkpoint_during is not None: - warnings.warn( - "`checkpoint_during` is deprecated and will be removed in a future version. Use `durability` instead.", - DeprecationWarning, - stacklevel=2, - ) - payload = { - "input": input, - "command": ( - {k: v for k, v in command.items() if v is not None} if command else None - ), - "stream_mode": stream_mode, - "stream_subgraphs": stream_subgraphs, - "stream_resumable": stream_resumable, - "config": config, - "context": context, - "metadata": metadata, - "assistant_id": assistant_id, - "interrupt_before": interrupt_before, - "interrupt_after": interrupt_after, - "webhook": webhook, - "checkpoint": checkpoint, - "checkpoint_id": checkpoint_id, - "checkpoint_during": checkpoint_during, - "multitask_strategy": multitask_strategy, - "if_not_exists": if_not_exists, - "on_completion": on_completion, - "after_seconds": after_seconds, - "durability": durability, - } - payload = {k: v for k, v in payload.items() if v is not None} - - def on_response(res: httpx.Response): - """Callback function to handle the response.""" - if on_run_created and (metadata := _get_run_metadata_from_response(res)): - on_run_created(metadata) - - return await self.http.post( - f"/threads/{thread_id}/runs" if thread_id else "/runs", - json=payload, - params=params, - headers=headers, - on_response=on_response if on_run_created else None, - ) - - async def create_batch( - self, - payloads: list[RunCreate], - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> list[Run]: - """Create a batch of stateless background runs.""" - - def filter_payload(payload: RunCreate): - return {k: v for k, v in payload.items() if v is not None} - - filtered = [filter_payload(payload) for payload in payloads] - return await self.http.post( - "/runs/batch", json=filtered, headers=headers, params=params - ) - - @overload - async def wait( - self, - thread_id: str, - assistant_id: str, - *, - input: Input | None = None, - command: Command | None = None, - metadata: Mapping[str, Any] | None = None, - config: Config | None = None, - context: Context | None = None, - checkpoint: Checkpoint | None = None, - checkpoint_id: str | None = None, - checkpoint_during: bool | None = None, - interrupt_before: All | Sequence[str] | None = None, - interrupt_after: All | Sequence[str] | None = None, - webhook: str | None = None, - on_disconnect: DisconnectMode | None = None, - multitask_strategy: MultitaskStrategy | None = None, - if_not_exists: IfNotExists | None = None, - after_seconds: int | None = None, - raise_error: bool = True, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - ) -> list[dict] | dict[str, Any]: ... - - @overload - async def wait( - self, - thread_id: None, - assistant_id: str, - *, - input: Input | None = None, - command: Command | None = None, - 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, - webhook: str | None = None, - on_disconnect: DisconnectMode | None = None, - on_completion: OnCompletionBehavior | None = None, - if_not_exists: IfNotExists | None = None, - after_seconds: int | None = None, - raise_error: bool = True, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - ) -> list[dict] | dict[str, Any]: ... - - async def wait( - self, - thread_id: str | None, - assistant_id: str, - *, - input: Input | None = None, - command: Command | None = None, - metadata: Mapping[str, Any] | None = None, - config: Config | None = None, - context: Context | None = None, - checkpoint: Checkpoint | None = None, - checkpoint_id: str | None = None, - checkpoint_during: bool | None = None, # deprecated - interrupt_before: All | Sequence[str] | None = None, - interrupt_after: All | Sequence[str] | None = None, - webhook: str | None = None, - on_disconnect: DisconnectMode | None = None, - on_completion: OnCompletionBehavior | None = None, - multitask_strategy: MultitaskStrategy | None = None, - if_not_exists: IfNotExists | None = None, - after_seconds: int | None = None, - raise_error: bool = True, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - durability: Durability | None = None, - ) -> list[dict] | dict[str, Any]: - """Create a run, wait until it finishes and return the final state. - - Args: - thread_id: the thread ID to create the run on. - If `None` will create a stateless run. - assistant_id: The assistant ID or graph name to run. - If using graph name, will default to first assistant created from that graph. - input: The input to the graph. - command: A command to execute. Cannot be combined with input. - metadata: Metadata to assign to the run. - config: The configuration for the assistant. - context: Static context to add to the assistant. - !!! version-added "Added in version 0.6.0" - checkpoint: The checkpoint to resume from. - checkpoint_during: (deprecated) Whether to checkpoint during the run (or only at the end/interruption). - interrupt_before: Nodes to interrupt immediately before they get executed. - interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. - webhook: Webhook to call after LangGraph API call is done. - on_disconnect: The disconnect mode to use. - Must be one of 'cancel' or 'continue'. - on_completion: Whether to delete or keep the thread created for a stateless run. - Must be one of 'delete' or 'keep'. - multitask_strategy: Multitask strategy to use. - Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. - if_not_exists: How to handle missing thread. Defaults to 'reject'. - Must be either 'reject' (raise error if missing), or 'create' (create new thread). - after_seconds: The number of seconds to wait before starting the run. - Use to schedule future runs. - headers: Optional custom headers to include with the request. - on_run_created: Optional callback to call when a run is created. - durability: The durability to use for the run. Values are "sync", "async", or "exit". - "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 - - Returns: - The output of the run. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - final_state_of_run = await client.runs.wait( - thread_id=None, - assistant_id="agent", - input={"messages": [{"role": "user", "content": "how are you?"}]}, - metadata={"name":"my_run"}, - context={"model_name": "anthropic"}, - interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], - interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], - webhook="https://my.fake.webhook.com", - multitask_strategy="interrupt" - ) - print(final_state_of_run) - ``` - - ```shell - ------------------------------------------------------------------------------------------------------------------------------------------- - - { - 'messages': [ - { - 'content': 'how are you?', - 'additional_kwargs': {}, - 'response_metadata': {}, - 'type': 'human', - 'name': None, - 'id': 'f51a862c-62fe-4866-863b-b0863e8ad78a', - '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-bf1cd3c6-768f-4c16-b62d-ba6f17ad8b36', - 'example': False, - 'tool_calls': [], - 'invalid_tool_calls': [], - 'usage_metadata': None - } - ] - } - ``` - - """ - if checkpoint_during is not None: - warnings.warn( - "`checkpoint_during` is deprecated and will be removed in a future version. Use `durability` instead.", - DeprecationWarning, - stacklevel=2, - ) - payload = { - "input": input, - "command": ( - {k: v for k, v in command.items() if v is not None} if command else None - ), - "config": config, - "context": context, - "metadata": metadata, - "assistant_id": assistant_id, - "interrupt_before": interrupt_before, - "interrupt_after": interrupt_after, - "webhook": webhook, - "checkpoint": checkpoint, - "checkpoint_id": checkpoint_id, - "multitask_strategy": multitask_strategy, - "checkpoint_during": checkpoint_during, - "if_not_exists": if_not_exists, - "on_disconnect": on_disconnect, - "on_completion": on_completion, - "after_seconds": after_seconds, - "durability": durability, - } - endpoint = ( - f"/threads/{thread_id}/runs/wait" if thread_id is not None else "/runs/wait" - ) - - def on_response(res: httpx.Response): - """Callback function to handle the response.""" - if on_run_created and (metadata := _get_run_metadata_from_response(res)): - on_run_created(metadata) - - response = await self.http.request_reconnect( - endpoint, - "POST", - json={k: v for k, v in payload.items() if v is not None}, - params=params, - 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 - - async def list( - self, - thread_id: str, - *, - limit: int = 10, - offset: int = 0, - status: RunStatus | None = None, - select: list[RunSelectField] | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> list[Run]: - """List runs. - - Args: - thread_id: The thread ID to list runs for. - limit: The maximum number of results to return. - offset: The number of results to skip. - status: The status of the run to filter by. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - The runs for the thread. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - await client.runs.list( - thread_id="thread_id", - limit=5, - offset=5, - ) - ``` - - """ - query_params: dict[str, Any] = { - "limit": limit, - "offset": offset, - } - if status is not None: - query_params["status"] = status - if select: - query_params["select"] = select - if params: - query_params.update(params) - return await self.http.get( - f"/threads/{thread_id}/runs", params=query_params, headers=headers - ) - - async def get( - self, - thread_id: str, - run_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Run: - """Get a run. - - Args: - thread_id: The thread ID to get. - run_id: The run ID to get. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `Run` object. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - run = await client.runs.get( - thread_id="thread_id_to_delete", - run_id="run_id_to_delete", - ) - ``` - - """ - - return await self.http.get( - f"/threads/{thread_id}/runs/{run_id}", headers=headers, params=params - ) - - async def cancel( - self, - thread_id: str, - run_id: str, - *, - wait: bool = False, - action: CancelAction = "interrupt", - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> None: - """Get a run. - - Args: - thread_id: The thread ID to cancel. - run_id: The run ID to cancel. - wait: Whether to wait until run has completed. - action: Action to take when cancelling the run. Possible values - are `interrupt` or `rollback`. Default is `interrupt`. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - await client.runs.cancel( - thread_id="thread_id_to_cancel", - run_id="run_id_to_cancel", - wait=True, - action="interrupt" - ) - ``` - - """ - query_params = { - "wait": 1 if wait else 0, - "action": action, - } - if params: - query_params.update(params) - if wait: - return await self.http.request_reconnect( - f"/threads/{thread_id}/runs/{run_id}/cancel", - "POST", - params=query_params, - headers=headers, - ) - else: - return await self.http.post( - f"/threads/{thread_id}/runs/{run_id}/cancel", - json=None, - params=query_params, - headers=headers, - ) - - async def join( - self, - thread_id: str, - run_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> dict: - """Block until a run is done. Returns the final state of the thread. - - Args: - thread_id: The thread ID to join. - run_id: The run ID to join. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - result =await client.runs.join( - thread_id="thread_id_to_join", - run_id="run_id_to_join" - ) - ``` - - """ - return await self.http.request_reconnect( - f"/threads/{thread_id}/runs/{run_id}/join", - "GET", - headers=headers, - params=params, - ) - - def join_stream( - self, - thread_id: str, - run_id: str, - *, - cancel_on_disconnect: bool = False, - stream_mode: StreamMode | Sequence[StreamMode] | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - last_event_id: str | None = None, - ) -> AsyncIterator[StreamPart]: - """Stream output from a run in real-time, until the run is done. - Output is not buffered, so any output produced before this call will - not be received here. - - Args: - thread_id: The thread ID to join. - run_id: The run ID to join. - cancel_on_disconnect: Whether to cancel the run when the stream is disconnected. - stream_mode: The stream mode(s) to use. Must be a subset of the stream modes passed - when creating the run. Background runs default to having the union of all - stream modes. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - last_event_id: The last event ID to use for the stream. - - Returns: - The stream of parts. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - async for part in client.runs.join_stream( - thread_id="thread_id_to_join", - run_id="run_id_to_join", - stream_mode=["values", "debug"] - ): - print(part) - ``` - - """ - query_params = { - "cancel_on_disconnect": cancel_on_disconnect, - "stream_mode": stream_mode, - } - if params: - query_params.update(params) - return self.http.stream( - f"/threads/{thread_id}/runs/{run_id}/stream", - "GET", - params=query_params, - headers={ - **({"Last-Event-ID": last_event_id} if last_event_id else {}), - **(headers or {}), - } - or None, - ) - - async def delete( - self, - thread_id: str, - run_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> None: - """Delete a run. - - Args: - thread_id: The thread ID to delete. - run_id: The run ID to delete. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - await client.runs.delete( - thread_id="thread_id_to_delete", - run_id="run_id_to_delete" - ) - ``` - - """ - await self.http.delete( - f"/threads/{thread_id}/runs/{run_id}", headers=headers, params=params - ) - - -class CronClient: - """Client for managing recurrent runs (cron jobs) in LangGraph. - - A run is a single invocation of an assistant with optional input, config, and context. - This client allows scheduling recurring runs to occur automatically. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024")) - cron_job = await client.crons.create_for_thread( - thread_id="thread_123", - assistant_id="asst_456", - schedule="0 9 * * *", - input={"message": "Daily update"} - ) - ``` - - !!! note "Feature Availability" - - The crons client functionality is not supported on all licenses. - Please check the relevant license documentation for the most up-to-date - details on feature availability. - """ - - def __init__(self, http_client: HttpClient) -> None: - self.http = http_client - - async def create_for_thread( - self, - thread_id: str, - assistant_id: str, - *, - schedule: str, - input: Input | None = None, - metadata: Mapping[str, Any] | None = None, - config: Config | None = None, - context: Context | None = None, - checkpoint_during: bool | None = None, - interrupt_before: All | list[str] | None = None, - interrupt_after: All | list[str] | None = None, - webhook: str | None = None, - multitask_strategy: str | None = None, - end_time: datetime | None = None, - enabled: bool | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Run: - """Create a cron job for a thread. - - Args: - thread_id: the thread ID to run the cron job on. - assistant_id: The assistant ID or graph name to use for the cron job. - If using graph name, will default to first assistant created from that graph. - schedule: The cron schedule to execute this job on. - Schedules are interpreted in UTC. - input: The input to the graph. - metadata: Metadata to assign to the cron job runs. - config: The configuration for the assistant. - context: Static context to add to the assistant. - !!! version-added "Added in version 0.6.0" - checkpoint_during: Whether to checkpoint during the run (or only at the end/interruption). - interrupt_before: Nodes to interrupt immediately before they get executed. - - interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. - - webhook: Webhook to call after LangGraph API call is done. - multitask_strategy: Multitask strategy to use. - Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. - end_time: The time to stop running the cron job. If not provided, the cron job will run indefinitely. - enabled: Whether the cron job is enabled or not. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - The cron run. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - cron_run = await client.crons.create_for_thread( - thread_id="my-thread-id", - assistant_id="agent", - schedule="27 15 * * *", - input={"messages": [{"role": "user", "content": "hello!"}]}, - metadata={"name":"my_run"}, - context={"model_name": "openai"}, - interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], - interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], - webhook="https://my.fake.webhook.com", - multitask_strategy="interrupt", - enabled=True, - ) - ``` - """ - payload = { - "schedule": schedule, - "input": input, - "config": config, - "metadata": metadata, - "context": context, - "assistant_id": assistant_id, - "checkpoint_during": checkpoint_during, - "interrupt_before": interrupt_before, - "interrupt_after": interrupt_after, - "webhook": webhook, - "end_time": end_time.isoformat() if end_time else None, - "enabled": enabled, - } - if multitask_strategy: - payload["multitask_strategy"] = multitask_strategy - payload = {k: v for k, v in payload.items() if v is not None} - return await self.http.post( - f"/threads/{thread_id}/runs/crons", - json=payload, - headers=headers, - params=params, - ) - - async def create( - self, - assistant_id: str, - *, - schedule: str, - input: Input | None = None, - metadata: Mapping[str, Any] | None = None, - config: Config | None = None, - context: Context | None = None, - checkpoint_during: bool | None = None, - interrupt_before: All | list[str] | None = None, - interrupt_after: All | list[str] | None = None, - webhook: str | None = None, - on_run_completed: OnCompletionBehavior | None = None, - multitask_strategy: str | None = None, - end_time: datetime | None = None, - enabled: bool | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Run: - """Create a cron run. - - Args: - assistant_id: The assistant ID or graph name to use for the cron job. - If using graph name, will default to first assistant created from that graph. - schedule: The cron schedule to execute this job on. - Schedules are interpreted in UTC. - input: The input to the graph. - metadata: Metadata to assign to the cron job runs. - config: The configuration for the assistant. - context: Static context to add to the assistant. - !!! version-added "Added in version 0.6.0" - checkpoint_during: Whether to checkpoint during the run (or only at the end/interruption). - interrupt_before: Nodes to interrupt immediately before they get executed. - interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. - webhook: Webhook to call after LangGraph API call is done. - on_run_completed: What to do with the thread after the run completes. - Must be one of 'delete' (default) or 'keep'. 'delete' removes the thread - after execution. 'keep' creates a new thread for each execution but does not - clean them up. Clients are responsible for cleaning up kept threads. - multitask_strategy: Multitask strategy to use. - Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. - end_time: The time to stop running the cron job. If not provided, the cron job will run indefinitely. - enabled: Whether the cron job is enabled or not. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - The cron run. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - cron_run = client.crons.create( - assistant_id="agent", - schedule="27 15 * * *", - input={"messages": [{"role": "user", "content": "hello!"}]}, - metadata={"name":"my_run"}, - context={"model_name": "openai"}, - interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], - interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], - webhook="https://my.fake.webhook.com", - multitask_strategy="interrupt", - enabled=True, - ) - ``` - - """ - payload = { - "schedule": schedule, - "input": input, - "config": config, - "metadata": metadata, - "context": context, - "assistant_id": assistant_id, - "checkpoint_during": checkpoint_during, - "interrupt_before": interrupt_before, - "interrupt_after": interrupt_after, - "webhook": webhook, - "on_run_completed": on_run_completed, - "end_time": end_time.isoformat() if end_time else None, - "enabled": enabled, - } - if multitask_strategy: - payload["multitask_strategy"] = multitask_strategy - payload = {k: v for k, v in payload.items() if v is not None} - return await self.http.post( - "/runs/crons", json=payload, headers=headers, params=params - ) - - async def delete( - self, - cron_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> None: - """Delete a cron. - - Args: - cron_id: The cron ID to delete. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - await client.crons.delete( - cron_id="cron_to_delete" - ) - ``` - - """ - await self.http.delete(f"/runs/crons/{cron_id}", headers=headers, params=params) - - async def update( - self, - cron_id: str, - *, - schedule: str | None = None, - end_time: datetime | None = None, - input: Input | None = None, - metadata: Mapping[str, Any] | None = None, - config: Config | None = None, - context: Context | None = None, - webhook: str | None = None, - interrupt_before: All | list[str] | None = None, - interrupt_after: All | list[str] | None = None, - on_run_completed: OnCompletionBehavior | None = None, - enabled: bool | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Cron: - """Update a cron job by ID. - - Args: - cron_id: The cron ID to update. - schedule: The cron schedule to execute this job on. - Schedules are interpreted in UTC. - end_time: The end date to stop running the cron. - input: The input to the graph. - metadata: Metadata to assign to the cron job runs. - config: The configuration for the assistant. - context: Static context added to the assistant. - webhook: Webhook to call after LangGraph API call is done. - interrupt_before: Nodes to interrupt immediately before they get executed. - interrupt_after: Nodes to interrupt immediately after they get executed. - on_run_completed: What to do with the thread after the run completes. - Must be one of 'delete' or 'keep'. 'delete' removes the thread - after execution. 'keep' creates a new thread for each execution but does not - clean them up. - enabled: Enable or disable the cron job. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - The updated cron job. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - updated_cron = await client.crons.update( - cron_id="1ef3cefa-4c09-6926-96d0-3dc97fd5e39b", - schedule="0 10 * * *", - enabled=False, - ) - ``` - - """ - payload = { - "schedule": schedule, - "end_time": end_time.isoformat() if end_time else None, - "input": input, - "metadata": metadata, - "config": config, - "context": context, - "webhook": webhook, - "interrupt_before": interrupt_before, - "interrupt_after": interrupt_after, - "on_run_completed": on_run_completed, - "enabled": enabled, - } - payload = {k: v for k, v in payload.items() if v is not None} - return await self.http.patch( - f"/runs/crons/{cron_id}", - json=payload, - headers=headers, - params=params, - ) - - async def search( - self, - *, - assistant_id: str | None = None, - thread_id: str | None = None, - enabled: bool | None = None, - limit: int = 10, - offset: int = 0, - sort_by: CronSortBy | None = None, - sort_order: SortOrder | None = None, - select: list[CronSelectField] | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> list[Cron]: - """Get a list of cron jobs. - - Args: - assistant_id: The assistant ID or graph name to search for. - thread_id: the thread ID to search for. - enabled: The enabled status to search for. - limit: The maximum number of results to return. - offset: The number of results to skip. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - The list of cron jobs returned by the search, - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - cron_jobs = await client.crons.search( - assistant_id="my_assistant_id", - thread_id="my_thread_id", - enabled=True, - limit=5, - offset=5, - ) - print(cron_jobs) - ``` - ```shell - - ---------------------------------------------------------- - - [ - { - 'cron_id': '1ef3cefa-4c09-6926-96d0-3dc97fd5e39b', - 'assistant_id': 'my_assistant_id', - 'thread_id': 'my_thread_id', - 'user_id': None, - 'payload': - { - 'input': {'start_time': ''}, - 'schedule': '4 * * * *', - 'assistant_id': 'my_assistant_id' - }, - 'schedule': '4 * * * *', - 'next_run_date': '2024-07-25T17:04:00+00:00', - 'end_time': None, - 'created_at': '2024-07-08T06:02:23.073257+00:00', - 'updated_at': '2024-07-08T06:02:23.073257+00:00' - } - ] - ``` - - """ - payload = { - "assistant_id": assistant_id, - "thread_id": thread_id, - "enabled": enabled, - "limit": limit, - "offset": offset, - } - if sort_by: - payload["sort_by"] = sort_by - if sort_order: - payload["sort_order"] = sort_order - if select: - payload["select"] = select - payload = {k: v for k, v in payload.items() if v is not None} - return await self.http.post( - "/runs/crons/search", json=payload, headers=headers, params=params - ) - - async def count( - self, - *, - assistant_id: str | None = None, - thread_id: str | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> int: - """Count cron jobs matching filters. - - Args: - assistant_id: Assistant ID to filter by. - thread_id: Thread ID to filter by. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - int: Number of crons matching the criteria. - """ - payload: dict[str, Any] = {} - if assistant_id: - payload["assistant_id"] = assistant_id - if thread_id: - payload["thread_id"] = thread_id - return await self.http.post( - "/runs/crons/count", json=payload, headers=headers, params=params - ) - - -class StoreClient: - """Client for interacting with the graph's shared storage. - - The Store provides a key-value storage system for persisting data across graph executions, - allowing for stateful operations and data sharing across threads. - - ???+ example "Example" - - ```python - client = get_client(url="http://localhost:2024") - await client.store.put_item(["users", "user123"], "mem-123451342", {"name": "Alice", "score": 100}) - ``` - """ - - def __init__(self, http: HttpClient) -> None: - self.http = http - - async def put_item( - self, - namespace: Sequence[str], - /, - key: str, - value: Mapping[str, Any], - index: Literal[False] | list[str] | None = None, - ttl: int | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> None: - """Store or update an item. - - Args: - namespace: A list of strings representing the namespace path. - key: The unique identifier for the item within the namespace. - value: A dictionary containing the item's data. - index: Controls search indexing - None (use defaults), False (disable), or list of field paths to index. - ttl: Optional time-to-live in minutes for the item, or None for no expiration. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - await client.store.put_item( - ["documents", "user123"], - key="item456", - value={"title": "My Document", "content": "Hello World"} - ) - ``` - """ - for label in namespace: - if "." in label: - raise ValueError( - f"Invalid namespace label '{label}'. Namespace labels cannot contain periods ('.')." - ) - payload = { - "namespace": namespace, - "key": key, - "value": value, - "index": index, - "ttl": ttl, - } - await self.http.put( - "/store/items", json=_provided_vals(payload), headers=headers, params=params - ) - - async def get_item( - self, - namespace: Sequence[str], - /, - key: str, - *, - refresh_ttl: bool | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Item: - """Retrieve a single item. - - Args: - key: The unique identifier for the item. - namespace: Optional list of strings representing the namespace path. - refresh_ttl: Whether to refresh the TTL on this read operation. If `None`, uses the store's default behavior. - - Returns: - Item: The retrieved item. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - item = await client.store.get_item( - ["documents", "user123"], - key="item456", - ) - print(item) - ``` - ```shell - - ---------------------------------------------------------------- - - { - 'namespace': ['documents', 'user123'], - 'key': 'item456', - 'value': {'title': 'My Document', 'content': 'Hello World'}, - 'created_at': '2024-07-30T12:00:00Z', - 'updated_at': '2024-07-30T12:00:00Z' - } - ``` - """ - for label in namespace: - if "." in label: - raise ValueError( - f"Invalid namespace label '{label}'. Namespace labels cannot contain periods ('.')." - ) - get_params = {"namespace": ".".join(namespace), "key": key} - if refresh_ttl is not None: - get_params["refresh_ttl"] = refresh_ttl - if params: - get_params = {**get_params, **params} - return await self.http.get("/store/items", params=get_params, headers=headers) - - async def delete_item( - self, - namespace: Sequence[str], - /, - key: str, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> None: - """Delete an item. - - Args: - key: The unique identifier for the item. - namespace: Optional list of strings representing the namespace path. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - await client.store.delete_item( - ["documents", "user123"], - key="item456", - ) - ``` - """ - await self.http.delete( - "/store/items", - json={"namespace": namespace, "key": key}, - headers=headers, - params=params, - ) - - async def search_items( - self, - namespace_prefix: Sequence[str], - /, - filter: Mapping[str, Any] | None = None, - limit: int = 10, - offset: int = 0, - query: str | None = None, - refresh_ttl: bool | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> SearchItemsResponse: - """Search for items within a namespace prefix. - - Args: - namespace_prefix: List of strings representing the namespace prefix. - filter: Optional dictionary of key-value pairs to filter results. - limit: Maximum number of items to return (default is 10). - offset: Number of items to skip before returning results (default is 0). - query: Optional query for natural language search. - refresh_ttl: Whether to refresh the TTL on items returned by this search. If `None`, uses the store's default behavior. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - A list of items matching the search criteria. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - items = await client.store.search_items( - ["documents"], - filter={"author": "John Doe"}, - limit=5, - offset=0 - ) - print(items) - ``` - ```shell - - ---------------------------------------------------------------- - - { - "items": [ - { - "namespace": ["documents", "user123"], - "key": "item789", - "value": { - "title": "Another Document", - "author": "John Doe" - }, - "created_at": "2024-07-30T12:00:00Z", - "updated_at": "2024-07-30T12:00:00Z" - }, - # ... additional items ... - ] - } - ``` - """ - payload = { - "namespace_prefix": namespace_prefix, - "filter": filter, - "limit": limit, - "offset": offset, - "query": query, - "refresh_ttl": refresh_ttl, - } - - return await self.http.post( - "/store/items/search", - json=_provided_vals(payload), - headers=headers, - params=params, - ) - - async def list_namespaces( - self, - prefix: list[str] | None = None, - suffix: list[str] | None = None, - max_depth: int | None = None, - limit: int = 100, - offset: int = 0, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> ListNamespaceResponse: - """List namespaces with optional match conditions. - - Args: - prefix: Optional list of strings representing the prefix to filter namespaces. - suffix: Optional list of strings representing the suffix to filter namespaces. - max_depth: Optional integer specifying the maximum depth of namespaces to return. - limit: Maximum number of namespaces to return (default is 100). - offset: Number of namespaces to skip before returning results (default is 0). - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - A list of namespaces matching the criteria. - - ???+ example "Example Usage" - - ```python - client = get_client(url="http://localhost:2024") - namespaces = await client.store.list_namespaces( - prefix=["documents"], - max_depth=3, - limit=10, - offset=0 - ) - print(namespaces) - - ---------------------------------------------------------------- - - [ - ["documents", "user123", "reports"], - ["documents", "user456", "invoices"], - ... - ] - ``` - """ - payload = { - "prefix": prefix, - "suffix": suffix, - "max_depth": max_depth, - "limit": limit, - "offset": offset, - } - return await self.http.post( - "/store/namespaces", - json=_provided_vals(payload), - headers=headers, - params=params, - ) - - -def get_sync_client( - *, - url: str | None = None, - api_key: str | None = NOT_PROVIDED, - headers: Mapping[str, str] | None = None, - timeout: TimeoutTypes | None = None, -) -> SyncLangGraphClient: - """Get a synchronous LangGraphClient instance. - - Args: - url: The URL of the LangGraph API. - api_key: API key for authentication. Can be: - - A string: use this exact API key - - `None`: explicitly skip loading from environment variables - - Not provided (default): auto-load from environment in this order: - 1. `LANGGRAPH_API_KEY` - 2. `LANGSMITH_API_KEY` - 3. `LANGCHAIN_API_KEY` - headers: Optional custom headers - timeout: Optional timeout configuration for the HTTP client. - Accepts an httpx.Timeout instance, a float (seconds), or a tuple of timeouts. - Tuple format is (connect, read, write, pool) - If not provided, defaults to connect=5s, read=300s, write=300s, and pool=5s. - Returns: - SyncLangGraphClient: The top-level synchronous client for accessing AssistantsClient, - ThreadsClient, RunsClient, and CronClient. - - ???+ example "Example" - - ```python - from langgraph_sdk import get_sync_client - - # get top-level synchronous LangGraphClient - client = get_sync_client(url="http://localhost:8123") - - # example usage: client..() - assistant = client.assistants.get(assistant_id="some_uuid") - ``` - - ???+ example "Skip auto-loading API key from environment:" - - ```python - from langgraph_sdk import get_sync_client - - # Don't load API key from environment variables - client = get_sync_client( - url="http://localhost:8123", - api_key=None - ) - ``` - """ - - if url is None: - url = "http://localhost:8123" - - transport = httpx.HTTPTransport(retries=5) - client = httpx.Client( - base_url=url, - transport=transport, - timeout=( - httpx.Timeout(timeout) # ty: ignore[invalid-argument-type] - if timeout is not None - else httpx.Timeout(connect=5, read=300, write=300, pool=5) - ), - headers=_get_headers(api_key, headers), - ) - return SyncLangGraphClient(client) - - -class SyncLangGraphClient: - """Synchronous client for interacting with the LangGraph API. - - This class provides synchronous access to LangGraph API endpoints for managing - assistants, threads, runs, cron jobs, and data storage. - - ???+ example "Example" - - ```python - client = get_sync_client(url="http://localhost:2024") - assistant = client.assistants.get("asst_123") - ``` - """ - - def __init__(self, client: httpx.Client) -> None: - self.http = SyncHttpClient(client) - self.assistants = SyncAssistantsClient(self.http) - self.threads = SyncThreadsClient(self.http) - self.runs = SyncRunsClient(self.http) - self.crons = SyncCronClient(self.http) - self.store = SyncStoreClient(self.http) - - def __enter__(self) -> SyncLangGraphClient: - """Enter the sync context manager.""" - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc_val: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - """Exit the sync context manager.""" - self.close() - - def close(self) -> None: - """Close the underlying HTTP client.""" - if hasattr(self, "http"): - self.http.client.close() - - -class SyncHttpClient: - """Handle synchronous requests to the LangGraph API. - - Provides error messaging and content handling enhancements above the - underlying httpx client, mirroring the interface of [HttpClient](#HttpClient) - but for sync usage. - - Attributes: - client (httpx.Client): Underlying HTTPX sync client. - """ - - def __init__(self, client: httpx.Client) -> None: - self.client = client - - def get( - self, - path: str, - *, - params: QueryParamTypes | None = None, - headers: Mapping[str, str] | None = None, - on_response: Callable[[httpx.Response], None] | None = None, - ) -> Any: - """Send a `GET` request.""" - r = self.client.get(path, params=params, headers=headers) - if on_response: - on_response(r) - _raise_for_status_typed(r) - return _decode_json(r) - - def post( - self, - path: str, - *, - json: dict[str, Any] | list | None, - params: QueryParamTypes | None = None, - headers: Mapping[str, str] | None = None, - on_response: Callable[[httpx.Response], None] | None = None, - ) -> Any: - """Send a `POST` request.""" - if json is not None: - request_headers, content = _encode_json(json) - else: - request_headers, content = {}, b"" - if headers: - request_headers.update(headers) - r = self.client.post( - path, headers=request_headers, content=content, params=params - ) - if on_response: - on_response(r) - _raise_for_status_typed(r) - return _decode_json(r) - - def put( - self, - path: str, - *, - json: dict, - params: QueryParamTypes | None = None, - headers: Mapping[str, str] | None = None, - on_response: Callable[[httpx.Response], None] | None = None, - ) -> Any: - """Send a `PUT` request.""" - request_headers, content = _encode_json(json) - if headers: - request_headers.update(headers) - - r = self.client.put( - path, headers=request_headers, content=content, params=params - ) - if on_response: - on_response(r) - _raise_for_status_typed(r) - return _decode_json(r) - - def patch( - self, - path: str, - *, - json: dict, - params: QueryParamTypes | None = None, - headers: Mapping[str, str] | None = None, - on_response: Callable[[httpx.Response], None] | None = None, - ) -> Any: - """Send a `PATCH` request.""" - request_headers, content = _encode_json(json) - if headers: - request_headers.update(headers) - r = self.client.patch( - path, headers=request_headers, content=content, params=params - ) - if on_response: - on_response(r) - _raise_for_status_typed(r) - return _decode_json(r) - - def delete( - self, - path: str, - *, - json: Any | None = None, - params: QueryParamTypes | None = None, - headers: Mapping[str, str] | None = None, - on_response: Callable[[httpx.Response], None] | None = None, - ) -> None: - """Send a `DELETE` request.""" - r = self.client.request( - "DELETE", path, json=json, params=params, headers=headers - ) - if on_response: - on_response(r) - _raise_for_status_typed(r) - - def request_reconnect( - self, - path: str, - method: str, - *, - json: dict[str, Any] | None = None, - params: QueryParamTypes | None = None, - headers: Mapping[str, str] | None = None, - on_response: Callable[[httpx.Response], None] | None = None, - reconnect_limit: int = 5, - ) -> Any: - """Send a request that automatically reconnects to Location header.""" - request_headers, content = _encode_json(json) - if headers: - request_headers.update(headers) - with self.client.stream( - method, path, headers=request_headers, content=content, params=params - ) as r: - if on_response: - on_response(r) - try: - r.raise_for_status() - except httpx.HTTPStatusError as e: - body = r.read().decode() - if sys.version_info >= (3, 11): - e.add_note(body) - else: - logger.error(f"Error from langgraph-api: {body}", exc_info=e) - raise e - loc = r.headers.get("location") - if reconnect_limit <= 0 or not loc: - return _decode_json(r) - try: - return _decode_json(r) - except httpx.HTTPError: - warnings.warn( - f"Request failed, attempting reconnect to Location: {loc}", - stacklevel=2, - ) - r.close() - return self.request_reconnect( - loc, - "GET", - headers=request_headers, - # don't pass on_response so it's only called once - reconnect_limit=reconnect_limit - 1, - ) - - def stream( - self, - path: str, - method: str, - *, - json: dict[str, Any] | None = None, - params: QueryParamTypes | None = None, - headers: Mapping[str, str] | None = None, - on_response: Callable[[httpx.Response], None] | None = None, - ) -> Iterator[StreamPart]: - """Stream the results of a request using SSE.""" - if json is not None: - request_headers, content = _encode_json(json) - else: - request_headers, content = {}, None - request_headers["Accept"] = "text/event-stream" - request_headers["Cache-Control"] = "no-store" - if headers: - request_headers.update(headers) - - reconnect_headers = { - key: value - for key, value in request_headers.items() - if key.lower() not in {"content-length", "content-type"} - } - - last_event_id: str | None = None - reconnect_path: str | None = None - reconnect_attempts = 0 - max_reconnect_attempts = 5 - - while True: - current_headers = dict( - request_headers if reconnect_path is None else reconnect_headers - ) - if last_event_id is not None: - current_headers["Last-Event-ID"] = last_event_id - - current_method = method if reconnect_path is None else "GET" - current_content = content if reconnect_path is None else None - current_params = params if reconnect_path is None else None - - retry = False - with self.client.stream( - current_method, - reconnect_path or path, - headers=current_headers, - content=current_content, - params=current_params, - ) as res: - if reconnect_path is None and on_response: - on_response(res) - # check status - _raise_for_status_typed(res) - # check content type - content_type = res.headers.get("content-type", "").partition(";")[0] - if "text/event-stream" not in content_type: - raise httpx.TransportError( - "Expected response header Content-Type to contain 'text/event-stream', " - f"got {content_type!r}" - ) - - reconnect_location = res.headers.get("location") - if reconnect_location: - reconnect_path = reconnect_location - - decoder = SSEDecoder() - try: - for line in iter_lines_raw(res): - sse = decoder.decode(cast(bytes, line).rstrip(b"\n")) - if sse is not None: - if decoder.last_event_id is not None: - last_event_id = decoder.last_event_id - if sse.event or sse.data is not None: - yield sse - except httpx.HTTPError: - # httpx.TransportError inherits from HTTPError, so transient - # disconnects during streaming land here. - if reconnect_path is None: - raise - retry = True - else: - if sse := decoder.decode(b""): - if decoder.last_event_id is not None: - last_event_id = decoder.last_event_id - if sse.event or sse.data is not None: - # See async stream implementation for rationale on - # skipping empty flush events. - yield sse - if retry: - reconnect_attempts += 1 - if reconnect_attempts > max_reconnect_attempts: - raise httpx.TransportError( - "Exceeded maximum SSE reconnection attempts" - ) - continue - break - - -def _encode_json(json: Any) -> tuple[dict[str, str], bytes]: - body = orjson.dumps( - json, - _orjson_default, - orjson.OPT_SERIALIZE_NUMPY | orjson.OPT_NON_STR_KEYS, - ) - content_length = str(len(body)) - content_type = "application/json" - headers = {"Content-Length": content_length, "Content-Type": content_type} - return headers, body - - -def _decode_json(r: httpx.Response) -> Any: - body = r.read() - return orjson.loads(body) if body else None - - -class SyncAssistantsClient: - """Client for managing assistants in LangGraph synchronously. - - This class provides methods to interact with assistants, which are versioned configurations of your graph. - - ???+ example "Example" - - ```python - client = get_sync_client(url="http://localhost:2024") - assistant = client.assistants.get("assistant_id_123") - ``` - """ - - def __init__(self, http: SyncHttpClient) -> None: - self.http = http - - def get( - self, - assistant_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Assistant: - """Get an assistant by ID. - - Args: - assistant_id: The ID of the assistant to get OR the name of the graph (to use the default assistant). - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `Assistant` Object. - - ???+ example "Example Usage" - - ```python - assistant = client.assistants.get( - assistant_id="my_assistant_id" - ) - print(assistant) - ``` - - ```shell - ---------------------------------------------------- - - { - 'assistant_id': 'my_assistant_id', - 'graph_id': 'agent', - 'created_at': '2024-06-25T17:10:33.109781+00:00', - 'updated_at': '2024-06-25T17:10:33.109781+00:00', - 'config': {}, - 'context': {}, - 'metadata': {'created_by': 'system'} - } - ``` - - """ - return self.http.get( - f"/assistants/{assistant_id}", headers=headers, params=params - ) - - def get_graph( - self, - assistant_id: str, - *, - xray: int | bool = False, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> dict[str, list[dict[str, Any]]]: - """Get the graph of an assistant by ID. - - Args: - assistant_id: The ID of the assistant to get the graph of. - xray: Include graph representation of subgraphs. If an integer value is provided, only subgraphs with a depth less than or equal to the value will be included. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - The graph information for the assistant in JSON format. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - graph_info = client.assistants.get_graph( - assistant_id="my_assistant_id" - ) - print(graph_info) - - -------------------------------------------------------------------------------------------------------------------------- - - { - 'nodes': - [ - {'id': '__start__', 'type': 'schema', 'data': '__start__'}, - {'id': '__end__', 'type': 'schema', 'data': '__end__'}, - {'id': 'agent','type': 'runnable','data': {'id': ['langgraph', 'utils', 'RunnableCallable'],'name': 'agent'}}, - ], - 'edges': - [ - {'source': '__start__', 'target': 'agent'}, - {'source': 'agent','target': '__end__'} - ] - } - ``` - - """ - query_params = {"xray": xray} - if params: - query_params.update(params) - return self.http.get( - f"/assistants/{assistant_id}/graph", params=query_params, headers=headers - ) - - def get_schemas( - self, - assistant_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> GraphSchema: - """Get the schemas of an assistant by ID. - - Args: - assistant_id: The ID of the assistant to get the schema of. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - GraphSchema: The graph schema for the assistant. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - schema = client.assistants.get_schemas( - assistant_id="my_assistant_id" - ) - print(schema) - ``` - ```shell - ---------------------------------------------------------------------------------------------------------------------------- - - { - 'graph_id': 'agent', - 'state_schema': - { - 'title': 'LangGraphInput', - '$ref': '#/definitions/AgentState', - 'definitions': - { - 'BaseMessage': - { - 'title': 'BaseMessage', - 'description': 'Base abstract Message class. Messages are the inputs and outputs of ChatModels.', - 'type': 'object', - 'properties': - { - 'content': - { - 'title': 'Content', - 'anyOf': [ - {'type': 'string'}, - {'type': 'array','items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}} - ] - }, - 'additional_kwargs': - { - 'title': 'Additional Kwargs', - 'type': 'object' - }, - 'response_metadata': - { - 'title': 'Response Metadata', - 'type': 'object' - }, - 'type': - { - 'title': 'Type', - 'type': 'string' - }, - 'name': - { - 'title': 'Name', - 'type': 'string' - }, - 'id': - { - 'title': 'Id', - 'type': 'string' - } - }, - 'required': ['content', 'type'] - }, - 'AgentState': - { - 'title': 'AgentState', - 'type': 'object', - 'properties': - { - 'messages': - { - 'title': 'Messages', - 'type': 'array', - 'items': {'$ref': '#/definitions/BaseMessage'} - } - }, - 'required': ['messages'] - } - } - }, - 'config_schema': - { - 'title': 'Configurable', - 'type': 'object', - 'properties': - { - 'model_name': - { - 'title': 'Model Name', - 'enum': ['anthropic', 'openai'], - 'type': 'string' - } - } - }, - 'context_schema': - { - 'title': 'Context', - 'type': 'object', - 'properties': - { - 'model_name': - { - 'title': 'Model Name', - 'enum': ['anthropic', 'openai'], - 'type': 'string' - } - } - } - } - ``` - - """ - return self.http.get( - f"/assistants/{assistant_id}/schemas", headers=headers, params=params - ) - - def get_subgraphs( - self, - assistant_id: str, - namespace: str | None = None, - recurse: bool = False, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Subgraphs: - """Get the schemas of an assistant by ID. - - Args: - assistant_id: The ID of the assistant to get the schema of. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - Subgraphs: The graph schema for the assistant. - - """ - get_params = {"recurse": recurse} - if params: - get_params = {**get_params, **params} - if namespace is not None: - return self.http.get( - f"/assistants/{assistant_id}/subgraphs/{namespace}", - params=get_params, - headers=headers, - ) - else: - return self.http.get( - f"/assistants/{assistant_id}/subgraphs", - params=get_params, - headers=headers, - ) - - def create( - self, - graph_id: str | None, - config: Config | None = None, - *, - context: Context | None = None, - metadata: Json = None, - assistant_id: str | None = None, - if_exists: OnConflictBehavior | None = None, - name: str | None = None, - headers: Mapping[str, str] | None = None, - description: str | None = None, - params: QueryParamTypes | None = None, - ) -> Assistant: - """Create a new assistant. - - Useful when graph is configurable and you want to create different assistants based on different configurations. - - Args: - graph_id: The ID of the graph the assistant should use. The graph ID is normally set in your langgraph.json configuration. - config: Configuration to use for the graph. - context: Static context to add to the assistant. - !!! version-added "Added in version 0.6.0" - metadata: Metadata to add to assistant. - assistant_id: Assistant ID to use, will default to a random UUID if not provided. - if_exists: How to handle duplicate creation. Defaults to 'raise' under the hood. - Must be either 'raise' (raise error if duplicate), or 'do_nothing' (return existing assistant). - name: The name of the assistant. Defaults to 'Untitled' under the hood. - headers: Optional custom headers to include with the request. - description: Optional description of the assistant. - The description field is available for langgraph-api server version>=0.0.45 - params: Optional query parameters to include with the request. - - Returns: - The created assistant. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - assistant = client.assistants.create( - graph_id="agent", - context={"model_name": "openai"}, - metadata={"number":1}, - assistant_id="my-assistant-id", - if_exists="do_nothing", - name="my_name" - ) - ``` - """ - payload: dict[str, Any] = { - "graph_id": graph_id, - } - if config: - payload["config"] = config - if context: - payload["context"] = context - if metadata: - payload["metadata"] = metadata - if assistant_id: - payload["assistant_id"] = assistant_id - if if_exists: - payload["if_exists"] = if_exists - if name: - payload["name"] = name - if description: - payload["description"] = description - return self.http.post( - "/assistants", json=payload, headers=headers, params=params - ) - - def update( - self, - assistant_id: str, - *, - graph_id: str | None = None, - config: Config | None = None, - context: Context | None = None, - metadata: Json = None, - name: str | None = None, - headers: Mapping[str, str] | None = None, - description: str | None = None, - params: QueryParamTypes | None = None, - ) -> Assistant: - """Update an assistant. - - Use this to point to a different graph, update the configuration, or change the metadata of an assistant. - - Args: - assistant_id: Assistant to update. - graph_id: The ID of the graph the assistant should use. - The graph ID is normally set in your langgraph.json configuration. If `None`, assistant will keep pointing to same graph. - config: Configuration to use for the graph. - context: Static context to add to the assistant. - !!! version-added "Added in version 0.6.0" - metadata: Metadata to merge with existing assistant metadata. - name: The new name for the assistant. - headers: Optional custom headers to include with the request. - description: Optional description of the assistant. - The description field is available for langgraph-api server version>=0.0.45 - - Returns: - The updated assistant. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - assistant = client.assistants.update( - assistant_id='e280dad7-8618-443f-87f1-8e41841c180f', - graph_id="other-graph", - context={"model_name": "anthropic"}, - metadata={"number":2} - ) - ``` - """ - payload: dict[str, Any] = {} - if graph_id: - payload["graph_id"] = graph_id - if config: - payload["config"] = config - if context: - payload["context"] = context - if metadata: - payload["metadata"] = metadata - if name: - payload["name"] = name - if description: - payload["description"] = description - return self.http.patch( - f"/assistants/{assistant_id}", - json=payload, - headers=headers, - params=params, - ) - - def delete( - self, - assistant_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> None: - """Delete an assistant. - - Args: - assistant_id: The assistant ID to delete. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - client.assistants.delete( - assistant_id="my_assistant_id" - ) - ``` - - """ - self.http.delete(f"/assistants/{assistant_id}", headers=headers, params=params) - - @overload - def search( - self, - *, - metadata: Json = None, - graph_id: str | None = None, - name: str | None = None, - limit: int = 10, - offset: int = 0, - sort_by: AssistantSortBy | None = None, - sort_order: SortOrder | None = None, - select: list[AssistantSelectField] | None = None, - response_format: Literal["object"], - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> AssistantsSearchResponse: ... - - @overload - def search( - self, - *, - metadata: Json = None, - graph_id: str | None = None, - name: str | None = None, - limit: int = 10, - offset: int = 0, - sort_by: AssistantSortBy | None = None, - sort_order: SortOrder | None = None, - select: list[AssistantSelectField] | None = None, - response_format: Literal["array"] = "array", - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> list[Assistant]: ... - - def search( - self, - *, - metadata: Json = None, - graph_id: str | None = None, - name: str | None = None, - limit: int = 10, - offset: int = 0, - sort_by: AssistantSortBy | None = None, - sort_order: SortOrder | None = None, - select: list[AssistantSelectField] | None = None, - response_format: Literal["array", "object"] = "array", - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> AssistantsSearchResponse | list[Assistant]: - """Search for assistants. - - Args: - metadata: Metadata to filter by. Exact match filter for each KV pair. - graph_id: The ID of the graph to filter by. - The graph ID is normally set in your langgraph.json configuration. - name: The name of the assistant to filter by. - The filtering logic will match assistants where 'name' is a substring (case insensitive) of the assistant name. - limit: The maximum number of results to return. - offset: The number of results to skip. - sort_by: The field to sort by. - sort_order: The order to sort by. - select: Specific assistant fields to include in the response. - response_format: Controls the response shape. Use ``"array"`` (default) - to return a bare list of assistants, or ``"object"`` to return - a mapping containing assistants plus pagination metadata. - Defaults to "array", though this default will be changed to "object" in a future release. - headers: Optional custom headers to include with the request. - - Returns: - A list of assistants (when ``response_format=\"array\"``) or a mapping - with the assistants and the next pagination cursor (when - ``response_format=\"object\"``). - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - response = client.assistants.search( - metadata = {"name":"my_name"}, - graph_id="my_graph_id", - limit=5, - offset=5, - response_format="object", - ) - assistants = response["assistants"] - next_cursor = response["next"] - ``` - """ - if response_format not in ("array", "object"): - raise ValueError("response_format must be 'array' or 'object'") - payload: dict[str, Any] = { - "limit": limit, - "offset": offset, - } - if metadata: - payload["metadata"] = metadata - if graph_id: - payload["graph_id"] = graph_id - if name: - payload["name"] = name - if sort_by: - payload["sort_by"] = sort_by - if sort_order: - payload["sort_order"] = sort_order - if select: - payload["select"] = select - next_cursor: str | None = None - - def capture_pagination(response: httpx.Response) -> None: - nonlocal next_cursor - next_cursor = response.headers.get("X-Pagination-Next") - - assistants = cast( - list[Assistant], - self.http.post( - "/assistants/search", - json=payload, - headers=headers, - params=params, - on_response=capture_pagination if response_format == "object" else None, - ), - ) - if response_format == "object": - return {"assistants": assistants, "next": next_cursor} - return assistants - - def count( - self, - *, - metadata: Json = None, - graph_id: str | None = None, - name: str | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> int: - """Count assistants matching filters. - - Args: - metadata: Metadata to filter by. Exact match for each key/value. - graph_id: Optional graph id to filter by. - name: Optional name to filter by. - The filtering logic will match assistants where 'name' is a substring (case insensitive) of the assistant name. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - int: Number of assistants matching the criteria. - """ - payload: dict[str, Any] = {} - if metadata: - payload["metadata"] = metadata - if graph_id: - payload["graph_id"] = graph_id - if name: - payload["name"] = name - return self.http.post( - "/assistants/count", json=payload, headers=headers, params=params - ) - - def get_versions( - self, - assistant_id: str, - metadata: Json = None, - limit: int = 10, - offset: int = 0, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> list[AssistantVersion]: - """List all versions of an assistant. - - Args: - assistant_id: The assistant ID to get versions for. - metadata: Metadata to filter versions by. Exact match filter for each KV pair. - limit: The maximum number of versions to return. - offset: The number of versions to skip. - headers: Optional custom headers to include with the request. - - Returns: - A list of assistants. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - assistant_versions = client.assistants.get_versions( - assistant_id="my_assistant_id" - ) - ``` - - """ - - payload: dict[str, Any] = { - "limit": limit, - "offset": offset, - } - if metadata: - payload["metadata"] = metadata - return self.http.post( - f"/assistants/{assistant_id}/versions", - json=payload, - headers=headers, - params=params, - ) - - def set_latest( - self, - assistant_id: str, - version: int, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Assistant: - """Change the version of an assistant. - - Args: - assistant_id: The assistant ID to delete. - version: The version to change to. - headers: Optional custom headers to include with the request. - - Returns: - `Assistant` Object. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - new_version_assistant = client.assistants.set_latest( - assistant_id="my_assistant_id", - version=3 - ) - ``` - - """ - - payload: dict[str, Any] = {"version": version} - - return self.http.post( - f"/assistants/{assistant_id}/latest", - json=payload, - headers=headers, - params=params, - ) - - -class SyncThreadsClient: - """Synchronous client for managing threads in LangGraph. - - This class provides methods to create, retrieve, and manage threads, - which represent conversations or stateful interactions. - - ???+ example "Example" - - ```python - client = get_sync_client(url="http://localhost:2024") - thread = client.threads.create(metadata={"user_id": "123"}) - ``` - """ - - def __init__(self, http: SyncHttpClient) -> None: - self.http = http - - def get( - self, - thread_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Thread: - """Get a thread by ID. - - Args: - thread_id: The ID of the thread to get. - headers: Optional custom headers to include with the request. - - Returns: - `Thread` object. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - thread = client.threads.get( - thread_id="my_thread_id" - ) - print(thread) - ``` - ```shell - ----------------------------------------------------- - - { - 'thread_id': 'my_thread_id', - 'created_at': '2024-07-18T18:35:15.540834+00:00', - 'updated_at': '2024-07-18T18:35:15.540834+00:00', - 'metadata': {'graph_id': 'agent'} - } - ``` - - """ - - return self.http.get(f"/threads/{thread_id}", headers=headers, params=params) - - def create( - self, - *, - metadata: Json = None, - thread_id: str | None = None, - if_exists: OnConflictBehavior | None = None, - supersteps: Sequence[dict[str, Sequence[dict[str, Any]]]] | None = None, - graph_id: str | None = None, - ttl: int | Mapping[str, Any] | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Thread: - """Create a new thread. - - Args: - metadata: Metadata to add to thread. - thread_id: ID of thread. - If `None`, ID will be a randomly generated UUID. - if_exists: How to handle duplicate creation. Defaults to 'raise' under the hood. - Must be either 'raise' (raise error if duplicate), or 'do_nothing' (return existing thread). - supersteps: Apply a list of supersteps when creating a thread, each containing a sequence of updates. - Each update has `values` or `command` and `as_node`. Used for copying a thread between deployments. - graph_id: Optional graph ID to associate with the thread. - ttl: Optional time-to-live in minutes for the thread. You can pass an - integer (minutes) or a mapping with keys `ttl` and optional - `strategy` (defaults to "delete"). - headers: Optional custom headers to include with the request. - - Returns: - The created `Thread`. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - thread = client.threads.create( - metadata={"number":1}, - thread_id="my-thread-id", - if_exists="raise" - ) - ``` - ) - """ - payload: dict[str, Any] = {} - 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 - if supersteps: - payload["supersteps"] = [ - { - "updates": [ - { - "values": u["values"], - "command": u.get("command"), - "as_node": u["as_node"], - } - for u in s["updates"] - ] - } - for s in supersteps - ] - if ttl is not None: - if isinstance(ttl, (int, float)): - payload["ttl"] = {"ttl": ttl, "strategy": "delete"} - else: - payload["ttl"] = ttl - - return self.http.post("/threads", json=payload, headers=headers, params=params) - - def update( - self, - thread_id: str, - *, - metadata: Mapping[str, Any], - ttl: int | Mapping[str, Any] | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Thread: - """Update a thread. - - Args: - thread_id: ID of thread to update. - metadata: Metadata to merge with existing thread metadata. - ttl: Optional time-to-live in minutes for the thread. You can pass an - integer (minutes) or a mapping with keys `ttl` and optional - `strategy` (defaults to "delete"). - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - The created `Thread`. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - thread = client.threads.update( - thread_id="my-thread-id", - metadata={"number":1}, - ttl=43_200, - ) - ``` - """ - payload: dict[str, Any] = {"metadata": metadata} - if ttl is not None: - if isinstance(ttl, (int, float)): - payload["ttl"] = {"ttl": ttl, "strategy": "delete"} - else: - payload["ttl"] = ttl - return self.http.patch( - f"/threads/{thread_id}", - json=payload, - headers=headers, - params=params, - ) - - def delete( - self, - thread_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> None: - """Delete a thread. - - Args: - thread_id: The ID of the thread to delete. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client.threads.delete( - thread_id="my_thread_id" - ) - ``` - - """ - self.http.delete(f"/threads/{thread_id}", headers=headers, params=params) - - def search( - self, - *, - metadata: Json = None, - values: Json = None, - ids: Sequence[str] | None = None, - status: ThreadStatus | None = None, - limit: int = 10, - offset: int = 0, - sort_by: ThreadSortBy | None = None, - sort_order: SortOrder | None = None, - select: list[ThreadSelectField] | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> list[Thread]: - """Search for threads. - - Args: - metadata: Thread metadata to filter on. - values: State values to filter on. - ids: List of thread IDs to filter by. - status: Thread status to filter on. - Must be one of 'idle', 'busy', 'interrupted' or 'error'. - limit: Limit on number of threads to return. - offset: Offset in threads table to start search from. - headers: Optional custom headers to include with the request. - - Returns: - List of the threads matching the search parameters. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - threads = client.threads.search( - metadata={"number":1}, - status="interrupted", - limit=15, - offset=5 - ) - ``` - """ - payload: dict[str, Any] = { - "limit": limit, - "offset": offset, - } - if metadata: - payload["metadata"] = metadata - if values: - payload["values"] = values - if ids: - payload["ids"] = ids - if status: - payload["status"] = status - if sort_by: - payload["sort_by"] = sort_by - if sort_order: - payload["sort_order"] = sort_order - if select: - payload["select"] = select - return self.http.post( - "/threads/search", json=payload, headers=headers, params=params - ) - - def count( - self, - *, - metadata: Json = None, - values: Json = None, - status: ThreadStatus | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> int: - """Count threads matching filters. - - Args: - metadata: Thread metadata to filter on. - values: State values to filter on. - status: Thread status to filter on. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - int: Number of threads matching the criteria. - """ - payload: dict[str, Any] = {} - if metadata: - payload["metadata"] = metadata - if values: - payload["values"] = values - if status: - payload["status"] = status - return self.http.post( - "/threads/count", json=payload, headers=headers, params=params - ) - - def copy( - self, - thread_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> None: - """Copy a thread. - - Args: - thread_id: The ID of the thread to copy. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - client.threads.copy( - thread_id="my_thread_id" - ) - ``` - - """ - return self.http.post( - f"/threads/{thread_id}/copy", json=None, headers=headers, params=params - ) - - def get_state( - self, - thread_id: str, - checkpoint: Checkpoint | None = None, - checkpoint_id: str | None = None, # deprecated - *, - subgraphs: bool = False, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> ThreadState: - """Get the state of a thread. - - Args: - thread_id: The ID of the thread to get the state of. - checkpoint: The checkpoint to get the state of. - subgraphs: Include subgraphs states. - headers: Optional custom headers to include with the request. - - Returns: - The thread of the state. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - thread_state = client.threads.get_state( - thread_id="my_thread_id", - checkpoint_id="my_checkpoint_id" - ) - print(thread_state) - ``` - - ```shell - ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- - - { - 'values': { - '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 - } - ] - }, - 'next': [], - 'checkpoint': - { - 'thread_id': 'e2496803-ecd5-4e0c-a779-3226296181c2', - 'checkpoint_ns': '', - 'checkpoint_id': '1ef4a9b8-e6fb-67b1-8001-abd5184439d1' - } - 'metadata': - { - 'step': 1, - 'run_id': '1ef4a9b8-d7da-679a-a45a-872054341df2', - 'source': 'loop', - 'writes': - { - 'agent': - { - 'messages': [ - { - 'id': 'run-159b782c-b679-4830-83c6-cef87798fe8b', - 'name': None, - 'type': 'ai', - 'content': "I'm doing well, thanks for asking! I'm an AI assistant created by Anthropic to be helpful, honest, and harmless.", - 'example': False, - 'tool_calls': [], - 'usage_metadata': None, - 'additional_kwargs': {}, - 'response_metadata': {}, - 'invalid_tool_calls': [] - } - ] - } - }, - 'user_id': None, - 'graph_id': 'agent', - 'thread_id': 'e2496803-ecd5-4e0c-a779-3226296181c2', - 'created_by': 'system', - 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, - 'created_at': '2024-07-25T15:35:44.184703+00:00', - 'parent_config': - { - 'thread_id': 'e2496803-ecd5-4e0c-a779-3226296181c2', - 'checkpoint_ns': '', - 'checkpoint_id': '1ef4a9b8-d80d-6fa7-8000-9300467fad0f' - } - } - ``` - - """ - if checkpoint: - return self.http.post( - f"/threads/{thread_id}/state/checkpoint", - json={"checkpoint": checkpoint, "subgraphs": subgraphs}, - headers=headers, - params=params, - ) - elif checkpoint_id: - get_params = {"subgraphs": subgraphs} - if params: - get_params = {**get_params, **params} - return self.http.get( - f"/threads/{thread_id}/state/{checkpoint_id}", - params=get_params, - headers=headers, - ) - else: - get_params = {"subgraphs": subgraphs} - if params: - get_params = {**get_params, **params} - return self.http.get( - f"/threads/{thread_id}/state", - params=get_params, - headers=headers, - ) - - def update_state( - self, - thread_id: str, - values: dict[str, Any] | Sequence[dict] | None, - *, - as_node: str | None = None, - checkpoint: Checkpoint | None = None, - checkpoint_id: str | None = None, # deprecated - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> ThreadUpdateStateResponse: - """Update the state of 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. - headers: Optional custom headers to include with the request. - - Returns: - Response after updating a thread's state. - - ???+ example "Example Usage" - - ```python - - response = await 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': {} - } - } - ``` - - """ - payload: dict[str, Any] = { - "values": values, - } - if checkpoint_id: - payload["checkpoint_id"] = checkpoint_id - if checkpoint: - payload["checkpoint"] = checkpoint - if as_node: - payload["as_node"] = as_node - return self.http.post( - f"/threads/{thread_id}/state", json=payload, headers=headers, params=params - ) - - def get_history( - self, - thread_id: str, - *, - limit: int = 10, - before: str | Checkpoint | None = None, - metadata: Mapping[str, Any] | None = None, - checkpoint: Checkpoint | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> list[ThreadState]: - """Get the state history of a thread. - - Args: - thread_id: The ID of the thread to get the state history for. - checkpoint: Return states for this subgraph. If empty defaults to root. - limit: The maximum number of states to return. - before: Return states before this checkpoint. - metadata: Filter states by metadata key-value pairs. - headers: Optional custom headers to include with the request. - - Returns: - The state history of the `Thread`. - - ???+ example "Example Usage" - - ```python - - thread_state = client.threads.get_history( - thread_id="my_thread_id", - limit=5, - before="my_timestamp", - metadata={"name":"my_name"} - ) - ``` - - """ - payload: dict[str, Any] = { - "limit": limit, - } - if before: - payload["before"] = before - if metadata: - payload["metadata"] = metadata - if checkpoint: - payload["checkpoint"] = checkpoint - return self.http.post( - f"/threads/{thread_id}/history", - json=payload, - headers=headers, - params=params, - ) - - def join_stream( - self, - thread_id: str, - *, - stream_mode: ThreadStreamMode | Sequence[ThreadStreamMode] = "run_modes", - last_event_id: str | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Iterator[StreamPart]: - """Get a stream of events for a thread. - - Args: - thread_id: The ID of the thread to get the stream for. - last_event_id: The ID of the last event to get. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - An iterator of stream parts. - - ???+ example "Example Usage" - - ```python - - for chunk in client.threads.join_stream( - thread_id="my_thread_id", - last_event_id="my_event_id", - stream_mode="run_modes", - ): - print(chunk) - ``` - - """ - query_params = { - "stream_mode": stream_mode, - } - if params: - query_params.update(params) - return self.http.stream( - f"/threads/{thread_id}/stream", - "GET", - headers={ - **({"Last-Event-ID": last_event_id} if last_event_id else {}), - **(headers or {}), - }, - params=query_params, - ) - - -class SyncRunsClient: - """Synchronous client for managing runs in LangGraph. - - This class provides methods to create, retrieve, and manage runs, which represent - individual executions of graphs. - - ???+ example "Example" - - ```python - client = get_sync_client(url="http://localhost:2024") - run = client.runs.create(thread_id="thread_123", assistant_id="asst_456") - ``` - """ - - def __init__(self, http: SyncHttpClient) -> None: - self.http = http - - @overload - def stream( - self, - thread_id: str, - assistant_id: str, - *, - input: Input | None = None, - command: Command | None = None, - stream_mode: StreamMode | Sequence[StreamMode] = "values", - stream_subgraphs: bool = False, - metadata: Mapping[str, Any] | None = None, - config: Config | None = None, - context: Context | None = None, - checkpoint: Checkpoint | None = None, - checkpoint_id: str | None = None, - checkpoint_during: bool | None = None, - interrupt_before: All | Sequence[str] | None = None, - interrupt_after: All | Sequence[str] | None = None, - feedback_keys: Sequence[str] | None = None, - on_disconnect: DisconnectMode | None = None, - webhook: str | None = None, - multitask_strategy: MultitaskStrategy | None = None, - if_not_exists: IfNotExists | None = None, - after_seconds: int | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - ) -> Iterator[StreamPart]: ... - - @overload - def stream( - self, - thread_id: None, - assistant_id: str, - *, - input: Input | None = None, - 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, - checkpoint_during: bool | None = None, - interrupt_before: All | Sequence[str] | None = None, - interrupt_after: All | Sequence[str] | None = None, - feedback_keys: Sequence[str] | None = None, - on_disconnect: DisconnectMode | None = None, - on_completion: OnCompletionBehavior | None = None, - if_not_exists: IfNotExists | None = None, - webhook: str | None = None, - after_seconds: int | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - ) -> Iterator[StreamPart]: ... - - def stream( - self, - thread_id: str | None, - assistant_id: str, - *, - input: Input | None = None, - 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, - checkpoint: Checkpoint | None = None, - checkpoint_id: str | None = None, - checkpoint_during: bool | None = None, # deprecated - interrupt_before: All | Sequence[str] | None = None, - interrupt_after: All | Sequence[str] | None = None, - feedback_keys: Sequence[str] | None = None, - on_disconnect: DisconnectMode | None = None, - on_completion: OnCompletionBehavior | None = None, - webhook: str | None = None, - multitask_strategy: MultitaskStrategy | None = None, - if_not_exists: IfNotExists | None = None, - after_seconds: int | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - durability: Durability | None = None, - ) -> Iterator[StreamPart]: - """Create a run and stream the results. - - Args: - thread_id: the thread ID to assign to the thread. - If `None` will create a stateless run. - assistant_id: The assistant ID or graph name to stream from. - If using graph name, will default to first assistant created from that graph. - input: The input to the graph. - command: The command to execute. - stream_mode: The stream mode(s) to use. - stream_subgraphs: Whether to stream output from subgraphs. - stream_resumable: Whether the stream is considered resumable. - If true, the stream can be resumed and replayed in its entirety even after disconnection. - metadata: Metadata to assign to the run. - config: The configuration for the assistant. - context: Static context to add to the assistant. - !!! version-added "Added in version 0.6.0" - checkpoint: The checkpoint to resume from. - checkpoint_during: (deprecated) Whether to checkpoint during the run (or only at the end/interruption). - interrupt_before: Nodes to interrupt immediately before they get executed. - interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. - feedback_keys: Feedback keys to assign to run. - on_disconnect: The disconnect mode to use. - Must be one of 'cancel' or 'continue'. - on_completion: Whether to delete or keep the thread created for a stateless run. - Must be one of 'delete' or 'keep'. - webhook: Webhook to call after LangGraph API call is done. - multitask_strategy: Multitask strategy to use. - Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. - if_not_exists: How to handle missing thread. Defaults to 'reject'. - Must be either 'reject' (raise error if missing), or 'create' (create new thread). - after_seconds: The number of seconds to wait before starting the run. - Use to schedule future runs. - headers: Optional custom headers to include with the request. - on_run_created: Optional callback to call when a run is created. - durability: The durability to use for the run. Values are "sync", "async", or "exit". - "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 - - - Returns: - Iterator of stream results. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - async for chunk in client.runs.stream( - thread_id=None, - assistant_id="agent", - input={"messages": [{"role": "user", "content": "how are you?"}]}, - stream_mode=["values","debug"], - metadata={"name":"my_run"}, - context={"model_name": "anthropic"}, - interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], - interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], - feedback_keys=["my_feedback_key_1","my_feedback_key_2"], - webhook="https://my.fake.webhook.com", - multitask_strategy="interrupt" - ): - print(chunk) - ``` - ```shell - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ - - 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) - ``` - """ - if checkpoint_during is not None: - warnings.warn( - "`checkpoint_during` is deprecated and will be removed in a future version. Use `durability` instead.", - DeprecationWarning, - stacklevel=2, - ) - payload = { - "input": input, - "command": ( - {k: v for k, v in command.items() if v is not None} if command else None - ), - "config": config, - "context": context, - "metadata": metadata, - "stream_mode": stream_mode, - "stream_subgraphs": stream_subgraphs, - "stream_resumable": stream_resumable, - "assistant_id": assistant_id, - "interrupt_before": interrupt_before, - "interrupt_after": interrupt_after, - "feedback_keys": feedback_keys, - "webhook": webhook, - "checkpoint": checkpoint, - "checkpoint_id": checkpoint_id, - "checkpoint_during": checkpoint_during, - "multitask_strategy": multitask_strategy, - "if_not_exists": if_not_exists, - "on_disconnect": on_disconnect, - "on_completion": on_completion, - "after_seconds": after_seconds, - "durability": durability, - } - endpoint = ( - f"/threads/{thread_id}/runs/stream" - if thread_id is not None - else "/runs/stream" - ) - - def on_response(res: httpx.Response): - """Callback function to handle the response.""" - if on_run_created and (metadata := _get_run_metadata_from_response(res)): - on_run_created(metadata) - - return self.http.stream( - endpoint, - "POST", - json={k: v for k, v in payload.items() if v is not None}, - params=params, - headers=headers, - on_response=on_response if on_run_created else None, - ) - - @overload - def create( - self, - thread_id: None, - assistant_id: str, - *, - input: Input | None = None, - 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, - checkpoint_during: bool | None = None, - interrupt_before: All | Sequence[str] | None = None, - interrupt_after: All | Sequence[str] | None = None, - webhook: str | None = None, - on_completion: OnCompletionBehavior | None = None, - if_not_exists: IfNotExists | None = None, - after_seconds: int | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - ) -> Run: ... - - @overload - def create( - self, - thread_id: str, - assistant_id: str, - *, - input: Input | None = None, - 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, - checkpoint: Checkpoint | None = None, - checkpoint_id: str | None = None, - checkpoint_during: bool | None = None, - interrupt_before: All | Sequence[str] | None = None, - interrupt_after: All | Sequence[str] | None = None, - webhook: str | None = None, - multitask_strategy: MultitaskStrategy | None = None, - if_not_exists: IfNotExists | None = None, - after_seconds: int | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - ) -> Run: ... - - def create( - self, - thread_id: str | None, - assistant_id: str, - *, - input: Input | None = None, - 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, - checkpoint: Checkpoint | None = None, - checkpoint_id: str | None = None, - checkpoint_during: bool | None = None, # deprecated - interrupt_before: All | Sequence[str] | None = None, - interrupt_after: All | Sequence[str] | None = None, - webhook: str | None = None, - multitask_strategy: MultitaskStrategy | None = None, - if_not_exists: IfNotExists | None = None, - on_completion: OnCompletionBehavior | None = None, - after_seconds: int | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - durability: Durability | None = None, - ) -> Run: - """Create a background run. - - Args: - thread_id: the thread ID to assign to the thread. - If `None` will create a stateless run. - assistant_id: The assistant ID or graph name to stream from. - If using graph name, will default to first assistant created from that graph. - input: The input to the graph. - command: The command to execute. - stream_mode: The stream mode(s) to use. - stream_subgraphs: Whether to stream output from subgraphs. - stream_resumable: Whether the stream is considered resumable. - If true, the stream can be resumed and replayed in its entirety even after disconnection. - metadata: Metadata to assign to the run. - config: The configuration for the assistant. - context: Static context to add to the assistant. - !!! version-added "Added in version 0.6.0" - checkpoint: The checkpoint to resume from. - checkpoint_during: (deprecated) Whether to checkpoint during the run (or only at the end/interruption). - interrupt_before: Nodes to interrupt immediately before they get executed. - interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. - webhook: Webhook to call after LangGraph API call is done. - multitask_strategy: Multitask strategy to use. - Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. - on_completion: Whether to delete or keep the thread created for a stateless run. - Must be one of 'delete' or 'keep'. - if_not_exists: How to handle missing thread. Defaults to 'reject'. - Must be either 'reject' (raise error if missing), or 'create' (create new thread). - after_seconds: The number of seconds to wait before starting the run. - Use to schedule future runs. - headers: Optional custom headers to include with the request. - on_run_created: Optional callback to call when a run is created. - durability: The durability to use for the run. Values are "sync", "async", or "exit". - "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 - - Returns: - The created background `Run`. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - background_run = client.runs.create( - thread_id="my_thread_id", - assistant_id="my_assistant_id", - input={"messages": [{"role": "user", "content": "hello!"}]}, - metadata={"name":"my_run"}, - context={"model_name": "openai"}, - interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], - interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], - webhook="https://my.fake.webhook.com", - multitask_strategy="interrupt" - ) - print(background_run) - ``` - - ```shell - -------------------------------------------------------------------------------- - - { - 'run_id': 'my_run_id', - 'thread_id': 'my_thread_id', - 'assistant_id': 'my_assistant_id', - 'created_at': '2024-07-25T15:35:42.598503+00:00', - 'updated_at': '2024-07-25T15:35:42.598503+00:00', - 'metadata': {}, - 'status': 'pending', - 'kwargs': - { - 'input': - { - 'messages': [ - { - 'role': 'user', - 'content': 'how are you?' - } - ] - }, - 'config': - { - 'metadata': - { - 'created_by': 'system' - }, - 'configurable': - { - 'run_id': 'my_run_id', - 'user_id': None, - 'graph_id': 'agent', - 'thread_id': 'my_thread_id', - 'checkpoint_id': None, - 'assistant_id': 'my_assistant_id' - } - }, - 'context': - { - 'model_name': 'openai' - }, - 'webhook': "https://my.fake.webhook.com", - 'temporary': False, - 'stream_mode': ['values'], - 'feedback_keys': None, - 'interrupt_after': ["node_to_stop_after_1","node_to_stop_after_2"], - 'interrupt_before': ["node_to_stop_before_1","node_to_stop_before_2"] - }, - 'multitask_strategy': 'interrupt' - } - ``` - """ - if checkpoint_during is not None: - warnings.warn( - "`checkpoint_during` is deprecated and will be removed in a future version. Use `durability` instead.", - DeprecationWarning, - stacklevel=2, - ) - payload = { - "input": input, - "command": ( - {k: v for k, v in command.items() if v is not None} if command else None - ), - "stream_mode": stream_mode, - "stream_subgraphs": stream_subgraphs, - "stream_resumable": stream_resumable, - "config": config, - "context": context, - "metadata": metadata, - "assistant_id": assistant_id, - "interrupt_before": interrupt_before, - "interrupt_after": interrupt_after, - "webhook": webhook, - "checkpoint": checkpoint, - "checkpoint_id": checkpoint_id, - "checkpoint_during": checkpoint_during, - "multitask_strategy": multitask_strategy, - "if_not_exists": if_not_exists, - "on_completion": on_completion, - "after_seconds": after_seconds, - "durability": durability, - } - payload = {k: v for k, v in payload.items() if v is not None} - - def on_response(res: httpx.Response): - """Callback function to handle the response.""" - if on_run_created and (metadata := _get_run_metadata_from_response(res)): - on_run_created(metadata) - - return self.http.post( - f"/threads/{thread_id}/runs" if thread_id else "/runs", - json=payload, - params=params, - headers=headers, - on_response=on_response if on_run_created else None, - ) - - def create_batch( - self, - payloads: list[RunCreate], - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> list[Run]: - """Create a batch of stateless background runs.""" - - def filter_payload(payload: RunCreate): - return {k: v for k, v in payload.items() if v is not None} - - filtered = [filter_payload(payload) for payload in payloads] - return self.http.post( - "/runs/batch", json=filtered, headers=headers, params=params - ) - - @overload - def wait( - self, - thread_id: str, - assistant_id: str, - *, - input: Input | None = None, - command: Command | None = None, - metadata: Mapping[str, Any] | None = None, - config: Config | None = None, - context: Context | None = None, - checkpoint: Checkpoint | None = None, - checkpoint_id: str | None = None, - checkpoint_during: bool | None = None, - interrupt_before: All | Sequence[str] | None = None, - interrupt_after: All | Sequence[str] | None = None, - webhook: str | None = None, - on_disconnect: DisconnectMode | None = None, - multitask_strategy: MultitaskStrategy | None = None, - if_not_exists: IfNotExists | None = None, - after_seconds: int | None = None, - raise_error: bool = True, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - ) -> list[dict] | dict[str, Any]: ... - - @overload - def wait( - self, - thread_id: None, - assistant_id: str, - *, - input: Input | None = None, - command: Command | None = None, - 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, - webhook: str | None = None, - on_disconnect: DisconnectMode | None = None, - on_completion: OnCompletionBehavior | None = None, - if_not_exists: IfNotExists | None = None, - after_seconds: int | None = None, - raise_error: bool = True, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - ) -> list[dict] | dict[str, Any]: ... - - def wait( - self, - thread_id: str | None, - assistant_id: str, - *, - input: Input | None = None, - command: Command | None = None, - metadata: Mapping[str, Any] | None = None, - config: Config | None = None, - context: Context | None = None, - checkpoint_during: bool | None = None, # deprecated - checkpoint: Checkpoint | None = None, - checkpoint_id: str | None = None, - interrupt_before: All | Sequence[str] | None = None, - interrupt_after: All | Sequence[str] | None = None, - webhook: str | None = None, - on_disconnect: DisconnectMode | None = None, - on_completion: OnCompletionBehavior | None = None, - multitask_strategy: MultitaskStrategy | None = None, - if_not_exists: IfNotExists | None = None, - after_seconds: int | None = None, - raise_error: bool = True, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - on_run_created: Callable[[RunCreateMetadata], None] | None = None, - durability: Durability | None = None, - ) -> list[dict] | dict[str, Any]: - """Create a run, wait until it finishes and return the final state. - - Args: - thread_id: the thread ID to create the run on. - If `None` will create a stateless run. - assistant_id: The assistant ID or graph name to run. - If using graph name, will default to first assistant created from that graph. - input: The input to the graph. - command: The command to execute. - metadata: Metadata to assign to the run. - config: The configuration for the assistant. - context: Static context to add to the assistant. - !!! version-added "Added in version 0.6.0" - checkpoint: The checkpoint to resume from. - checkpoint_during: (deprecated) Whether to checkpoint during the run (or only at the end/interruption). - interrupt_before: Nodes to interrupt immediately before they get executed. - interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. - webhook: Webhook to call after LangGraph API call is done. - on_disconnect: The disconnect mode to use. - Must be one of 'cancel' or 'continue'. - on_completion: Whether to delete or keep the thread created for a stateless run. - Must be one of 'delete' or 'keep'. - multitask_strategy: Multitask strategy to use. - Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. - if_not_exists: How to handle missing thread. Defaults to 'reject'. - Must be either 'reject' (raise error if missing), or 'create' (create new thread). - after_seconds: The number of seconds to wait before starting the run. - Use to schedule future runs. - raise_error: Whether to raise an error if the run fails. - headers: Optional custom headers to include with the request. - on_run_created: Optional callback to call when a run is created. - durability: The durability to use for the run. Values are "sync", "async", or "exit". - "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 - - Returns: - The output of the `Run`. - - ???+ example "Example Usage" - - ```python - - final_state_of_run = client.runs.wait( - thread_id=None, - assistant_id="agent", - input={"messages": [{"role": "user", "content": "how are you?"}]}, - metadata={"name":"my_run"}, - context={"model_name": "anthropic"}, - interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], - interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], - webhook="https://my.fake.webhook.com", - multitask_strategy="interrupt" - ) - print(final_state_of_run) - ``` - - ```shell - - ------------------------------------------------------------------------------------------------------------------------------------------- - - { - 'messages': [ - { - 'content': 'how are you?', - 'additional_kwargs': {}, - 'response_metadata': {}, - 'type': 'human', - 'name': None, - 'id': 'f51a862c-62fe-4866-863b-b0863e8ad78a', - '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-bf1cd3c6-768f-4c16-b62d-ba6f17ad8b36', - 'example': False, - 'tool_calls': [], - 'invalid_tool_calls': [], - 'usage_metadata': None - } - ] - } - ``` - - """ - if checkpoint_during is not None: - warnings.warn( - "`checkpoint_during` is deprecated and will be removed in a future version. Use `durability` instead.", - DeprecationWarning, - stacklevel=2, - ) - payload = { - "input": input, - "command": ( - {k: v for k, v in command.items() if v is not None} if command else None - ), - "config": config, - "context": context, - "metadata": metadata, - "assistant_id": assistant_id, - "interrupt_before": interrupt_before, - "interrupt_after": interrupt_after, - "webhook": webhook, - "checkpoint": checkpoint, - "checkpoint_id": checkpoint_id, - "multitask_strategy": multitask_strategy, - "if_not_exists": if_not_exists, - "on_disconnect": on_disconnect, - "checkpoint_during": checkpoint_during, - "on_completion": on_completion, - "after_seconds": after_seconds, - "raise_error": raise_error, - "durability": durability, - } - - def on_response(res: httpx.Response): - """Callback function to handle the response.""" - if on_run_created and (metadata := _get_run_metadata_from_response(res)): - on_run_created(metadata) - - endpoint = ( - f"/threads/{thread_id}/runs/wait" if thread_id is not None else "/runs/wait" - ) - return self.http.request_reconnect( - endpoint, - "POST", - json={k: v for k, v in payload.items() if v is not None}, - params=params, - headers=headers, - on_response=on_response if on_run_created else None, - ) - - def list( - self, - thread_id: str, - *, - limit: int = 10, - offset: int = 0, - status: RunStatus | None = None, - select: list[RunSelectField] | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> list[Run]: - """List runs. - - Args: - thread_id: The thread ID to list runs for. - limit: The maximum number of results to return. - offset: The number of results to skip. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - The runs for the thread. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - client.runs.list( - thread_id="thread_id", - limit=5, - offset=5, - ) - ``` - - """ - query_params: dict[str, Any] = {"limit": limit, "offset": offset} - if status is not None: - query_params["status"] = status - if select: - query_params["select"] = select - if params: - query_params.update(params) - return self.http.get( - f"/threads/{thread_id}/runs", params=query_params, headers=headers - ) - - def get( - self, - thread_id: str, - run_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Run: - """Get a run. - - Args: - thread_id: The thread ID to get. - run_id: The run ID to get. - headers: Optional custom headers to include with the request. - - Returns: - `Run` object. - - ???+ example "Example Usage" - - ```python - - run = client.runs.get( - thread_id="thread_id_to_delete", - run_id="run_id_to_delete", - ) - ``` - """ - - return self.http.get( - f"/threads/{thread_id}/runs/{run_id}", headers=headers, params=params - ) - - def cancel( - self, - thread_id: str, - run_id: str, - *, - wait: bool = False, - action: CancelAction = "interrupt", - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> None: - """Get a run. - - Args: - thread_id: The thread ID to cancel. - run_id: The run ID to cancel. - wait: Whether to wait until run has completed. - action: Action to take when cancelling the run. Possible values - are `interrupt` or `rollback`. Default is `interrupt`. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - client.runs.cancel( - thread_id="thread_id_to_cancel", - run_id="run_id_to_cancel", - wait=True, - action="interrupt" - ) - ``` - - """ - query_params = { - "wait": 1 if wait else 0, - "action": action, - } - if params: - query_params.update(params) - if wait: - return self.http.request_reconnect( - f"/threads/{thread_id}/runs/{run_id}/cancel", - "POST", - json=None, - params=query_params, - headers=headers, - ) - return self.http.post( - f"/threads/{thread_id}/runs/{run_id}/cancel", - json=None, - params=query_params, - headers=headers, - ) - - def join( - self, - thread_id: str, - run_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> dict: - """Block until a run is done. Returns the final state of the thread. - - Args: - thread_id: The thread ID to join. - run_id: The run ID to join. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - client.runs.join( - thread_id="thread_id_to_join", - run_id="run_id_to_join" - ) - ``` - - """ - return self.http.request_reconnect( - f"/threads/{thread_id}/runs/{run_id}/join", - "GET", - headers=headers, - params=params, - ) - - def join_stream( - self, - thread_id: str, - run_id: str, - *, - cancel_on_disconnect: bool = False, - stream_mode: StreamMode | Sequence[StreamMode] | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - last_event_id: str | None = None, - ) -> Iterator[StreamPart]: - """Stream output from a run in real-time, until the run is done. - Output is not buffered, so any output produced before this call will - not be received here. - - Args: - thread_id: The thread ID to join. - run_id: The run ID to join. - stream_mode: The stream mode(s) to use. Must be a subset of the stream modes passed - when creating the run. Background runs default to having the union of all - stream modes. - cancel_on_disconnect: Whether to cancel the run when the stream is disconnected. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - last_event_id: The last event ID to use for the stream. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - client.runs.join_stream( - thread_id="thread_id_to_join", - run_id="run_id_to_join", - stream_mode=["values", "debug"] - ) - ``` - - """ - query_params = { - "stream_mode": stream_mode, - "cancel_on_disconnect": cancel_on_disconnect, - } - if params: - query_params.update(params) - return self.http.stream( - f"/threads/{thread_id}/runs/{run_id}/stream", - "GET", - params=query_params, - headers={ - **({"Last-Event-ID": last_event_id} if last_event_id else {}), - **(headers or {}), - } - or None, - ) - - def delete( - self, - thread_id: str, - run_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> None: - """Delete a run. - - Args: - thread_id: The thread ID to delete. - run_id: The run ID to delete. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:2024") - client.runs.delete( - thread_id="thread_id_to_delete", - run_id="run_id_to_delete" - ) - ``` - - """ - self.http.delete( - f"/threads/{thread_id}/runs/{run_id}", headers=headers, params=params - ) - - -class SyncCronClient: - """Synchronous client for managing cron jobs in LangGraph. - - This class provides methods to create and manage scheduled tasks (cron jobs) for automated graph executions. - - ???+ example "Example" - - ```python - client = get_sync_client(url="http://localhost:8123") - cron_job = client.crons.create_for_thread(thread_id="thread_123", assistant_id="asst_456", schedule="0 * * * *") - ``` - - !!! note "Feature Availability" - - The crons client functionality is not supported on all licenses. - Please check the relevant license documentation for the most up-to-date - details on feature availability. - """ - - def __init__(self, http_client: SyncHttpClient) -> None: - self.http = http_client - - def create_for_thread( - self, - thread_id: str, - assistant_id: str, - *, - schedule: str, - input: Input | None = None, - metadata: Mapping[str, Any] | None = None, - config: Config | None = None, - context: Context | None = None, - checkpoint_during: bool | None = None, - interrupt_before: All | list[str] | None = None, - interrupt_after: All | list[str] | None = None, - webhook: str | None = None, - multitask_strategy: str | None = None, - end_time: datetime | None = None, - enabled: bool | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Run: - """Create a cron job for a thread. - - Args: - thread_id: the thread ID to run the cron job on. - assistant_id: The assistant ID or graph name to use for the cron job. - If using graph name, will default to first assistant created from that graph. - schedule: The cron schedule to execute this job on. - Schedules are interpreted in UTC. - input: The input to the graph. - metadata: Metadata to assign to the cron job runs. - config: The configuration for the assistant. - context: Static context to add to the assistant. - !!! version-added "Added in version 0.6.0" - checkpoint_during: Whether to checkpoint during the run (or only at the end/interruption). - interrupt_before: Nodes to interrupt immediately before they get executed. - interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. - webhook: Webhook to call after LangGraph API call is done. - multitask_strategy: Multitask strategy to use. - Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. - end_time: The time to stop running the cron job. If not provided, the cron job will run indefinitely. - enabled: Whether the cron job is enabled. By default, it is considered enabled. - headers: Optional custom headers to include with the request. - - Returns: - The cron `Run`. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:8123") - cron_run = client.crons.create_for_thread( - thread_id="my-thread-id", - assistant_id="agent", - schedule="27 15 * * *", - input={"messages": [{"role": "user", "content": "hello!"}]}, - metadata={"name":"my_run"}, - context={"model_name": "openai"}, - interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], - interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], - webhook="https://my.fake.webhook.com", - multitask_strategy="interrupt", - enabled=True - ) - ``` - """ - payload = { - "schedule": schedule, - "input": input, - "config": config, - "metadata": metadata, - "context": context, - "assistant_id": assistant_id, - "interrupt_before": interrupt_before, - "interrupt_after": interrupt_after, - "checkpoint_during": checkpoint_during, - "webhook": webhook, - "multitask_strategy": multitask_strategy, - "end_time": end_time.isoformat() if end_time else None, - "enabled": enabled, - } - payload = {k: v for k, v in payload.items() if v is not None} - return self.http.post( - f"/threads/{thread_id}/runs/crons", - json=payload, - headers=headers, - params=params, - ) - - def create( - self, - assistant_id: str, - *, - schedule: str, - input: Input | None = None, - metadata: Mapping[str, Any] | None = None, - config: Config | None = None, - context: Context | None = None, - checkpoint_during: bool | None = None, - interrupt_before: All | list[str] | None = None, - interrupt_after: All | list[str] | None = None, - webhook: str | None = None, - on_run_completed: OnCompletionBehavior | None = None, - multitask_strategy: str | None = None, - end_time: datetime | None = None, - enabled: bool | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Run: - """Create a cron run. - - Args: - assistant_id: The assistant ID or graph name to use for the cron job. - If using graph name, will default to first assistant created from that graph. - schedule: The cron schedule to execute this job on. - Schedules are interpreted in UTC. - input: The input to the graph. - metadata: Metadata to assign to the cron job runs. - config: The configuration for the assistant. - context: Static context to add to the assistant. - !!! version-added "Added in version 0.6.0" - checkpoint_during: Whether to checkpoint during the run (or only at the end/interruption). - interrupt_before: Nodes to interrupt immediately before they get executed. - interrupt_after: Nodes to Nodes to interrupt immediately after they get executed. - webhook: Webhook to call after LangGraph API call is done. - on_run_completed: What to do with the thread after the run completes. - Must be one of 'delete' (default) or 'keep'. 'delete' removes the thread - after execution. 'keep' creates a new thread for each execution but does not - clean them up. Clients are responsible for cleaning up kept threads. - multitask_strategy: Multitask strategy to use. - Must be one of 'reject', 'interrupt', 'rollback', or 'enqueue'. - end_time: The time to stop running the cron job. If not provided, the cron job will run indefinitely. - enabled: Whether the cron job is enabled. By default, it is considered enabled. - headers: Optional custom headers to include with the request. - - Returns: - The cron `Run`. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:8123") - cron_run = client.crons.create( - assistant_id="agent", - schedule="27 15 * * *", - input={"messages": [{"role": "user", "content": "hello!"}]}, - metadata={"name":"my_run"}, - context={"model_name": "openai"}, - checkpoint_during=True, - interrupt_before=["node_to_stop_before_1","node_to_stop_before_2"], - interrupt_after=["node_to_stop_after_1","node_to_stop_after_2"], - webhook="https://my.fake.webhook.com", - multitask_strategy="interrupt", - enabled=True - ) - ``` - - """ - payload = { - "schedule": schedule, - "input": input, - "config": config, - "metadata": metadata, - "context": context, - "assistant_id": assistant_id, - "interrupt_before": interrupt_before, - "interrupt_after": interrupt_after, - "webhook": webhook, - "checkpoint_during": checkpoint_during, - "on_run_completed": on_run_completed, - "multitask_strategy": multitask_strategy, - "end_time": end_time.isoformat() if end_time else None, - "enabled": enabled, - } - payload = {k: v for k, v in payload.items() if v is not None} - return self.http.post( - "/runs/crons", json=payload, headers=headers, params=params - ) - - def delete( - self, - cron_id: str, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> None: - """Delete a cron. - - Args: - cron_id: The cron ID to delete. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:8123") - client.crons.delete( - cron_id="cron_to_delete" - ) - ``` - - """ - self.http.delete(f"/runs/crons/{cron_id}", headers=headers, params=params) - - def update( - self, - cron_id: str, - *, - schedule: str | None = None, - end_time: datetime | None = None, - input: Input | None = None, - metadata: Mapping[str, Any] | None = None, - config: Config | None = None, - context: Context | None = None, - webhook: str | None = None, - interrupt_before: All | list[str] | None = None, - interrupt_after: All | list[str] | None = None, - on_run_completed: OnCompletionBehavior | None = None, - enabled: bool | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Cron: - """Update a cron job by ID. - - Args: - cron_id: The cron ID to update. - schedule: The cron schedule to execute this job on. - Schedules are interpreted in UTC. - end_time: The end date to stop running the cron. - input: The input to the graph. - metadata: Metadata to assign to the cron job runs. - config: The configuration for the assistant. - context: Static context added to the assistant. - webhook: Webhook to call after LangGraph API call is done. - interrupt_before: Nodes to interrupt immediately before they get executed. - interrupt_after: Nodes to interrupt immediately after they get executed. - on_run_completed: What to do with the thread after the run completes. - Must be one of 'delete' or 'keep'. 'delete' removes the thread - after execution. 'keep' creates a new thread for each execution but does not - clean them up. - enabled: Enable or disable the cron job. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - The updated cron job. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:8123") - updated_cron = client.crons.update( - cron_id="1ef3cefa-4c09-6926-96d0-3dc97fd5e39b", - schedule="0 10 * * *", - enabled=False, - ) - ``` - - """ - payload = { - "schedule": schedule, - "end_time": end_time.isoformat() if end_time else None, - "input": input, - "metadata": metadata, - "config": config, - "context": context, - "webhook": webhook, - "interrupt_before": interrupt_before, - "interrupt_after": interrupt_after, - "on_run_completed": on_run_completed, - "enabled": enabled, - } - payload = {k: v for k, v in payload.items() if v is not None} - return self.http.patch( - f"/runs/crons/{cron_id}", - json=payload, - headers=headers, - params=params, - ) - - def search( - self, - *, - assistant_id: str | None = None, - thread_id: str | None = None, - enabled: bool | None = None, - limit: int = 10, - offset: int = 0, - sort_by: CronSortBy | None = None, - sort_order: SortOrder | None = None, - select: list[CronSelectField] | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> list[Cron]: - """Get a list of cron jobs. - - Args: - assistant_id: The assistant ID or graph name to search for. - thread_id: the thread ID to search for. - enabled: Whether the cron job is enabled. - limit: The maximum number of results to return. - offset: The number of results to skip. - headers: Optional custom headers to include with the request. - - Returns: - The list of cron jobs returned by the search, - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:8123") - cron_jobs = client.crons.search( - assistant_id="my_assistant_id", - thread_id="my_thread_id", - enabled=True, - limit=5, - offset=5, - ) - print(cron_jobs) - ``` - - ```shell - ---------------------------------------------------------- - - [ - { - 'cron_id': '1ef3cefa-4c09-6926-96d0-3dc97fd5e39b', - 'assistant_id': 'my_assistant_id', - 'thread_id': 'my_thread_id', - 'user_id': None, - 'payload': - { - 'input': {'start_time': ''}, - 'schedule': '4 * * * *', - 'assistant_id': 'my_assistant_id' - }, - 'schedule': '4 * * * *', - 'next_run_date': '2024-07-25T17:04:00+00:00', - 'end_time': None, - 'created_at': '2024-07-08T06:02:23.073257+00:00', - 'updated_at': '2024-07-08T06:02:23.073257+00:00' - } - ] - ``` - """ - payload = { - "assistant_id": assistant_id, - "thread_id": thread_id, - "enabled": enabled, - "limit": limit, - "offset": offset, - } - if sort_by: - payload["sort_by"] = sort_by - if sort_order: - payload["sort_order"] = sort_order - if select: - payload["select"] = select - payload = {k: v for k, v in payload.items() if v is not None} - return self.http.post( - "/runs/crons/search", json=payload, headers=headers, params=params - ) - - def count( - self, - *, - assistant_id: str | None = None, - thread_id: str | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> int: - """Count cron jobs matching filters. - - Args: - assistant_id: Assistant ID to filter by. - thread_id: Thread ID to filter by. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - int: Number of crons matching the criteria. - """ - payload: dict[str, Any] = {} - if assistant_id: - payload["assistant_id"] = assistant_id - if thread_id: - payload["thread_id"] = thread_id - return self.http.post( - "/runs/crons/count", json=payload, headers=headers, params=params - ) - - -class SyncStoreClient: - """A client for synchronous operations on a key-value store. - - Provides methods to interact with a remote key-value store, allowing - storage and retrieval of items within namespaced hierarchies. - - ???+ example "Example" - - ```python - client = get_sync_client(url="http://localhost:2024")) - client.store.put_item(["users", "profiles"], "user123", {"name": "Alice", "age": 30}) - ``` - """ - - def __init__(self, http: SyncHttpClient) -> None: - self.http = http - - def put_item( - self, - namespace: Sequence[str], - /, - key: str, - value: Mapping[str, Any], - index: Literal[False] | list[str] | None = None, - ttl: int | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> None: - """Store or update an item. - - Args: - namespace: A list of strings representing the namespace path. - key: The unique identifier for the item within the namespace. - value: A dictionary containing the item's data. - index: Controls search indexing - None (use defaults), False (disable), or list of field paths to index. - ttl: Optional time-to-live in minutes for the item, or None for no expiration. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:8123") - client.store.put_item( - ["documents", "user123"], - key="item456", - value={"title": "My Document", "content": "Hello World"} - ) - ``` - """ - for label in namespace: - if "." in label: - raise ValueError( - f"Invalid namespace label '{label}'. Namespace labels cannot contain periods ('.')." - ) - payload = { - "namespace": namespace, - "key": key, - "value": value, - "index": index, - "ttl": ttl, - } - self.http.put( - "/store/items", json=_provided_vals(payload), headers=headers, params=params - ) - - def get_item( - self, - namespace: Sequence[str], - /, - key: str, - *, - refresh_ttl: bool | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> Item: - """Retrieve a single item. - - Args: - key: The unique identifier for the item. - namespace: Optional list of strings representing the namespace path. - refresh_ttl: Whether to refresh the TTL on this read operation. If `None`, uses the store's default behavior. - headers: Optional custom headers to include with the request. - - Returns: - The retrieved item. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:8123") - item = client.store.get_item( - ["documents", "user123"], - key="item456", - ) - print(item) - ``` - - ```shell - ---------------------------------------------------------------- - - { - 'namespace': ['documents', 'user123'], - 'key': 'item456', - 'value': {'title': 'My Document', 'content': 'Hello World'}, - 'created_at': '2024-07-30T12:00:00Z', - 'updated_at': '2024-07-30T12:00:00Z' - } - ``` - """ - for label in namespace: - if "." in label: - raise ValueError( - f"Invalid namespace label '{label}'. Namespace labels cannot contain periods ('.')." - ) - - query_params = {"key": key, "namespace": ".".join(namespace)} - if refresh_ttl is not None: - query_params["refresh_ttl"] = refresh_ttl - if params: - query_params.update(params) - return self.http.get("/store/items", params=query_params, headers=headers) - - def delete_item( - self, - namespace: Sequence[str], - /, - key: str, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> None: - """Delete an item. - - Args: - key: The unique identifier for the item. - namespace: Optional list of strings representing the namespace path. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - `None` - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:8123") - client.store.delete_item( - ["documents", "user123"], - key="item456", - ) - ``` - """ - self.http.delete( - "/store/items", - json={"key": key, "namespace": namespace}, - headers=headers, - params=params, - ) - - def search_items( - self, - namespace_prefix: Sequence[str], - /, - filter: Mapping[str, Any] | None = None, - limit: int = 10, - offset: int = 0, - query: str | None = None, - refresh_ttl: bool | None = None, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> SearchItemsResponse: - """Search for items within a namespace prefix. - - Args: - namespace_prefix: List of strings representing the namespace prefix. - filter: Optional dictionary of key-value pairs to filter results. - limit: Maximum number of items to return (default is 10). - offset: Number of items to skip before returning results (default is 0). - query: Optional query for natural language search. - refresh_ttl: Whether to refresh the TTL on items returned by this search. If `None`, uses the store's default behavior. - headers: Optional custom headers to include with the request. - params: Optional query parameters to include with the request. - - Returns: - A list of items matching the search criteria. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:8123") - items = client.store.search_items( - ["documents"], - filter={"author": "John Doe"}, - limit=5, - offset=0 - ) - print(items) - ``` - ```shell - ---------------------------------------------------------------- - - { - "items": [ - { - "namespace": ["documents", "user123"], - "key": "item789", - "value": { - "title": "Another Document", - "author": "John Doe" - }, - "created_at": "2024-07-30T12:00:00Z", - "updated_at": "2024-07-30T12:00:00Z" - }, - # ... additional items ... - ] - } - ``` - """ - payload = { - "namespace_prefix": namespace_prefix, - "filter": filter, - "limit": limit, - "offset": offset, - "query": query, - "refresh_ttl": refresh_ttl, - } - return self.http.post( - "/store/items/search", - json=_provided_vals(payload), - headers=headers, - params=params, - ) - - def list_namespaces( - self, - prefix: list[str] | None = None, - suffix: list[str] | None = None, - max_depth: int | None = None, - limit: int = 100, - offset: int = 0, - *, - headers: Mapping[str, str] | None = None, - params: QueryParamTypes | None = None, - ) -> ListNamespaceResponse: - """List namespaces with optional match conditions. - - Args: - prefix: Optional list of strings representing the prefix to filter namespaces. - suffix: Optional list of strings representing the suffix to filter namespaces. - max_depth: Optional integer specifying the maximum depth of namespaces to return. - limit: Maximum number of namespaces to return (default is 100). - offset: Number of namespaces to skip before returning results (default is 0). - headers: Optional custom headers to include with the request. - - Returns: - A list of namespaces matching the criteria. - - ???+ example "Example Usage" - - ```python - client = get_sync_client(url="http://localhost:8123") - namespaces = client.store.list_namespaces( - prefix=["documents"], - max_depth=3, - limit=10, - offset=0 - ) - print(namespaces) - ``` - - ```shell - ---------------------------------------------------------------- - - [ - ["documents", "user123", "reports"], - ["documents", "user456", "invoices"], - ... - ] - ``` - """ - payload = { - "prefix": prefix, - "suffix": suffix, - "max_depth": max_depth, - "limit": limit, - "offset": offset, - } - return self.http.post( - "/store/namespaces", - json=_provided_vals(payload), - headers=headers, - params=params, - ) - - -def _provided_vals(d: Mapping[str, Any]) -> dict[str, Any]: - return {k: v for k, v in d.items() if v is not None} - - -_registered_transports: list[httpx.ASGITransport] = [] - - -# Do not move; this is used in the server. -def configure_loopback_transports(app: Any) -> None: - for transport in _registered_transports: - transport.app = app - - -@functools.lru_cache(maxsize=1) -def get_asgi_transport() -> type[httpx.ASGITransport]: - try: - from langgraph_api import asgi_transport # type: ignore[unresolved-import] - - return asgi_transport.ASGITransport - except ImportError: - # Older versions of the server - return httpx.ASGITransport - - -TimeoutTypes = ( - None - | float - | tuple[float | None, float | None] - | tuple[float | None, float | None, float | None, float | None] - | httpx.Timeout -) +from langgraph_sdk._async.assistants import AssistantsClient + +# Re-export factory functions +# Re-export async clients +from langgraph_sdk._async.client import LangGraphClient, get_client +from langgraph_sdk._async.cron import CronClient +from langgraph_sdk._async.http import HttpClient, _adecode_json, _aencode_json +from langgraph_sdk._async.runs import RunsClient +from langgraph_sdk._async.store import StoreClient +from langgraph_sdk._async.threads import ThreadsClient +from langgraph_sdk._shared.utilities import configure_loopback_transports +from langgraph_sdk._sync.assistants import SyncAssistantsClient + +# Re-export sync clients +from langgraph_sdk._sync.client import SyncLangGraphClient, get_sync_client +from langgraph_sdk._sync.cron import SyncCronClient +from langgraph_sdk._sync.http import SyncHttpClient, _decode_json, _encode_json +from langgraph_sdk._sync.runs import SyncRunsClient +from langgraph_sdk._sync.store import SyncStoreClient +from langgraph_sdk._sync.threads import SyncThreadsClient + +__all__ = [ + "AssistantsClient", + "CronClient", + "HttpClient", + "LangGraphClient", + "RunsClient", + "StoreClient", + "SyncAssistantsClient", + "SyncCronClient", + "SyncHttpClient", + "SyncLangGraphClient", + "SyncRunsClient", + "SyncStoreClient", + "SyncThreadsClient", + "ThreadsClient", + "_adecode_json", + "_aencode_json", + "_decode_json", + "_encode_json", + "configure_loopback_transports", + "get_client", + "get_sync_client", +] diff --git a/libs/sdk-py/tests/test_client_exports.py b/libs/sdk-py/tests/test_client_exports.py new file mode 100644 index 000000000..ac45d5a0a --- /dev/null +++ b/libs/sdk-py/tests/test_client_exports.py @@ -0,0 +1,91 @@ +"""Test that all expected symbols are exported from langgraph_sdk.client. + +This test ensures backwards compatibility during refactoring. +""" + +import httpx + +from langgraph_sdk import get_client as public_get_client +from langgraph_sdk import get_sync_client as public_get_sync_client +from langgraph_sdk.client import ( + AssistantsClient, + CronClient, + HttpClient, + LangGraphClient, + RunsClient, + StoreClient, + SyncAssistantsClient, + SyncCronClient, + SyncHttpClient, + SyncLangGraphClient, + SyncRunsClient, + SyncStoreClient, + SyncThreadsClient, + ThreadsClient, + _adecode_json, + _aencode_json, + _decode_json, + _encode_json, + configure_loopback_transports, + get_client, + get_sync_client, +) + + +def test_client_exports(): + """Verify all expected symbols can be imported from langgraph_sdk.client.""" + # Factory functions (public API) + assert callable(get_client) + assert callable(get_sync_client) + + # Top-level client classes + assert LangGraphClient is not None + assert SyncLangGraphClient is not None + + # HTTP client classes + assert HttpClient is not None + assert SyncHttpClient is not None + + # Resource client classes - Async + assert AssistantsClient is not None + assert ThreadsClient is not None + assert RunsClient is not None + assert CronClient is not None + assert StoreClient is not None + + # Resource client classes - Sync + assert SyncAssistantsClient is not None + assert SyncThreadsClient is not None + assert SyncRunsClient is not None + assert SyncCronClient is not None + assert SyncStoreClient is not None + + # Internal utilities (used by tests) + assert callable(_aencode_json) + assert callable(_adecode_json) + + # Sync JSON utilities (might be used internally) + assert callable(_encode_json) + assert callable(_decode_json) + + # Loopback transport configuration (used by langgraph-api) + assert callable(configure_loopback_transports) + + +def test_public_api_exports(): + """Verify public API exports from langgraph_sdk package.""" + assert callable(public_get_client) + assert callable(public_get_sync_client) + + +def test_client_instantiation(): + """Verify that we can instantiate clients.""" + # Test async client instantiation + async_http = httpx.AsyncClient(base_url="http://test.example.com") + async_client = HttpClient(async_http) + assert async_client is not None + + # Test sync client instantiation + sync_http = httpx.Client(base_url="http://test.example.com") + sync_client = SyncHttpClient(sync_http) + assert sync_client is not None From eac6abb8eef1784c7711586be3b09fbe26d34969 Mon Sep 17 00:00:00 2001 From: William FH <13333726+hinthornw@users.noreply.github.com> Date: Sat, 14 Feb 2026 10:02:07 -0800 Subject: [PATCH 06/41] chore: update to add prune method (#6804) --- .../sdk-py/langgraph_sdk/_async/assistants.py | 13 +++- libs/sdk-py/langgraph_sdk/_async/runs.py | 60 +++++++++++++++++++ libs/sdk-py/langgraph_sdk/_async/threads.py | 55 ++++++++++++++++- libs/sdk-py/langgraph_sdk/_sync/assistants.py | 15 ++++- libs/sdk-py/langgraph_sdk/_sync/runs.py | 60 +++++++++++++++++++ libs/sdk-py/langgraph_sdk/_sync/threads.py | 58 +++++++++++++++++- libs/sdk-py/langgraph_sdk/schema.py | 23 ++++++- 7 files changed, 277 insertions(+), 7 deletions(-) diff --git a/libs/sdk-py/langgraph_sdk/_async/assistants.py b/libs/sdk-py/langgraph_sdk/_async/assistants.py index 447535252..68a8de891 100644 --- a/libs/sdk-py/langgraph_sdk/_async/assistants.py +++ b/libs/sdk-py/langgraph_sdk/_async/assistants.py @@ -446,6 +446,7 @@ class AssistantsClient: self, assistant_id: str, *, + delete_threads: bool = False, headers: Mapping[str, str] | None = None, params: QueryParamTypes | None = None, ) -> None: @@ -453,6 +454,9 @@ class AssistantsClient: Args: assistant_id: The assistant ID to delete. + delete_threads: If true, delete all threads with `metadata.assistant_id` + matching this assistant, along with runs and checkpoints belonging to + those threads. headers: Optional custom headers to include with the request. params: Optional query parameters to include with the request. @@ -469,8 +473,15 @@ class AssistantsClient: ``` """ + query_params: dict[str, Any] = {} + if delete_threads: + query_params["delete_threads"] = True + if params: + query_params.update(params) await self.http.delete( - f"/assistants/{assistant_id}", headers=headers, params=params + f"/assistants/{assistant_id}", + headers=headers, + params=query_params or None, ) @overload diff --git a/libs/sdk-py/langgraph_sdk/_async/runs.py b/libs/sdk-py/langgraph_sdk/_async/runs.py index 1b02c2555..a6a5663bf 100644 --- a/libs/sdk-py/langgraph_sdk/_async/runs.py +++ b/libs/sdk-py/langgraph_sdk/_async/runs.py @@ -12,6 +12,7 @@ from langgraph_sdk._async.http import HttpClient from langgraph_sdk._shared.utilities import _get_run_metadata_from_response from langgraph_sdk.schema import ( All, + BulkCancelRunsStatus, CancelAction, Checkpoint, Command, @@ -886,6 +887,65 @@ class RunsClient: headers=headers, ) + async def cancel_many( + self, + *, + thread_id: str | None = None, + run_ids: Sequence[str] | None = None, + status: BulkCancelRunsStatus | None = None, + action: CancelAction = "interrupt", + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Cancel one or more runs. + + Can cancel runs by thread ID and run IDs, or by status filter. + + Args: + thread_id: The ID of the thread containing runs to cancel. + run_ids: List of run IDs to cancel. + status: Filter runs by status to cancel. Must be one of + `"pending"`, `"running"`, or `"all"`. + action: Action to take when cancelling the run. Possible values + are `"interrupt"` or `"rollback"`. Default is `"interrupt"`. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + # Cancel all pending runs + await client.runs.cancel_many(status="pending") + # Cancel specific runs on a thread + await client.runs.cancel_many( + thread_id="my_thread_id", + run_ids=["run_1", "run_2"], + action="rollback", + ) + ``` + + """ + payload: dict[str, Any] = {} + if thread_id: + payload["thread_id"] = thread_id + if run_ids: + payload["run_ids"] = run_ids + if status: + payload["status"] = status + query_params: dict[str, Any] = {"action": action} + if params: + query_params.update(params) + await self.http.post( + "/runs/cancel", + json=payload, + headers=headers, + params=query_params, + ) + async def join( self, thread_id: str, diff --git a/libs/sdk-py/langgraph_sdk/_async/threads.py b/libs/sdk-py/langgraph_sdk/_async/threads.py index d7081cd83..4d3126bfb 100644 --- a/libs/sdk-py/langgraph_sdk/_async/threads.py +++ b/libs/sdk-py/langgraph_sdk/_async/threads.py @@ -10,6 +10,7 @@ from langgraph_sdk.schema import ( Checkpoint, Json, OnConflictBehavior, + PruneStrategy, QueryParamTypes, SortOrder, StreamPart, @@ -45,6 +46,7 @@ class ThreadsClient: self, thread_id: str, *, + include: Sequence[str] | None = None, headers: Mapping[str, str] | None = None, params: QueryParamTypes | None = None, ) -> Thread: @@ -52,6 +54,8 @@ class ThreadsClient: Args: thread_id: The ID of the thread to get. + include: Additional fields to include in the response. + Supported values: `"ttl"`. headers: Optional custom headers to include with the request. params: Optional query parameters to include with the request. @@ -80,9 +84,15 @@ class ThreadsClient: ``` """ - + query_params: dict[str, Any] = {} + if include: + query_params["include"] = ",".join(include) + if params: + query_params.update(params) return await self.http.get( - f"/threads/{thread_id}", headers=headers, params=params + f"/threads/{thread_id}", + headers=headers, + params=query_params or None, ) async def create( @@ -372,6 +382,47 @@ class ThreadsClient: f"/threads/{thread_id}/copy", json=None, headers=headers, params=params ) + async def prune( + self, + thread_ids: Sequence[str], + *, + strategy: PruneStrategy = "delete", + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> dict[str, Any]: + """Prune threads by ID. + + Args: + thread_ids: List of thread IDs to prune. + strategy: The prune strategy. `"delete"` removes threads entirely. + `"keep_latest"` prunes old checkpoints but keeps threads and their + latest state. Defaults to `"delete"`. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + A dict containing `pruned_count` (number of threads pruned). + + ???+ example "Example Usage" + + ```python + client = get_client(url="http://localhost:2024") + result = await client.threads.prune( + thread_ids=["thread_1", "thread_2"], + ) + print(result) # {'pruned_count': 2} + ``` + + """ + payload: dict[str, Any] = { + "thread_ids": thread_ids, + } + if strategy != "delete": + payload["strategy"] = strategy + return await self.http.post( + "/threads/prune", json=payload, headers=headers, params=params + ) + async def get_state( self, thread_id: str, diff --git a/libs/sdk-py/langgraph_sdk/_sync/assistants.py b/libs/sdk-py/langgraph_sdk/_sync/assistants.py index 0f5dec393..995f7607a 100644 --- a/libs/sdk-py/langgraph_sdk/_sync/assistants.py +++ b/libs/sdk-py/langgraph_sdk/_sync/assistants.py @@ -448,6 +448,7 @@ class SyncAssistantsClient: self, assistant_id: str, *, + delete_threads: bool = False, headers: Mapping[str, str] | None = None, params: QueryParamTypes | None = None, ) -> None: @@ -455,6 +456,9 @@ class SyncAssistantsClient: Args: assistant_id: The assistant ID to delete. + delete_threads: If true, delete all threads with `metadata.assistant_id` + matching this assistant, along with runs and checkpoints belonging to + those threads. headers: Optional custom headers to include with the request. params: Optional query parameters to include with the request. @@ -471,7 +475,16 @@ class SyncAssistantsClient: ``` """ - self.http.delete(f"/assistants/{assistant_id}", headers=headers, params=params) + query_params: dict[str, Any] = {} + if delete_threads: + query_params["delete_threads"] = True + if params: + query_params.update(params) + self.http.delete( + f"/assistants/{assistant_id}", + headers=headers, + params=query_params or None, + ) @overload def search( diff --git a/libs/sdk-py/langgraph_sdk/_sync/runs.py b/libs/sdk-py/langgraph_sdk/_sync/runs.py index ab6e1943f..7a020fb78 100644 --- a/libs/sdk-py/langgraph_sdk/_sync/runs.py +++ b/libs/sdk-py/langgraph_sdk/_sync/runs.py @@ -12,6 +12,7 @@ from langgraph_sdk._shared.utilities import _get_run_metadata_from_response from langgraph_sdk._sync.http import SyncHttpClient from langgraph_sdk.schema import ( All, + BulkCancelRunsStatus, CancelAction, Checkpoint, Command, @@ -869,6 +870,65 @@ class SyncRunsClient: headers=headers, ) + def cancel_many( + self, + *, + thread_id: str | None = None, + run_ids: Sequence[str] | None = None, + status: BulkCancelRunsStatus | None = None, + action: CancelAction = "interrupt", + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> None: + """Cancel one or more runs. + + Can cancel runs by thread ID and run IDs, or by status filter. + + Args: + thread_id: The ID of the thread containing runs to cancel. + run_ids: List of run IDs to cancel. + status: Filter runs by status to cancel. Must be one of + `"pending"`, `"running"`, or `"all"`. + action: Action to take when cancelling the run. Possible values + are `"interrupt"` or `"rollback"`. Default is `"interrupt"`. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + `None` + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + # Cancel all pending runs + client.runs.cancel_many(status="pending") + # Cancel specific runs on a thread + client.runs.cancel_many( + thread_id="my_thread_id", + run_ids=["run_1", "run_2"], + action="rollback", + ) + ``` + + """ + payload: dict[str, Any] = {} + if thread_id: + payload["thread_id"] = thread_id + if run_ids: + payload["run_ids"] = run_ids + if status: + payload["status"] = status + query_params: dict[str, Any] = {"action": action} + if params: + query_params.update(params) + self.http.post( + "/runs/cancel", + json=payload, + headers=headers, + params=query_params, + ) + def join( self, thread_id: str, diff --git a/libs/sdk-py/langgraph_sdk/_sync/threads.py b/libs/sdk-py/langgraph_sdk/_sync/threads.py index 1086da193..c5fb41498 100644 --- a/libs/sdk-py/langgraph_sdk/_sync/threads.py +++ b/libs/sdk-py/langgraph_sdk/_sync/threads.py @@ -10,6 +10,7 @@ from langgraph_sdk.schema import ( Checkpoint, Json, OnConflictBehavior, + PruneStrategy, QueryParamTypes, SortOrder, StreamPart, @@ -44,6 +45,7 @@ class SyncThreadsClient: self, thread_id: str, *, + include: Sequence[str] | None = None, headers: Mapping[str, str] | None = None, params: QueryParamTypes | None = None, ) -> Thread: @@ -51,7 +53,10 @@ class SyncThreadsClient: Args: thread_id: The ID of the thread to get. + include: Additional fields to include in the response. + Supported values: `"ttl"`. headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. Returns: `Thread` object. @@ -77,8 +82,16 @@ class SyncThreadsClient: ``` """ - - return self.http.get(f"/threads/{thread_id}", headers=headers, params=params) + query_params: dict[str, Any] = {} + if include: + query_params["include"] = ",".join(include) + if params: + query_params.update(params) + return self.http.get( + f"/threads/{thread_id}", + headers=headers, + params=query_params or None, + ) def create( self, @@ -357,6 +370,47 @@ class SyncThreadsClient: f"/threads/{thread_id}/copy", json=None, headers=headers, params=params ) + def prune( + self, + thread_ids: Sequence[str], + *, + strategy: PruneStrategy = "delete", + headers: Mapping[str, str] | None = None, + params: QueryParamTypes | None = None, + ) -> dict[str, Any]: + """Prune threads by ID. + + Args: + thread_ids: List of thread IDs to prune. + strategy: The prune strategy. `"delete"` removes threads entirely. + `"keep_latest"` prunes old checkpoints but keeps threads and their + latest state. Defaults to `"delete"`. + headers: Optional custom headers to include with the request. + params: Optional query parameters to include with the request. + + Returns: + A dict containing `pruned_count` (number of threads pruned). + + ???+ example "Example Usage" + + ```python + client = get_sync_client(url="http://localhost:2024") + result = client.threads.prune( + thread_ids=["thread_1", "thread_2"], + ) + print(result) # {'pruned_count': 2} + ``` + + """ + payload: dict[str, Any] = { + "thread_ids": thread_ids, + } + if strategy != "delete": + payload["strategy"] = strategy + return self.http.post( + "/threads/prune", json=payload, headers=headers, params=params + ) + def get_state( self, thread_id: str, diff --git a/libs/sdk-py/langgraph_sdk/schema.py b/libs/sdk-py/langgraph_sdk/schema.py index 1578a949e..323302dc8 100644 --- a/libs/sdk-py/langgraph_sdk/schema.py +++ b/libs/sdk-py/langgraph_sdk/schema.py @@ -117,6 +117,13 @@ Specifies behavior if the thread doesn't exist: - "reject": Reject the operation if the thread doesn't exist. """ +PruneStrategy = Literal["delete", "keep_latest"] +""" +Strategy for pruning threads: +- "delete": Remove threads entirely. +- "keep_latest": Prune old checkpoints but keep threads and their latest state. +""" + CancelAction = Literal["interrupt", "rollback"] """ Action to take when cancelling the run. @@ -124,6 +131,14 @@ Action to take when cancelling the run. - "rollback": Cancel the run. Then delete the run and associated checkpoints. """ +BulkCancelRunsStatus = Literal["pending", "running", "all"] +""" +Filter runs by status when bulk-cancelling: +- "pending": Cancel only pending runs. +- "running": Cancel only running runs. +- "all": Cancel all runs regardless of status. +""" + AssistantSortBy = Literal[ "assistant_id", "graph_id", "name", "created_at", "updated_at" ] @@ -137,7 +152,13 @@ The field to sort by. """ CronSortBy = Literal[ - "cron_id", "assistant_id", "thread_id", "created_at", "updated_at", "next_run_date" + "cron_id", + "assistant_id", + "thread_id", + "created_at", + "updated_at", + "next_run_date", + "end_time", ] """ The field to sort by. From 34769f31bcf5449e70e516740d29a13eb3918096 Mon Sep 17 00:00:00 2001 From: John Kennedy <65985482+jkennedyvz@users.noreply.github.com> Date: Sat, 14 Feb 2026 11:36:12 -0800 Subject: [PATCH 07/41] chore: update dependabot.yml to comply with posture checks (#6780) - Add schedule.day: monday to all entries - Add groups configuration to prevent noisy per-dependency PRs - Split pip directories into individual entries per Dependabot v2 spec - Add npm ecosystem entries for js-examples and js-monorepo-example subdirectories - Specify package-manager: uv for all Python entries (repo uses uv.lock) Thank you for contributing to LangGraph! Follow these steps to mark your pull request as ready for review. **If any of these steps are not completed, your PR will not be considered for review.** - [x] **PR title**: Follows the format: {TYPE}({SCOPE}): {DESCRIPTION} - Examples: - feat(core): add multi-tenant support - fix(cli): resolve flag parsing error - docs(openai): update API usage examples - Allowed `{TYPE}` values: - feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert, release - Allowed `{SCOPE}` values (optional): - langgraph, docs, cli, checkpoint, checkpoint-postgres, checkpoint-sqlite, prebuilt, scheduler-kafka, sdk-py - Once you've written the title, please delete this checklist item; do not include it in the PR. - [x] **PR message**: ***Delete this entire checklist*** and replace with - **Description:** a description of the change. Include a [closing keyword](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) if applicable. - **Issue:** the issue # it fixes, if applicable - **Dependencies:** any dependencies required for this change - **Twitter handle:** if your PR gets announced, and you'd like a mention, we'll gladly shout you out! - [x] **Add tests and docs**: If you're adding a new integration, you must include: 1. A test for the integration, preferably unit tests that do not rely on network access, 2. An example notebook showing its use. It lives in `docs/docs/integrations` directory. - [x] **Lint and test**: Run `make format`, `make lint` and `make test` from the root of the package(s) you've modified. We will not consider a PR unless these three are passing in CI. See [contribution guidelines](https://docs.langchain.com/oss/python/contributing/overview) for more. Additional guidelines: - Make sure optional dependencies are imported within a function. - Please do not add dependencies to `pyproject.toml` files (even optional ones) unless they are **required** for unit tests. - Most PRs should not touch more than one package. - Changes should be backwards compatible. --- .github/dependabot.yml | 106 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 8 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 84770db13..5467fb922 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,15 +4,105 @@ updates: directory: "/" schedule: interval: "weekly" + day: "monday" + groups: + all-dependencies: + patterns: + - "*" - package-ecosystem: "pip" - directories: - - "libs/checkpoint" - - "libs/checkpoint-postgres" - - "libs/checkpoint-sqlite" - - "libs/cli" - - "libs/langgraph" - - "libs/prebuilt" - - "libs/sdk-py" + directory: "/libs/checkpoint" schedule: interval: "weekly" + day: "monday" + groups: + all-dependencies: + patterns: + - "*" + package-manager: "uv" + + - package-ecosystem: "pip" + directory: "/libs/checkpoint-postgres" + schedule: + interval: "weekly" + day: "monday" + groups: + all-dependencies: + patterns: + - "*" + package-manager: "uv" + + - package-ecosystem: "pip" + directory: "/libs/checkpoint-sqlite" + schedule: + interval: "weekly" + day: "monday" + groups: + all-dependencies: + patterns: + - "*" + package-manager: "uv" + + - package-ecosystem: "pip" + directory: "/libs/cli" + schedule: + interval: "weekly" + day: "monday" + groups: + all-dependencies: + patterns: + - "*" + package-manager: "uv" + + - package-ecosystem: "pip" + directory: "/libs/langgraph" + schedule: + interval: "weekly" + day: "monday" + groups: + all-dependencies: + patterns: + - "*" + package-manager: "uv" + + - package-ecosystem: "pip" + directory: "/libs/prebuilt" + schedule: + interval: "weekly" + day: "monday" + groups: + all-dependencies: + patterns: + - "*" + package-manager: "uv" + + - package-ecosystem: "pip" + directory: "/libs/sdk-py" + schedule: + interval: "weekly" + day: "monday" + groups: + all-dependencies: + patterns: + - "*" + package-manager: "uv" + + - package-ecosystem: "npm" + directory: "/libs/cli/js-examples" + schedule: + interval: "weekly" + day: "monday" + groups: + all-dependencies: + patterns: + - "*" + + - package-ecosystem: "npm" + directory: "/libs/cli/js-monorepo-example" + schedule: + interval: "weekly" + day: "monday" + groups: + all-dependencies: + patterns: + - "*" From fe4daa1c7c453fe124e68096a9458ebdf6d4a479 Mon Sep 17 00:00:00 2001 From: William FH <13333726+hinthornw@users.noreply.github.com> Date: Sat, 14 Feb 2026 11:41:27 -0800 Subject: [PATCH 08/41] release(sdk-py): 0.3.6 (#6805) --- libs/sdk-py/langgraph_sdk/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/sdk-py/langgraph_sdk/__init__.py b/libs/sdk-py/langgraph_sdk/__init__.py index c635f7961..372c05530 100644 --- a/libs/sdk-py/langgraph_sdk/__init__.py +++ b/libs/sdk-py/langgraph_sdk/__init__.py @@ -3,6 +3,6 @@ from langgraph_sdk.client import get_client, get_sync_client from langgraph_sdk.encryption import Encryption from langgraph_sdk.encryption.types import EncryptionContext -__version__ = "0.3.5" +__version__ = "0.3.6" __all__ = ["Auth", "Encryption", "EncryptionContext", "get_client", "get_sync_client"] From 7216504ce2ecb56f62ebb08ac787d11b7491de5b Mon Sep 17 00:00:00 2001 From: William FH <13333726+hinthornw@users.noreply.github.com> Date: Sat, 14 Feb 2026 11:44:02 -0800 Subject: [PATCH 09/41] fix: dependabot (#6806) --- .github/dependabot.yml | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5467fb922..b6fe84a1a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -10,7 +10,7 @@ updates: patterns: - "*" - - package-ecosystem: "pip" + - package-ecosystem: "uv" directory: "/libs/checkpoint" schedule: interval: "weekly" @@ -19,9 +19,8 @@ updates: all-dependencies: patterns: - "*" - package-manager: "uv" - - package-ecosystem: "pip" + - package-ecosystem: "uv" directory: "/libs/checkpoint-postgres" schedule: interval: "weekly" @@ -30,9 +29,8 @@ updates: all-dependencies: patterns: - "*" - package-manager: "uv" - - package-ecosystem: "pip" + - package-ecosystem: "uv" directory: "/libs/checkpoint-sqlite" schedule: interval: "weekly" @@ -41,9 +39,8 @@ updates: all-dependencies: patterns: - "*" - package-manager: "uv" - - package-ecosystem: "pip" + - package-ecosystem: "uv" directory: "/libs/cli" schedule: interval: "weekly" @@ -52,9 +49,8 @@ updates: all-dependencies: patterns: - "*" - package-manager: "uv" - - package-ecosystem: "pip" + - package-ecosystem: "uv" directory: "/libs/langgraph" schedule: interval: "weekly" @@ -63,9 +59,8 @@ updates: all-dependencies: patterns: - "*" - package-manager: "uv" - - package-ecosystem: "pip" + - package-ecosystem: "uv" directory: "/libs/prebuilt" schedule: interval: "weekly" @@ -74,9 +69,8 @@ updates: all-dependencies: patterns: - "*" - package-manager: "uv" - - package-ecosystem: "pip" + - package-ecosystem: "uv" directory: "/libs/sdk-py" schedule: interval: "weekly" @@ -85,7 +79,6 @@ updates: all-dependencies: patterns: - "*" - package-manager: "uv" - package-ecosystem: "npm" directory: "/libs/cli/js-examples" From 52bbd346735c78ac7b36999d6ea0a4a15e115f29 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 01:01:50 -0800 Subject: [PATCH 10/41] chore(deps): bump the all-dependencies group in /libs/checkpoint-postgres with 2 updates (#6808) Bumps the all-dependencies group in /libs/checkpoint-postgres with 2 updates: [orjson](https://github.com/ijl/orjson) and [ruff](https://github.com/astral-sh/ruff). Updates `orjson` from 3.11.5 to 3.11.7
Release notes

Sourced from orjson's releases.

3.11.7

Changed

  • Use a faster library to serialize float. Users with byte-exact regression tests should note positive exponents are now written using a +, e.g., 1.2e+30 instead of 1.2e30. Both formats are spec-compliant.
  • ABI compatibility with CPython 3.15 alpha 5 free-threading.

3.11.6

Changed

  • orjson now includes code licensed under the Mozilla Public License 2.0 (MPL-2.0).
  • Drop support for Python 3.9.
  • ABI compatibility with CPython 3.15 alpha 5.
  • Build now depends on Rust 1.89 or later instead of 1.85.

Fixed

  • Fix sporadic crash serializing deeply nested list of dict.
Changelog

Sourced from orjson's changelog.

3.11.7 - 2026-02-02

Changed

  • Use a faster library to serialize float. Users with byte-exact regression tests should note positive exponents are now written using a +, e.g., 1.2e+30 instead of 1.2e30. Both formats are spec-compliant.
  • ABI compatibility with CPython 3.15 alpha 5 free-threading.

3.11.6 - 2026-01-29

Changed

  • orjson now includes code licensed under the Mozilla Public License 2.0 (MPL-2.0).
  • Drop support for Python 3.9.
  • ABI compatibility with CPython 3.15 alpha 5.
  • Build now depends on Rust 1.89 or later instead of 1.85.

Fixed

  • Fix sporadic crash serializing deeply nested list of dict.
Commits

Updates `ruff` from 0.14.13 to 0.15.1
Release notes

Sourced from ruff's releases.

0.15.1

Release Notes

Released on 2026-02-12.

Preview features

  • [airflow] Add ruff rules to catch deprecated Airflow imports for Airflow 3.1 (AIR321) (#22376)
  • [airflow] Third positional parameter not named ti_key should be flagged for BaseOperatorLink.get_link (AIR303) (#22828)
  • [flake8-gettext] Fix false negatives for plural argument of ngettext (INT001, INT002, INT003) (#21078)
  • [pyflakes] Fix infinite loop in preview fix for unused-import (F401) (#23038)
  • [pygrep-hooks] Detect non-existent mock methods in standalone expressions (PGH005) (#22830)
  • [pylint] Allow dunder submodules and improve diagnostic range (PLC2701) (#22804)
  • [pyupgrade] Improve diagnostic range for tuples (UP024) (#23013)
  • [refurb] Check subscripts in tuple do not use lambda parameters in reimplemented-operator (FURB118) (#23079)
  • [ruff] Detect mutable defaults in field calls (RUF008) (#23046)
  • [ruff] Ignore std cmath.inf (RUF069) (#23120)
  • [ruff] New rule float-equality-comparison (RUF069) (#20585)
  • Don't format unlabeled Markdown code blocks (#23106)
  • Markdown formatting support in LSP (#23063)
  • Support Quarto Markdown language markers (#22947)
  • Support formatting pycon Markdown code blocks (#23112)
  • Use extension mapping to select Markdown code block language (#22934)

Bug fixes

  • Avoid false positive for undefined variables in FAST001 (#23224)
  • Avoid introducing syntax errors for FAST003 autofix (#23227)
  • Avoid suggesting InitVar for __post_init__ that references PEP 695 type parameters (#23226)
  • Deduplicate type variables in generic functions (#23225)
  • Fix exception handler parenthesis removal for Python 3.14+ (#23126)
  • Fix f-string middle panic when parsing t-strings (#23232)
  • Wrap RUF020 target for multiline fixes (#23210)
  • Wrap UP007 target for multiline fixes (#23208)
  • Fix missing diagnostics for last range suppression in file (#23242)
  • [pyupgrade] Fix syntax error on string with newline escape and comment (UP037) (#22968)

Rule changes

  • Use ruff instead of Ruff as the program name in GitHub output format (#23240)
  • [PT006] Fix syntax error when unpacking nested tuples in parametrize fixes (#22441) (#22464)
  • [airflow] Catch deprecated attribute access from context key for Airflow 3.0 (AIR301) (#22850)
  • [airflow] Capture deprecated arguments and a decorator (AIR301) (#23170)
  • [flake8-boolean-trap] Add multiprocessing.Value to excluded functions for FBT003 (#23010)
  • [flake8-bugbear] Add a secondary annotation showing the previous occurrence (B033) (#22634)
  • [flake8-type-checking] Add sub-diagnostic showing the runtime use of an annotation (TC004) (#23091)
  • [isort] Support configurable import section heading comments (#23151)
  • [ruff] Improve the diagnostic for RUF012 (#23202)

Formatter

... (truncated)

Changelog

Sourced from ruff's changelog.

0.15.1

Released on 2026-02-12.

Preview features

  • [airflow] Add ruff rules to catch deprecated Airflow imports for Airflow 3.1 (AIR321) (#22376)
  • [airflow] Third positional parameter not named ti_key should be flagged for BaseOperatorLink.get_link (AIR303) (#22828)
  • [flake8-gettext] Fix false negatives for plural argument of ngettext (INT001, INT002, INT003) (#21078)
  • [pyflakes] Fix infinite loop in preview fix for unused-import (F401) (#23038)
  • [pygrep-hooks] Detect non-existent mock methods in standalone expressions (PGH005) (#22830)
  • [pylint] Allow dunder submodules and improve diagnostic range (PLC2701) (#22804)
  • [pyupgrade] Improve diagnostic range for tuples (UP024) (#23013)
  • [refurb] Check subscripts in tuple do not use lambda parameters in reimplemented-operator (FURB118) (#23079)
  • [ruff] Detect mutable defaults in field calls (RUF008) (#23046)
  • [ruff] Ignore std cmath.inf (RUF069) (#23120)
  • [ruff] New rule float-equality-comparison (RUF069) (#20585)
  • Don't format unlabeled Markdown code blocks (#23106)
  • Markdown formatting support in LSP (#23063)
  • Support Quarto Markdown language markers (#22947)
  • Support formatting pycon Markdown code blocks (#23112)
  • Use extension mapping to select Markdown code block language (#22934)

Bug fixes

  • Avoid false positive for undefined variables in FAST001 (#23224)
  • Avoid introducing syntax errors for FAST003 autofix (#23227)
  • Avoid suggesting InitVar for __post_init__ that references PEP 695 type parameters (#23226)
  • Deduplicate type variables in generic functions (#23225)
  • Fix exception handler parenthesis removal for Python 3.14+ (#23126)
  • Fix f-string middle panic when parsing t-strings (#23232)
  • Wrap RUF020 target for multiline fixes (#23210)
  • Wrap UP007 target for multiline fixes (#23208)
  • Fix missing diagnostics for last range suppression in file (#23242)
  • [pyupgrade] Fix syntax error on string with newline escape and comment (UP037) (#22968)

Rule changes

  • Use ruff instead of Ruff as the program name in GitHub output format (#23240)
  • [PT006] Fix syntax error when unpacking nested tuples in parametrize fixes (#22441) (#22464)
  • [airflow] Catch deprecated attribute access from context key for Airflow 3.0 (AIR301) (#22850)
  • [airflow] Capture deprecated arguments and a decorator (AIR301) (#23170)
  • [flake8-boolean-trap] Add multiprocessing.Value to excluded functions for FBT003 (#23010)
  • [flake8-bugbear] Add a secondary annotation showing the previous occurrence (B033) (#22634)
  • [flake8-type-checking] Add sub-diagnostic showing the runtime use of an annotation (TC004) (#23091)
  • [isort] Support configurable import section heading comments (#23151)
  • [ruff] Improve the diagnostic for RUF012 (#23202)

Formatter

... (truncated)

Commits
  • a2f11d2 Prepare for 0.15.1 (#23253)
  • d29628e Remove docker-run-action (#23254)
  • 8a04266 [ty] Allow discovering dependencies in system Python environments (#22994)
  • 55d06c8 Ensure pending suppression diagnostics are reported (#23242)
  • d056a9f [isort] support for configurable import section heading comments (#23151)
  • e22fa4f [ty] Fix method calls on subclasses of Any (#23248)
  • fa56c15 [ty] Fix bound method access on None (#23246)
  • 4fd07d0 Make range suppression test snapshot actually useful (#23251)
  • 8c63bce [ty] Include conditional symbols (like datetime.UTC) in auto-import in more...
  • 46be943 Exclude WASM artifacts from GitHub releases (#23221)
  • Additional commits viewable in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- libs/checkpoint-postgres/uv.lock | 189 +++++++++++++++---------------- 1 file changed, 94 insertions(+), 95 deletions(-) diff --git a/libs/checkpoint-postgres/uv.lock b/libs/checkpoint-postgres/uv.lock index 6f17c71bf..3b2994632 100644 --- a/libs/checkpoint-postgres/uv.lock +++ b/libs/checkpoint-postgres/uv.lock @@ -528,83 +528,83 @@ wheels = [ [[package]] name = "orjson" -version = "3.11.5" +version = "3.11.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/04/b8/333fdb27840f3bf04022d21b654a35f58e15407183aeb16f3b41aa053446/orjson-3.11.5.tar.gz", hash = "sha256:82393ab47b4fe44ffd0a7659fa9cfaacc717eb617c93cde83795f14af5c2e9d5", size = 5972347, upload-time = "2025-12-06T15:55:39.458Z" } +sdist = { url = "https://files.pythonhosted.org/packages/53/45/b268004f745ede84e5798b48ee12b05129d19235d0e15267aa57dcdb400b/orjson-3.11.7.tar.gz", hash = "sha256:9b1a67243945819ce55d24a30b59d6a168e86220452d2c96f4d1f093e71c0c49", size = 6144992, upload-time = "2026-02-02T15:38:49.29Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/79/19/b22cf9dad4db20c8737041046054cbd4f38bb5a2d0e4bb60487832ce3d76/orjson-3.11.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:df9eadb2a6386d5ea2bfd81309c505e125cfc9ba2b1b99a97e60985b0b3665d1", size = 245719, upload-time = "2025-12-06T15:53:43.877Z" }, - { url = "https://files.pythonhosted.org/packages/03/2e/b136dd6bf30ef5143fbe76a4c142828b55ccc618be490201e9073ad954a1/orjson-3.11.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc70da619744467d8f1f49a8cadae5ec7bbe054e5232d95f92ed8737f8c5870", size = 132467, upload-time = "2025-12-06T15:53:45.379Z" }, - { url = "https://files.pythonhosted.org/packages/ae/fc/ae99bfc1e1887d20a0268f0e2686eb5b13d0ea7bbe01de2b566febcd2130/orjson-3.11.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:073aab025294c2f6fc0807201c76fdaed86f8fc4be52c440fb78fbb759a1ac09", size = 130702, upload-time = "2025-12-06T15:53:46.659Z" }, - { url = "https://files.pythonhosted.org/packages/6e/43/ef7912144097765997170aca59249725c3ab8ef6079f93f9d708dd058df5/orjson-3.11.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:835f26fa24ba0bb8c53ae2a9328d1706135b74ec653ed933869b74b6909e63fd", size = 135907, upload-time = "2025-12-06T15:53:48.487Z" }, - { url = "https://files.pythonhosted.org/packages/3f/da/24d50e2d7f4092ddd4d784e37a3fa41f22ce8ed97abc9edd222901a96e74/orjson-3.11.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667c132f1f3651c14522a119e4dd631fad98761fa960c55e8e7430bb2a1ba4ac", size = 139935, upload-time = "2025-12-06T15:53:49.88Z" }, - { url = "https://files.pythonhosted.org/packages/02/4a/b4cb6fcbfff5b95a3a019a8648255a0fac9b221fbf6b6e72be8df2361feb/orjson-3.11.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42e8961196af655bb5e63ce6c60d25e8798cd4dfbc04f4203457fa3869322c2e", size = 137541, upload-time = "2025-12-06T15:53:51.226Z" }, - { url = "https://files.pythonhosted.org/packages/a5/99/a11bd129f18c2377c27b2846a9d9be04acec981f770d711ba0aaea563984/orjson-3.11.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75412ca06e20904c19170f8a24486c4e6c7887dea591ba18a1ab572f1300ee9f", size = 139031, upload-time = "2025-12-06T15:53:52.309Z" }, - { url = "https://files.pythonhosted.org/packages/64/29/d7b77d7911574733a036bb3e8ad7053ceb2b7d6ea42208b9dbc55b23b9ed/orjson-3.11.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6af8680328c69e15324b5af3ae38abbfcf9cbec37b5346ebfd52339c3d7e8a18", size = 141622, upload-time = "2025-12-06T15:53:53.606Z" }, - { url = "https://files.pythonhosted.org/packages/93/41/332db96c1de76b2feda4f453e91c27202cd092835936ce2b70828212f726/orjson-3.11.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a86fe4ff4ea523eac8f4b57fdac319faf037d3c1be12405e6a7e86b3fbc4756a", size = 413800, upload-time = "2025-12-06T15:53:54.866Z" }, - { url = "https://files.pythonhosted.org/packages/76/e1/5a0d148dd1f89ad2f9651df67835b209ab7fcb1118658cf353425d7563e9/orjson-3.11.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e607b49b1a106ee2086633167033afbd63f76f2999e9236f638b06b112b24ea7", size = 151198, upload-time = "2025-12-06T15:53:56.383Z" }, - { url = "https://files.pythonhosted.org/packages/0d/96/8db67430d317a01ae5cf7971914f6775affdcfe99f5bff9ef3da32492ecc/orjson-3.11.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7339f41c244d0eea251637727f016b3d20050636695bc78345cce9029b189401", size = 141984, upload-time = "2025-12-06T15:53:57.746Z" }, - { url = "https://files.pythonhosted.org/packages/71/49/40d21e1aa1ac569e521069228bb29c9b5a350344ccf922a0227d93c2ed44/orjson-3.11.5-cp310-cp310-win32.whl", hash = "sha256:8be318da8413cdbbce77b8c5fac8d13f6eb0f0db41b30bb598631412619572e8", size = 135272, upload-time = "2025-12-06T15:53:59.769Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7e/d0e31e78be0c100e08be64f48d2850b23bcb4d4c70d114f4e43b39f6895a/orjson-3.11.5-cp310-cp310-win_amd64.whl", hash = "sha256:b9f86d69ae822cabc2a0f6c099b43e8733dda788405cba2665595b7e8dd8d167", size = 133360, upload-time = "2025-12-06T15:54:01.25Z" }, - { url = "https://files.pythonhosted.org/packages/fd/68/6b3659daec3a81aed5ab47700adb1a577c76a5452d35b91c88efee89987f/orjson-3.11.5-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9c8494625ad60a923af6b2b0bd74107146efe9b55099e20d7740d995f338fcd8", size = 245318, upload-time = "2025-12-06T15:54:02.355Z" }, - { url = "https://files.pythonhosted.org/packages/e9/00/92db122261425f61803ccf0830699ea5567439d966cbc35856fe711bfe6b/orjson-3.11.5-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:7bb2ce0b82bc9fd1168a513ddae7a857994b780b2945a8c51db4ab1c4b751ebc", size = 129491, upload-time = "2025-12-06T15:54:03.877Z" }, - { url = "https://files.pythonhosted.org/packages/94/4f/ffdcb18356518809d944e1e1f77589845c278a1ebbb5a8297dfefcc4b4cb/orjson-3.11.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67394d3becd50b954c4ecd24ac90b5051ee7c903d167459f93e77fc6f5b4c968", size = 132167, upload-time = "2025-12-06T15:54:04.944Z" }, - { url = "https://files.pythonhosted.org/packages/97/c6/0a8caff96f4503f4f7dd44e40e90f4d14acf80d3b7a97cb88747bb712d3e/orjson-3.11.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:298d2451f375e5f17b897794bcc3e7b821c0f32b4788b9bcae47ada24d7f3cf7", size = 130516, upload-time = "2025-12-06T15:54:06.274Z" }, - { url = "https://files.pythonhosted.org/packages/4d/63/43d4dc9bd9954bff7052f700fdb501067f6fb134a003ddcea2a0bb3854ed/orjson-3.11.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa5e4244063db8e1d87e0f54c3f7522f14b2dc937e65d5241ef0076a096409fd", size = 135695, upload-time = "2025-12-06T15:54:07.702Z" }, - { url = "https://files.pythonhosted.org/packages/87/6f/27e2e76d110919cb7fcb72b26166ee676480a701bcf8fc53ac5d0edce32f/orjson-3.11.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1db2088b490761976c1b2e956d5d4e6409f3732e9d79cfa69f876c5248d1baf9", size = 139664, upload-time = "2025-12-06T15:54:08.828Z" }, - { url = "https://files.pythonhosted.org/packages/d4/f8/5966153a5f1be49b5fbb8ca619a529fde7bc71aa0a376f2bb83fed248bcd/orjson-3.11.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2ed66358f32c24e10ceea518e16eb3549e34f33a9d51f99ce23b0251776a1ef", size = 137289, upload-time = "2025-12-06T15:54:09.898Z" }, - { url = "https://files.pythonhosted.org/packages/a7/34/8acb12ff0299385c8bbcbb19fbe40030f23f15a6de57a9c587ebf71483fb/orjson-3.11.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2021afda46c1ed64d74b555065dbd4c2558d510d8cec5ea6a53001b3e5e82a9", size = 138784, upload-time = "2025-12-06T15:54:11.022Z" }, - { url = "https://files.pythonhosted.org/packages/ee/27/910421ea6e34a527f73d8f4ee7bdffa48357ff79c7b8d6eb6f7b82dd1176/orjson-3.11.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b42ffbed9128e547a1647a3e50bc88ab28ae9daa61713962e0d3dd35e820c125", size = 141322, upload-time = "2025-12-06T15:54:12.427Z" }, - { url = "https://files.pythonhosted.org/packages/87/a3/4b703edd1a05555d4bb1753d6ce44e1a05b7a6d7c164d5b332c795c63d70/orjson-3.11.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8d5f16195bb671a5dd3d1dbea758918bada8f6cc27de72bd64adfbd748770814", size = 413612, upload-time = "2025-12-06T15:54:13.858Z" }, - { url = "https://files.pythonhosted.org/packages/1b/36/034177f11d7eeea16d3d2c42a1883b0373978e08bc9dad387f5074c786d8/orjson-3.11.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c0e5d9f7a0227df2927d343a6e3859bebf9208b427c79bd31949abcc2fa32fa5", size = 150993, upload-time = "2025-12-06T15:54:15.189Z" }, - { url = "https://files.pythonhosted.org/packages/44/2f/ea8b24ee046a50a7d141c0227c4496b1180b215e728e3b640684f0ea448d/orjson-3.11.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:23d04c4543e78f724c4dfe656b3791b5f98e4c9253e13b2636f1af5d90e4a880", size = 141774, upload-time = "2025-12-06T15:54:16.451Z" }, - { url = "https://files.pythonhosted.org/packages/8a/12/cc440554bf8200eb23348a5744a575a342497b65261cd65ef3b28332510a/orjson-3.11.5-cp311-cp311-win32.whl", hash = "sha256:c404603df4865f8e0afe981aa3c4b62b406e6d06049564d58934860b62b7f91d", size = 135109, upload-time = "2025-12-06T15:54:17.73Z" }, - { url = "https://files.pythonhosted.org/packages/a3/83/e0c5aa06ba73a6760134b169f11fb970caa1525fa4461f94d76e692299d9/orjson-3.11.5-cp311-cp311-win_amd64.whl", hash = "sha256:9645ef655735a74da4990c24ffbd6894828fbfa117bc97c1edd98c282ecb52e1", size = 133193, upload-time = "2025-12-06T15:54:19.426Z" }, - { url = "https://files.pythonhosted.org/packages/cb/35/5b77eaebc60d735e832c5b1a20b155667645d123f09d471db0a78280fb49/orjson-3.11.5-cp311-cp311-win_arm64.whl", hash = "sha256:1cbf2735722623fcdee8e712cbaaab9e372bbcb0c7924ad711b261c2eccf4a5c", size = 126830, upload-time = "2025-12-06T15:54:20.836Z" }, - { url = "https://files.pythonhosted.org/packages/ef/a4/8052a029029b096a78955eadd68ab594ce2197e24ec50e6b6d2ab3f4e33b/orjson-3.11.5-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:334e5b4bff9ad101237c2d799d9fd45737752929753bf4faf4b207335a416b7d", size = 245347, upload-time = "2025-12-06T15:54:22.061Z" }, - { url = "https://files.pythonhosted.org/packages/64/67/574a7732bd9d9d79ac620c8790b4cfe0717a3d5a6eb2b539e6e8995e24a0/orjson-3.11.5-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:ff770589960a86eae279f5d8aa536196ebda8273a2a07db2a54e82b93bc86626", size = 129435, upload-time = "2025-12-06T15:54:23.615Z" }, - { url = "https://files.pythonhosted.org/packages/52/8d/544e77d7a29d90cf4d9eecd0ae801c688e7f3d1adfa2ebae5e1e94d38ab9/orjson-3.11.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed24250e55efbcb0b35bed7caaec8cedf858ab2f9f2201f17b8938c618c8ca6f", size = 132074, upload-time = "2025-12-06T15:54:24.694Z" }, - { url = "https://files.pythonhosted.org/packages/6e/57/b9f5b5b6fbff9c26f77e785baf56ae8460ef74acdb3eae4931c25b8f5ba9/orjson-3.11.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a66d7769e98a08a12a139049aac2f0ca3adae989817f8c43337455fbc7669b85", size = 130520, upload-time = "2025-12-06T15:54:26.185Z" }, - { url = "https://files.pythonhosted.org/packages/f6/6d/d34970bf9eb33f9ec7c979a262cad86076814859e54eb9a059a52f6dc13d/orjson-3.11.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86cfc555bfd5794d24c6a1903e558b50644e5e68e6471d66502ce5cb5fdef3f9", size = 136209, upload-time = "2025-12-06T15:54:27.264Z" }, - { url = "https://files.pythonhosted.org/packages/e7/39/bc373b63cc0e117a105ea12e57280f83ae52fdee426890d57412432d63b3/orjson-3.11.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a230065027bc2a025e944f9d4714976a81e7ecfa940923283bca7bbc1f10f626", size = 139837, upload-time = "2025-12-06T15:54:28.75Z" }, - { url = "https://files.pythonhosted.org/packages/cb/aa/7c4818c8d7d324da220f4f1af55c343956003aa4d1ce1857bdc1d396ba69/orjson-3.11.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b29d36b60e606df01959c4b982729c8845c69d1963f88686608be9ced96dbfaa", size = 137307, upload-time = "2025-12-06T15:54:29.856Z" }, - { url = "https://files.pythonhosted.org/packages/46/bf/0993b5a056759ba65145effe3a79dd5a939d4a070eaa5da2ee3180fbb13f/orjson-3.11.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c74099c6b230d4261fdc3169d50efc09abf38ace1a42ea2f9994b1d79153d477", size = 139020, upload-time = "2025-12-06T15:54:31.024Z" }, - { url = "https://files.pythonhosted.org/packages/65/e8/83a6c95db3039e504eda60fc388f9faedbb4f6472f5aba7084e06552d9aa/orjson-3.11.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e697d06ad57dd0c7a737771d470eedc18e68dfdefcdd3b7de7f33dfda5b6212e", size = 141099, upload-time = "2025-12-06T15:54:32.196Z" }, - { url = "https://files.pythonhosted.org/packages/b9/b4/24fdc024abfce31c2f6812973b0a693688037ece5dc64b7a60c1ce69e2f2/orjson-3.11.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e08ca8a6c851e95aaecc32bc44a5aa75d0ad26af8cdac7c77e4ed93acf3d5b69", size = 413540, upload-time = "2025-12-06T15:54:33.361Z" }, - { url = "https://files.pythonhosted.org/packages/d9/37/01c0ec95d55ed0c11e4cae3e10427e479bba40c77312b63e1f9665e0737d/orjson-3.11.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e8b5f96c05fce7d0218df3fdfeb962d6b8cfff7e3e20264306b46dd8b217c0f3", size = 151530, upload-time = "2025-12-06T15:54:34.6Z" }, - { url = "https://files.pythonhosted.org/packages/f9/d4/f9ebc57182705bb4bbe63f5bbe14af43722a2533135e1d2fb7affa0c355d/orjson-3.11.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ddbfdb5099b3e6ba6d6ea818f61997bb66de14b411357d24c4612cf1ebad08ca", size = 141863, upload-time = "2025-12-06T15:54:35.801Z" }, - { url = "https://files.pythonhosted.org/packages/0d/04/02102b8d19fdcb009d72d622bb5781e8f3fae1646bf3e18c53d1bc8115b5/orjson-3.11.5-cp312-cp312-win32.whl", hash = "sha256:9172578c4eb09dbfcf1657d43198de59b6cef4054de385365060ed50c458ac98", size = 135255, upload-time = "2025-12-06T15:54:37.209Z" }, - { url = "https://files.pythonhosted.org/packages/d4/fb/f05646c43d5450492cb387de5549f6de90a71001682c17882d9f66476af5/orjson-3.11.5-cp312-cp312-win_amd64.whl", hash = "sha256:2b91126e7b470ff2e75746f6f6ee32b9ab67b7a93c8ba1d15d3a0caaf16ec875", size = 133252, upload-time = "2025-12-06T15:54:38.401Z" }, - { url = "https://files.pythonhosted.org/packages/dc/a6/7b8c0b26ba18c793533ac1cd145e131e46fcf43952aa94c109b5b913c1f0/orjson-3.11.5-cp312-cp312-win_arm64.whl", hash = "sha256:acbc5fac7e06777555b0722b8ad5f574739e99ffe99467ed63da98f97f9ca0fe", size = 126777, upload-time = "2025-12-06T15:54:39.515Z" }, - { url = "https://files.pythonhosted.org/packages/10/43/61a77040ce59f1569edf38f0b9faadc90c8cf7e9bec2e0df51d0132c6bb7/orjson-3.11.5-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3b01799262081a4c47c035dd77c1301d40f568f77cc7ec1bb7db5d63b0a01629", size = 245271, upload-time = "2025-12-06T15:54:40.878Z" }, - { url = "https://files.pythonhosted.org/packages/55/f9/0f79be617388227866d50edd2fd320cb8fb94dc1501184bb1620981a0aba/orjson-3.11.5-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:61de247948108484779f57a9f406e4c84d636fa5a59e411e6352484985e8a7c3", size = 129422, upload-time = "2025-12-06T15:54:42.403Z" }, - { url = "https://files.pythonhosted.org/packages/77/42/f1bf1549b432d4a78bfa95735b79b5dac75b65b5bb815bba86ad406ead0a/orjson-3.11.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:894aea2e63d4f24a7f04a1908307c738d0dce992e9249e744b8f4e8dd9197f39", size = 132060, upload-time = "2025-12-06T15:54:43.531Z" }, - { url = "https://files.pythonhosted.org/packages/25/49/825aa6b929f1a6ed244c78acd7b22c1481fd7e5fda047dc8bf4c1a807eb6/orjson-3.11.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ddc21521598dbe369d83d4d40338e23d4101dad21dae0e79fa20465dbace019f", size = 130391, upload-time = "2025-12-06T15:54:45.059Z" }, - { url = "https://files.pythonhosted.org/packages/42/ec/de55391858b49e16e1aa8f0bbbb7e5997b7345d8e984a2dec3746d13065b/orjson-3.11.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cce16ae2f5fb2c53c3eafdd1706cb7b6530a67cc1c17abe8ec747f5cd7c0c51", size = 135964, upload-time = "2025-12-06T15:54:46.576Z" }, - { url = "https://files.pythonhosted.org/packages/1c/40/820bc63121d2d28818556a2d0a09384a9f0262407cf9fa305e091a8048df/orjson-3.11.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e46c762d9f0e1cfb4ccc8515de7f349abbc95b59cb5a2bd68df5973fdef913f8", size = 139817, upload-time = "2025-12-06T15:54:48.084Z" }, - { url = "https://files.pythonhosted.org/packages/09/c7/3a445ca9a84a0d59d26365fd8898ff52bdfcdcb825bcc6519830371d2364/orjson-3.11.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7345c759276b798ccd6d77a87136029e71e66a8bbf2d2755cbdde1d82e78706", size = 137336, upload-time = "2025-12-06T15:54:49.426Z" }, - { url = "https://files.pythonhosted.org/packages/9a/b3/dc0d3771f2e5d1f13368f56b339c6782f955c6a20b50465a91acb79fe961/orjson-3.11.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75bc2e59e6a2ac1dd28901d07115abdebc4563b5b07dd612bf64260a201b1c7f", size = 138993, upload-time = "2025-12-06T15:54:50.939Z" }, - { url = "https://files.pythonhosted.org/packages/d1/a2/65267e959de6abe23444659b6e19c888f242bf7725ff927e2292776f6b89/orjson-3.11.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:54aae9b654554c3b4edd61896b978568c6daa16af96fa4681c9b5babd469f863", size = 141070, upload-time = "2025-12-06T15:54:52.414Z" }, - { url = "https://files.pythonhosted.org/packages/63/c9/da44a321b288727a322c6ab17e1754195708786a04f4f9d2220a5076a649/orjson-3.11.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4bdd8d164a871c4ec773f9de0f6fe8769c2d6727879c37a9666ba4183b7f8228", size = 413505, upload-time = "2025-12-06T15:54:53.67Z" }, - { url = "https://files.pythonhosted.org/packages/7f/17/68dc14fa7000eefb3d4d6d7326a190c99bb65e319f02747ef3ebf2452f12/orjson-3.11.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a261fef929bcf98a60713bf5e95ad067cea16ae345d9a35034e73c3990e927d2", size = 151342, upload-time = "2025-12-06T15:54:55.113Z" }, - { url = "https://files.pythonhosted.org/packages/c4/c5/ccee774b67225bed630a57478529fc026eda33d94fe4c0eac8fe58d4aa52/orjson-3.11.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c028a394c766693c5c9909dec76b24f37e6a1b91999e8d0c0d5feecbe93c3e05", size = 141823, upload-time = "2025-12-06T15:54:56.331Z" }, - { url = "https://files.pythonhosted.org/packages/67/80/5d00e4155d0cd7390ae2087130637671da713959bb558db9bac5e6f6b042/orjson-3.11.5-cp313-cp313-win32.whl", hash = "sha256:2cc79aaad1dfabe1bd2d50ee09814a1253164b3da4c00a78c458d82d04b3bdef", size = 135236, upload-time = "2025-12-06T15:54:57.507Z" }, - { url = "https://files.pythonhosted.org/packages/95/fe/792cc06a84808dbdc20ac6eab6811c53091b42f8e51ecebf14b540e9cfe4/orjson-3.11.5-cp313-cp313-win_amd64.whl", hash = "sha256:ff7877d376add4e16b274e35a3f58b7f37b362abf4aa31863dadacdd20e3a583", size = 133167, upload-time = "2025-12-06T15:54:58.71Z" }, - { url = "https://files.pythonhosted.org/packages/46/2c/d158bd8b50e3b1cfdcf406a7e463f6ffe3f0d167b99634717acdaf5e299f/orjson-3.11.5-cp313-cp313-win_arm64.whl", hash = "sha256:59ac72ea775c88b163ba8d21b0177628bd015c5dd060647bbab6e22da3aad287", size = 126712, upload-time = "2025-12-06T15:54:59.892Z" }, - { url = "https://files.pythonhosted.org/packages/c2/60/77d7b839e317ead7bb225d55bb50f7ea75f47afc489c81199befc5435b50/orjson-3.11.5-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e446a8ea0a4c366ceafc7d97067bfd55292969143b57e3c846d87fc701e797a0", size = 245252, upload-time = "2025-12-06T15:55:01.127Z" }, - { url = "https://files.pythonhosted.org/packages/f1/aa/d4639163b400f8044cef0fb9aa51b0337be0da3a27187a20d1166e742370/orjson-3.11.5-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:53deb5addae9c22bbe3739298f5f2196afa881ea75944e7720681c7080909a81", size = 129419, upload-time = "2025-12-06T15:55:02.723Z" }, - { url = "https://files.pythonhosted.org/packages/30/94/9eabf94f2e11c671111139edf5ec410d2f21e6feee717804f7e8872d883f/orjson-3.11.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cd00d49d6063d2b8791da5d4f9d20539c5951f965e45ccf4e96d33505ce68f", size = 132050, upload-time = "2025-12-06T15:55:03.918Z" }, - { url = "https://files.pythonhosted.org/packages/3d/c8/ca10f5c5322f341ea9a9f1097e140be17a88f88d1cfdd29df522970d9744/orjson-3.11.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3fd15f9fc8c203aeceff4fda211157fad114dde66e92e24097b3647a08f4ee9e", size = 130370, upload-time = "2025-12-06T15:55:05.173Z" }, - { url = "https://files.pythonhosted.org/packages/25/d4/e96824476d361ee2edd5c6290ceb8d7edf88d81148a6ce172fc00278ca7f/orjson-3.11.5-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9df95000fbe6777bf9820ae82ab7578e8662051bb5f83d71a28992f539d2cda7", size = 136012, upload-time = "2025-12-06T15:55:06.402Z" }, - { url = "https://files.pythonhosted.org/packages/85/8e/9bc3423308c425c588903f2d103cfcfe2539e07a25d6522900645a6f257f/orjson-3.11.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92a8d676748fca47ade5bc3da7430ed7767afe51b2f8100e3cd65e151c0eaceb", size = 139809, upload-time = "2025-12-06T15:55:07.656Z" }, - { url = "https://files.pythonhosted.org/packages/e9/3c/b404e94e0b02a232b957c54643ce68d0268dacb67ac33ffdee24008c8b27/orjson-3.11.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa0f513be38b40234c77975e68805506cad5d57b3dfd8fe3baa7f4f4051e15b4", size = 137332, upload-time = "2025-12-06T15:55:08.961Z" }, - { url = "https://files.pythonhosted.org/packages/51/30/cc2d69d5ce0ad9b84811cdf4a0cd5362ac27205a921da524ff42f26d65e0/orjson-3.11.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1863e75b92891f553b7922ce4ee10ed06db061e104f2b7815de80cdcb135ad", size = 138983, upload-time = "2025-12-06T15:55:10.595Z" }, - { url = "https://files.pythonhosted.org/packages/0e/87/de3223944a3e297d4707d2fe3b1ffb71437550e165eaf0ca8bbe43ccbcb1/orjson-3.11.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4be86b58e9ea262617b8ca6251a2f0d63cc132a6da4b5fcc8e0a4128782c829", size = 141069, upload-time = "2025-12-06T15:55:11.832Z" }, - { url = "https://files.pythonhosted.org/packages/65/30/81d5087ae74be33bcae3ff2d80f5ccaa4a8fedc6d39bf65a427a95b8977f/orjson-3.11.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:b923c1c13fa02084eb38c9c065afd860a5cff58026813319a06949c3af5732ac", size = 413491, upload-time = "2025-12-06T15:55:13.314Z" }, - { url = "https://files.pythonhosted.org/packages/d0/6f/f6058c21e2fc1efaf918986dbc2da5cd38044f1a2d4b7b91ad17c4acf786/orjson-3.11.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:1b6bd351202b2cd987f35a13b5e16471cf4d952b42a73c391cc537974c43ef6d", size = 151375, upload-time = "2025-12-06T15:55:14.715Z" }, - { url = "https://files.pythonhosted.org/packages/54/92/c6921f17d45e110892899a7a563a925b2273d929959ce2ad89e2525b885b/orjson-3.11.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bb150d529637d541e6af06bbe3d02f5498d628b7f98267ff87647584293ab439", size = 141850, upload-time = "2025-12-06T15:55:15.94Z" }, - { url = "https://files.pythonhosted.org/packages/88/86/cdecb0140a05e1a477b81f24739da93b25070ee01ce7f7242f44a6437594/orjson-3.11.5-cp314-cp314-win32.whl", hash = "sha256:9cc1e55c884921434a84a0c3dd2699eb9f92e7b441d7f53f3941079ec6ce7499", size = 135278, upload-time = "2025-12-06T15:55:17.202Z" }, - { url = "https://files.pythonhosted.org/packages/e4/97/b638d69b1e947d24f6109216997e38922d54dcdcdb1b11c18d7efd2d3c59/orjson-3.11.5-cp314-cp314-win_amd64.whl", hash = "sha256:a4f3cb2d874e03bc7767c8f88adaa1a9a05cecea3712649c3b58589ec7317310", size = 133170, upload-time = "2025-12-06T15:55:18.468Z" }, - { url = "https://files.pythonhosted.org/packages/8f/dd/f4fff4a6fe601b4f8f3ba3aa6da8ac33d17d124491a3b804c662a70e1636/orjson-3.11.5-cp314-cp314-win_arm64.whl", hash = "sha256:38b22f476c351f9a1c43e5b07d8b5a02eb24a6ab8e75f700f7d479d4568346a5", size = 126713, upload-time = "2025-12-06T15:55:19.738Z" }, + { url = "https://files.pythonhosted.org/packages/de/1a/a373746fa6d0e116dd9e54371a7b54622c44d12296d5d0f3ad5e3ff33490/orjson-3.11.7-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a02c833f38f36546ba65a452127633afce4cf0dd7296b753d3bb54e55e5c0174", size = 229140, upload-time = "2026-02-02T15:37:06.082Z" }, + { url = "https://files.pythonhosted.org/packages/52/a2/fa129e749d500f9b183e8a3446a193818a25f60261e9ce143ad61e975208/orjson-3.11.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b63c6e6738d7c3470ad01601e23376aa511e50e1f3931395b9f9c722406d1a67", size = 128670, upload-time = "2026-02-02T15:37:08.002Z" }, + { url = "https://files.pythonhosted.org/packages/08/93/1e82011cd1e0bd051ef9d35bed1aa7fb4ea1f0a055dc2c841b46b43a9ebd/orjson-3.11.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:043d3006b7d32c7e233b8cfb1f01c651013ea079e08dcef7189a29abd8befe11", size = 123832, upload-time = "2026-02-02T15:37:09.191Z" }, + { url = "https://files.pythonhosted.org/packages/fe/d8/a26b431ef962c7d55736674dddade876822f3e33223c1f47a36879350d04/orjson-3.11.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57036b27ac8a25d81112eb0cc9835cd4833c5b16e1467816adc0015f59e870dc", size = 129171, upload-time = "2026-02-02T15:37:11.112Z" }, + { url = "https://files.pythonhosted.org/packages/a7/19/f47819b84a580f490da260c3ee9ade214cf4cf78ac9ce8c1c758f80fdfc9/orjson-3.11.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:733ae23ada68b804b222c44affed76b39e30806d38660bf1eb200520d259cc16", size = 141967, upload-time = "2026-02-02T15:37:12.282Z" }, + { url = "https://files.pythonhosted.org/packages/5b/cd/37ece39a0777ba077fdcdbe4cccae3be8ed00290c14bf8afdc548befc260/orjson-3.11.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5fdfad2093bdd08245f2e204d977facd5f871c88c4a71230d5bcbd0e43bf6222", size = 130991, upload-time = "2026-02-02T15:37:13.465Z" }, + { url = "https://files.pythonhosted.org/packages/8f/ed/f2b5d66aa9b6b5c02ff5f120efc7b38c7c4962b21e6be0f00fd99a5c348e/orjson-3.11.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cededd6738e1c153530793998e31c05086582b08315db48ab66649768f326baa", size = 133674, upload-time = "2026-02-02T15:37:14.694Z" }, + { url = "https://files.pythonhosted.org/packages/c4/6e/baa83e68d1aa09fa8c3e5b2c087d01d0a0bd45256de719ed7bc22c07052d/orjson-3.11.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:14f440c7268c8f8633d1b3d443a434bd70cb15686117ea6beff8fdc8f5917a1e", size = 138722, upload-time = "2026-02-02T15:37:16.501Z" }, + { url = "https://files.pythonhosted.org/packages/0c/47/7f8ef4963b772cd56999b535e553f7eb5cd27e9dd6c049baee6f18bfa05d/orjson-3.11.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3a2479753bbb95b0ebcf7969f562cdb9668e6d12416a35b0dda79febf89cdea2", size = 409056, upload-time = "2026-02-02T15:37:17.895Z" }, + { url = "https://files.pythonhosted.org/packages/38/eb/2df104dd2244b3618f25325a656f85cc3277f74bbd91224752410a78f3c7/orjson-3.11.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:71924496986275a737f38e3f22b4e0878882b3f7a310d2ff4dc96e812789120c", size = 144196, upload-time = "2026-02-02T15:37:19.349Z" }, + { url = "https://files.pythonhosted.org/packages/b6/2a/ee41de0aa3a6686598661eae2b4ebdff1340c65bfb17fcff8b87138aab21/orjson-3.11.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4a9eefdc70bf8bf9857f0290f973dec534ac84c35cd6a7f4083be43e7170a8f", size = 134979, upload-time = "2026-02-02T15:37:20.906Z" }, + { url = "https://files.pythonhosted.org/packages/4c/fa/92fc5d3d402b87a8b28277a9ed35386218a6a5287c7fe5ee9b9f02c53fb2/orjson-3.11.7-cp310-cp310-win32.whl", hash = "sha256:ae9e0b37a834cef7ce8f99de6498f8fad4a2c0bf6bfc3d02abd8ed56aa15b2de", size = 127968, upload-time = "2026-02-02T15:37:23.178Z" }, + { url = "https://files.pythonhosted.org/packages/07/29/a576bf36d73d60df06904d3844a9df08e25d59eba64363aaf8ec2f9bff41/orjson-3.11.7-cp310-cp310-win_amd64.whl", hash = "sha256:d772afdb22555f0c58cfc741bdae44180122b3616faa1ecadb595cd526e4c993", size = 125128, upload-time = "2026-02-02T15:37:24.329Z" }, + { url = "https://files.pythonhosted.org/packages/37/02/da6cb01fc6087048d7f61522c327edf4250f1683a58a839fdcc435746dd5/orjson-3.11.7-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9487abc2c2086e7c8eb9a211d2ce8855bae0e92586279d0d27b341d5ad76c85c", size = 228664, upload-time = "2026-02-02T15:37:25.542Z" }, + { url = "https://files.pythonhosted.org/packages/c1/c2/5885e7a5881dba9a9af51bc564e8967225a642b3e03d089289a35054e749/orjson-3.11.7-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:79cacb0b52f6004caf92405a7e1f11e6e2de8bdf9019e4f76b44ba045125cd6b", size = 125344, upload-time = "2026-02-02T15:37:26.92Z" }, + { url = "https://files.pythonhosted.org/packages/a4/1d/4e7688de0a92d1caf600dfd5fb70b4c5bfff51dfa61ac555072ef2d0d32a/orjson-3.11.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2e85fe4698b6a56d5e2ebf7ae87544d668eb6bde1ad1226c13f44663f20ec9e", size = 128404, upload-time = "2026-02-02T15:37:28.108Z" }, + { url = "https://files.pythonhosted.org/packages/2f/b2/ec04b74ae03a125db7bd69cffd014b227b7f341e3261bf75b5eb88a1aa92/orjson-3.11.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8d14b71c0b12963fe8a62aac87119f1afdf4cb88a400f61ca5ae581449efcb5", size = 123677, upload-time = "2026-02-02T15:37:30.287Z" }, + { url = "https://files.pythonhosted.org/packages/4c/69/f95bdf960605f08f827f6e3291fe243d8aa9c5c9ff017a8d7232209184c3/orjson-3.11.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91c81ef070c8f3220054115e1ef468b1c9ce8497b4e526cb9f68ab4dc0a7ac62", size = 128950, upload-time = "2026-02-02T15:37:31.595Z" }, + { url = "https://files.pythonhosted.org/packages/a4/1b/de59c57bae1d148ef298852abd31909ac3089cff370dfd4cd84cc99cbc42/orjson-3.11.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:411ebaf34d735e25e358a6d9e7978954a9c9d58cfb47bc6683cdc3964cd2f910", size = 141756, upload-time = "2026-02-02T15:37:32.985Z" }, + { url = "https://files.pythonhosted.org/packages/ee/9e/9decc59f4499f695f65c650f6cfa6cd4c37a3fbe8fa235a0a3614cb54386/orjson-3.11.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a16bcd08ab0bcdfc7e8801d9c4a9cc17e58418e4d48ddc6ded4e9e4b1a94062b", size = 130812, upload-time = "2026-02-02T15:37:34.204Z" }, + { url = "https://files.pythonhosted.org/packages/28/e6/59f932bcabd1eac44e334fe8e3281a92eacfcb450586e1f4bde0423728d8/orjson-3.11.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c0b51672e466fd7e56230ffbae7f1639e18d0ce023351fb75da21b71bc2c960", size = 133444, upload-time = "2026-02-02T15:37:35.446Z" }, + { url = "https://files.pythonhosted.org/packages/f1/36/b0f05c0eaa7ca30bc965e37e6a2956b0d67adb87a9872942d3568da846ae/orjson-3.11.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:136dcd6a2e796dfd9ffca9fc027d778567b0b7c9968d092842d3c323cef88aa8", size = 138609, upload-time = "2026-02-02T15:37:36.657Z" }, + { url = "https://files.pythonhosted.org/packages/b8/03/58ec7d302b8d86944c60c7b4b82975d5161fcce4c9bc8c6cb1d6741b6115/orjson-3.11.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:7ba61079379b0ae29e117db13bda5f28d939766e410d321ec1624afc6a0b0504", size = 408918, upload-time = "2026-02-02T15:37:38.076Z" }, + { url = "https://files.pythonhosted.org/packages/06/3a/868d65ef9a8b99be723bd510de491349618abd9f62c826cf206d962db295/orjson-3.11.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0527a4510c300e3b406591b0ba69b5dc50031895b0a93743526a3fc45f59d26e", size = 143998, upload-time = "2026-02-02T15:37:39.706Z" }, + { url = "https://files.pythonhosted.org/packages/5b/c7/1e18e1c83afe3349f4f6dc9e14910f0ae5f82eac756d1412ea4018938535/orjson-3.11.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a709e881723c9b18acddcfb8ba357322491ad553e277cf467e1e7e20e2d90561", size = 134802, upload-time = "2026-02-02T15:37:41.002Z" }, + { url = "https://files.pythonhosted.org/packages/d4/0b/ccb7ee1a65b37e8eeb8b267dc953561d72370e85185e459616d4345bab34/orjson-3.11.7-cp311-cp311-win32.whl", hash = "sha256:c43b8b5bab288b6b90dac410cca7e986a4fa747a2e8f94615aea407da706980d", size = 127828, upload-time = "2026-02-02T15:37:42.241Z" }, + { url = "https://files.pythonhosted.org/packages/af/9e/55c776dffda3f381e0f07d010a4f5f3902bf48eaba1bb7684d301acd4924/orjson-3.11.7-cp311-cp311-win_amd64.whl", hash = "sha256:6543001328aa857187f905308a028935864aefe9968af3848401b6fe80dbb471", size = 124941, upload-time = "2026-02-02T15:37:43.444Z" }, + { url = "https://files.pythonhosted.org/packages/aa/8e/424a620fa7d263b880162505fb107ef5e0afaa765b5b06a88312ac291560/orjson-3.11.7-cp311-cp311-win_arm64.whl", hash = "sha256:1ee5cc7160a821dfe14f130bc8e63e7611051f964b463d9e2a3a573204446a4d", size = 126245, upload-time = "2026-02-02T15:37:45.18Z" }, + { url = "https://files.pythonhosted.org/packages/80/bf/76f4f1665f6983385938f0e2a5d7efa12a58171b8456c252f3bae8a4cf75/orjson-3.11.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bd03ea7606833655048dab1a00734a2875e3e86c276e1d772b2a02556f0d895f", size = 228545, upload-time = "2026-02-02T15:37:46.376Z" }, + { url = "https://files.pythonhosted.org/packages/79/53/6c72c002cb13b5a978a068add59b25a8bdf2800ac1c9c8ecdb26d6d97064/orjson-3.11.7-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:89e440ebc74ce8ab5c7bc4ce6757b4a6b1041becb127df818f6997b5c71aa60b", size = 125224, upload-time = "2026-02-02T15:37:47.697Z" }, + { url = "https://files.pythonhosted.org/packages/2c/83/10e48852865e5dd151bdfe652c06f7da484578ed02c5fca938e3632cb0b8/orjson-3.11.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ede977b5fe5ac91b1dffc0a517ca4542d2ec8a6a4ff7b2652d94f640796342a", size = 128154, upload-time = "2026-02-02T15:37:48.954Z" }, + { url = "https://files.pythonhosted.org/packages/6e/52/a66e22a2b9abaa374b4a081d410edab6d1e30024707b87eab7c734afe28d/orjson-3.11.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b7b1dae39230a393df353827c855a5f176271c23434cfd2db74e0e424e693e10", size = 123548, upload-time = "2026-02-02T15:37:50.187Z" }, + { url = "https://files.pythonhosted.org/packages/de/38/605d371417021359f4910c496f764c48ceb8997605f8c25bf1dfe58c0ebe/orjson-3.11.7-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed46f17096e28fb28d2975834836a639af7278aa87c84f68ab08fbe5b8bd75fa", size = 129000, upload-time = "2026-02-02T15:37:51.426Z" }, + { url = "https://files.pythonhosted.org/packages/44/98/af32e842b0ffd2335c89714d48ca4e3917b42f5d6ee5537832e069a4b3ac/orjson-3.11.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3726be79e36e526e3d9c1aceaadbfb4a04ee80a72ab47b3f3c17fefb9812e7b8", size = 141686, upload-time = "2026-02-02T15:37:52.607Z" }, + { url = "https://files.pythonhosted.org/packages/96/0b/fc793858dfa54be6feee940c1463370ece34b3c39c1ca0aa3845f5ba9892/orjson-3.11.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0724e265bc548af1dedebd9cb3d24b4e1c1e685a343be43e87ba922a5c5fff2f", size = 130812, upload-time = "2026-02-02T15:37:53.944Z" }, + { url = "https://files.pythonhosted.org/packages/dc/91/98a52415059db3f374757d0b7f0f16e3b5cd5976c90d1c2b56acaea039e6/orjson-3.11.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7745312efa9e11c17fbd3cb3097262d079da26930ae9ae7ba28fb738367cbad", size = 133440, upload-time = "2026-02-02T15:37:55.615Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b6/cb540117bda61791f46381f8c26c8f93e802892830a6055748d3bb1925ab/orjson-3.11.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f904c24bdeabd4298f7a977ef14ca2a022ca921ed670b92ecd16ab6f3d01f867", size = 138386, upload-time = "2026-02-02T15:37:56.814Z" }, + { url = "https://files.pythonhosted.org/packages/63/1a/50a3201c334a7f17c231eee5f841342190723794e3b06293f26e7cf87d31/orjson-3.11.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b9fc4d0f81f394689e0814617aadc4f2ea0e8025f38c226cbf22d3b5ddbf025d", size = 408853, upload-time = "2026-02-02T15:37:58.291Z" }, + { url = "https://files.pythonhosted.org/packages/87/cd/8de1c67d0be44fdc22701e5989c0d015a2adf391498ad42c4dc589cd3013/orjson-3.11.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:849e38203e5be40b776ed2718e587faf204d184fc9a008ae441f9442320c0cab", size = 144130, upload-time = "2026-02-02T15:38:00.163Z" }, + { url = "https://files.pythonhosted.org/packages/0f/fe/d605d700c35dd55f51710d159fc54516a280923cd1b7e47508982fbb387d/orjson-3.11.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4682d1db3bcebd2b64757e0ddf9e87ae5f00d29d16c5cdf3a62f561d08cc3dd2", size = 134818, upload-time = "2026-02-02T15:38:01.507Z" }, + { url = "https://files.pythonhosted.org/packages/e4/e4/15ecc67edb3ddb3e2f46ae04475f2d294e8b60c1825fbe28a428b93b3fbd/orjson-3.11.7-cp312-cp312-win32.whl", hash = "sha256:f4f7c956b5215d949a1f65334cf9d7612dde38f20a95f2315deef167def91a6f", size = 127923, upload-time = "2026-02-02T15:38:02.75Z" }, + { url = "https://files.pythonhosted.org/packages/34/70/2e0855361f76198a3965273048c8e50a9695d88cd75811a5b46444895845/orjson-3.11.7-cp312-cp312-win_amd64.whl", hash = "sha256:bf742e149121dc5648ba0a08ea0871e87b660467ef168a3a5e53bc1fbd64bb74", size = 125007, upload-time = "2026-02-02T15:38:04.032Z" }, + { url = "https://files.pythonhosted.org/packages/68/40/c2051bd19fc467610fed469dc29e43ac65891571138f476834ca192bc290/orjson-3.11.7-cp312-cp312-win_arm64.whl", hash = "sha256:26c3b9132f783b7d7903bf1efb095fed8d4a3a85ec0d334ee8beff3d7a4749d5", size = 126089, upload-time = "2026-02-02T15:38:05.297Z" }, + { url = "https://files.pythonhosted.org/packages/89/25/6e0e52cac5aab51d7b6dcd257e855e1dec1c2060f6b28566c509b4665f62/orjson-3.11.7-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1d98b30cc1313d52d4af17d9c3d307b08389752ec5f2e5febdfada70b0f8c733", size = 228390, upload-time = "2026-02-02T15:38:06.8Z" }, + { url = "https://files.pythonhosted.org/packages/a5/29/a77f48d2fc8a05bbc529e5ff481fb43d914f9e383ea2469d4f3d51df3d00/orjson-3.11.7-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:d897e81f8d0cbd2abb82226d1860ad2e1ab3ff16d7b08c96ca00df9d45409ef4", size = 125189, upload-time = "2026-02-02T15:38:08.181Z" }, + { url = "https://files.pythonhosted.org/packages/89/25/0a16e0729a0e6a1504f9d1a13cdd365f030068aab64cec6958396b9969d7/orjson-3.11.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:814be4b49b228cfc0b3c565acf642dd7d13538f966e3ccde61f4f55be3e20785", size = 128106, upload-time = "2026-02-02T15:38:09.41Z" }, + { url = "https://files.pythonhosted.org/packages/66/da/a2e505469d60666a05ab373f1a6322eb671cb2ba3a0ccfc7d4bc97196787/orjson-3.11.7-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d06e5c5fed5caedd2e540d62e5b1c25e8c82431b9e577c33537e5fa4aa909539", size = 123363, upload-time = "2026-02-02T15:38:10.73Z" }, + { url = "https://files.pythonhosted.org/packages/23/bf/ed73f88396ea35c71b38961734ea4a4746f7ca0768bf28fd551d37e48dd0/orjson-3.11.7-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31c80ce534ac4ea3739c5ee751270646cbc46e45aea7576a38ffec040b4029a1", size = 129007, upload-time = "2026-02-02T15:38:12.138Z" }, + { url = "https://files.pythonhosted.org/packages/73/3c/b05d80716f0225fc9008fbf8ab22841dcc268a626aa550561743714ce3bf/orjson-3.11.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f50979824bde13d32b4320eedd513431c921102796d86be3eee0b58e58a3ecd1", size = 141667, upload-time = "2026-02-02T15:38:13.398Z" }, + { url = "https://files.pythonhosted.org/packages/61/e8/0be9b0addd9bf86abfc938e97441dcd0375d494594b1c8ad10fe57479617/orjson-3.11.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e54f3808e2b6b945078c41aa8d9b5834b28c50843846e97807e5adb75fa9705", size = 130832, upload-time = "2026-02-02T15:38:14.698Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ec/c68e3b9021a31d9ec15a94931db1410136af862955854ed5dd7e7e4f5bff/orjson-3.11.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12b80df61aab7b98b490fe9e4879925ba666fccdfcd175252ce4d9035865ace", size = 133373, upload-time = "2026-02-02T15:38:16.109Z" }, + { url = "https://files.pythonhosted.org/packages/d2/45/f3466739aaafa570cc8e77c6dbb853c48bf56e3b43738020e2661e08b0ac/orjson-3.11.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:996b65230271f1a97026fd0e6a753f51fbc0c335d2ad0c6201f711b0da32693b", size = 138307, upload-time = "2026-02-02T15:38:17.453Z" }, + { url = "https://files.pythonhosted.org/packages/e1/84/9f7f02288da1ffb31405c1be07657afd1eecbcb4b64ee2817b6fe0f785fa/orjson-3.11.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ab49d4b2a6a1d415ddb9f37a21e02e0d5dbfe10b7870b21bf779fc21e9156157", size = 408695, upload-time = "2026-02-02T15:38:18.831Z" }, + { url = "https://files.pythonhosted.org/packages/18/07/9dd2f0c0104f1a0295ffbe912bc8d63307a539b900dd9e2c48ef7810d971/orjson-3.11.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:390a1dce0c055ddf8adb6aa94a73b45a4a7d7177b5c584b8d1c1947f2ba60fb3", size = 144099, upload-time = "2026-02-02T15:38:20.28Z" }, + { url = "https://files.pythonhosted.org/packages/a5/66/857a8e4a3292e1f7b1b202883bcdeb43a91566cf59a93f97c53b44bd6801/orjson-3.11.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1eb80451a9c351a71dfaf5b7ccc13ad065405217726b59fdbeadbcc544f9d223", size = 134806, upload-time = "2026-02-02T15:38:22.186Z" }, + { url = "https://files.pythonhosted.org/packages/0a/5b/6ebcf3defc1aab3a338ca777214966851e92efb1f30dc7fc8285216e6d1b/orjson-3.11.7-cp313-cp313-win32.whl", hash = "sha256:7477aa6a6ec6139c5cb1cc7b214643592169a5494d200397c7fc95d740d5fcf3", size = 127914, upload-time = "2026-02-02T15:38:23.511Z" }, + { url = "https://files.pythonhosted.org/packages/00/04/c6f72daca5092e3117840a1b1e88dfc809cc1470cf0734890d0366b684a1/orjson-3.11.7-cp313-cp313-win_amd64.whl", hash = "sha256:b9f95dcdea9d4f805daa9ddf02617a89e484c6985fa03055459f90e87d7a0757", size = 124986, upload-time = "2026-02-02T15:38:24.836Z" }, + { url = "https://files.pythonhosted.org/packages/03/ba/077a0f6f1085d6b806937246860fafbd5b17f3919c70ee3f3d8d9c713f38/orjson-3.11.7-cp313-cp313-win_arm64.whl", hash = "sha256:800988273a014a0541483dc81021247d7eacb0c845a9d1a34a422bc718f41539", size = 126045, upload-time = "2026-02-02T15:38:26.216Z" }, + { url = "https://files.pythonhosted.org/packages/e9/1e/745565dca749813db9a093c5ebc4bac1a9475c64d54b95654336ac3ed961/orjson-3.11.7-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:de0a37f21d0d364954ad5de1970491d7fbd0fb1ef7417d4d56a36dc01ba0c0a0", size = 228391, upload-time = "2026-02-02T15:38:27.757Z" }, + { url = "https://files.pythonhosted.org/packages/46/19/e40f6225da4d3aa0c8dc6e5219c5e87c2063a560fe0d72a88deb59776794/orjson-3.11.7-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:c2428d358d85e8da9d37cba18b8c4047c55222007a84f97156a5b22028dfbfc0", size = 125188, upload-time = "2026-02-02T15:38:29.241Z" }, + { url = "https://files.pythonhosted.org/packages/9d/7e/c4de2babef2c0817fd1f048fd176aa48c37bec8aef53d2fa932983032cce/orjson-3.11.7-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4bc6c6ac52cdaa267552544c73e486fecbd710b7ac09bc024d5a78555a22f6", size = 128097, upload-time = "2026-02-02T15:38:30.618Z" }, + { url = "https://files.pythonhosted.org/packages/eb/74/233d360632bafd2197f217eee7fb9c9d0229eac0c18128aee5b35b0014fe/orjson-3.11.7-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd0d68edd7dfca1b2eca9361a44ac9f24b078de3481003159929a0573f21a6bf", size = 123364, upload-time = "2026-02-02T15:38:32.363Z" }, + { url = "https://files.pythonhosted.org/packages/79/51/af79504981dd31efe20a9e360eb49c15f06df2b40e7f25a0a52d9ae888e8/orjson-3.11.7-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:623ad1b9548ef63886319c16fa317848e465a21513b31a6ad7b57443c3e0dcf5", size = 129076, upload-time = "2026-02-02T15:38:33.68Z" }, + { url = "https://files.pythonhosted.org/packages/67/e2/da898eb68b72304f8de05ca6715870d09d603ee98d30a27e8a9629abc64b/orjson-3.11.7-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6e776b998ac37c0396093d10290e60283f59cfe0fc3fccbd0ccc4bd04dd19892", size = 141705, upload-time = "2026-02-02T15:38:34.989Z" }, + { url = "https://files.pythonhosted.org/packages/c5/89/15364d92acb3d903b029e28d834edb8780c2b97404cbf7929aa6b9abdb24/orjson-3.11.7-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c6c3af76716f4a9c290371ba2e390ede06f6603edb277b481daf37f6f464e", size = 130855, upload-time = "2026-02-02T15:38:36.379Z" }, + { url = "https://files.pythonhosted.org/packages/c2/8b/ecdad52d0b38d4b8f514be603e69ccd5eacf4e7241f972e37e79792212ec/orjson-3.11.7-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a56df3239294ea5964adf074c54bcc4f0ccd21636049a2cf3ca9cf03b5d03cf1", size = 133386, upload-time = "2026-02-02T15:38:37.704Z" }, + { url = "https://files.pythonhosted.org/packages/b9/0e/45e1dcf10e17d0924b7c9162f87ec7b4ca79e28a0548acf6a71788d3e108/orjson-3.11.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bda117c4148e81f746655d5a3239ae9bd00cb7bc3ca178b5fc5a5997e9744183", size = 138295, upload-time = "2026-02-02T15:38:39.096Z" }, + { url = "https://files.pythonhosted.org/packages/63/d7/4d2e8b03561257af0450f2845b91fbd111d7e526ccdf737267108075e0ba/orjson-3.11.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:23d6c20517a97a9daf1d48b580fcdc6f0516c6f4b5038823426033690b4d2650", size = 408720, upload-time = "2026-02-02T15:38:40.634Z" }, + { url = "https://files.pythonhosted.org/packages/78/cf/d45343518282108b29c12a65892445fc51f9319dc3c552ceb51bb5905ed2/orjson-3.11.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8ff206156006da5b847c9304b6308a01e8cdbc8cce824e2779a5ba71c3def141", size = 144152, upload-time = "2026-02-02T15:38:42.262Z" }, + { url = "https://files.pythonhosted.org/packages/a9/3a/d6001f51a7275aacd342e77b735c71fa04125a3f93c36fee4526bc8c654e/orjson-3.11.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:962d046ee1765f74a1da723f4b33e3b228fe3a48bd307acce5021dfefe0e29b2", size = 134814, upload-time = "2026-02-02T15:38:43.627Z" }, + { url = "https://files.pythonhosted.org/packages/1d/d3/f19b47ce16820cc2c480f7f1723e17f6d411b3a295c60c8ad3aa9ff1c96a/orjson-3.11.7-cp314-cp314-win32.whl", hash = "sha256:89e13dd3f89f1c38a9c9eba5fbf7cdc2d1feca82f5f290864b4b7a6aac704576", size = 127997, upload-time = "2026-02-02T15:38:45.06Z" }, + { url = "https://files.pythonhosted.org/packages/12/df/172771902943af54bf661a8d102bdf2e7f932127968080632bda6054b62c/orjson-3.11.7-cp314-cp314-win_amd64.whl", hash = "sha256:845c3e0d8ded9c9271cd79596b9b552448b885b97110f628fb687aee2eed11c1", size = 124985, upload-time = "2026-02-02T15:38:46.388Z" }, + { url = "https://files.pythonhosted.org/packages/6f/1c/f2a8d8a1b17514660a614ce5f7aac74b934e69f5abc2700cc7ced882a009/orjson-3.11.7-cp314-cp314-win_arm64.whl", hash = "sha256:4a2e9c5be347b937a2e0203866f12bba36082e89b402ddb9e927d5822e43088d", size = 126038, upload-time = "2026-02-02T15:38:47.703Z" }, ] [[package]] @@ -1073,28 +1073,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.14.13" +version = "0.15.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/50/0a/1914efb7903174b381ee2ffeebb4253e729de57f114e63595114c8ca451f/ruff-0.14.13.tar.gz", hash = "sha256:83cd6c0763190784b99650a20fec7633c59f6ebe41c5cc9d45ee42749563ad47", size = 6059504, upload-time = "2026-01-15T20:15:16.918Z" } +sdist = { url = "https://files.pythonhosted.org/packages/04/dc/4e6ac71b511b141cf626357a3946679abeba4cf67bc7cc5a17920f31e10d/ruff-0.15.1.tar.gz", hash = "sha256:c590fe13fb57c97141ae975c03a1aedb3d3156030cabd740d6ff0b0d601e203f", size = 4540855, upload-time = "2026-02-12T23:09:09.998Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/ae/0deefbc65ca74b0ab1fd3917f94dc3b398233346a74b8bbb0a916a1a6bf6/ruff-0.14.13-py3-none-linux_armv6l.whl", hash = "sha256:76f62c62cd37c276cb03a275b198c7c15bd1d60c989f944db08a8c1c2dbec18b", size = 13062418, upload-time = "2026-01-15T20:14:50.779Z" }, - { url = "https://files.pythonhosted.org/packages/47/df/5916604faa530a97a3c154c62a81cb6b735c0cb05d1e26d5ad0f0c8ac48a/ruff-0.14.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:914a8023ece0528d5cc33f5a684f5f38199bbb566a04815c2c211d8f40b5d0ed", size = 13442344, upload-time = "2026-01-15T20:15:07.94Z" }, - { url = "https://files.pythonhosted.org/packages/4c/f3/e0e694dd69163c3a1671e102aa574a50357536f18a33375050334d5cd517/ruff-0.14.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d24899478c35ebfa730597a4a775d430ad0d5631b8647a3ab368c29b7e7bd063", size = 12354720, upload-time = "2026-01-15T20:15:09.854Z" }, - { url = "https://files.pythonhosted.org/packages/c3/e8/67f5fcbbaee25e8fc3b56cc33e9892eca7ffe09f773c8e5907757a7e3bdb/ruff-0.14.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9aaf3870f14d925bbaf18b8a2347ee0ae7d95a2e490e4d4aea6813ed15ebc80e", size = 12774493, upload-time = "2026-01-15T20:15:20.908Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ce/d2e9cb510870b52a9565d885c0d7668cc050e30fa2c8ac3fb1fda15c083d/ruff-0.14.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac5b7f63dd3b27cc811850f5ffd8fff845b00ad70e60b043aabf8d6ecc304e09", size = 12815174, upload-time = "2026-01-15T20:15:05.74Z" }, - { url = "https://files.pythonhosted.org/packages/88/00/c38e5da58beebcf4fa32d0ddd993b63dfacefd02ab7922614231330845bf/ruff-0.14.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78d2b1097750d90ba82ce4ba676e85230a0ed694178ca5e61aa9b459970b3eb9", size = 13680909, upload-time = "2026-01-15T20:15:14.537Z" }, - { url = "https://files.pythonhosted.org/packages/61/61/cd37c9dd5bd0a3099ba79b2a5899ad417d8f3b04038810b0501a80814fd7/ruff-0.14.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d0bf87705acbbcb8d4c24b2d77fbb73d40210a95c3903b443cd9e30824a5032", size = 15144215, upload-time = "2026-01-15T20:15:22.886Z" }, - { url = "https://files.pythonhosted.org/packages/56/8a/85502d7edbf98c2df7b8876f316c0157359165e16cdf98507c65c8d07d3d/ruff-0.14.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3eb5da8e2c9e9f13431032fdcbe7681de9ceda5835efee3269417c13f1fed5c", size = 14706067, upload-time = "2026-01-15T20:14:48.271Z" }, - { url = "https://files.pythonhosted.org/packages/7e/2f/de0df127feb2ee8c1e54354dc1179b4a23798f0866019528c938ba439aca/ruff-0.14.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:642442b42957093811cd8d2140dfadd19c7417030a7a68cf8d51fcdd5f217427", size = 14133916, upload-time = "2026-01-15T20:14:57.357Z" }, - { url = "https://files.pythonhosted.org/packages/0d/77/9b99686bb9fe07a757c82f6f95e555c7a47801a9305576a9c67e0a31d280/ruff-0.14.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4acdf009f32b46f6e8864af19cbf6841eaaed8638e65c8dac845aea0d703c841", size = 13859207, upload-time = "2026-01-15T20:14:55.111Z" }, - { url = "https://files.pythonhosted.org/packages/7d/46/2bdcb34a87a179a4d23022d818c1c236cb40e477faf0d7c9afb6813e5876/ruff-0.14.13-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:591a7f68860ea4e003917d19b5c4f5ac39ff558f162dc753a2c5de897fd5502c", size = 14043686, upload-time = "2026-01-15T20:14:52.841Z" }, - { url = "https://files.pythonhosted.org/packages/1a/a9/5c6a4f56a0512c691cf143371bcf60505ed0f0860f24a85da8bd123b2bf1/ruff-0.14.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:774c77e841cc6e046fc3e91623ce0903d1cd07e3a36b1a9fe79b81dab3de506b", size = 12663837, upload-time = "2026-01-15T20:15:18.921Z" }, - { url = "https://files.pythonhosted.org/packages/fe/bb/b920016ece7651fa7fcd335d9d199306665486694d4361547ccb19394c44/ruff-0.14.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:61f4e40077a1248436772bb6512db5fc4457fe4c49e7a94ea7c5088655dd21ae", size = 12805867, upload-time = "2026-01-15T20:14:59.272Z" }, - { url = "https://files.pythonhosted.org/packages/7d/b3/0bd909851e5696cd21e32a8fc25727e5f58f1934b3596975503e6e85415c/ruff-0.14.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6d02f1428357fae9e98ac7aa94b7e966fd24151088510d32cf6f902d6c09235e", size = 13208528, upload-time = "2026-01-15T20:15:03.732Z" }, - { url = "https://files.pythonhosted.org/packages/3b/3b/e2d94cb613f6bbd5155a75cbe072813756363eba46a3f2177a1fcd0cd670/ruff-0.14.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e399341472ce15237be0c0ae5fbceca4b04cd9bebab1a2b2c979e015455d8f0c", size = 13929242, upload-time = "2026-01-15T20:15:11.918Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c5/abd840d4132fd51a12f594934af5eba1d5d27298a6f5b5d6c3be45301caf/ruff-0.14.13-py3-none-win32.whl", hash = "sha256:ef720f529aec113968b45dfdb838ac8934e519711da53a0456038a0efecbd680", size = 12919024, upload-time = "2026-01-15T20:14:43.647Z" }, - { url = "https://files.pythonhosted.org/packages/c2/55/6384b0b8ce731b6e2ade2b5449bf07c0e4c31e8a2e68ea65b3bafadcecc5/ruff-0.14.13-py3-none-win_amd64.whl", hash = "sha256:6070bd026e409734b9257e03e3ef18c6e1a216f0435c6751d7a8ec69cb59abef", size = 14097887, upload-time = "2026-01-15T20:15:01.48Z" }, - { url = "https://files.pythonhosted.org/packages/4d/e1/7348090988095e4e39560cfc2f7555b1b2a7357deba19167b600fdf5215d/ruff-0.14.13-py3-none-win_arm64.whl", hash = "sha256:7ab819e14f1ad9fe39f246cfcc435880ef7a9390d81a2b6ac7e01039083dd247", size = 13080224, upload-time = "2026-01-15T20:14:45.853Z" }, + { url = "https://files.pythonhosted.org/packages/23/bf/e6e4324238c17f9d9120a9d60aa99a7daaa21204c07fcd84e2ef03bb5fd1/ruff-0.15.1-py3-none-linux_armv6l.whl", hash = "sha256:b101ed7cf4615bda6ffe65bdb59f964e9f4a0d3f85cbf0e54f0ab76d7b90228a", size = 10367819, upload-time = "2026-02-12T23:09:03.598Z" }, + { url = "https://files.pythonhosted.org/packages/b3/ea/c8f89d32e7912269d38c58f3649e453ac32c528f93bb7f4219258be2e7ed/ruff-0.15.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:939c995e9277e63ea632cc8d3fae17aa758526f49a9a850d2e7e758bfef46602", size = 10798618, upload-time = "2026-02-12T23:09:22.928Z" }, + { url = "https://files.pythonhosted.org/packages/5e/0f/1d0d88bc862624247d82c20c10d4c0f6bb2f346559d8af281674cf327f15/ruff-0.15.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1d83466455fdefe60b8d9c8df81d3c1bbb2115cede53549d3b522ce2bc703899", size = 10148518, upload-time = "2026-02-12T23:08:58.339Z" }, + { url = "https://files.pythonhosted.org/packages/f5/c8/291c49cefaa4a9248e986256df2ade7add79388fe179e0691be06fae6f37/ruff-0.15.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9457e3c3291024866222b96108ab2d8265b477e5b1534c7ddb1810904858d16", size = 10518811, upload-time = "2026-02-12T23:09:31.865Z" }, + { url = "https://files.pythonhosted.org/packages/c3/1a/f5707440e5ae43ffa5365cac8bbb91e9665f4a883f560893829cf16a606b/ruff-0.15.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:92c92b003e9d4f7fbd33b1867bb15a1b785b1735069108dfc23821ba045b29bc", size = 10196169, upload-time = "2026-02-12T23:09:17.306Z" }, + { url = "https://files.pythonhosted.org/packages/2a/ff/26ddc8c4da04c8fd3ee65a89c9fb99eaa5c30394269d424461467be2271f/ruff-0.15.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fe5c41ab43e3a06778844c586251eb5a510f67125427625f9eb2b9526535779", size = 10990491, upload-time = "2026-02-12T23:09:25.503Z" }, + { url = "https://files.pythonhosted.org/packages/fc/00/50920cb385b89413f7cdb4bb9bc8fc59c1b0f30028d8bccc294189a54955/ruff-0.15.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66a6dd6df4d80dc382c6484f8ce1bcceb55c32e9f27a8b94c32f6c7331bf14fb", size = 11843280, upload-time = "2026-02-12T23:09:19.88Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6d/2f5cad8380caf5632a15460c323ae326f1e1a2b5b90a6ee7519017a017ca/ruff-0.15.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a4a42cbb8af0bda9bcd7606b064d7c0bc311a88d141d02f78920be6acb5aa83", size = 11274336, upload-time = "2026-02-12T23:09:14.907Z" }, + { url = "https://files.pythonhosted.org/packages/a3/1d/5f56cae1d6c40b8a318513599b35ea4b075d7dc1cd1d04449578c29d1d75/ruff-0.15.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ab064052c31dddada35079901592dfba2e05f5b1e43af3954aafcbc1096a5b2", size = 11137288, upload-time = "2026-02-12T23:09:07.475Z" }, + { url = "https://files.pythonhosted.org/packages/cd/20/6f8d7d8f768c93b0382b33b9306b3b999918816da46537d5a61635514635/ruff-0.15.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:5631c940fe9fe91f817a4c2ea4e81f47bee3ca4aa646134a24374f3c19ad9454", size = 11070681, upload-time = "2026-02-12T23:08:55.43Z" }, + { url = "https://files.pythonhosted.org/packages/9a/67/d640ac76069f64cdea59dba02af2e00b1fa30e2103c7f8d049c0cff4cafd/ruff-0.15.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:68138a4ba184b4691ccdc39f7795c66b3c68160c586519e7e8444cf5a53e1b4c", size = 10486401, upload-time = "2026-02-12T23:09:27.927Z" }, + { url = "https://files.pythonhosted.org/packages/65/3d/e1429f64a3ff89297497916b88c32a5cc88eeca7e9c787072d0e7f1d3e1e/ruff-0.15.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:518f9af03bfc33c03bdb4cb63fabc935341bb7f54af500f92ac309ecfbba6330", size = 10197452, upload-time = "2026-02-12T23:09:12.147Z" }, + { url = "https://files.pythonhosted.org/packages/78/83/e2c3bade17dad63bf1e1c2ffaf11490603b760be149e1419b07049b36ef2/ruff-0.15.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:da79f4d6a826caaea95de0237a67e33b81e6ec2e25fc7e1993a4015dffca7c61", size = 10693900, upload-time = "2026-02-12T23:09:34.418Z" }, + { url = "https://files.pythonhosted.org/packages/a1/27/fdc0e11a813e6338e0706e8b39bb7a1d61ea5b36873b351acee7e524a72a/ruff-0.15.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3dd86dccb83cd7d4dcfac303ffc277e6048600dfc22e38158afa208e8bf94a1f", size = 11227302, upload-time = "2026-02-12T23:09:36.536Z" }, + { url = "https://files.pythonhosted.org/packages/f6/58/ac864a75067dcbd3b95be5ab4eb2b601d7fbc3d3d736a27e391a4f92a5c1/ruff-0.15.1-py3-none-win32.whl", hash = "sha256:660975d9cb49b5d5278b12b03bb9951d554543a90b74ed5d366b20e2c57c2098", size = 10462555, upload-time = "2026-02-12T23:09:29.899Z" }, + { url = "https://files.pythonhosted.org/packages/e0/5e/d4ccc8a27ecdb78116feac4935dfc39d1304536f4296168f91ed3ec00cd2/ruff-0.15.1-py3-none-win_amd64.whl", hash = "sha256:c820fef9dd5d4172a6570e5721704a96c6679b80cf7be41659ed439653f62336", size = 11599956, upload-time = "2026-02-12T23:09:01.157Z" }, + { url = "https://files.pythonhosted.org/packages/2a/07/5bda6a85b220c64c65686bc85bd0bbb23b29c62b3a9f9433fa55f17cda93/ruff-0.15.1-py3-none-win_arm64.whl", hash = "sha256:5ff7d5f0f88567850f45081fac8f4ec212be8d0b963e385c3f7d0d2eb4899416", size = 10874604, upload-time = "2026-02-12T23:09:05.515Z" }, ] [[package]] From 72be9b23ee86218c85536e27d05502ca439ee2da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 01:02:33 -0800 Subject: [PATCH 11/41] chore(deps): bump the all-dependencies group in /libs/checkpoint with 4 updates (#6812) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the all-dependencies group in /libs/checkpoint with 4 updates: [langchain-core](https://github.com/langchain-ai/langchain), [ormsgpack](https://github.com/ormsgpack/ormsgpack), [redis](https://github.com/redis/redis-py) and [ruff](https://github.com/astral-sh/ruff). Updates `langchain-core` from 1.2.7 to 1.2.12
Release notes

Sourced from langchain-core's releases.

langchain-core==1.2.12

Changes since langchain-core==1.2.11

release(core): 1.2.12 (#35192) fix(core): fix setting ChatGeneration.text (#35191)

langchain-core==1.2.11

Changes since langchain-core==1.2.10

release(core): 1.2.11 (#35144) fix(openai): sanitize urls when counting tokens in images (#35143) chore(core): clean up docstring mismatch and redundant logic in langchain-core (#35064) fix(core): replace bare except with Exception in tracer (#35138)

langchain-core==1.2.10

Changes since langchain-core==1.2.9

release(core): 1.2.10 (#35136) chore(deps): bump the langchain-deps group across 3 directories with 40 updates (#35129) chore(deps): bump the langchain-deps group across 3 directories with 11 updates (#35121) feat(core): add ContextOverflowError, raise in anthropic and openai (#35099) feat(model-profiles): add text_inputs and text_outputs (#35084) feat(core): count tokens from tool schemas in count_tokens_approximately (#35098) docs(core): add missing name docstring for RunnableSerializable (#35088)

langchain-core==1.2.9

Changes since langchain-core==1.2.8

release(core): 1.2.9 (#35025) fix(core): adjust cap when scaling approximate token counts (#35017) revert: precompile hex color regex pattern at module level (#35016) chore: add make type target (#35015) revert: "chore: add typing target in Makefile" (#35013) chore: add typing target in Makefile (#35012) fix(core): apply cap when scaling approximate token counts (#35005) feat(core): allow scaling by reported usage when counting tokens approximately (#34996) test(core): increase delta_time for flaky test (#34982) chore: enrich pyproject.toml files (#34980)

langchain-core==1.2.8

Changes since langchain-core==1.2.7

release(core): 1.2.8 (#34975) docs(core): add examples for pretty_repr, pretty_print (#34968) docs(core): use proper admonition for get_buffer_string (#34967) docs: add usage examples to core classes (#34841) chore(core): fix docstring format (#34966) chore(deps): bump the uv group across 20 directories with 3 updates (#34941) docs: add example to create_message function docstring (#34851) docs(core): clarify @​tool decorator argument and return type requirements (#34860)

... (truncated)

Commits
  • b06716f release(core): 1.2.12 (#35192)
  • 16cabfa fix(core): fix setting ChatGeneration.text (#35191)
  • 8f859bd release(huggingface): 1.2.1 (#35182)
  • 19ddd42 fix(ollama): raise error when clients are not initialized (#35185)
  • a50d86c docs(langchain-classic): clarify MultiVectorRetriever usage (#35053)
  • f89e30e chore(huggingface): version bump for huggingface-hub and transformers deps (#...
  • 6ac12b3 chore: bump pillow from 11.3.0 to 12.1.1 in /libs/partners/openai (#35177)
  • d41deda fix(langchain-classic): validate ensemble retriever weights (#35078)
  • 9d0bd83 chore: bump pillow from 11.3.0 to 12.1.1 in /libs/partners/perplexity (#35176)
  • f22f5d5 chore(deps): bump pillow from 11.3.0 to 12.1.1 in /libs/langchain (#35175)
  • Additional commits viewable in compare view

Updates `ormsgpack` from 1.12.1 to 1.12.2
Release notes

Sourced from ormsgpack's releases.

1.12.2

Changed

  • Add Python 3.14 free-threaded Windows x86_64 wheel
  • Improve serialization performance
  • Update dependencies

Fixed

  • Fix unpackb crash on Windows with Python 3.14 free-threaded and on Linux s390x (#499)
Changelog

Sourced from ormsgpack's changelog.

1.12.2 - 2026-01-18

Changed


- Add Python 3.14 free-threaded Windows x86_64 wheel
- Improve serialization performance
- Update dependencies

Fixed


- Fix ``unpackb`` crash on Windows with Python 3.14 free-threaded and
  on Linux s390x (:issue:`499`)
</code></pre>
</blockquote>
</details>
<details>
<summary>Commits</summary>

<ul>
<li><a
href="https://github.com/ormsgpack/ormsgpack/commit/9645772ab1e19420fa509197a95fb40fcc92fe9f"><code>9645772</code></a>
1.12.2</li>
<li><a
href="https://github.com/ormsgpack/ormsgpack/commit/cfc189fe17ea41cce9baffff0c55da105fce0d2e"><code>cfc189f</code></a>
Update Changelog</li>
<li><a
href="https://github.com/ormsgpack/ormsgpack/commit/cf8c3bb3988e063f628e62e3ead0de24c3a95381"><code>cf8c3bb</code></a>
Lint docs</li>
<li><a
href="https://github.com/ormsgpack/ormsgpack/commit/cc6e45a07d5cb13098da5752cc552deed525c8f6"><code>cc6e45a</code></a>
Update development dependencies</li>
<li><a
href="https://github.com/ormsgpack/ormsgpack/commit/42f501fc0fdbb86601bcecafd77e0096e41b266f"><code>42f501f</code></a>
Update dependencies</li>
<li><a
href="https://github.com/ormsgpack/ormsgpack/commit/6e621b8abcfa48cd9b4248bb5889baf3fdca06d3"><code>6e621b8</code></a>
Update repository url</li>
<li><a
href="https://github.com/ormsgpack/ormsgpack/commit/079c7fcf9b96d5c869af106c61d156f06bd5f6cd"><code>079c7fc</code></a>
Bump urllib3 from 2.6.0 to 2.6.3</li>
<li><a
href="https://github.com/ormsgpack/ormsgpack/commit/4bb944cf066fca788024ebd3614164627daeac33"><code>4bb944c</code></a>
Bump ruff from 0.14.11 to 0.14.12 in the uv group</li>
<li><a
href="https://github.com/ormsgpack/ormsgpack/commit/2f447c2475c60f0e966428825229f456734a35dc"><code>2f447c2</code></a>
Trigger workflows on merge group events</li>
<li><a
href="https://github.com/ormsgpack/ormsgpack/commit/2acc85d4437bcf6baa3a4f16fe333e46c97d7a66"><code>2acc85d</code></a>
Bump chrono from 0.4.42 to 0.4.43</li>
<li>Additional commits viewable in <a
href="https://github.com/ormsgpack/ormsgpack/compare/1.12.1...1.12.2">compare
view</a></li>
</ul>
</details>

<br />
Updates `redis` from 7.1.0 to 7.1.1
Release notes

Sourced from redis's releases.

7.1.1

Changes

🧪 Experimental Features

  • Added initial health check policies, refactored add_database method (#3906)

🧰 Maintenance

  • Disabled SCH in MultiDBClient underlying clients by default (#3938)
  • Added logging for MultiDBClients (#3865 #3896)

We'd like to thank all the contributors who worked on this release! @​vladvildanov

Commits

Updates `ruff` from 0.14.13 to 0.15.1
Release notes

Sourced from ruff's releases.

0.15.1

Release Notes

Released on 2026-02-12.

Preview features

  • [airflow] Add ruff rules to catch deprecated Airflow imports for Airflow 3.1 (AIR321) (#22376)
  • [airflow] Third positional parameter not named ti_key should be flagged for BaseOperatorLink.get_link (AIR303) (#22828)
  • [flake8-gettext] Fix false negatives for plural argument of ngettext (INT001, INT002, INT003) (#21078)
  • [pyflakes] Fix infinite loop in preview fix for unused-import (F401) (#23038)
  • [pygrep-hooks] Detect non-existent mock methods in standalone expressions (PGH005) (#22830)
  • [pylint] Allow dunder submodules and improve diagnostic range (PLC2701) (#22804)
  • [pyupgrade] Improve diagnostic range for tuples (UP024) (#23013)
  • [refurb] Check subscripts in tuple do not use lambda parameters in reimplemented-operator (FURB118) (#23079)
  • [ruff] Detect mutable defaults in field calls (RUF008) (#23046)
  • [ruff] Ignore std cmath.inf (RUF069) (#23120)
  • [ruff] New rule float-equality-comparison (RUF069) (#20585)
  • Don't format unlabeled Markdown code blocks (#23106)
  • Markdown formatting support in LSP (#23063)
  • Support Quarto Markdown language markers (#22947)
  • Support formatting pycon Markdown code blocks (#23112)
  • Use extension mapping to select Markdown code block language (#22934)

Bug fixes

  • Avoid false positive for undefined variables in FAST001 (#23224)
  • Avoid introducing syntax errors for FAST003 autofix (#23227)
  • Avoid suggesting InitVar for __post_init__ that references PEP 695 type parameters (#23226)
  • Deduplicate type variables in generic functions (#23225)
  • Fix exception handler parenthesis removal for Python 3.14+ (#23126)
  • Fix f-string middle panic when parsing t-strings (#23232)
  • Wrap RUF020 target for multiline fixes (#23210)
  • Wrap UP007 target for multiline fixes (#23208)
  • Fix missing diagnostics for last range suppression in file (#23242)
  • [pyupgrade] Fix syntax error on string with newline escape and comment (UP037) (#22968)

Rule changes

  • Use ruff instead of Ruff as the program name in GitHub output format (#23240)
  • [PT006] Fix syntax error when unpacking nested tuples in parametrize fixes (#22441) (#22464)
  • [airflow] Catch deprecated attribute access from context key for Airflow 3.0 (AIR301) (#22850)
  • [airflow] Capture deprecated arguments and a decorator (AIR301) (#23170)
  • [flake8-boolean-trap] Add multiprocessing.Value to excluded functions for FBT003 (#23010)
  • [flake8-bugbear] Add a secondary annotation showing the previous occurrence (B033) (#22634)
  • [flake8-type-checking] Add sub-diagnostic showing the runtime use of an annotation (TC004) (#23091)
  • [isort] Support configurable import section heading comments (#23151)
  • [ruff] Improve the diagnostic for RUF012 (#23202)

Formatter

... (truncated)

Changelog

Sourced from ruff's changelog.

0.15.1

Released on 2026-02-12.

Preview features

  • [airflow] Add ruff rules to catch deprecated Airflow imports for Airflow 3.1 (AIR321) (#22376)
  • [airflow] Third positional parameter not named ti_key should be flagged for BaseOperatorLink.get_link (AIR303) (#22828)
  • [flake8-gettext] Fix false negatives for plural argument of ngettext (INT001, INT002, INT003) (#21078)
  • [pyflakes] Fix infinite loop in preview fix for unused-import (F401) (#23038)
  • [pygrep-hooks] Detect non-existent mock methods in standalone expressions (PGH005) (#22830)
  • [pylint] Allow dunder submodules and improve diagnostic range (PLC2701) (#22804)
  • [pyupgrade] Improve diagnostic range for tuples (UP024) (#23013)
  • [refurb] Check subscripts in tuple do not use lambda parameters in reimplemented-operator (FURB118) (#23079)
  • [ruff] Detect mutable defaults in field calls (RUF008) (#23046)
  • [ruff] Ignore std cmath.inf (RUF069) (#23120)
  • [ruff] New rule float-equality-comparison (RUF069) (#20585)
  • Don't format unlabeled Markdown code blocks (#23106)
  • Markdown formatting support in LSP (#23063)
  • Support Quarto Markdown language markers (#22947)
  • Support formatting pycon Markdown code blocks (#23112)
  • Use extension mapping to select Markdown code block language (#22934)

Bug fixes

  • Avoid false positive for undefined variables in FAST001 (#23224)
  • Avoid introducing syntax errors for FAST003 autofix (#23227)
  • Avoid suggesting InitVar for __post_init__ that references PEP 695 type parameters (#23226)
  • Deduplicate type variables in generic functions (#23225)
  • Fix exception handler parenthesis removal for Python 3.14+ (#23126)
  • Fix f-string middle panic when parsing t-strings (#23232)
  • Wrap RUF020 target for multiline fixes (#23210)
  • Wrap UP007 target for multiline fixes (#23208)
  • Fix missing diagnostics for last range suppression in file (#23242)
  • [pyupgrade] Fix syntax error on string with newline escape and comment (UP037) (#22968)

Rule changes

  • Use ruff instead of Ruff as the program name in GitHub output format (#23240)
  • [PT006] Fix syntax error when unpacking nested tuples in parametrize fixes (#22441) (#22464)
  • [airflow] Catch deprecated attribute access from context key for Airflow 3.0 (AIR301) (#22850)
  • [airflow] Capture deprecated arguments and a decorator (AIR301) (#23170)
  • [flake8-boolean-trap] Add multiprocessing.Value to excluded functions for FBT003 (#23010)
  • [flake8-bugbear] Add a secondary annotation showing the previous occurrence (B033) (#22634)
  • [flake8-type-checking] Add sub-diagnostic showing the runtime use of an annotation (TC004) (#23091)
  • [isort] Support configurable import section heading comments (#23151)
  • [ruff] Improve the diagnostic for RUF012 (#23202)

Formatter

... (truncated)

Commits
  • a2f11d2 Prepare for 0.15.1 (#23253)
  • d29628e Remove docker-run-action (#23254)
  • 8a04266 [ty] Allow discovering dependencies in system Python environments (#22994)
  • 55d06c8 Ensure pending suppression diagnostics are reported (#23242)
  • d056a9f [isort] support for configurable import section heading comments (#23151)
  • e22fa4f [ty] Fix method calls on subclasses of Any (#23248)
  • fa56c15 [ty] Fix bound method access on None (#23246)
  • 4fd07d0 Make range suppression test snapshot actually useful (#23251)
  • 8c63bce [ty] Include conditional symbols (like datetime.UTC) in auto-import in more...
  • 46be943 Exclude WASM artifacts from GitHub releases (#23221)
  • Additional commits viewable in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- libs/checkpoint/uv.lock | 150 ++++++++++++++++++++-------------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/libs/checkpoint/uv.lock b/libs/checkpoint/uv.lock index 53c4f12e5..206d40d37 100644 --- a/libs/checkpoint/uv.lock +++ b/libs/checkpoint/uv.lock @@ -267,7 +267,7 @@ wheels = [ [[package]] name = "langchain-core" -version = "1.2.7" +version = "1.2.12" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsonpatch" }, @@ -279,9 +279,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "uuid-utils" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a2/0e/664d8d81b3493e09cbab72448d2f9d693d1fa5aa2bcc488602203a9b6da0/langchain_core-1.2.7.tar.gz", hash = "sha256:e1460639f96c352b4a41c375f25aeb8d16ffc1769499fb1c20503aad59305ced", size = 837039, upload-time = "2026-01-09T17:44:25.505Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/1d/08e935d1532fcc90981f6e5bb6825914c9227ea7a962c62b1e18619b49e7/langchain_core-1.2.12.tar.gz", hash = "sha256:4d7fa6643d7ab06fc1905a9b7dcbe96a6f3c181046b56edf9c0c17ecd412d9e9", size = 831329, upload-time = "2026-02-12T20:53:15.01Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/6f/34a9fba14d191a67f7e2ee3dbce3e9b86d2fa7310e2c7f2c713583481bd2/langchain_core-1.2.7-py3-none-any.whl", hash = "sha256:452f4fef7a3d883357b22600788d37e3d8854ef29da345b7ac7099f33c31828b", size = 490232, upload-time = "2026-01-09T17:44:24.236Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a5/678ab0e5cc57794f20ae5ed12c1442506ef1108c9434f950aebc6044e5a3/langchain_core-1.2.12-py3-none-any.whl", hash = "sha256:66ca17a2a9cb007ab29021968e6adfcf4228067151dc2bd6ebfff265ffaf92f5", size = 500132, upload-time = "2026-02-12T20:53:13.806Z" }, ] [[package]] @@ -755,57 +755,58 @@ wheels = [ [[package]] name = "ormsgpack" -version = "1.12.1" +version = "1.12.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/96/34c40d621996c2f377a18decbd3c59f031dde73c3ba47d1e1e8f29a05aaa/ormsgpack-1.12.1.tar.gz", hash = "sha256:a3877fde1e4f27a39f92681a0aab6385af3a41d0c25375d33590ae20410ea2ac", size = 39476, upload-time = "2025-12-14T07:57:43.248Z" } +sdist = { url = "https://files.pythonhosted.org/packages/12/0c/f1761e21486942ab9bb6feaebc610fa074f7c5e496e6962dea5873348077/ormsgpack-1.12.2.tar.gz", hash = "sha256:944a2233640273bee67521795a73cf1e959538e0dfb7ac635505010455e53b33", size = 39031, upload-time = "2026-01-18T20:55:28.023Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/da/caf25cc54d6870089a0b5614c4c5914dd3fae45f9f7f84a32445ad0612e3/ormsgpack-1.12.1-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:62e3614cab63fa5aa42f5f0ca3cd12899f0bfc5eb8a5a0ebab09d571c89d427d", size = 376182, upload-time = "2025-12-14T07:56:46.094Z" }, - { url = "https://files.pythonhosted.org/packages/fc/02/ccc9170c6bee86f428707f15b5ad68d42c71d43856e1b8e37cdfea50af5b/ormsgpack-1.12.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86d9fbf85c05c69c33c229d2eba7c8c3500a56596cd8348131c918acd040d6af", size = 202339, upload-time = "2025-12-14T07:56:47.609Z" }, - { url = "https://files.pythonhosted.org/packages/86/c7/10309a5a6421adaedab710a72470143d664bb0a043cc095c1311878325a0/ormsgpack-1.12.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8d246e66f09d8e0f96e770829149ee83206e90ed12f5987998bb7be84aec99fe", size = 210720, upload-time = "2025-12-14T07:56:48.66Z" }, - { url = "https://files.pythonhosted.org/packages/1b/b4/92a0f7a00c5f0c71b51dc3112e53b1ca937b9891a08979d06524db11b799/ormsgpack-1.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfc2c830a1ed2d00de713d08c9e62efa699e8fd29beafa626aaebe466f583ebb", size = 211264, upload-time = "2025-12-14T07:56:49.976Z" }, - { url = "https://files.pythonhosted.org/packages/33/fa/5cce85c8e58fcaa048c75fbbe37816a1b3fb58ba4289a7dedc4f4ed9ce82/ormsgpack-1.12.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc892757d8f9eea5208268a527cf93c98409802f6a9f7c8d71a7b8f9ba5cb944", size = 386076, upload-time = "2025-12-14T07:56:51.74Z" }, - { url = "https://files.pythonhosted.org/packages/88/d0/f18d258c733eb22eadad748659f7984d0b6a851fb3deefcb33f50e9a947a/ormsgpack-1.12.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0de1dbcf11ea739ac4a882b43d5c2055e6d99ce64e8d6502e25d6d881700c017", size = 479570, upload-time = "2025-12-14T07:56:52.912Z" }, - { url = "https://files.pythonhosted.org/packages/3f/3a/b362dff090f4740090fe51d512f24b1e320d1f96497ebf9248e2a04ac88f/ormsgpack-1.12.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d5065dfb9ec4db93241c60847624d9aeef4ccb449c26a018c216b55c69be83c0", size = 387859, upload-time = "2025-12-14T07:56:53.968Z" }, - { url = "https://files.pythonhosted.org/packages/7c/8a/d948965598b2b7872800076da5c02573aa72f716be57a3d4fe60490b2a2a/ormsgpack-1.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:7d17103c4726181d7000c61b751c881f1b6f401d146df12da028fc730227df19", size = 115906, upload-time = "2025-12-14T07:56:55.068Z" }, - { url = "https://files.pythonhosted.org/packages/57/e2/f5b89365c8dc8025c27d31316038f1c103758ddbf87dc0fa8e3f78f66907/ormsgpack-1.12.1-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4038f59ae0e19dac5e5d9aae4ec17ff84a79e046342ee73ccdecf3547ecf0d34", size = 376180, upload-time = "2025-12-14T07:56:56.521Z" }, - { url = "https://files.pythonhosted.org/packages/ca/87/3f694e06f5e32c6d65066f53b4a025282a5072b6b336c17560b00e04606d/ormsgpack-1.12.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16c63b0c5a3eec467e4bb33a14dabba076b7d934dff62898297b5c0b5f7c3cb3", size = 202338, upload-time = "2025-12-14T07:56:57.585Z" }, - { url = "https://files.pythonhosted.org/packages/e5/f5/6d95d7b7c11f97a92522082fc7e5d1ab34537929f1e13f4c369f392f19d0/ormsgpack-1.12.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:74fd6a8e037eb310dda865298e8d122540af00fe5658ec18b97a1d34f4012e4d", size = 210720, upload-time = "2025-12-14T07:56:58.968Z" }, - { url = "https://files.pythonhosted.org/packages/2b/9d/9a49a2686f8b7165dcb2342b8554951263c30c0f0825f1fcc2d56e736a6b/ormsgpack-1.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58ad60308e233dd824a1859eabb5fe092e123e885eafa4ad5789322329c80fb5", size = 211264, upload-time = "2025-12-14T07:57:00.099Z" }, - { url = "https://files.pythonhosted.org/packages/02/31/2fdc36eaeca2182900b96fc7b19755f293283fe681750e3d295733d62f0e/ormsgpack-1.12.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:35127464c941c1219acbe1a220e48d55e7933373d12257202f4042f7044b4c90", size = 386081, upload-time = "2025-12-14T07:57:01.177Z" }, - { url = "https://files.pythonhosted.org/packages/f0/65/0a765432f08ae26b4013c6a9aed97be17a9ef85f1600948a474b518e27dd/ormsgpack-1.12.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c48d1c50794692d1e6e3f8c3bb65f5c3acfaae9347e506484a65d60b3d91fb50", size = 479572, upload-time = "2025-12-14T07:57:02.738Z" }, - { url = "https://files.pythonhosted.org/packages/4e/4f/f2f15ebef786ad71cea420bf8692448fbddf04d1bf3feaa68bd5ee3172e6/ormsgpack-1.12.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b512b2ad6feaaefdc26e05431ed2843e42483041e354e167c53401afaa83d919", size = 387862, upload-time = "2025-12-14T07:57:03.842Z" }, - { url = "https://files.pythonhosted.org/packages/15/eb/86fbef1d605fa91ecef077f93f9d0e34fc39b23475dfe3ffb92f6c8db28d/ormsgpack-1.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:93f30db95e101a9616323bfc50807ad00e7f6197cea2216d2d24af42afc77d88", size = 115900, upload-time = "2025-12-14T07:57:05.137Z" }, - { url = "https://files.pythonhosted.org/packages/5b/67/7ba1a46e6a6e263fc42a4fafc24afc1ab21a66116553cad670426f0bd9ef/ormsgpack-1.12.1-cp311-cp311-win_arm64.whl", hash = "sha256:d75b5fa14f6abffce2c392ee03b4731199d8a964c81ee8645c4c79af0e80fd50", size = 109868, upload-time = "2025-12-14T07:57:06.834Z" }, - { url = "https://files.pythonhosted.org/packages/17/fe/ab9167ca037406b5703add24049cf3e18021a3b16133ea20615b1f160ea4/ormsgpack-1.12.1-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4d7fb0e1b6fbc701d75269f7405a4f79230a6ce0063fb1092e4f6577e312f86d", size = 376725, upload-time = "2025-12-14T07:57:07.894Z" }, - { url = "https://files.pythonhosted.org/packages/c7/ea/2820e65f506894c459b840d1091ae6e327fde3d5a3f3b002a11a1b9bdf7d/ormsgpack-1.12.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43a9353e2db5b024c91a47d864ef15eaa62d81824cfc7740fed4cef7db738694", size = 202466, upload-time = "2025-12-14T07:57:09.049Z" }, - { url = "https://files.pythonhosted.org/packages/45/8b/def01c13339c5bbec2ee1469ef53e7fadd66c8d775df974ee4def1572515/ormsgpack-1.12.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fc8fe866b7706fc25af0adf1f600bc06ece5b15ca44e34641327198b821e5c3c", size = 210748, upload-time = "2025-12-14T07:57:10.074Z" }, - { url = "https://files.pythonhosted.org/packages/5d/d2/bf350c92f7f067dd9484499705f2d8366d8d9008a670e3d1d0add1908f85/ormsgpack-1.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:813755b5f598a78242042e05dfd1ada4e769e94b98c9ab82554550f97ff4d641", size = 211510, upload-time = "2025-12-14T07:57:11.165Z" }, - { url = "https://files.pythonhosted.org/packages/74/92/9d689bcb95304a6da26c4d59439c350940c25d1b35f146d402ccc6344c51/ormsgpack-1.12.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8eea2a13536fae45d78f93f2cc846c9765c7160c85f19cfefecc20873c137cdd", size = 386237, upload-time = "2025-12-14T07:57:12.306Z" }, - { url = "https://files.pythonhosted.org/packages/17/fe/bd3107547f8b6129265dd957f40b9cd547d2445db2292aacb13335a7ea89/ormsgpack-1.12.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7a02ebda1a863cbc604740e76faca8eee1add322db2dcbe6cf32669fffdff65c", size = 479589, upload-time = "2025-12-14T07:57:13.475Z" }, - { url = "https://files.pythonhosted.org/packages/c1/7c/e8e5cc9edb967d44f6f85e9ebdad440b59af3fae00b137a4327dc5aed9bb/ormsgpack-1.12.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3c0bd63897c439931cdf29348e5e6e8c330d529830e848d10767615c0f3d1b82", size = 388077, upload-time = "2025-12-14T07:57:14.551Z" }, - { url = "https://files.pythonhosted.org/packages/35/6b/5031797e43b58506f28a8760b26dc23f2620fb4f2200c4c1b3045603e67e/ormsgpack-1.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:362f2e812f8d7035dc25a009171e09d7cc97cb30d3c9e75a16aeae00ca3c1dcf", size = 116190, upload-time = "2025-12-14T07:57:15.575Z" }, - { url = "https://files.pythonhosted.org/packages/1e/fd/9f43ea6425e383a6b2dbfafebb06fd60e8d68c700ef715adfbcdb499f75d/ormsgpack-1.12.1-cp312-cp312-win_arm64.whl", hash = "sha256:6190281e381db2ed0045052208f47a995ccf61eed48f1215ae3cce3fbccd59c5", size = 109990, upload-time = "2025-12-14T07:57:16.419Z" }, - { url = "https://files.pythonhosted.org/packages/11/42/f110dfe7cf23a52a82e23eb23d9a6a76ae495447d474686dfa758f3d71d6/ormsgpack-1.12.1-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:9663d6b3ecc917c063d61a99169ce196a80f3852e541ae404206836749459279", size = 376746, upload-time = "2025-12-14T07:57:17.699Z" }, - { url = "https://files.pythonhosted.org/packages/11/76/b386e508a8ae207daec240201a81adb26467bf99b163560724e86bd9ff33/ormsgpack-1.12.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32e85cfbaf01a94a92520e7fe7851cfcfe21a5698299c28ab86194895f9b9233", size = 202489, upload-time = "2025-12-14T07:57:18.807Z" }, - { url = "https://files.pythonhosted.org/packages/ea/0e/5db7a63f387149024572daa3d9512fe8fb14bf4efa0722d6d491bed280e7/ormsgpack-1.12.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dabfd2c24b59c7c69870a5ecee480dfae914a42a0c2e7c9d971cf531e2ba471a", size = 210757, upload-time = "2025-12-14T07:57:19.893Z" }, - { url = "https://files.pythonhosted.org/packages/64/79/3a9899e57cb57430bd766fc1b4c9ad410cb2ba6070bc8cf6301e7d385768/ormsgpack-1.12.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51bbf2b64afeded34ccd8e25402e4bca038757913931fa0d693078d75563f6f9", size = 211518, upload-time = "2025-12-14T07:57:20.972Z" }, - { url = "https://files.pythonhosted.org/packages/d7/cd/4f41710ae9fe50d7fcbe476793b3c487746d0e1cc194cc0fee42ff6d989b/ormsgpack-1.12.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9959a71dde1bd0ced84af17facc06a8afada495a34e9cb1bad8e9b20d4c59cef", size = 386251, upload-time = "2025-12-14T07:57:22.099Z" }, - { url = "https://files.pythonhosted.org/packages/bf/54/ba0c97d6231b1f01daafaa520c8cce1e1b7fceaae6fdc1c763925874a7de/ormsgpack-1.12.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:e9be0e3b62d758f21f5b20e0e06b3a240ec546c4a327bf771f5825462aa74714", size = 479607, upload-time = "2025-12-14T07:57:23.525Z" }, - { url = "https://files.pythonhosted.org/packages/18/75/19a9a97a462776d525baf41cfb7072734528775f0a3d5fbfab3aa7756b9b/ormsgpack-1.12.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a29d49ab7fdd77ea787818e60cb4ef491708105b9c4c9b0f919201625eb036b5", size = 388062, upload-time = "2025-12-14T07:57:24.616Z" }, - { url = "https://files.pythonhosted.org/packages/a8/6a/ec26e3f44e9632ecd2f43638b7b37b500eaea5d79cab984ad0b94be14f82/ormsgpack-1.12.1-cp313-cp313-win_amd64.whl", hash = "sha256:c418390b47a1d367e803f6c187f77e4d67c7ae07ba962e3a4a019001f4b0291a", size = 116195, upload-time = "2025-12-14T07:57:25.626Z" }, - { url = "https://files.pythonhosted.org/packages/7d/64/bfa5f4a34d0f15c6aba1b73e73f7441a66d635bd03249d334a4796b7a924/ormsgpack-1.12.1-cp313-cp313-win_arm64.whl", hash = "sha256:cfa22c91cffc10a7fbd43729baff2de7d9c28cef2509085a704168ae31f02568", size = 109986, upload-time = "2025-12-14T07:57:26.569Z" }, - { url = "https://files.pythonhosted.org/packages/87/0e/78e5697164e3223b9b216c13e99f1acbc1ee9833490d68842b13da8ba883/ormsgpack-1.12.1-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:b93c91efb1a70751a1902a5b43b27bd8fd38e0ca0365cf2cde2716423c15c3a6", size = 376758, upload-time = "2025-12-14T07:57:27.641Z" }, - { url = "https://files.pythonhosted.org/packages/2c/0e/3a3cbb64703263d7bbaed7effa3ce78cb9add360a60aa7c544d7df28b641/ormsgpack-1.12.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf0ea0389167b5fa8d2933dd3f33e887ec4ba68f89c25214d7eec4afd746d22", size = 202487, upload-time = "2025-12-14T07:57:29.051Z" }, - { url = "https://files.pythonhosted.org/packages/d7/2c/807ebe2b77995599bbb1dec8c3f450d5d7dddee14ce3e1e71dc60e2e2a74/ormsgpack-1.12.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4c29af837f35af3375070689e781161e7cf019eb2f7cd641734ae45cd001c0d", size = 210853, upload-time = "2025-12-14T07:57:30.508Z" }, - { url = "https://files.pythonhosted.org/packages/25/57/2cdfc354e3ad8e847628f511f4d238799d90e9e090941e50b9d5ba955ae2/ormsgpack-1.12.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:336fc65aa0fe65896a3dabaae31e332a0a98b4a00ad7b0afde21a7505fd23ff3", size = 211545, upload-time = "2025-12-14T07:57:31.585Z" }, - { url = "https://files.pythonhosted.org/packages/76/1d/c6fda560e4a8ff865b3aec8a86f7c95ab53f4532193a6ae4ab9db35f85aa/ormsgpack-1.12.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:940f60aabfefe71dd6b82cb33f4ff10b2e7f5fcfa5f103cdb0a23b6aae4c713c", size = 386333, upload-time = "2025-12-14T07:57:32.957Z" }, - { url = "https://files.pythonhosted.org/packages/fc/3e/715081b36fceb8b497c68b87d384e1cc6d9c9c130ce3b435634d3d785b86/ormsgpack-1.12.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:596ad9e1b6d4c95595c54aaf49b1392609ca68f562ce06f4f74a5bc4053bcda4", size = 479701, upload-time = "2025-12-14T07:57:34.686Z" }, - { url = "https://files.pythonhosted.org/packages/6d/cf/01ad04def42b3970fc1a302c07f4b46339edf62ef9650247097260471f40/ormsgpack-1.12.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:575210e8fcbc7b0375026ba040a5eef223e9f66a4453d9623fc23282ae09c3c8", size = 388148, upload-time = "2025-12-14T07:57:35.771Z" }, - { url = "https://files.pythonhosted.org/packages/15/91/1fff2fc2b5943c740028f339154e7103c8f2edf1a881d9fbba2ce11c3b1d/ormsgpack-1.12.1-cp314-cp314-win_amd64.whl", hash = "sha256:647daa3718572280893456be44c60aea6690b7f2edc54c55648ee66e8f06550f", size = 116201, upload-time = "2025-12-14T07:57:36.763Z" }, - { url = "https://files.pythonhosted.org/packages/ed/66/142b542aed3f96002c7d1c33507ca6e1e0d0a42b9253ab27ef7ed5793bd9/ormsgpack-1.12.1-cp314-cp314-win_arm64.whl", hash = "sha256:a8b3ab762a6deaf1b6490ab46dda0c51528cf8037e0246c40875c6fe9e37b699", size = 110029, upload-time = "2025-12-14T07:57:37.703Z" }, - { url = "https://files.pythonhosted.org/packages/38/b3/ef4494438c90359e1547eaed3c5ec46e2c431d59a3de2af4e70ebd594c49/ormsgpack-1.12.1-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:12087214e436c1f6c28491949571abea759a63111908c4f7266586d78144d7a8", size = 376777, upload-time = "2025-12-14T07:57:38.795Z" }, - { url = "https://files.pythonhosted.org/packages/05/a0/1149a7163f8b0dfbc64bf9099b6f16d102ad3b03bcc11afee198d751da2d/ormsgpack-1.12.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e6d54c14cf86ef13f10ccade94d1e7de146aa9b17d371e18b16e95f329393b7", size = 202490, upload-time = "2025-12-14T07:57:40.168Z" }, - { url = "https://files.pythonhosted.org/packages/68/82/f2ec5e758d6a7106645cca9bb7137d98bce5d363789fa94075be6572057c/ormsgpack-1.12.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f3584d07882b7ea2a1a589f795a3af97fe4c2932b739408e6d1d9d286cad862", size = 211733, upload-time = "2025-12-14T07:57:42.253Z" }, + { url = "https://files.pythonhosted.org/packages/93/fa/a91f70829ebccf6387c4946e0a1a109f6ba0d6a28d65f628bedfad94b890/ormsgpack-1.12.2-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:c1429217f8f4d7fcb053523bbbac6bed5e981af0b85ba616e6df7cce53c19657", size = 378262, upload-time = "2026-01-18T20:55:22.284Z" }, + { url = "https://files.pythonhosted.org/packages/5f/62/3698a9a0c487252b5c6a91926e5654e79e665708ea61f67a8bdeceb022bf/ormsgpack-1.12.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f13034dc6c84a6280c6c33db7ac420253852ea233fc3ee27c8875f8dd651163", size = 203034, upload-time = "2026-01-18T20:55:53.324Z" }, + { url = "https://files.pythonhosted.org/packages/66/3a/f716f64edc4aec2744e817660b317e2f9bb8de372338a95a96198efa1ac1/ormsgpack-1.12.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:59f5da97000c12bc2d50e988bdc8576b21f6ab4e608489879d35b2c07a8ab51a", size = 210538, upload-time = "2026-01-18T20:55:20.097Z" }, + { url = "https://files.pythonhosted.org/packages/72/30/a436be9ce27d693d4e19fa94900028067133779f09fc45776db3f689c822/ormsgpack-1.12.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e4459c3f27066beadb2b81ea48a076a417aafffff7df1d3c11c519190ed44f2", size = 212401, upload-time = "2026-01-18T20:55:46.447Z" }, + { url = "https://files.pythonhosted.org/packages/10/c5/cde98300fd33fee84ca71de4751b19aeeca675f0cf3c0ec4b043f40f3b76/ormsgpack-1.12.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a1c460655d7288407ffa09065e322a7231997c0d62ce914bf3a96ad2dc6dedd", size = 387080, upload-time = "2026-01-18T20:56:00.884Z" }, + { url = "https://files.pythonhosted.org/packages/6a/31/30bf445ef827546747c10889dd254b3d84f92b591300efe4979d792f4c41/ormsgpack-1.12.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:458e4568be13d311ef7d8877275e7ccbe06c0e01b39baaac874caaa0f46d826c", size = 482346, upload-time = "2026-01-18T20:55:39.831Z" }, + { url = "https://files.pythonhosted.org/packages/2e/f5/e1745ddf4fa246c921b5ca253636c4c700ff768d78032f79171289159f6e/ormsgpack-1.12.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8cde5eaa6c6cbc8622db71e4a23de56828e3d876aeb6460ffbcb5b8aff91093b", size = 425178, upload-time = "2026-01-18T20:55:27.106Z" }, + { url = "https://files.pythonhosted.org/packages/8d/a2/e6532ed7716aed03dede8df2d0d0d4150710c2122647d94b474147ccd891/ormsgpack-1.12.2-cp310-cp310-win_amd64.whl", hash = "sha256:dc7a33be14c347893edbb1ceda89afbf14c467d593a5ee92c11de4f1666b4d4f", size = 117183, upload-time = "2026-01-18T20:55:55.52Z" }, + { url = "https://files.pythonhosted.org/packages/4b/08/8b68f24b18e69d92238aa8f258218e6dfeacf4381d9d07ab8df303f524a9/ormsgpack-1.12.2-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:bd5f4bf04c37888e864f08e740c5a573c4017f6fd6e99fa944c5c935fabf2dd9", size = 378266, upload-time = "2026-01-18T20:55:59.876Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/29fc13044ecb7c153523ae0a1972269fcd613650d1fa1a9cec1044c6b666/ormsgpack-1.12.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34d5b28b3570e9fed9a5a76528fc7230c3c76333bc214798958e58e9b79cc18a", size = 203035, upload-time = "2026-01-18T20:55:30.59Z" }, + { url = "https://files.pythonhosted.org/packages/ad/c2/00169fb25dd8f9213f5e8a549dfb73e4d592009ebc85fbbcd3e1dcac575b/ormsgpack-1.12.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3708693412c28f3538fb5a65da93787b6bbab3484f6bc6e935bfb77a62400ae5", size = 210539, upload-time = "2026-01-18T20:55:48.569Z" }, + { url = "https://files.pythonhosted.org/packages/1b/33/543627f323ff3c73091f51d6a20db28a1a33531af30873ea90c5ac95a9b5/ormsgpack-1.12.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43013a3f3e2e902e1d05e72c0f1aeb5bedbb8e09240b51e26792a3c89267e181", size = 212401, upload-time = "2026-01-18T20:56:10.101Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5d/f70e2c3da414f46186659d24745483757bcc9adccb481a6eb93e2b729301/ormsgpack-1.12.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7c8b1667a72cbba74f0ae7ecf3105a5e01304620ed14528b2cb4320679d2869b", size = 387082, upload-time = "2026-01-18T20:56:12.047Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d6/06e8dc920c7903e051f30934d874d4afccc9bb1c09dcaf0bc03a7de4b343/ormsgpack-1.12.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:df6961442140193e517303d0b5d7bc2e20e69a879c2d774316125350c4a76b92", size = 482346, upload-time = "2026-01-18T20:56:05.152Z" }, + { url = "https://files.pythonhosted.org/packages/66/c4/f337ac0905eed9c393ef990c54565cd33644918e0a8031fe48c098c71dbf/ormsgpack-1.12.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c6a4c34ddef109647c769d69be65fa1de7a6022b02ad45546a69b3216573eb4a", size = 425181, upload-time = "2026-01-18T20:55:37.83Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/6d5758fabef3babdf4bbbc453738cc7de9cd3334e4c38dd5737e27b85653/ormsgpack-1.12.2-cp311-cp311-win_amd64.whl", hash = "sha256:73670ed0375ecc303858e3613f407628dd1fca18fe6ac57b7b7ce66cc7bb006c", size = 117182, upload-time = "2026-01-18T20:55:31.472Z" }, + { url = "https://files.pythonhosted.org/packages/c4/57/17a15549233c37e7fd054c48fe9207492e06b026dbd872b826a0b5f833b6/ormsgpack-1.12.2-cp311-cp311-win_arm64.whl", hash = "sha256:c2be829954434e33601ae5da328cccce3266b098927ca7a30246a0baec2ce7bd", size = 111464, upload-time = "2026-01-18T20:55:38.811Z" }, + { url = "https://files.pythonhosted.org/packages/4c/36/16c4b1921c308a92cef3bf6663226ae283395aa0ff6e154f925c32e91ff5/ormsgpack-1.12.2-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7a29d09b64b9694b588ff2f80e9826bdceb3a2b91523c5beae1fab27d5c940e7", size = 378618, upload-time = "2026-01-18T20:55:50.835Z" }, + { url = "https://files.pythonhosted.org/packages/c0/68/468de634079615abf66ed13bb5c34ff71da237213f29294363beeeca5306/ormsgpack-1.12.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b39e629fd2e1c5b2f46f99778450b59454d1f901bc507963168985e79f09c5d", size = 203186, upload-time = "2026-01-18T20:56:11.163Z" }, + { url = "https://files.pythonhosted.org/packages/73/a9/d756e01961442688b7939bacd87ce13bfad7d26ce24f910f6028178b2cc8/ormsgpack-1.12.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:958dcb270d30a7cb633a45ee62b9444433fa571a752d2ca484efdac07480876e", size = 210738, upload-time = "2026-01-18T20:56:09.181Z" }, + { url = "https://files.pythonhosted.org/packages/7b/ba/795b1036888542c9113269a3f5690ab53dd2258c6fb17676ac4bd44fcf94/ormsgpack-1.12.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d379d72b6c5e964851c77cfedfb386e474adee4fd39791c2c5d9efb53505cc", size = 212569, upload-time = "2026-01-18T20:56:06.135Z" }, + { url = "https://files.pythonhosted.org/packages/6c/aa/bff73c57497b9e0cba8837c7e4bcab584b1a6dbc91a5dd5526784a5030c8/ormsgpack-1.12.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8463a3fc5f09832e67bdb0e2fda6d518dc4281b133166146a67f54c08496442e", size = 387166, upload-time = "2026-01-18T20:55:36.738Z" }, + { url = "https://files.pythonhosted.org/packages/d3/cf/f8283cba44bcb7b14f97b6274d449db276b3a86589bdb363169b51bc12de/ormsgpack-1.12.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:eddffb77eff0bad4e67547d67a130604e7e2dfbb7b0cde0796045be4090f35c6", size = 482498, upload-time = "2026-01-18T20:55:29.626Z" }, + { url = "https://files.pythonhosted.org/packages/05/be/71e37b852d723dfcbe952ad04178c030df60d6b78eba26bfd14c9a40575e/ormsgpack-1.12.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fcd55e5f6ba0dbce624942adf9f152062135f991a0126064889f68eb850de0dd", size = 425518, upload-time = "2026-01-18T20:55:49.556Z" }, + { url = "https://files.pythonhosted.org/packages/7a/0c/9803aa883d18c7ef197213cd2cbf73ba76472a11fe100fb7dab2884edf48/ormsgpack-1.12.2-cp312-cp312-win_amd64.whl", hash = "sha256:d024b40828f1dde5654faebd0d824f9cc29ad46891f626272dd5bfd7af2333a4", size = 117462, upload-time = "2026-01-18T20:55:47.726Z" }, + { url = "https://files.pythonhosted.org/packages/c8/9e/029e898298b2cc662f10d7a15652a53e3b525b1e7f07e21fef8536a09bb8/ormsgpack-1.12.2-cp312-cp312-win_arm64.whl", hash = "sha256:da538c542bac7d1c8f3f2a937863dba36f013108ce63e55745941dda4b75dbb6", size = 111559, upload-time = "2026-01-18T20:55:54.273Z" }, + { url = "https://files.pythonhosted.org/packages/eb/29/bb0eba3288c0449efbb013e9c6f58aea79cf5cb9ee1921f8865f04c1a9d7/ormsgpack-1.12.2-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5ea60cb5f210b1cfbad8c002948d73447508e629ec375acb82910e3efa8ff355", size = 378661, upload-time = "2026-01-18T20:55:57.765Z" }, + { url = "https://files.pythonhosted.org/packages/6e/31/5efa31346affdac489acade2926989e019e8ca98129658a183e3add7af5e/ormsgpack-1.12.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3601f19afdbea273ed70b06495e5794606a8b690a568d6c996a90d7255e51c1", size = 203194, upload-time = "2026-01-18T20:56:08.252Z" }, + { url = "https://files.pythonhosted.org/packages/eb/56/d0087278beef833187e0167f8527235ebe6f6ffc2a143e9de12a98b1ce87/ormsgpack-1.12.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:29a9f17a3dac6054c0dce7925e0f4995c727f7c41859adf9b5572180f640d172", size = 210778, upload-time = "2026-01-18T20:55:17.694Z" }, + { url = "https://files.pythonhosted.org/packages/1c/a2/072343e1413d9443e5a252a8eb591c2d5b1bffbe5e7bfc78c069361b92eb/ormsgpack-1.12.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39c1bd2092880e413902910388be8715f70b9f15f20779d44e673033a6146f2d", size = 212592, upload-time = "2026-01-18T20:55:32.747Z" }, + { url = "https://files.pythonhosted.org/packages/a2/8b/a0da3b98a91d41187a63b02dda14267eefc2a74fcb43cc2701066cf1510e/ormsgpack-1.12.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:50b7249244382209877deedeee838aef1542f3d0fc28b8fe71ca9d7e1896a0d7", size = 387164, upload-time = "2026-01-18T20:55:40.853Z" }, + { url = "https://files.pythonhosted.org/packages/19/bb/6d226bc4cf9fc20d8eb1d976d027a3f7c3491e8f08289a2e76abe96a65f3/ormsgpack-1.12.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:5af04800d844451cf102a59c74a841324868d3f1625c296a06cc655c542a6685", size = 482516, upload-time = "2026-01-18T20:55:42.033Z" }, + { url = "https://files.pythonhosted.org/packages/fb/f1/bb2c7223398543dedb3dbf8bb93aaa737b387de61c5feaad6f908841b782/ormsgpack-1.12.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cec70477d4371cd524534cd16472d8b9cc187e0e3043a8790545a9a9b296c258", size = 425539, upload-time = "2026-01-18T20:55:24.727Z" }, + { url = "https://files.pythonhosted.org/packages/7b/e8/0fb45f57a2ada1fed374f7494c8cd55e2f88ccd0ab0a669aa3468716bf5f/ormsgpack-1.12.2-cp313-cp313-win_amd64.whl", hash = "sha256:21f4276caca5c03a818041d637e4019bc84f9d6ca8baa5ea03e5cc8bf56140e9", size = 117459, upload-time = "2026-01-18T20:55:56.876Z" }, + { url = "https://files.pythonhosted.org/packages/7a/d4/0cfeea1e960d550a131001a7f38a5132c7ae3ebde4c82af1f364ccc5d904/ormsgpack-1.12.2-cp313-cp313-win_arm64.whl", hash = "sha256:baca4b6773d20a82e36d6fd25f341064244f9f86a13dead95dd7d7f996f51709", size = 111577, upload-time = "2026-01-18T20:55:43.605Z" }, + { url = "https://files.pythonhosted.org/packages/94/16/24d18851334be09c25e87f74307c84950f18c324a4d3c0b41dabdbf19c29/ormsgpack-1.12.2-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:bc68dd5915f4acf66ff2010ee47c8906dc1cf07399b16f4089f8c71733f6e36c", size = 378717, upload-time = "2026-01-18T20:55:26.164Z" }, + { url = "https://files.pythonhosted.org/packages/b5/a2/88b9b56f83adae8032ac6a6fa7f080c65b3baf9b6b64fd3d37bd202991d4/ormsgpack-1.12.2-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46d084427b4132553940070ad95107266656cb646ea9da4975f85cb1a6676553", size = 203183, upload-time = "2026-01-18T20:55:18.815Z" }, + { url = "https://files.pythonhosted.org/packages/a9/80/43e4555963bf602e5bdc79cbc8debd8b6d5456c00d2504df9775e74b450b/ormsgpack-1.12.2-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c010da16235806cf1d7bc4c96bf286bfa91c686853395a299b3ddb49499a3e13", size = 210814, upload-time = "2026-01-18T20:55:33.973Z" }, + { url = "https://files.pythonhosted.org/packages/78/e1/7cfbf28de8bca6efe7e525b329c31277d1b64ce08dcba723971c241a9d60/ormsgpack-1.12.2-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18867233df592c997154ff942a6503df274b5ac1765215bceba7a231bea2745d", size = 212634, upload-time = "2026-01-18T20:55:28.634Z" }, + { url = "https://files.pythonhosted.org/packages/95/f8/30ae5716e88d792a4e879debee195653c26ddd3964c968594ddef0a3cc7e/ormsgpack-1.12.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b009049086ddc6b8f80c76b3955df1aa22a5fbd7673c525cd63bf91f23122ede", size = 387139, upload-time = "2026-01-18T20:56:02.013Z" }, + { url = "https://files.pythonhosted.org/packages/dc/81/aee5b18a3e3a0e52f718b37ab4b8af6fae0d9d6a65103036a90c2a8ffb5d/ormsgpack-1.12.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:1dcc17d92b6390d4f18f937cf0b99054824a7815818012ddca925d6e01c2e49e", size = 482578, upload-time = "2026-01-18T20:55:35.117Z" }, + { url = "https://files.pythonhosted.org/packages/bd/17/71c9ba472d5d45f7546317f467a5fc941929cd68fb32796ca3d13dcbaec2/ormsgpack-1.12.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f04b5e896d510b07c0ad733d7fce2d44b260c5e6c402d272128f8941984e4285", size = 425539, upload-time = "2026-01-18T20:56:04.009Z" }, + { url = "https://files.pythonhosted.org/packages/2e/a6/ac99cd7fe77e822fed5250ff4b86fa66dd4238937dd178d2299f10b69816/ormsgpack-1.12.2-cp314-cp314-win_amd64.whl", hash = "sha256:ae3aba7eed4ca7cb79fd3436eddd29140f17ea254b91604aa1eb19bfcedb990f", size = 117493, upload-time = "2026-01-18T20:56:07.343Z" }, + { url = "https://files.pythonhosted.org/packages/3a/67/339872846a1ae4592535385a1c1f93614138566d7af094200c9c3b45d1e5/ormsgpack-1.12.2-cp314-cp314-win_arm64.whl", hash = "sha256:118576ea6006893aea811b17429bfc561b4778fad393f5f538c84af70b01260c", size = 111579, upload-time = "2026-01-18T20:55:21.161Z" }, + { url = "https://files.pythonhosted.org/packages/49/c2/6feb972dc87285ad381749d3882d8aecbde9f6ecf908dd717d33d66df095/ormsgpack-1.12.2-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7121b3d355d3858781dc40dafe25a32ff8a8242b9d80c692fd548a4b1f7fd3c8", size = 378721, upload-time = "2026-01-18T20:55:52.12Z" }, + { url = "https://files.pythonhosted.org/packages/a3/9a/900a6b9b413e0f8a471cf07830f9cf65939af039a362204b36bd5b581d8b/ormsgpack-1.12.2-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ee766d2e78251b7a63daf1cddfac36a73562d3ddef68cacfb41b2af64698033", size = 203170, upload-time = "2026-01-18T20:55:44.469Z" }, + { url = "https://files.pythonhosted.org/packages/87/4c/27a95466354606b256f24fad464d7c97ab62bce6cc529dd4673e1179b8fb/ormsgpack-1.12.2-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:292410a7d23de9b40444636b9b8f1e4e4b814af7f1ef476e44887e52a123f09d", size = 212816, upload-time = "2026-01-18T20:55:23.501Z" }, + { url = "https://files.pythonhosted.org/packages/73/cd/29cee6007bddf7a834e6cd6f536754c0535fcb939d384f0f37a38b1cddb8/ormsgpack-1.12.2-cp314-cp314t-win_amd64.whl", hash = "sha256:837dd316584485b72ef451d08dd3e96c4a11d12e4963aedb40e08f89685d8ec2", size = 117232, upload-time = "2026-01-18T20:55:45.448Z" }, ] [[package]] @@ -1197,14 +1198,14 @@ wheels = [ [[package]] name = "redis" -version = "7.1.0" +version = "7.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "async-timeout", marker = "python_full_version < '3.11.3'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/43/c8/983d5c6579a411d8a99bc5823cc5712768859b5ce2c8afe1a65b37832c81/redis-7.1.0.tar.gz", hash = "sha256:b1cc3cfa5a2cb9c2ab3ba700864fb0ad75617b41f01352ce5779dabf6d5f9c3c", size = 4796669, upload-time = "2025-11-19T15:54:39.961Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/80/2971931d27651affa88a44c0ad7b8c4a19dc29c998abb20b23868d319b59/redis-7.1.1.tar.gz", hash = "sha256:a2814b2bda15b39dad11391cc48edac4697214a8a5a4bd10abe936ab4892eb43", size = 4800064, upload-time = "2026-02-09T18:39:40.292Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/f0/8956f8a86b20d7bb9d6ac0187cf4cd54d8065bc9a1a09eb8011d4d326596/redis-7.1.0-py3-none-any.whl", hash = "sha256:23c52b208f92b56103e17c5d06bdc1a6c2c0b3106583985a76a18f83b265de2b", size = 354159, upload-time = "2025-11-19T15:54:38.064Z" }, + { url = "https://files.pythonhosted.org/packages/29/55/1de1d812ba1481fa4b37fb03b4eec0fcb71b6a0d44c04ea3482eb017600f/redis-7.1.1-py3-none-any.whl", hash = "sha256:f77817f16071c2950492c67d40b771fa493eb3fccc630a424a10976dbb794b7a", size = 356057, upload-time = "2026-02-09T18:39:38.602Z" }, ] [[package]] @@ -1236,28 +1237,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.14.13" +version = "0.15.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/50/0a/1914efb7903174b381ee2ffeebb4253e729de57f114e63595114c8ca451f/ruff-0.14.13.tar.gz", hash = "sha256:83cd6c0763190784b99650a20fec7633c59f6ebe41c5cc9d45ee42749563ad47", size = 6059504, upload-time = "2026-01-15T20:15:16.918Z" } +sdist = { url = "https://files.pythonhosted.org/packages/04/dc/4e6ac71b511b141cf626357a3946679abeba4cf67bc7cc5a17920f31e10d/ruff-0.15.1.tar.gz", hash = "sha256:c590fe13fb57c97141ae975c03a1aedb3d3156030cabd740d6ff0b0d601e203f", size = 4540855, upload-time = "2026-02-12T23:09:09.998Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/ae/0deefbc65ca74b0ab1fd3917f94dc3b398233346a74b8bbb0a916a1a6bf6/ruff-0.14.13-py3-none-linux_armv6l.whl", hash = "sha256:76f62c62cd37c276cb03a275b198c7c15bd1d60c989f944db08a8c1c2dbec18b", size = 13062418, upload-time = "2026-01-15T20:14:50.779Z" }, - { url = "https://files.pythonhosted.org/packages/47/df/5916604faa530a97a3c154c62a81cb6b735c0cb05d1e26d5ad0f0c8ac48a/ruff-0.14.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:914a8023ece0528d5cc33f5a684f5f38199bbb566a04815c2c211d8f40b5d0ed", size = 13442344, upload-time = "2026-01-15T20:15:07.94Z" }, - { url = "https://files.pythonhosted.org/packages/4c/f3/e0e694dd69163c3a1671e102aa574a50357536f18a33375050334d5cd517/ruff-0.14.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d24899478c35ebfa730597a4a775d430ad0d5631b8647a3ab368c29b7e7bd063", size = 12354720, upload-time = "2026-01-15T20:15:09.854Z" }, - { url = "https://files.pythonhosted.org/packages/c3/e8/67f5fcbbaee25e8fc3b56cc33e9892eca7ffe09f773c8e5907757a7e3bdb/ruff-0.14.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9aaf3870f14d925bbaf18b8a2347ee0ae7d95a2e490e4d4aea6813ed15ebc80e", size = 12774493, upload-time = "2026-01-15T20:15:20.908Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ce/d2e9cb510870b52a9565d885c0d7668cc050e30fa2c8ac3fb1fda15c083d/ruff-0.14.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac5b7f63dd3b27cc811850f5ffd8fff845b00ad70e60b043aabf8d6ecc304e09", size = 12815174, upload-time = "2026-01-15T20:15:05.74Z" }, - { url = "https://files.pythonhosted.org/packages/88/00/c38e5da58beebcf4fa32d0ddd993b63dfacefd02ab7922614231330845bf/ruff-0.14.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78d2b1097750d90ba82ce4ba676e85230a0ed694178ca5e61aa9b459970b3eb9", size = 13680909, upload-time = "2026-01-15T20:15:14.537Z" }, - { url = "https://files.pythonhosted.org/packages/61/61/cd37c9dd5bd0a3099ba79b2a5899ad417d8f3b04038810b0501a80814fd7/ruff-0.14.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d0bf87705acbbcb8d4c24b2d77fbb73d40210a95c3903b443cd9e30824a5032", size = 15144215, upload-time = "2026-01-15T20:15:22.886Z" }, - { url = "https://files.pythonhosted.org/packages/56/8a/85502d7edbf98c2df7b8876f316c0157359165e16cdf98507c65c8d07d3d/ruff-0.14.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3eb5da8e2c9e9f13431032fdcbe7681de9ceda5835efee3269417c13f1fed5c", size = 14706067, upload-time = "2026-01-15T20:14:48.271Z" }, - { url = "https://files.pythonhosted.org/packages/7e/2f/de0df127feb2ee8c1e54354dc1179b4a23798f0866019528c938ba439aca/ruff-0.14.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:642442b42957093811cd8d2140dfadd19c7417030a7a68cf8d51fcdd5f217427", size = 14133916, upload-time = "2026-01-15T20:14:57.357Z" }, - { url = "https://files.pythonhosted.org/packages/0d/77/9b99686bb9fe07a757c82f6f95e555c7a47801a9305576a9c67e0a31d280/ruff-0.14.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4acdf009f32b46f6e8864af19cbf6841eaaed8638e65c8dac845aea0d703c841", size = 13859207, upload-time = "2026-01-15T20:14:55.111Z" }, - { url = "https://files.pythonhosted.org/packages/7d/46/2bdcb34a87a179a4d23022d818c1c236cb40e477faf0d7c9afb6813e5876/ruff-0.14.13-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:591a7f68860ea4e003917d19b5c4f5ac39ff558f162dc753a2c5de897fd5502c", size = 14043686, upload-time = "2026-01-15T20:14:52.841Z" }, - { url = "https://files.pythonhosted.org/packages/1a/a9/5c6a4f56a0512c691cf143371bcf60505ed0f0860f24a85da8bd123b2bf1/ruff-0.14.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:774c77e841cc6e046fc3e91623ce0903d1cd07e3a36b1a9fe79b81dab3de506b", size = 12663837, upload-time = "2026-01-15T20:15:18.921Z" }, - { url = "https://files.pythonhosted.org/packages/fe/bb/b920016ece7651fa7fcd335d9d199306665486694d4361547ccb19394c44/ruff-0.14.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:61f4e40077a1248436772bb6512db5fc4457fe4c49e7a94ea7c5088655dd21ae", size = 12805867, upload-time = "2026-01-15T20:14:59.272Z" }, - { url = "https://files.pythonhosted.org/packages/7d/b3/0bd909851e5696cd21e32a8fc25727e5f58f1934b3596975503e6e85415c/ruff-0.14.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6d02f1428357fae9e98ac7aa94b7e966fd24151088510d32cf6f902d6c09235e", size = 13208528, upload-time = "2026-01-15T20:15:03.732Z" }, - { url = "https://files.pythonhosted.org/packages/3b/3b/e2d94cb613f6bbd5155a75cbe072813756363eba46a3f2177a1fcd0cd670/ruff-0.14.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e399341472ce15237be0c0ae5fbceca4b04cd9bebab1a2b2c979e015455d8f0c", size = 13929242, upload-time = "2026-01-15T20:15:11.918Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c5/abd840d4132fd51a12f594934af5eba1d5d27298a6f5b5d6c3be45301caf/ruff-0.14.13-py3-none-win32.whl", hash = "sha256:ef720f529aec113968b45dfdb838ac8934e519711da53a0456038a0efecbd680", size = 12919024, upload-time = "2026-01-15T20:14:43.647Z" }, - { url = "https://files.pythonhosted.org/packages/c2/55/6384b0b8ce731b6e2ade2b5449bf07c0e4c31e8a2e68ea65b3bafadcecc5/ruff-0.14.13-py3-none-win_amd64.whl", hash = "sha256:6070bd026e409734b9257e03e3ef18c6e1a216f0435c6751d7a8ec69cb59abef", size = 14097887, upload-time = "2026-01-15T20:15:01.48Z" }, - { url = "https://files.pythonhosted.org/packages/4d/e1/7348090988095e4e39560cfc2f7555b1b2a7357deba19167b600fdf5215d/ruff-0.14.13-py3-none-win_arm64.whl", hash = "sha256:7ab819e14f1ad9fe39f246cfcc435880ef7a9390d81a2b6ac7e01039083dd247", size = 13080224, upload-time = "2026-01-15T20:14:45.853Z" }, + { url = "https://files.pythonhosted.org/packages/23/bf/e6e4324238c17f9d9120a9d60aa99a7daaa21204c07fcd84e2ef03bb5fd1/ruff-0.15.1-py3-none-linux_armv6l.whl", hash = "sha256:b101ed7cf4615bda6ffe65bdb59f964e9f4a0d3f85cbf0e54f0ab76d7b90228a", size = 10367819, upload-time = "2026-02-12T23:09:03.598Z" }, + { url = "https://files.pythonhosted.org/packages/b3/ea/c8f89d32e7912269d38c58f3649e453ac32c528f93bb7f4219258be2e7ed/ruff-0.15.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:939c995e9277e63ea632cc8d3fae17aa758526f49a9a850d2e7e758bfef46602", size = 10798618, upload-time = "2026-02-12T23:09:22.928Z" }, + { url = "https://files.pythonhosted.org/packages/5e/0f/1d0d88bc862624247d82c20c10d4c0f6bb2f346559d8af281674cf327f15/ruff-0.15.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1d83466455fdefe60b8d9c8df81d3c1bbb2115cede53549d3b522ce2bc703899", size = 10148518, upload-time = "2026-02-12T23:08:58.339Z" }, + { url = "https://files.pythonhosted.org/packages/f5/c8/291c49cefaa4a9248e986256df2ade7add79388fe179e0691be06fae6f37/ruff-0.15.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9457e3c3291024866222b96108ab2d8265b477e5b1534c7ddb1810904858d16", size = 10518811, upload-time = "2026-02-12T23:09:31.865Z" }, + { url = "https://files.pythonhosted.org/packages/c3/1a/f5707440e5ae43ffa5365cac8bbb91e9665f4a883f560893829cf16a606b/ruff-0.15.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:92c92b003e9d4f7fbd33b1867bb15a1b785b1735069108dfc23821ba045b29bc", size = 10196169, upload-time = "2026-02-12T23:09:17.306Z" }, + { url = "https://files.pythonhosted.org/packages/2a/ff/26ddc8c4da04c8fd3ee65a89c9fb99eaa5c30394269d424461467be2271f/ruff-0.15.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fe5c41ab43e3a06778844c586251eb5a510f67125427625f9eb2b9526535779", size = 10990491, upload-time = "2026-02-12T23:09:25.503Z" }, + { url = "https://files.pythonhosted.org/packages/fc/00/50920cb385b89413f7cdb4bb9bc8fc59c1b0f30028d8bccc294189a54955/ruff-0.15.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66a6dd6df4d80dc382c6484f8ce1bcceb55c32e9f27a8b94c32f6c7331bf14fb", size = 11843280, upload-time = "2026-02-12T23:09:19.88Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6d/2f5cad8380caf5632a15460c323ae326f1e1a2b5b90a6ee7519017a017ca/ruff-0.15.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a4a42cbb8af0bda9bcd7606b064d7c0bc311a88d141d02f78920be6acb5aa83", size = 11274336, upload-time = "2026-02-12T23:09:14.907Z" }, + { url = "https://files.pythonhosted.org/packages/a3/1d/5f56cae1d6c40b8a318513599b35ea4b075d7dc1cd1d04449578c29d1d75/ruff-0.15.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ab064052c31dddada35079901592dfba2e05f5b1e43af3954aafcbc1096a5b2", size = 11137288, upload-time = "2026-02-12T23:09:07.475Z" }, + { url = "https://files.pythonhosted.org/packages/cd/20/6f8d7d8f768c93b0382b33b9306b3b999918816da46537d5a61635514635/ruff-0.15.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:5631c940fe9fe91f817a4c2ea4e81f47bee3ca4aa646134a24374f3c19ad9454", size = 11070681, upload-time = "2026-02-12T23:08:55.43Z" }, + { url = "https://files.pythonhosted.org/packages/9a/67/d640ac76069f64cdea59dba02af2e00b1fa30e2103c7f8d049c0cff4cafd/ruff-0.15.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:68138a4ba184b4691ccdc39f7795c66b3c68160c586519e7e8444cf5a53e1b4c", size = 10486401, upload-time = "2026-02-12T23:09:27.927Z" }, + { url = "https://files.pythonhosted.org/packages/65/3d/e1429f64a3ff89297497916b88c32a5cc88eeca7e9c787072d0e7f1d3e1e/ruff-0.15.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:518f9af03bfc33c03bdb4cb63fabc935341bb7f54af500f92ac309ecfbba6330", size = 10197452, upload-time = "2026-02-12T23:09:12.147Z" }, + { url = "https://files.pythonhosted.org/packages/78/83/e2c3bade17dad63bf1e1c2ffaf11490603b760be149e1419b07049b36ef2/ruff-0.15.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:da79f4d6a826caaea95de0237a67e33b81e6ec2e25fc7e1993a4015dffca7c61", size = 10693900, upload-time = "2026-02-12T23:09:34.418Z" }, + { url = "https://files.pythonhosted.org/packages/a1/27/fdc0e11a813e6338e0706e8b39bb7a1d61ea5b36873b351acee7e524a72a/ruff-0.15.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3dd86dccb83cd7d4dcfac303ffc277e6048600dfc22e38158afa208e8bf94a1f", size = 11227302, upload-time = "2026-02-12T23:09:36.536Z" }, + { url = "https://files.pythonhosted.org/packages/f6/58/ac864a75067dcbd3b95be5ab4eb2b601d7fbc3d3d736a27e391a4f92a5c1/ruff-0.15.1-py3-none-win32.whl", hash = "sha256:660975d9cb49b5d5278b12b03bb9951d554543a90b74ed5d366b20e2c57c2098", size = 10462555, upload-time = "2026-02-12T23:09:29.899Z" }, + { url = "https://files.pythonhosted.org/packages/e0/5e/d4ccc8a27ecdb78116feac4935dfc39d1304536f4296168f91ed3ec00cd2/ruff-0.15.1-py3-none-win_amd64.whl", hash = "sha256:c820fef9dd5d4172a6570e5721704a96c6679b80cf7be41659ed439653f62336", size = 11599956, upload-time = "2026-02-12T23:09:01.157Z" }, + { url = "https://files.pythonhosted.org/packages/2a/07/5bda6a85b220c64c65686bc85bd0bbb23b29c62b3a9f9433fa55f17cda93/ruff-0.15.1-py3-none-win_arm64.whl", hash = "sha256:5ff7d5f0f88567850f45081fac8f4ec212be8d0b963e385c3f7d0d2eb4899416", size = 10874604, upload-time = "2026-02-12T23:09:05.515Z" }, ] [[package]] From 3701fa480693915e5458e151719bd8f0f6b1d49c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 01:23:26 -0800 Subject: [PATCH 12/41] chore(deps): bump nbconvert from 7.16.6 to 7.17.0 in /libs/langgraph (#6832) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [nbconvert](https://github.com/jupyter/nbconvert) from 7.16.6 to 7.17.0.
Release notes

Sourced from nbconvert's releases.

v7.17.0

7.17.0

(Full Changelog)

Enhancements made

Bugs fixed

Maintenance and upkeep improvements

Documentation improvements

Contributors to this release

The following people contributed discussions, new ideas, code and documentation contributions, and review. See our definition of contributors.

(GitHub contributors page for this release)

@​bollwyvl (activity) | @​Carreau (activity) | @​h3pdesign (activity) | @​hackowitz-af (activity) | @​krassowski (activity) | @​mberlanda (activity) | @​mgorny (activity) | @​minrk (activity) | @​MSeal (activity) | @​QuLogic (activity) | @​salmankadaya (activity) | @​shreve (activity) | @​th3gowtham (activity)

Changelog

Sourced from nbconvert's changelog.

7.17.0

(Full Changelog)

Enhancements made

Bugs fixed

Maintenance and upkeep improvements

Documentation improvements

Contributors to this release

The following people contributed discussions, new ideas, code and documentation contributions, and review. See our definition of contributors.

(GitHub contributors page for this release)

@​bollwyvl (activity) | @​Carreau (activity) | @​h3pdesign (activity) | @​hackowitz-af (activity) | @​krassowski (activity) | @​mberlanda (activity) | @​mgorny (activity) | @​minrk (activity) | @​MSeal (activity) | @​QuLogic (activity) | @​salmankadaya (activity) | @​shreve (activity) | @​th3gowtham (activity)

Commits
  • 21b35d8 Publish 7.17.0
  • c9ac1d1 Fix CVE-2025-53000: Secure Inkscape Windows path (registry first + block CWD)...
  • b13276d avoid cov environment on free-threaded Pythons (#2267)
  • 7c7055f [pre-commit.ci] auto fixes from pre-commit.com hooks
  • 74f3ddd Fix QtPNGExporter returning empty bytes on macOS
  • 216550b fix links
  • 39777ac try to comment fialing test
  • 7b591ca ruff-check
  • 6ec7638 parent
  • 59414b3 fix mypy
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=nbconvert&package-manager=uv&previous-version=7.16.6&new-version=7.17.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/langchain-ai/langgraph/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- libs/langgraph/uv.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/langgraph/uv.lock b/libs/langgraph/uv.lock index 7dd87e65d..e9313a2f5 100644 --- a/libs/langgraph/uv.lock +++ b/libs/langgraph/uv.lock @@ -2137,7 +2137,7 @@ wheels = [ [[package]] name = "nbconvert" -version = "7.16.6" +version = "7.17.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "beautifulsoup4" }, @@ -2155,9 +2155,9 @@ dependencies = [ { name = "pygments" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715, upload-time = "2025-01-28T09:29:14.724Z" } +sdist = { url = "https://files.pythonhosted.org/packages/38/47/81f886b699450d0569f7bc551df2b1673d18df7ff25cc0c21ca36ed8a5ff/nbconvert-7.17.0.tar.gz", hash = "sha256:1b2696f1b5be12309f6c7d707c24af604b87dfaf6d950794c7b07acab96dda78", size = 862855, upload-time = "2026-01-29T16:37:48.478Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525, upload-time = "2025-01-28T09:29:12.551Z" }, + { url = "https://files.pythonhosted.org/packages/0d/4b/8d5f796a792f8a25f6925a96032f098789f448571eb92011df1ae59e8ea8/nbconvert-7.17.0-py3-none-any.whl", hash = "sha256:4f99a63b337b9a23504347afdab24a11faa7d86b405e5c8f9881cd313336d518", size = 261510, upload-time = "2026-01-29T16:37:46.322Z" }, ] [[package]] From d280bca8da6feb14cda525d9e63fd083cfe095f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 01:24:06 -0800 Subject: [PATCH 13/41] chore(deps): bump langchain-core from 1.2.10 to 1.2.11 in /libs/sdk-py (#6829) Bumps [langchain-core](https://github.com/langchain-ai/langchain) from 1.2.10 to 1.2.11.
Release notes

Sourced from langchain-core's releases.

langchain-core==1.2.11

Changes since langchain-core==1.2.10

release(core): 1.2.11 (#35144) fix(openai): sanitize urls when counting tokens in images (#35143) chore(core): clean up docstring mismatch and redundant logic in langchain-core (#35064) fix(core): replace bare except with Exception in tracer (#35138)

Commits
  • 524e1da release(core): 1.2.11 (#35144)
  • 2b4b1dc fix(openai): sanitize urls when counting tokens in images (#35143)
  • 0493b27 fix(anthropic): support effort="max" and remove beta headers (#35141)
  • a5f22e7 chore(core): clean up docstring mismatch and redundant logic in langchain-cor...
  • 97ee14c fix(core): replace bare except with Exception in tracer (#35138)
  • 990e807 release(standard-tests): release 1.1.5 (#35139)
  • 74dffca release(langchain): 1.2.10 (#35137)
  • See full diff in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=langchain-core&package-manager=uv&previous-version=1.2.10&new-version=1.2.11)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/langchain-ai/langgraph/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- libs/sdk-py/uv.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/sdk-py/uv.lock b/libs/sdk-py/uv.lock index 9c764b02b..67e40046d 100644 --- a/libs/sdk-py/uv.lock +++ b/libs/sdk-py/uv.lock @@ -246,7 +246,7 @@ wheels = [ [[package]] name = "langchain-core" -version = "1.2.10" +version = "1.2.11" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsonpatch" }, @@ -258,9 +258,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "uuid-utils" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ae/60/5dfd49eb4143a3ba72fb93607a71109e56bc92c7144f97eeae103a118e80/langchain_core-1.2.10.tar.gz", hash = "sha256:8c1fa1515b4bf59bf61ff0ff5813dd2b91d4ca1b8bf2ee31c5536364fa4699ae", size = 826391, upload-time = "2026-02-10T14:48:31.679Z" } +sdist = { url = "https://files.pythonhosted.org/packages/12/17/1943cedfc118e04b8128e4c3e1dbf0fa0ea58eefddbb6198cfd699d19f01/langchain_core-1.2.11.tar.gz", hash = "sha256:f164bb36602dd74a3a50c1334fca75309ad5ed95767acdfdbb9fa95ce28a1e01", size = 831211, upload-time = "2026-02-10T20:35:28.35Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/1b/e27c9d03ae431d7b47d2b3289285473d3e724f17c13c0e2409ec158b91e4/langchain_core-1.2.10-py3-none-any.whl", hash = "sha256:fa327dd6a8a596e73a402ec3fa48ea5c4a5f5ac898e983063d1b70b4fddcdf8e", size = 496673, upload-time = "2026-02-10T14:48:29.388Z" }, + { url = "https://files.pythonhosted.org/packages/10/30/1f80e3fc674353cad975ed5294353d42512535d2094ef032c06454c2c873/langchain_core-1.2.11-py3-none-any.whl", hash = "sha256:ae11ceb8dda60d0b9d09e763116e592f1683327c17be5b715f350fd29aee65d3", size = 500062, upload-time = "2026-02-10T20:35:26.698Z" }, ] [[package]] From 443cee2fb36a5adac55a4c04cecba18b6ef8e339 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 01:27:17 -0800 Subject: [PATCH 14/41] chore(deps): bump cryptography from 46.0.3 to 46.0.5 in /libs/langgraph (#6837) Bumps [cryptography](https://github.com/pyca/cryptography) from 46.0.3 to 46.0.5.
Changelog

Sourced from cryptography's changelog.

46.0.5 - 2026-02-10


* An attacker could create a malicious public key that reveals portions
of your
private key when using certain uncommon elliptic curves (binary curves).
This version now includes additional security checks to prevent this
attack.
This issue only affects binary elliptic curves, which are rarely used in
real-world applications. Credit to **XlabAI Team of Tencent Xuanwu Lab
and
Atuin Automated Vulnerability Discovery Engine** for reporting the
issue.
  **CVE-2026-26007**
* Support for ``SECT*`` binary elliptic curves is deprecated and will be
  removed in the next release.

.. v46-0-4:

46.0.4 - 2026-01-27

  • Dropped support for win_arm64 wheels_.
  • Updated Windows, macOS, and Linux wheels to be compiled with OpenSSL 3.5.5.

.. _v46-0-3:

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=cryptography&package-manager=uv&previous-version=46.0.3&new-version=46.0.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/langchain-ai/langgraph/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- libs/langgraph/uv.lock | 105 ++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 55 deletions(-) diff --git a/libs/langgraph/uv.lock b/libs/langgraph/uv.lock index e9313a2f5..605825454 100644 --- a/libs/langgraph/uv.lock +++ b/libs/langgraph/uv.lock @@ -524,66 +524,61 @@ toml = [ [[package]] name = "cryptography" -version = "46.0.3" +version = "46.0.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "python_full_version >= '3.11' and python_full_version < '3.14' and platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9f/33/c00162f49c0e2fe8064a62cb92b93e50c74a72bc370ab92f86112b33ff62/cryptography-46.0.3.tar.gz", hash = "sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1", size = 749258, upload-time = "2025-10-15T23:18:31.74Z" } +sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064, upload-time = "2026-02-10T19:18:38.255Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/42/9c391dd801d6cf0d561b5890549d4b27bafcc53b39c31a817e69d87c625b/cryptography-46.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a", size = 7225004, upload-time = "2025-10-15T23:16:52.239Z" }, - { url = "https://files.pythonhosted.org/packages/1c/67/38769ca6b65f07461eb200e85fc1639b438bdc667be02cf7f2cd6a64601c/cryptography-46.0.3-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc", size = 4296667, upload-time = "2025-10-15T23:16:54.369Z" }, - { url = "https://files.pythonhosted.org/packages/5c/49/498c86566a1d80e978b42f0d702795f69887005548c041636df6ae1ca64c/cryptography-46.0.3-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d", size = 4450807, upload-time = "2025-10-15T23:16:56.414Z" }, - { url = "https://files.pythonhosted.org/packages/4b/0a/863a3604112174c8624a2ac3c038662d9e59970c7f926acdcfaed8d61142/cryptography-46.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb", size = 4299615, upload-time = "2025-10-15T23:16:58.442Z" }, - { url = "https://files.pythonhosted.org/packages/64/02/b73a533f6b64a69f3cd3872acb6ebc12aef924d8d103133bb3ea750dc703/cryptography-46.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849", size = 4016800, upload-time = "2025-10-15T23:17:00.378Z" }, - { url = "https://files.pythonhosted.org/packages/25/d5/16e41afbfa450cde85a3b7ec599bebefaef16b5c6ba4ec49a3532336ed72/cryptography-46.0.3-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8", size = 4984707, upload-time = "2025-10-15T23:17:01.98Z" }, - { url = "https://files.pythonhosted.org/packages/c9/56/e7e69b427c3878352c2fb9b450bd0e19ed552753491d39d7d0a2f5226d41/cryptography-46.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec", size = 4482541, upload-time = "2025-10-15T23:17:04.078Z" }, - { url = "https://files.pythonhosted.org/packages/78/f6/50736d40d97e8483172f1bb6e698895b92a223dba513b0ca6f06b2365339/cryptography-46.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91", size = 4299464, upload-time = "2025-10-15T23:17:05.483Z" }, - { url = "https://files.pythonhosted.org/packages/00/de/d8e26b1a855f19d9994a19c702fa2e93b0456beccbcfe437eda00e0701f2/cryptography-46.0.3-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e", size = 4950838, upload-time = "2025-10-15T23:17:07.425Z" }, - { url = "https://files.pythonhosted.org/packages/8f/29/798fc4ec461a1c9e9f735f2fc58741b0daae30688f41b2497dcbc9ed1355/cryptography-46.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926", size = 4481596, upload-time = "2025-10-15T23:17:09.343Z" }, - { url = "https://files.pythonhosted.org/packages/15/8d/03cd48b20a573adfff7652b76271078e3045b9f49387920e7f1f631d125e/cryptography-46.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71", size = 4426782, upload-time = "2025-10-15T23:17:11.22Z" }, - { url = "https://files.pythonhosted.org/packages/fa/b1/ebacbfe53317d55cf33165bda24c86523497a6881f339f9aae5c2e13e57b/cryptography-46.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac", size = 4698381, upload-time = "2025-10-15T23:17:12.829Z" }, - { url = "https://files.pythonhosted.org/packages/96/92/8a6a9525893325fc057a01f654d7efc2c64b9de90413adcf605a85744ff4/cryptography-46.0.3-cp311-abi3-win32.whl", hash = "sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018", size = 3055988, upload-time = "2025-10-15T23:17:14.65Z" }, - { url = "https://files.pythonhosted.org/packages/7e/bf/80fbf45253ea585a1e492a6a17efcb93467701fa79e71550a430c5e60df0/cryptography-46.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb", size = 3514451, upload-time = "2025-10-15T23:17:16.142Z" }, - { url = "https://files.pythonhosted.org/packages/2e/af/9b302da4c87b0beb9db4e756386a7c6c5b8003cd0e742277888d352ae91d/cryptography-46.0.3-cp311-abi3-win_arm64.whl", hash = "sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c", size = 2928007, upload-time = "2025-10-15T23:17:18.04Z" }, - { url = "https://files.pythonhosted.org/packages/f5/e2/a510aa736755bffa9d2f75029c229111a1d02f8ecd5de03078f4c18d91a3/cryptography-46.0.3-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:00a5e7e87938e5ff9ff5447ab086a5706a957137e6e433841e9d24f38a065217", size = 7158012, upload-time = "2025-10-15T23:17:19.982Z" }, - { url = "https://files.pythonhosted.org/packages/73/dc/9aa866fbdbb95b02e7f9d086f1fccfeebf8953509b87e3f28fff927ff8a0/cryptography-46.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c8daeb2d2174beb4575b77482320303f3d39b8e81153da4f0fb08eb5fe86a6c5", size = 4288728, upload-time = "2025-10-15T23:17:21.527Z" }, - { url = "https://files.pythonhosted.org/packages/c5/fd/bc1daf8230eaa075184cbbf5f8cd00ba9db4fd32d63fb83da4671b72ed8a/cryptography-46.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:39b6755623145ad5eff1dab323f4eae2a32a77a7abef2c5089a04a3d04366715", size = 4435078, upload-time = "2025-10-15T23:17:23.042Z" }, - { url = "https://files.pythonhosted.org/packages/82/98/d3bd5407ce4c60017f8ff9e63ffee4200ab3e23fe05b765cab805a7db008/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:db391fa7c66df6762ee3f00c95a89e6d428f4d60e7abc8328f4fe155b5ac6e54", size = 4293460, upload-time = "2025-10-15T23:17:24.885Z" }, - { url = "https://files.pythonhosted.org/packages/26/e9/e23e7900983c2b8af7a08098db406cf989d7f09caea7897e347598d4cd5b/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:78a97cf6a8839a48c49271cdcbd5cf37ca2c1d6b7fdd86cc864f302b5e9bf459", size = 3995237, upload-time = "2025-10-15T23:17:26.449Z" }, - { url = "https://files.pythonhosted.org/packages/91/15/af68c509d4a138cfe299d0d7ddb14afba15233223ebd933b4bbdbc7155d3/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:dfb781ff7eaa91a6f7fd41776ec37c5853c795d3b358d4896fdbb5df168af422", size = 4967344, upload-time = "2025-10-15T23:17:28.06Z" }, - { url = "https://files.pythonhosted.org/packages/ca/e3/8643d077c53868b681af077edf6b3cb58288b5423610f21c62aadcbe99f4/cryptography-46.0.3-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:6f61efb26e76c45c4a227835ddeae96d83624fb0d29eb5df5b96e14ed1a0afb7", size = 4466564, upload-time = "2025-10-15T23:17:29.665Z" }, - { url = "https://files.pythonhosted.org/packages/0e/43/c1e8726fa59c236ff477ff2b5dc071e54b21e5a1e51aa2cee1676f1c986f/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:23b1a8f26e43f47ceb6d6a43115f33a5a37d57df4ea0ca295b780ae8546e8044", size = 4292415, upload-time = "2025-10-15T23:17:31.686Z" }, - { url = "https://files.pythonhosted.org/packages/42/f9/2f8fefdb1aee8a8e3256a0568cffc4e6d517b256a2fe97a029b3f1b9fe7e/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:b419ae593c86b87014b9be7396b385491ad7f320bde96826d0dd174459e54665", size = 4931457, upload-time = "2025-10-15T23:17:33.478Z" }, - { url = "https://files.pythonhosted.org/packages/79/30/9b54127a9a778ccd6d27c3da7563e9f2d341826075ceab89ae3b41bf5be2/cryptography-46.0.3-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:50fc3343ac490c6b08c0cf0d704e881d0d660be923fd3076db3e932007e726e3", size = 4466074, upload-time = "2025-10-15T23:17:35.158Z" }, - { url = "https://files.pythonhosted.org/packages/ac/68/b4f4a10928e26c941b1b6a179143af9f4d27d88fe84a6a3c53592d2e76bf/cryptography-46.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:22d7e97932f511d6b0b04f2bfd818d73dcd5928db509460aaf48384778eb6d20", size = 4420569, upload-time = "2025-10-15T23:17:37.188Z" }, - { url = "https://files.pythonhosted.org/packages/a3/49/3746dab4c0d1979888f125226357d3262a6dd40e114ac29e3d2abdf1ec55/cryptography-46.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d55f3dffadd674514ad19451161118fd010988540cee43d8bc20675e775925de", size = 4681941, upload-time = "2025-10-15T23:17:39.236Z" }, - { url = "https://files.pythonhosted.org/packages/fd/30/27654c1dbaf7e4a3531fa1fc77986d04aefa4d6d78259a62c9dc13d7ad36/cryptography-46.0.3-cp314-cp314t-win32.whl", hash = "sha256:8a6e050cb6164d3f830453754094c086ff2d0b2f3a897a1d9820f6139a1f0914", size = 3022339, upload-time = "2025-10-15T23:17:40.888Z" }, - { url = "https://files.pythonhosted.org/packages/f6/30/640f34ccd4d2a1bc88367b54b926b781b5a018d65f404d409aba76a84b1c/cryptography-46.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:760f83faa07f8b64e9c33fc963d790a2edb24efb479e3520c14a45741cd9b2db", size = 3494315, upload-time = "2025-10-15T23:17:42.769Z" }, - { url = "https://files.pythonhosted.org/packages/ba/8b/88cc7e3bd0a8e7b861f26981f7b820e1f46aa9d26cc482d0feba0ecb4919/cryptography-46.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:516ea134e703e9fe26bcd1277a4b59ad30586ea90c365a87781d7887a646fe21", size = 2919331, upload-time = "2025-10-15T23:17:44.468Z" }, - { url = "https://files.pythonhosted.org/packages/fd/23/45fe7f376a7df8daf6da3556603b36f53475a99ce4faacb6ba2cf3d82021/cryptography-46.0.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936", size = 7218248, upload-time = "2025-10-15T23:17:46.294Z" }, - { url = "https://files.pythonhosted.org/packages/27/32/b68d27471372737054cbd34c84981f9edbc24fe67ca225d389799614e27f/cryptography-46.0.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683", size = 4294089, upload-time = "2025-10-15T23:17:48.269Z" }, - { url = "https://files.pythonhosted.org/packages/26/42/fa8389d4478368743e24e61eea78846a0006caffaf72ea24a15159215a14/cryptography-46.0.3-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d", size = 4440029, upload-time = "2025-10-15T23:17:49.837Z" }, - { url = "https://files.pythonhosted.org/packages/5f/eb/f483db0ec5ac040824f269e93dd2bd8a21ecd1027e77ad7bdf6914f2fd80/cryptography-46.0.3-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0", size = 4297222, upload-time = "2025-10-15T23:17:51.357Z" }, - { url = "https://files.pythonhosted.org/packages/fd/cf/da9502c4e1912cb1da3807ea3618a6829bee8207456fbbeebc361ec38ba3/cryptography-46.0.3-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc", size = 4012280, upload-time = "2025-10-15T23:17:52.964Z" }, - { url = "https://files.pythonhosted.org/packages/6b/8f/9adb86b93330e0df8b3dcf03eae67c33ba89958fc2e03862ef1ac2b42465/cryptography-46.0.3-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3", size = 4978958, upload-time = "2025-10-15T23:17:54.965Z" }, - { url = "https://files.pythonhosted.org/packages/d1/a0/5fa77988289c34bdb9f913f5606ecc9ada1adb5ae870bd0d1054a7021cc4/cryptography-46.0.3-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971", size = 4473714, upload-time = "2025-10-15T23:17:56.754Z" }, - { url = "https://files.pythonhosted.org/packages/14/e5/fc82d72a58d41c393697aa18c9abe5ae1214ff6f2a5c18ac470f92777895/cryptography-46.0.3-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac", size = 4296970, upload-time = "2025-10-15T23:17:58.588Z" }, - { url = "https://files.pythonhosted.org/packages/78/06/5663ed35438d0b09056973994f1aec467492b33bd31da36e468b01ec1097/cryptography-46.0.3-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04", size = 4940236, upload-time = "2025-10-15T23:18:00.897Z" }, - { url = "https://files.pythonhosted.org/packages/fc/59/873633f3f2dcd8a053b8dd1d38f783043b5fce589c0f6988bf55ef57e43e/cryptography-46.0.3-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506", size = 4472642, upload-time = "2025-10-15T23:18:02.749Z" }, - { url = "https://files.pythonhosted.org/packages/3d/39/8e71f3930e40f6877737d6f69248cf74d4e34b886a3967d32f919cc50d3b/cryptography-46.0.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963", size = 4423126, upload-time = "2025-10-15T23:18:04.85Z" }, - { url = "https://files.pythonhosted.org/packages/cd/c7/f65027c2810e14c3e7268353b1681932b87e5a48e65505d8cc17c99e36ae/cryptography-46.0.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4", size = 4686573, upload-time = "2025-10-15T23:18:06.908Z" }, - { url = "https://files.pythonhosted.org/packages/0a/6e/1c8331ddf91ca4730ab3086a0f1be19c65510a33b5a441cb334e7a2d2560/cryptography-46.0.3-cp38-abi3-win32.whl", hash = "sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df", size = 3036695, upload-time = "2025-10-15T23:18:08.672Z" }, - { url = "https://files.pythonhosted.org/packages/90/45/b0d691df20633eff80955a0fc7695ff9051ffce8b69741444bd9ed7bd0db/cryptography-46.0.3-cp38-abi3-win_amd64.whl", hash = "sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f", size = 3501720, upload-time = "2025-10-15T23:18:10.632Z" }, - { url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740, upload-time = "2025-10-15T23:18:12.277Z" }, - { url = "https://files.pythonhosted.org/packages/d9/cd/1a8633802d766a0fa46f382a77e096d7e209e0817892929655fe0586ae32/cryptography-46.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a23582810fedb8c0bc47524558fb6c56aac3fc252cb306072fd2815da2a47c32", size = 3689163, upload-time = "2025-10-15T23:18:13.821Z" }, - { url = "https://files.pythonhosted.org/packages/4c/59/6b26512964ace6480c3e54681a9859c974172fb141c38df11eadd8416947/cryptography-46.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e7aec276d68421f9574040c26e2a7c3771060bc0cff408bae1dcb19d3ab1e63c", size = 3429474, upload-time = "2025-10-15T23:18:15.477Z" }, - { url = "https://files.pythonhosted.org/packages/06/8a/e60e46adab4362a682cf142c7dcb5bf79b782ab2199b0dcb81f55970807f/cryptography-46.0.3-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7ce938a99998ed3c8aa7e7272dca1a610401ede816d36d0693907d863b10d9ea", size = 3698132, upload-time = "2025-10-15T23:18:17.056Z" }, - { url = "https://files.pythonhosted.org/packages/da/38/f59940ec4ee91e93d3311f7532671a5cef5570eb04a144bf203b58552d11/cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:191bb60a7be5e6f54e30ba16fdfae78ad3a342a0599eb4193ba88e3f3d6e185b", size = 4243992, upload-time = "2025-10-15T23:18:18.695Z" }, - { url = "https://files.pythonhosted.org/packages/b0/0c/35b3d92ddebfdfda76bb485738306545817253d0a3ded0bfe80ef8e67aa5/cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c70cc23f12726be8f8bc72e41d5065d77e4515efae3690326764ea1b07845cfb", size = 4409944, upload-time = "2025-10-15T23:18:20.597Z" }, - { url = "https://files.pythonhosted.org/packages/99/55/181022996c4063fc0e7666a47049a1ca705abb9c8a13830f074edb347495/cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:9394673a9f4de09e28b5356e7fff97d778f8abad85c9d5ac4a4b7e25a0de7717", size = 4242957, upload-time = "2025-10-15T23:18:22.18Z" }, - { url = "https://files.pythonhosted.org/packages/ba/af/72cd6ef29f9c5f731251acadaeb821559fe25f10852f44a63374c9ca08c1/cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:94cd0549accc38d1494e1f8de71eca837d0509d0d44bf11d158524b0e12cebf9", size = 4409447, upload-time = "2025-10-15T23:18:24.209Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c3/e90f4a4feae6410f914f8ebac129b9ae7a8c92eb60a638012dde42030a9d/cryptography-46.0.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6b5063083824e5509fdba180721d55909ffacccc8adbec85268b48439423d78c", size = 3438528, upload-time = "2025-10-15T23:18:26.227Z" }, + { url = "https://files.pythonhosted.org/packages/f7/81/b0bb27f2ba931a65409c6b8a8b358a7f03c0e46eceacddff55f7c84b1f3b/cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad", size = 7176289, upload-time = "2026-02-10T19:17:08.274Z" }, + { url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637, upload-time = "2026-02-10T19:17:10.53Z" }, + { url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742, upload-time = "2026-02-10T19:17:12.388Z" }, + { url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528, upload-time = "2026-02-10T19:17:13.853Z" }, + { url = "https://files.pythonhosted.org/packages/22/29/c2e812ebc38c57b40e7c583895e73c8c5adb4d1e4a0cc4c5a4fdab2b1acc/cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d", size = 4947993, upload-time = "2026-02-10T19:17:15.618Z" }, + { url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855, upload-time = "2026-02-10T19:17:17.221Z" }, + { url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635, upload-time = "2026-02-10T19:17:18.792Z" }, + { url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038, upload-time = "2026-02-10T19:17:20.256Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/45e76c68d7311432741faf1fbf7fac8a196a0a735ca21f504c75d37e2558/cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0", size = 4912181, upload-time = "2026-02-10T19:17:21.825Z" }, + { url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482, upload-time = "2026-02-10T19:17:25.133Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497, upload-time = "2026-02-10T19:17:26.66Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819, upload-time = "2026-02-10T19:17:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/ea/ed/325d2a490c5e94038cdb0117da9397ece1f11201f425c4e9c57fe5b9f08b/cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48", size = 3028230, upload-time = "2026-02-10T19:17:30.518Z" }, + { url = "https://files.pythonhosted.org/packages/e9/5a/ac0f49e48063ab4255d9e3b79f5def51697fce1a95ea1370f03dc9db76f6/cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4", size = 3480909, upload-time = "2026-02-10T19:17:32.083Z" }, + { url = "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2", size = 7119287, upload-time = "2026-02-10T19:17:33.801Z" }, + { url = "https://files.pythonhosted.org/packages/67/c8/581a6702e14f0898a0848105cbefd20c058099e2c2d22ef4e476dfec75d7/cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678", size = 4265728, upload-time = "2026-02-10T19:17:35.569Z" }, + { url = "https://files.pythonhosted.org/packages/dd/4a/ba1a65ce8fc65435e5a849558379896c957870dd64fecea97b1ad5f46a37/cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87", size = 4408287, upload-time = "2026-02-10T19:17:36.938Z" }, + { url = "https://files.pythonhosted.org/packages/f8/67/8ffdbf7b65ed1ac224d1c2df3943553766914a8ca718747ee3871da6107e/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee", size = 4270291, upload-time = "2026-02-10T19:17:38.748Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e5/f52377ee93bc2f2bba55a41a886fd208c15276ffbd2569f2ddc89d50e2c5/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981", size = 4927539, upload-time = "2026-02-10T19:17:40.241Z" }, + { url = "https://files.pythonhosted.org/packages/3b/02/cfe39181b02419bbbbcf3abdd16c1c5c8541f03ca8bda240debc467d5a12/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9", size = 4442199, upload-time = "2026-02-10T19:17:41.789Z" }, + { url = "https://files.pythonhosted.org/packages/c0/96/2fcaeb4873e536cf71421a388a6c11b5bc846e986b2b069c79363dc1648e/cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648", size = 3960131, upload-time = "2026-02-10T19:17:43.379Z" }, + { url = "https://files.pythonhosted.org/packages/d8/d2/b27631f401ddd644e94c5cf33c9a4069f72011821cf3dc7309546b0642a0/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4", size = 4270072, upload-time = "2026-02-10T19:17:45.481Z" }, + { url = "https://files.pythonhosted.org/packages/f4/a7/60d32b0370dae0b4ebe55ffa10e8599a2a59935b5ece1b9f06edb73abdeb/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0", size = 4892170, upload-time = "2026-02-10T19:17:46.997Z" }, + { url = "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663", size = 4441741, upload-time = "2026-02-10T19:17:48.661Z" }, + { url = "https://files.pythonhosted.org/packages/5f/eb/eee00b28c84c726fe8fa0158c65afe312d9c3b78d9d01daf700f1f6e37ff/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826", size = 4396728, upload-time = "2026-02-10T19:17:50.058Z" }, + { url = "https://files.pythonhosted.org/packages/65/f4/6bc1a9ed5aef7145045114b75b77c2a8261b4d38717bd8dea111a63c3442/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d", size = 4652001, upload-time = "2026-02-10T19:17:51.54Z" }, + { url = "https://files.pythonhosted.org/packages/86/ef/5d00ef966ddd71ac2e6951d278884a84a40ffbd88948ef0e294b214ae9e4/cryptography-46.0.5-cp314-cp314t-win32.whl", hash = "sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a", size = 3003637, upload-time = "2026-02-10T19:17:52.997Z" }, + { url = "https://files.pythonhosted.org/packages/b7/57/f3f4160123da6d098db78350fdfd9705057aad21de7388eacb2401dceab9/cryptography-46.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4", size = 3469487, upload-time = "2026-02-10T19:17:54.549Z" }, + { url = "https://files.pythonhosted.org/packages/e2/fa/a66aa722105ad6a458bebd64086ca2b72cdd361fed31763d20390f6f1389/cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31", size = 7170514, upload-time = "2026-02-10T19:17:56.267Z" }, + { url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349, upload-time = "2026-02-10T19:17:58.419Z" }, + { url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667, upload-time = "2026-02-10T19:18:00.619Z" }, + { url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980, upload-time = "2026-02-10T19:18:02.379Z" }, + { url = "https://files.pythonhosted.org/packages/8e/7c/c4f45e0eeff9b91e3f12dbd0e165fcf2a38847288fcfd889deea99fb7b6d/cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76", size = 4939143, upload-time = "2026-02-10T19:18:03.964Z" }, + { url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674, upload-time = "2026-02-10T19:18:05.588Z" }, + { url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801, upload-time = "2026-02-10T19:18:07.167Z" }, + { url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755, upload-time = "2026-02-10T19:18:09.813Z" }, + { url = "https://files.pythonhosted.org/packages/33/45/726809d1176959f4a896b86907b98ff4391a8aa29c0aaaf9450a8a10630e/cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d", size = 4901539, upload-time = "2026-02-10T19:18:11.263Z" }, + { url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794, upload-time = "2026-02-10T19:18:12.914Z" }, + { url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160, upload-time = "2026-02-10T19:18:14.375Z" }, + { url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123, upload-time = "2026-02-10T19:18:15.886Z" }, + { url = "https://files.pythonhosted.org/packages/45/2d/9c5f2926cb5300a8eefc3f4f0b3f3df39db7f7ce40c8365444c49363cbda/cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72", size = 3010220, upload-time = "2026-02-10T19:18:17.361Z" }, + { url = "https://files.pythonhosted.org/packages/48/ef/0c2f4a8e31018a986949d34a01115dd057bf536905dca38897bacd21fac3/cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595", size = 3467050, upload-time = "2026-02-10T19:18:18.899Z" }, + { url = "https://files.pythonhosted.org/packages/eb/dd/2d9fdb07cebdf3d51179730afb7d5e576153c6744c3ff8fded23030c204e/cryptography-46.0.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:3b4995dc971c9fb83c25aa44cf45f02ba86f71ee600d81091c2f0cbae116b06c", size = 3476964, upload-time = "2026-02-10T19:18:20.687Z" }, + { url = "https://files.pythonhosted.org/packages/e9/6f/6cc6cc9955caa6eaf83660b0da2b077c7fe8ff9950a3c5e45d605038d439/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bc84e875994c3b445871ea7181d424588171efec3e185dced958dad9e001950a", size = 4218321, upload-time = "2026-02-10T19:18:22.349Z" }, + { url = "https://files.pythonhosted.org/packages/3e/5d/c4da701939eeee699566a6c1367427ab91a8b7088cc2328c09dbee940415/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2ae6971afd6246710480e3f15824ed3029a60fc16991db250034efd0b9fb4356", size = 4381786, upload-time = "2026-02-10T19:18:24.529Z" }, + { url = "https://files.pythonhosted.org/packages/ac/97/a538654732974a94ff96c1db621fa464f455c02d4bb7d2652f4edc21d600/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d861ee9e76ace6cf36a6a89b959ec08e7bc2493ee39d07ffe5acb23ef46d27da", size = 4217990, upload-time = "2026-02-10T19:18:25.957Z" }, + { url = "https://files.pythonhosted.org/packages/ae/11/7e500d2dd3ba891197b9efd2da5454b74336d64a7cc419aa7327ab74e5f6/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:2b7a67c9cd56372f3249b39699f2ad479f6991e62ea15800973b956f4b73e257", size = 4381252, upload-time = "2026-02-10T19:18:27.496Z" }, + { url = "https://files.pythonhosted.org/packages/bc/58/6b3d24e6b9bc474a2dcdee65dfd1f008867015408a271562e4b690561a4d/cryptography-46.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8456928655f856c6e1533ff59d5be76578a7157224dbd9ce6872f25055ab9ab7", size = 3407605, upload-time = "2026-02-10T19:18:29.233Z" }, ] [[package]] From b2332013086d1d48ba844bccbe41a10010bba57b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 01:27:42 -0800 Subject: [PATCH 15/41] chore(deps): bump protobuf from 6.33.4 to 6.33.5 in /libs/langgraph (#6833) Bumps [protobuf](https://github.com/protocolbuffers/protobuf) from 6.33.4 to 6.33.5.
Release notes

Sourced from protobuf's releases.

Protocol Buffers v34.0-rc1

Announcements

Bazel

Compiler

C++

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=protobuf&package-manager=uv&previous-version=6.33.4&new-version=6.33.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/langchain-ai/langgraph/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- libs/langgraph/uv.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libs/langgraph/uv.lock b/libs/langgraph/uv.lock index 605825454..88e0c62c4 100644 --- a/libs/langgraph/uv.lock +++ b/libs/langgraph/uv.lock @@ -2523,17 +2523,17 @@ wheels = [ [[package]] name = "protobuf" -version = "6.33.4" +version = "6.33.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/53/b8/cda15d9d46d03d4aa3a67cb6bffe05173440ccf86a9541afaf7ac59a1b6b/protobuf-6.33.4.tar.gz", hash = "sha256:dc2e61bca3b10470c1912d166fe0af67bfc20eb55971dcef8dfa48ce14f0ed91", size = 444346, upload-time = "2026-01-12T18:33:40.109Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/25/7c72c307aafc96fa87062aa6291d9f7c94836e43214d43722e86037aac02/protobuf-6.33.5.tar.gz", hash = "sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c", size = 444465, upload-time = "2026-01-29T21:51:33.494Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/be/24ef9f3095bacdf95b458543334d0c4908ccdaee5130420bf064492c325f/protobuf-6.33.4-cp310-abi3-win32.whl", hash = "sha256:918966612c8232fc6c24c78e1cd89784307f5814ad7506c308ee3cf86662850d", size = 425612, upload-time = "2026-01-12T18:33:29.656Z" }, - { url = "https://files.pythonhosted.org/packages/31/ad/e5693e1974a28869e7cd244302911955c1cebc0161eb32dfa2b25b6e96f0/protobuf-6.33.4-cp310-abi3-win_amd64.whl", hash = "sha256:8f11ffae31ec67fc2554c2ef891dcb561dae9a2a3ed941f9e134c2db06657dbc", size = 436962, upload-time = "2026-01-12T18:33:31.345Z" }, - { url = "https://files.pythonhosted.org/packages/66/15/6ee23553b6bfd82670207ead921f4d8ef14c107e5e11443b04caeb5ab5ec/protobuf-6.33.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2fe67f6c014c84f655ee06f6f66213f9254b3a8b6bda6cda0ccd4232c73c06f0", size = 427612, upload-time = "2026-01-12T18:33:32.646Z" }, - { url = "https://files.pythonhosted.org/packages/2b/48/d301907ce6d0db75f959ca74f44b475a9caa8fcba102d098d3c3dd0f2d3f/protobuf-6.33.4-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:757c978f82e74d75cba88eddec479df9b99a42b31193313b75e492c06a51764e", size = 324484, upload-time = "2026-01-12T18:33:33.789Z" }, - { url = "https://files.pythonhosted.org/packages/92/1c/e53078d3f7fe710572ab2dcffd993e1e3b438ae71cfc031b71bae44fcb2d/protobuf-6.33.4-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:c7c64f259c618f0bef7bee042075e390debbf9682334be2b67408ec7c1c09ee6", size = 339256, upload-time = "2026-01-12T18:33:35.231Z" }, - { url = "https://files.pythonhosted.org/packages/e8/8e/971c0edd084914f7ee7c23aa70ba89e8903918adca179319ee94403701d5/protobuf-6.33.4-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:3df850c2f8db9934de4cf8f9152f8dc2558f49f298f37f90c517e8e5c84c30e9", size = 323311, upload-time = "2026-01-12T18:33:36.305Z" }, - { url = "https://files.pythonhosted.org/packages/75/b1/1dc83c2c661b4c62d56cc081706ee33a4fc2835bd90f965baa2663ef7676/protobuf-6.33.4-py3-none-any.whl", hash = "sha256:1fe3730068fcf2e595816a6c34fe66eeedd37d51d0400b72fabc848811fdc1bc", size = 170532, upload-time = "2026-01-12T18:33:39.199Z" }, + { url = "https://files.pythonhosted.org/packages/b1/79/af92d0a8369732b027e6d6084251dd8e782c685c72da161bd4a2e00fbabb/protobuf-6.33.5-cp310-abi3-win32.whl", hash = "sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b", size = 425769, upload-time = "2026-01-29T21:51:21.751Z" }, + { url = "https://files.pythonhosted.org/packages/55/75/bb9bc917d10e9ee13dee8607eb9ab963b7cf8be607c46e7862c748aa2af7/protobuf-6.33.5-cp310-abi3-win_amd64.whl", hash = "sha256:3093804752167bcab3998bec9f1048baae6e29505adaf1afd14a37bddede533c", size = 437118, upload-time = "2026-01-29T21:51:24.022Z" }, + { url = "https://files.pythonhosted.org/packages/a2/6b/e48dfc1191bc5b52950246275bf4089773e91cb5ba3592621723cdddca62/protobuf-6.33.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a5cb85982d95d906df1e2210e58f8e4f1e3cdc088e52c921a041f9c9a0386de5", size = 427766, upload-time = "2026-01-29T21:51:25.413Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b1/c79468184310de09d75095ed1314b839eb2f72df71097db9d1404a1b2717/protobuf-6.33.5-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190", size = 324638, upload-time = "2026-01-29T21:51:26.423Z" }, + { url = "https://files.pythonhosted.org/packages/c5/f5/65d838092fd01c44d16037953fd4c2cc851e783de9b8f02b27ec4ffd906f/protobuf-6.33.5-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd", size = 339411, upload-time = "2026-01-29T21:51:27.446Z" }, + { url = "https://files.pythonhosted.org/packages/9b/53/a9443aa3ca9ba8724fdfa02dd1887c1bcd8e89556b715cfbacca6b63dbec/protobuf-6.33.5-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0", size = 323465, upload-time = "2026-01-29T21:51:28.925Z" }, + { url = "https://files.pythonhosted.org/packages/57/bf/2086963c69bdac3d7cff1cc7ff79b8ce5ea0bec6797a017e1be338a46248/protobuf-6.33.5-py3-none-any.whl", hash = "sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02", size = 170687, upload-time = "2026-01-29T21:51:32.557Z" }, ] [[package]] From a181e0bb91b110239562d2b8b02d38e28aa213dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 01:28:08 -0800 Subject: [PATCH 16/41] chore(deps): bump langchain-core from 1.2.7 to 1.2.11 in /libs/checkpoint-sqlite (#6828) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [langchain-core](https://github.com/langchain-ai/langchain) from 1.2.7 to 1.2.11.
Release notes

Sourced from langchain-core's releases.

langchain-core==1.2.11

Changes since langchain-core==1.2.10

release(core): 1.2.11 (#35144) fix(openai): sanitize urls when counting tokens in images (#35143) chore(core): clean up docstring mismatch and redundant logic in langchain-core (#35064) fix(core): replace bare except with Exception in tracer (#35138)

langchain-core==1.2.10

Changes since langchain-core==1.2.9

release(core): 1.2.10 (#35136) chore(deps): bump the langchain-deps group across 3 directories with 40 updates (#35129) chore(deps): bump the langchain-deps group across 3 directories with 11 updates (#35121) feat(core): add ContextOverflowError, raise in anthropic and openai (#35099) feat(model-profiles): add text_inputs and text_outputs (#35084) feat(core): count tokens from tool schemas in count_tokens_approximately (#35098) docs(core): add missing name docstring for RunnableSerializable (#35088)

langchain-core==1.2.9

Changes since langchain-core==1.2.8

release(core): 1.2.9 (#35025) fix(core): adjust cap when scaling approximate token counts (#35017) revert: precompile hex color regex pattern at module level (#35016) chore: add make type target (#35015) revert: "chore: add typing target in Makefile" (#35013) chore: add typing target in Makefile (#35012) fix(core): apply cap when scaling approximate token counts (#35005) feat(core): allow scaling by reported usage when counting tokens approximately (#34996) test(core): increase delta_time for flaky test (#34982) chore: enrich pyproject.toml files (#34980)

langchain-core==1.2.8

Changes since langchain-core==1.2.7

release(core): 1.2.8 (#34975) docs(core): add examples for pretty_repr, pretty_print (#34968) docs(core): use proper admonition for get_buffer_string (#34967) docs: add usage examples to core classes (#34841) chore(core): fix docstring format (#34966) chore(deps): bump the uv group across 20 directories with 3 updates (#34941) docs: add example to create_message function docstring (#34851) docs(core): clarify @​tool decorator argument and return type requirements (#34860) fix(core): fix nested mustache variable extraction and update docs (#34872) fix(core): allow base model annotations for empty model (#34932) chore: upgrade urllib3 to 2.6.3 (#34940) fix(core): prevent crash in ParrotFakeChatModel when messages list is empty (#34943) fix(core): google docstring parsing with no arguments/reserved arguments (#34861) test(core): add tests for approximate token counting with multimodal messages (#34898)

... (truncated)

Commits
  • 524e1da release(core): 1.2.11 (#35144)
  • 2b4b1dc fix(openai): sanitize urls when counting tokens in images (#35143)
  • 0493b27 fix(anthropic): support effort="max" and remove beta headers (#35141)
  • a5f22e7 chore(core): clean up docstring mismatch and redundant logic in langchain-cor...
  • 97ee14c fix(core): replace bare except with Exception in tracer (#35138)
  • 990e807 release(standard-tests): release 1.1.5 (#35139)
  • 74dffca release(langchain): 1.2.10 (#35137)
  • f41e049 release(core): 1.2.10 (#35136)
  • de05838 chore(deps): bump the langchain-deps group across 3 directories with 40 updat...
  • d6e86aa chore(deps): bump the other-deps group across 3 directories with 12 updates (...
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=langchain-core&package-manager=uv&previous-version=1.2.7&new-version=1.2.11)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/langchain-ai/langgraph/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- libs/checkpoint-sqlite/uv.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/checkpoint-sqlite/uv.lock b/libs/checkpoint-sqlite/uv.lock index 06d542c93..3d6e2b7a6 100644 --- a/libs/checkpoint-sqlite/uv.lock +++ b/libs/checkpoint-sqlite/uv.lock @@ -249,7 +249,7 @@ wheels = [ [[package]] name = "langchain-core" -version = "1.2.7" +version = "1.2.11" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsonpatch" }, @@ -261,9 +261,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "uuid-utils" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a2/0e/664d8d81b3493e09cbab72448d2f9d693d1fa5aa2bcc488602203a9b6da0/langchain_core-1.2.7.tar.gz", hash = "sha256:e1460639f96c352b4a41c375f25aeb8d16ffc1769499fb1c20503aad59305ced", size = 837039, upload-time = "2026-01-09T17:44:25.505Z" } +sdist = { url = "https://files.pythonhosted.org/packages/12/17/1943cedfc118e04b8128e4c3e1dbf0fa0ea58eefddbb6198cfd699d19f01/langchain_core-1.2.11.tar.gz", hash = "sha256:f164bb36602dd74a3a50c1334fca75309ad5ed95767acdfdbb9fa95ce28a1e01", size = 831211, upload-time = "2026-02-10T20:35:28.35Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/6f/34a9fba14d191a67f7e2ee3dbce3e9b86d2fa7310e2c7f2c713583481bd2/langchain_core-1.2.7-py3-none-any.whl", hash = "sha256:452f4fef7a3d883357b22600788d37e3d8854ef29da345b7ac7099f33c31828b", size = 490232, upload-time = "2026-01-09T17:44:24.236Z" }, + { url = "https://files.pythonhosted.org/packages/10/30/1f80e3fc674353cad975ed5294353d42512535d2094ef032c06454c2c873/langchain_core-1.2.11-py3-none-any.whl", hash = "sha256:ae11ceb8dda60d0b9d09e763116e592f1683327c17be5b715f350fd29aee65d3", size = 500062, upload-time = "2026-02-10T20:35:26.698Z" }, ] [[package]] From 270621db662ef9df938b47225a50642d76edf266 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 01:30:58 -0800 Subject: [PATCH 17/41] chore(deps): bump the all-dependencies group in /libs/prebuilt with 3 updates (#6810) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the all-dependencies group in /libs/prebuilt with 3 updates: [langchain-core](https://github.com/langchain-ai/langchain), [syrupy](https://github.com/syrupy-project/syrupy) and [ruff](https://github.com/astral-sh/ruff). Updates `langchain-core` from 1.2.7 to 1.2.12
Release notes

Sourced from langchain-core's releases.

langchain-core==1.2.12

Changes since langchain-core==1.2.11

release(core): 1.2.12 (#35192) fix(core): fix setting ChatGeneration.text (#35191)

langchain-core==1.2.11

Changes since langchain-core==1.2.10

release(core): 1.2.11 (#35144) fix(openai): sanitize urls when counting tokens in images (#35143) chore(core): clean up docstring mismatch and redundant logic in langchain-core (#35064) fix(core): replace bare except with Exception in tracer (#35138)

langchain-core==1.2.10

Changes since langchain-core==1.2.9

release(core): 1.2.10 (#35136) chore(deps): bump the langchain-deps group across 3 directories with 40 updates (#35129) chore(deps): bump the langchain-deps group across 3 directories with 11 updates (#35121) feat(core): add ContextOverflowError, raise in anthropic and openai (#35099) feat(model-profiles): add text_inputs and text_outputs (#35084) feat(core): count tokens from tool schemas in count_tokens_approximately (#35098) docs(core): add missing name docstring for RunnableSerializable (#35088)

langchain-core==1.2.9

Changes since langchain-core==1.2.8

release(core): 1.2.9 (#35025) fix(core): adjust cap when scaling approximate token counts (#35017) revert: precompile hex color regex pattern at module level (#35016) chore: add make type target (#35015) revert: "chore: add typing target in Makefile" (#35013) chore: add typing target in Makefile (#35012) fix(core): apply cap when scaling approximate token counts (#35005) feat(core): allow scaling by reported usage when counting tokens approximately (#34996) test(core): increase delta_time for flaky test (#34982) chore: enrich pyproject.toml files (#34980)

langchain-core==1.2.8

Changes since langchain-core==1.2.7

release(core): 1.2.8 (#34975) docs(core): add examples for pretty_repr, pretty_print (#34968) docs(core): use proper admonition for get_buffer_string (#34967) docs: add usage examples to core classes (#34841) chore(core): fix docstring format (#34966) chore(deps): bump the uv group across 20 directories with 3 updates (#34941) docs: add example to create_message function docstring (#34851) docs(core): clarify @​tool decorator argument and return type requirements (#34860)

... (truncated)

Commits
  • b06716f release(core): 1.2.12 (#35192)
  • 16cabfa fix(core): fix setting ChatGeneration.text (#35191)
  • 8f859bd release(huggingface): 1.2.1 (#35182)
  • 19ddd42 fix(ollama): raise error when clients are not initialized (#35185)
  • a50d86c docs(langchain-classic): clarify MultiVectorRetriever usage (#35053)
  • f89e30e chore(huggingface): version bump for huggingface-hub and transformers deps (#...
  • 6ac12b3 chore: bump pillow from 11.3.0 to 12.1.1 in /libs/partners/openai (#35177)
  • d41deda fix(langchain-classic): validate ensemble retriever weights (#35078)
  • 9d0bd83 chore: bump pillow from 11.3.0 to 12.1.1 in /libs/partners/perplexity (#35176)
  • f22f5d5 chore(deps): bump pillow from 11.3.0 to 12.1.1 in /libs/langchain (#35175)
  • Additional commits viewable in compare view

Updates `syrupy` from 5.0.0 to 5.1.0
Release notes

Sourced from syrupy's releases.

v5.1.0

5.1.0 (2026-01-25)

Features

  • add serializer plugin system; plugins for data models (#1062) (df9bc8f)
Changelog

Sourced from syrupy's changelog.

5.1.0 (2026-01-25)

Features

  • add serializer plugin system; plugins for data models (#1062) (df9bc8f)
Commits
  • 7096efd chore(release): 5.1.0 [skip ci]
  • 07aa00d chore(deps): update dependency attrs to v25 (#1063)
  • 1f29ae0 docs: add bwrob as a contributor for code (#1064)
  • df9bc8f feat: add serializer plugin system; plugins for data models (#1062)
  • 841257d chore(deps): update dependency coverage to v7.13.1 (#1061)
  • 2d8dfa7 chore(deps): update codecov/codecov-action action to v5.5.2 (#1056)
  • f5f9ef7 chore(deps): update dependency debugpy to v1.8.18 (#1057)
  • eaeb6ae chore(deps): update dependency pytest to v9.0.2 (#1055)
  • 263b23b chore(deps): update python docker tag to v3.14.1 (#1054)
  • a0dd77b chore(deps): update actions/checkout action to v6.0.1 (#1053)
  • Additional commits viewable in compare view

Updates `ruff` from 0.14.13 to 0.15.1
Release notes

Sourced from ruff's releases.

0.15.1

Release Notes

Released on 2026-02-12.

Preview features

  • [airflow] Add ruff rules to catch deprecated Airflow imports for Airflow 3.1 (AIR321) (#22376)
  • [airflow] Third positional parameter not named ti_key should be flagged for BaseOperatorLink.get_link (AIR303) (#22828)
  • [flake8-gettext] Fix false negatives for plural argument of ngettext (INT001, INT002, INT003) (#21078)
  • [pyflakes] Fix infinite loop in preview fix for unused-import (F401) (#23038)
  • [pygrep-hooks] Detect non-existent mock methods in standalone expressions (PGH005) (#22830)
  • [pylint] Allow dunder submodules and improve diagnostic range (PLC2701) (#22804)
  • [pyupgrade] Improve diagnostic range for tuples (UP024) (#23013)
  • [refurb] Check subscripts in tuple do not use lambda parameters in reimplemented-operator (FURB118) (#23079)
  • [ruff] Detect mutable defaults in field calls (RUF008) (#23046)
  • [ruff] Ignore std cmath.inf (RUF069) (#23120)
  • [ruff] New rule float-equality-comparison (RUF069) (#20585)
  • Don't format unlabeled Markdown code blocks (#23106)
  • Markdown formatting support in LSP (#23063)
  • Support Quarto Markdown language markers (#22947)
  • Support formatting pycon Markdown code blocks (#23112)
  • Use extension mapping to select Markdown code block language (#22934)

Bug fixes

  • Avoid false positive for undefined variables in FAST001 (#23224)
  • Avoid introducing syntax errors for FAST003 autofix (#23227)
  • Avoid suggesting InitVar for __post_init__ that references PEP 695 type parameters (#23226)
  • Deduplicate type variables in generic functions (#23225)
  • Fix exception handler parenthesis removal for Python 3.14+ (#23126)
  • Fix f-string middle panic when parsing t-strings (#23232)
  • Wrap RUF020 target for multiline fixes (#23210)
  • Wrap UP007 target for multiline fixes (#23208)
  • Fix missing diagnostics for last range suppression in file (#23242)
  • [pyupgrade] Fix syntax error on string with newline escape and comment (UP037) (#22968)

Rule changes

  • Use ruff instead of Ruff as the program name in GitHub output format (#23240)
  • [PT006] Fix syntax error when unpacking nested tuples in parametrize fixes (#22441) (#22464)
  • [airflow] Catch deprecated attribute access from context key for Airflow 3.0 (AIR301) (#22850)
  • [airflow] Capture deprecated arguments and a decorator (AIR301) (#23170)
  • [flake8-boolean-trap] Add multiprocessing.Value to excluded functions for FBT003 (#23010)
  • [flake8-bugbear] Add a secondary annotation showing the previous occurrence (B033) (#22634)
  • [flake8-type-checking] Add sub-diagnostic showing the runtime use of an annotation (TC004) (#23091)
  • [isort] Support configurable import section heading comments (#23151)
  • [ruff] Improve the diagnostic for RUF012 (#23202)

Formatter

... (truncated)

Changelog

Sourced from ruff's changelog.

0.15.1

Released on 2026-02-12.

Preview features

  • [airflow] Add ruff rules to catch deprecated Airflow imports for Airflow 3.1 (AIR321) (#22376)
  • [airflow] Third positional parameter not named ti_key should be flagged for BaseOperatorLink.get_link (AIR303) (#22828)
  • [flake8-gettext] Fix false negatives for plural argument of ngettext (INT001, INT002, INT003) (#21078)
  • [pyflakes] Fix infinite loop in preview fix for unused-import (F401) (#23038)
  • [pygrep-hooks] Detect non-existent mock methods in standalone expressions (PGH005) (#22830)
  • [pylint] Allow dunder submodules and improve diagnostic range (PLC2701) (#22804)
  • [pyupgrade] Improve diagnostic range for tuples (UP024) (#23013)
  • [refurb] Check subscripts in tuple do not use lambda parameters in reimplemented-operator (FURB118) (#23079)
  • [ruff] Detect mutable defaults in field calls (RUF008) (#23046)
  • [ruff] Ignore std cmath.inf (RUF069) (#23120)
  • [ruff] New rule float-equality-comparison (RUF069) (#20585)
  • Don't format unlabeled Markdown code blocks (#23106)
  • Markdown formatting support in LSP (#23063)
  • Support Quarto Markdown language markers (#22947)
  • Support formatting pycon Markdown code blocks (#23112)
  • Use extension mapping to select Markdown code block language (#22934)

Bug fixes

  • Avoid false positive for undefined variables in FAST001 (#23224)
  • Avoid introducing syntax errors for FAST003 autofix (#23227)
  • Avoid suggesting InitVar for __post_init__ that references PEP 695 type parameters (#23226)
  • Deduplicate type variables in generic functions (#23225)
  • Fix exception handler parenthesis removal for Python 3.14+ (#23126)
  • Fix f-string middle panic when parsing t-strings (#23232)
  • Wrap RUF020 target for multiline fixes (#23210)
  • Wrap UP007 target for multiline fixes (#23208)
  • Fix missing diagnostics for last range suppression in file (#23242)
  • [pyupgrade] Fix syntax error on string with newline escape and comment (UP037) (#22968)

Rule changes

  • Use ruff instead of Ruff as the program name in GitHub output format (#23240)
  • [PT006] Fix syntax error when unpacking nested tuples in parametrize fixes (#22441) (#22464)
  • [airflow] Catch deprecated attribute access from context key for Airflow 3.0 (AIR301) (#22850)
  • [airflow] Capture deprecated arguments and a decorator (AIR301) (#23170)
  • [flake8-boolean-trap] Add multiprocessing.Value to excluded functions for FBT003 (#23010)
  • [flake8-bugbear] Add a secondary annotation showing the previous occurrence (B033) (#22634)
  • [flake8-type-checking] Add sub-diagnostic showing the runtime use of an annotation (TC004) (#23091)
  • [isort] Support configurable import section heading comments (#23151)
  • [ruff] Improve the diagnostic for RUF012 (#23202)

Formatter

... (truncated)

Commits
  • a2f11d2 Prepare for 0.15.1 (#23253)
  • d29628e Remove docker-run-action (#23254)
  • 8a04266 [ty] Allow discovering dependencies in system Python environments (#22994)
  • 55d06c8 Ensure pending suppression diagnostics are reported (#23242)
  • d056a9f [isort] support for configurable import section heading comments (#23151)
  • e22fa4f [ty] Fix method calls on subclasses of Any (#23248)
  • fa56c15 [ty] Fix bound method access on None (#23246)
  • 4fd07d0 Make range suppression test snapshot actually useful (#23251)
  • 8c63bce [ty] Include conditional symbols (like datetime.UTC) in auto-import in more...
  • 46be943 Exclude WASM artifacts from GitHub releases (#23221)
  • Additional commits viewable in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- libs/prebuilt/uv.lock | 51 +++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/libs/prebuilt/uv.lock b/libs/prebuilt/uv.lock index 2a2f2d66f..b75d467b7 100644 --- a/libs/prebuilt/uv.lock +++ b/libs/prebuilt/uv.lock @@ -249,7 +249,7 @@ wheels = [ [[package]] name = "langchain-core" -version = "1.2.7" +version = "1.2.12" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsonpatch" }, @@ -261,9 +261,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "uuid-utils" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a2/0e/664d8d81b3493e09cbab72448d2f9d693d1fa5aa2bcc488602203a9b6da0/langchain_core-1.2.7.tar.gz", hash = "sha256:e1460639f96c352b4a41c375f25aeb8d16ffc1769499fb1c20503aad59305ced", size = 837039, upload-time = "2026-01-09T17:44:25.505Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/1d/08e935d1532fcc90981f6e5bb6825914c9227ea7a962c62b1e18619b49e7/langchain_core-1.2.12.tar.gz", hash = "sha256:4d7fa6643d7ab06fc1905a9b7dcbe96a6f3c181046b56edf9c0c17ecd412d9e9", size = 831329, upload-time = "2026-02-12T20:53:15.01Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/6f/34a9fba14d191a67f7e2ee3dbce3e9b86d2fa7310e2c7f2c713583481bd2/langchain_core-1.2.7-py3-none-any.whl", hash = "sha256:452f4fef7a3d883357b22600788d37e3d8854ef29da345b7ac7099f33c31828b", size = 490232, upload-time = "2026-01-09T17:44:24.236Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a5/678ab0e5cc57794f20ae5ed12c1442506ef1108c9434f950aebc6044e5a3/langchain_core-1.2.12-py3-none-any.whl", hash = "sha256:66ca17a2a9cb007ab29021968e6adfcf4228067151dc2bd6ebfff265ffaf92f5", size = 500132, upload-time = "2026-02-12T20:53:13.806Z" }, ] [[package]] @@ -1305,28 +1305,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.14.13" +version = "0.15.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/50/0a/1914efb7903174b381ee2ffeebb4253e729de57f114e63595114c8ca451f/ruff-0.14.13.tar.gz", hash = "sha256:83cd6c0763190784b99650a20fec7633c59f6ebe41c5cc9d45ee42749563ad47", size = 6059504, upload-time = "2026-01-15T20:15:16.918Z" } +sdist = { url = "https://files.pythonhosted.org/packages/04/dc/4e6ac71b511b141cf626357a3946679abeba4cf67bc7cc5a17920f31e10d/ruff-0.15.1.tar.gz", hash = "sha256:c590fe13fb57c97141ae975c03a1aedb3d3156030cabd740d6ff0b0d601e203f", size = 4540855, upload-time = "2026-02-12T23:09:09.998Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/ae/0deefbc65ca74b0ab1fd3917f94dc3b398233346a74b8bbb0a916a1a6bf6/ruff-0.14.13-py3-none-linux_armv6l.whl", hash = "sha256:76f62c62cd37c276cb03a275b198c7c15bd1d60c989f944db08a8c1c2dbec18b", size = 13062418, upload-time = "2026-01-15T20:14:50.779Z" }, - { url = "https://files.pythonhosted.org/packages/47/df/5916604faa530a97a3c154c62a81cb6b735c0cb05d1e26d5ad0f0c8ac48a/ruff-0.14.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:914a8023ece0528d5cc33f5a684f5f38199bbb566a04815c2c211d8f40b5d0ed", size = 13442344, upload-time = "2026-01-15T20:15:07.94Z" }, - { url = "https://files.pythonhosted.org/packages/4c/f3/e0e694dd69163c3a1671e102aa574a50357536f18a33375050334d5cd517/ruff-0.14.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d24899478c35ebfa730597a4a775d430ad0d5631b8647a3ab368c29b7e7bd063", size = 12354720, upload-time = "2026-01-15T20:15:09.854Z" }, - { url = "https://files.pythonhosted.org/packages/c3/e8/67f5fcbbaee25e8fc3b56cc33e9892eca7ffe09f773c8e5907757a7e3bdb/ruff-0.14.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9aaf3870f14d925bbaf18b8a2347ee0ae7d95a2e490e4d4aea6813ed15ebc80e", size = 12774493, upload-time = "2026-01-15T20:15:20.908Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ce/d2e9cb510870b52a9565d885c0d7668cc050e30fa2c8ac3fb1fda15c083d/ruff-0.14.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac5b7f63dd3b27cc811850f5ffd8fff845b00ad70e60b043aabf8d6ecc304e09", size = 12815174, upload-time = "2026-01-15T20:15:05.74Z" }, - { url = "https://files.pythonhosted.org/packages/88/00/c38e5da58beebcf4fa32d0ddd993b63dfacefd02ab7922614231330845bf/ruff-0.14.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78d2b1097750d90ba82ce4ba676e85230a0ed694178ca5e61aa9b459970b3eb9", size = 13680909, upload-time = "2026-01-15T20:15:14.537Z" }, - { url = "https://files.pythonhosted.org/packages/61/61/cd37c9dd5bd0a3099ba79b2a5899ad417d8f3b04038810b0501a80814fd7/ruff-0.14.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d0bf87705acbbcb8d4c24b2d77fbb73d40210a95c3903b443cd9e30824a5032", size = 15144215, upload-time = "2026-01-15T20:15:22.886Z" }, - { url = "https://files.pythonhosted.org/packages/56/8a/85502d7edbf98c2df7b8876f316c0157359165e16cdf98507c65c8d07d3d/ruff-0.14.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3eb5da8e2c9e9f13431032fdcbe7681de9ceda5835efee3269417c13f1fed5c", size = 14706067, upload-time = "2026-01-15T20:14:48.271Z" }, - { url = "https://files.pythonhosted.org/packages/7e/2f/de0df127feb2ee8c1e54354dc1179b4a23798f0866019528c938ba439aca/ruff-0.14.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:642442b42957093811cd8d2140dfadd19c7417030a7a68cf8d51fcdd5f217427", size = 14133916, upload-time = "2026-01-15T20:14:57.357Z" }, - { url = "https://files.pythonhosted.org/packages/0d/77/9b99686bb9fe07a757c82f6f95e555c7a47801a9305576a9c67e0a31d280/ruff-0.14.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4acdf009f32b46f6e8864af19cbf6841eaaed8638e65c8dac845aea0d703c841", size = 13859207, upload-time = "2026-01-15T20:14:55.111Z" }, - { url = "https://files.pythonhosted.org/packages/7d/46/2bdcb34a87a179a4d23022d818c1c236cb40e477faf0d7c9afb6813e5876/ruff-0.14.13-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:591a7f68860ea4e003917d19b5c4f5ac39ff558f162dc753a2c5de897fd5502c", size = 14043686, upload-time = "2026-01-15T20:14:52.841Z" }, - { url = "https://files.pythonhosted.org/packages/1a/a9/5c6a4f56a0512c691cf143371bcf60505ed0f0860f24a85da8bd123b2bf1/ruff-0.14.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:774c77e841cc6e046fc3e91623ce0903d1cd07e3a36b1a9fe79b81dab3de506b", size = 12663837, upload-time = "2026-01-15T20:15:18.921Z" }, - { url = "https://files.pythonhosted.org/packages/fe/bb/b920016ece7651fa7fcd335d9d199306665486694d4361547ccb19394c44/ruff-0.14.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:61f4e40077a1248436772bb6512db5fc4457fe4c49e7a94ea7c5088655dd21ae", size = 12805867, upload-time = "2026-01-15T20:14:59.272Z" }, - { url = "https://files.pythonhosted.org/packages/7d/b3/0bd909851e5696cd21e32a8fc25727e5f58f1934b3596975503e6e85415c/ruff-0.14.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6d02f1428357fae9e98ac7aa94b7e966fd24151088510d32cf6f902d6c09235e", size = 13208528, upload-time = "2026-01-15T20:15:03.732Z" }, - { url = "https://files.pythonhosted.org/packages/3b/3b/e2d94cb613f6bbd5155a75cbe072813756363eba46a3f2177a1fcd0cd670/ruff-0.14.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e399341472ce15237be0c0ae5fbceca4b04cd9bebab1a2b2c979e015455d8f0c", size = 13929242, upload-time = "2026-01-15T20:15:11.918Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c5/abd840d4132fd51a12f594934af5eba1d5d27298a6f5b5d6c3be45301caf/ruff-0.14.13-py3-none-win32.whl", hash = "sha256:ef720f529aec113968b45dfdb838ac8934e519711da53a0456038a0efecbd680", size = 12919024, upload-time = "2026-01-15T20:14:43.647Z" }, - { url = "https://files.pythonhosted.org/packages/c2/55/6384b0b8ce731b6e2ade2b5449bf07c0e4c31e8a2e68ea65b3bafadcecc5/ruff-0.14.13-py3-none-win_amd64.whl", hash = "sha256:6070bd026e409734b9257e03e3ef18c6e1a216f0435c6751d7a8ec69cb59abef", size = 14097887, upload-time = "2026-01-15T20:15:01.48Z" }, - { url = "https://files.pythonhosted.org/packages/4d/e1/7348090988095e4e39560cfc2f7555b1b2a7357deba19167b600fdf5215d/ruff-0.14.13-py3-none-win_arm64.whl", hash = "sha256:7ab819e14f1ad9fe39f246cfcc435880ef7a9390d81a2b6ac7e01039083dd247", size = 13080224, upload-time = "2026-01-15T20:14:45.853Z" }, + { url = "https://files.pythonhosted.org/packages/23/bf/e6e4324238c17f9d9120a9d60aa99a7daaa21204c07fcd84e2ef03bb5fd1/ruff-0.15.1-py3-none-linux_armv6l.whl", hash = "sha256:b101ed7cf4615bda6ffe65bdb59f964e9f4a0d3f85cbf0e54f0ab76d7b90228a", size = 10367819, upload-time = "2026-02-12T23:09:03.598Z" }, + { url = "https://files.pythonhosted.org/packages/b3/ea/c8f89d32e7912269d38c58f3649e453ac32c528f93bb7f4219258be2e7ed/ruff-0.15.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:939c995e9277e63ea632cc8d3fae17aa758526f49a9a850d2e7e758bfef46602", size = 10798618, upload-time = "2026-02-12T23:09:22.928Z" }, + { url = "https://files.pythonhosted.org/packages/5e/0f/1d0d88bc862624247d82c20c10d4c0f6bb2f346559d8af281674cf327f15/ruff-0.15.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1d83466455fdefe60b8d9c8df81d3c1bbb2115cede53549d3b522ce2bc703899", size = 10148518, upload-time = "2026-02-12T23:08:58.339Z" }, + { url = "https://files.pythonhosted.org/packages/f5/c8/291c49cefaa4a9248e986256df2ade7add79388fe179e0691be06fae6f37/ruff-0.15.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9457e3c3291024866222b96108ab2d8265b477e5b1534c7ddb1810904858d16", size = 10518811, upload-time = "2026-02-12T23:09:31.865Z" }, + { url = "https://files.pythonhosted.org/packages/c3/1a/f5707440e5ae43ffa5365cac8bbb91e9665f4a883f560893829cf16a606b/ruff-0.15.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:92c92b003e9d4f7fbd33b1867bb15a1b785b1735069108dfc23821ba045b29bc", size = 10196169, upload-time = "2026-02-12T23:09:17.306Z" }, + { url = "https://files.pythonhosted.org/packages/2a/ff/26ddc8c4da04c8fd3ee65a89c9fb99eaa5c30394269d424461467be2271f/ruff-0.15.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fe5c41ab43e3a06778844c586251eb5a510f67125427625f9eb2b9526535779", size = 10990491, upload-time = "2026-02-12T23:09:25.503Z" }, + { url = "https://files.pythonhosted.org/packages/fc/00/50920cb385b89413f7cdb4bb9bc8fc59c1b0f30028d8bccc294189a54955/ruff-0.15.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66a6dd6df4d80dc382c6484f8ce1bcceb55c32e9f27a8b94c32f6c7331bf14fb", size = 11843280, upload-time = "2026-02-12T23:09:19.88Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6d/2f5cad8380caf5632a15460c323ae326f1e1a2b5b90a6ee7519017a017ca/ruff-0.15.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a4a42cbb8af0bda9bcd7606b064d7c0bc311a88d141d02f78920be6acb5aa83", size = 11274336, upload-time = "2026-02-12T23:09:14.907Z" }, + { url = "https://files.pythonhosted.org/packages/a3/1d/5f56cae1d6c40b8a318513599b35ea4b075d7dc1cd1d04449578c29d1d75/ruff-0.15.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ab064052c31dddada35079901592dfba2e05f5b1e43af3954aafcbc1096a5b2", size = 11137288, upload-time = "2026-02-12T23:09:07.475Z" }, + { url = "https://files.pythonhosted.org/packages/cd/20/6f8d7d8f768c93b0382b33b9306b3b999918816da46537d5a61635514635/ruff-0.15.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:5631c940fe9fe91f817a4c2ea4e81f47bee3ca4aa646134a24374f3c19ad9454", size = 11070681, upload-time = "2026-02-12T23:08:55.43Z" }, + { url = "https://files.pythonhosted.org/packages/9a/67/d640ac76069f64cdea59dba02af2e00b1fa30e2103c7f8d049c0cff4cafd/ruff-0.15.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:68138a4ba184b4691ccdc39f7795c66b3c68160c586519e7e8444cf5a53e1b4c", size = 10486401, upload-time = "2026-02-12T23:09:27.927Z" }, + { url = "https://files.pythonhosted.org/packages/65/3d/e1429f64a3ff89297497916b88c32a5cc88eeca7e9c787072d0e7f1d3e1e/ruff-0.15.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:518f9af03bfc33c03bdb4cb63fabc935341bb7f54af500f92ac309ecfbba6330", size = 10197452, upload-time = "2026-02-12T23:09:12.147Z" }, + { url = "https://files.pythonhosted.org/packages/78/83/e2c3bade17dad63bf1e1c2ffaf11490603b760be149e1419b07049b36ef2/ruff-0.15.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:da79f4d6a826caaea95de0237a67e33b81e6ec2e25fc7e1993a4015dffca7c61", size = 10693900, upload-time = "2026-02-12T23:09:34.418Z" }, + { url = "https://files.pythonhosted.org/packages/a1/27/fdc0e11a813e6338e0706e8b39bb7a1d61ea5b36873b351acee7e524a72a/ruff-0.15.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3dd86dccb83cd7d4dcfac303ffc277e6048600dfc22e38158afa208e8bf94a1f", size = 11227302, upload-time = "2026-02-12T23:09:36.536Z" }, + { url = "https://files.pythonhosted.org/packages/f6/58/ac864a75067dcbd3b95be5ab4eb2b601d7fbc3d3d736a27e391a4f92a5c1/ruff-0.15.1-py3-none-win32.whl", hash = "sha256:660975d9cb49b5d5278b12b03bb9951d554543a90b74ed5d366b20e2c57c2098", size = 10462555, upload-time = "2026-02-12T23:09:29.899Z" }, + { url = "https://files.pythonhosted.org/packages/e0/5e/d4ccc8a27ecdb78116feac4935dfc39d1304536f4296168f91ed3ec00cd2/ruff-0.15.1-py3-none-win_amd64.whl", hash = "sha256:c820fef9dd5d4172a6570e5721704a96c6679b80cf7be41659ed439653f62336", size = 11599956, upload-time = "2026-02-12T23:09:01.157Z" }, + { url = "https://files.pythonhosted.org/packages/2a/07/5bda6a85b220c64c65686bc85bd0bbb23b29c62b3a9f9433fa55f17cda93/ruff-0.15.1-py3-none-win_arm64.whl", hash = "sha256:5ff7d5f0f88567850f45081fac8f4ec212be8d0b963e385c3f7d0d2eb4899416", size = 10874604, upload-time = "2026-02-12T23:09:05.515Z" }, ] [[package]] @@ -1343,14 +1342,14 @@ wheels = [ [[package]] name = "syrupy" -version = "5.0.0" +version = "5.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c1/90/1a442d21527009d4b40f37fe50b606ebb68a6407142c2b5cc508c34b696b/syrupy-5.0.0.tar.gz", hash = "sha256:3282fe963fa5d4d3e47231b16d1d4d0f4523705e8199eeb99a22a1bc9f5942f2", size = 48881, upload-time = "2025-09-28T21:15:12.783Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/b0/24bca682d6a6337854be37f242d116cceeda9942571d5804c44bc1bdd427/syrupy-5.1.0.tar.gz", hash = "sha256:df543c7aa50d3cf1246e83d58fe490afe5f7dab7b41e74ecc0d8d23ae19bd4b8", size = 50495, upload-time = "2026-01-25T14:53:06.2Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9d/9a/6c68aad2ccfce6e2eeebbf5bb709d0240592eb51ff142ec4c8fbf3c2460a/syrupy-5.0.0-py3-none-any.whl", hash = "sha256:c848e1a980ca52a28715cd2d2b4d434db424699c05653bd1158fb31cf56e9546", size = 49087, upload-time = "2025-09-28T21:15:11.639Z" }, + { url = "https://files.pythonhosted.org/packages/de/70/cf880c3b95a6034ef673e74b369941b42315c01f1554a5637a4f8b911009/syrupy-5.1.0-py3-none-any.whl", hash = "sha256:95162d2b05e61ed3e13f117b88dfab7c58bd6f90e66ebbf918e8a77114ad51c5", size = 51658, upload-time = "2026-01-25T14:53:05.105Z" }, ] [[package]] From df94475d3a7cb25965db8ee026b3b358d84294f3 Mon Sep 17 00:00:00 2001 From: William FH <13333726+hinthornw@users.noreply.github.com> Date: Tue, 17 Feb 2026 06:12:35 -0800 Subject: [PATCH 18/41] fix(ci): skip server startup tests when LANGSMITH_API_KEY unavailable (#6844) Co-authored-by: Claude Opus 4.6 --- .github/workflows/_integration_test.yml | 31 ++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/.github/workflows/_integration_test.yml b/.github/workflows/_integration_test.yml index 352f58511..04dd8ce83 100644 --- a/.github/workflows/_integration_test.yml +++ b/.github/workflows/_integration_test.yml @@ -49,19 +49,22 @@ jobs: - name: Install cli globally if: steps.changed-files.outputs.all run: pip install -e . - - name: Build and test service ${{ matrix.example.name }} + - name: Build service ${{ matrix.example.name }} if: steps.changed-files.outputs.all working-directory: ${{ matrix.example.workdir }} + run: | + langgraph build -t ${{ matrix.example.tag }} + - name: Test service ${{ matrix.example.name }} + if: ${{ steps.changed-files.outputs.all && secrets.LANGSMITH_API_KEY != '' }} + working-directory: ${{ matrix.example.workdir }} env: LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }} run: | - # Build the image for this example - langgraph build -t ${{ matrix.example.tag }} # Prepare environment file from local or parent example directory if [ -f .env.example ]; then cp .env.example .env; elif [ -f ../.env.example ]; then cp ../.env.example .env && cp ../.env.example ../.env; fi - if [ -n "${{ secrets.LANGSMITH_API_KEY }}" ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env; if [ -f ../.env ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> ../.env; fi; fi + echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env + if [ -f ../.env ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> ../.env; fi # Run the integration test using the built tag - # Compute repo root to reference the shared script robustly REPO_ROOT=$(git rev-parse --show-toplevel) timeout 60 python "$REPO_ROOT/.github/scripts/run_langgraph_cli_test.py" -t ${{ matrix.example.tag }} @@ -82,17 +85,29 @@ jobs: working-directory: libs/cli/python-monorepo-example run: | langgraph build -t langgraph-test-g -c apps/agent/langgraph.json + - name: Test Python monorepo service + if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' && secrets.LANGSMITH_API_KEY != '' }} + working-directory: libs/cli/python-monorepo-example + env: + LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }} + run: | cp apps/agent/.env.example apps/agent/.env - if [ -n "${{ secrets.LANGSMITH_API_KEY }}" ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> apps/agent/.env; fi + echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> apps/agent/.env timeout 60 python ../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-g -c apps/agent/langgraph.json - - name: Build and test prerelease reqs service + - name: Build prerelease reqs service if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' }} working-directory: libs/cli/examples/graph_prerelease_reqs run: | langgraph build -t langgraph-test-h + - name: Test prerelease reqs service + if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' && secrets.LANGSMITH_API_KEY != '' }} + working-directory: libs/cli/examples/graph_prerelease_reqs + env: + LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }} + run: | cp ../.env.example .env - if [ -n "${{ secrets.LANGSMITH_API_KEY }}" ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env; fi + echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-h echo "Finished starting up langgraph-test-h" LANGGRAPH_VERSION=$(docker run --rm --entrypoint "" langgraph-test-h python -c "import sys; from importlib.metadata import version; v = version('langgraph'); print(v);") From 20570cf700b2ccb6d04e474b4071b98130e3d68c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 08:58:20 -0800 Subject: [PATCH 19/41] chore(deps): bump langsmith from 0.3.66 to 0.3.87 in /libs/cli/js-monorepo-example (#6840) Bumps [langsmith](https://github.com/langchain-ai/langsmith-sdk) from 0.3.66 to 0.3.87.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=langsmith&package-manager=npm_and_yarn&previous-version=0.3.66&new-version=0.3.87)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/langchain-ai/langgraph/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- libs/cli/js-monorepo-example/yarn.lock | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libs/cli/js-monorepo-example/yarn.lock b/libs/cli/js-monorepo-example/yarn.lock index 292469589..8022490b4 100644 --- a/libs/cli/js-monorepo-example/yarn.lock +++ b/libs/cli/js-monorepo-example/yarn.lock @@ -1417,15 +1417,14 @@ keyv@^4.5.3: json-buffer "3.0.1" langsmith@^0.3.46: - version "0.3.66" - resolved "https://registry.yarnpkg.com/langsmith/-/langsmith-0.3.66.tgz#33f13458c6d1086b5f530a25f00c38acd448e0fa" - integrity sha512-d50FJ25HPAT2e/6u7oPAYFYH7uvVhxf7vThAOE5tP6YFIUHwLMBmJj8R4Z7APp5jF4/m8upvbK4J4jP5UIN+Eg== + version "0.3.87" + resolved "https://registry.yarnpkg.com/langsmith/-/langsmith-0.3.87.tgz#f1c991c93a5d4d226a31671be7e4443b4b8673b1" + integrity sha512-XXR1+9INH8YX96FKWc5tie0QixWz6tOqAsAKfcJyPkE0xPep+NDz0IQLR32q4bn10QK3LqD2HN6T3n6z1YLW7Q== dependencies: "@types/uuid" "^10.0.0" chalk "^4.1.2" console-table-printer "^2.12.1" p-queue "^6.6.2" - p-retry "4" semver "^7.6.3" uuid "^10.0.0" From 17b3285907688217b5a33b15e4d74a118b1d882c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 09:21:26 -0800 Subject: [PATCH 20/41] chore(deps): bump the all-dependencies group in /libs/sdk-py with 4 updates (#6809) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the all-dependencies group in /libs/sdk-py with 4 updates: [orjson](https://github.com/ijl/orjson), [ruff](https://github.com/astral-sh/ruff), [mypy](https://github.com/python/mypy) and [ty](https://github.com/astral-sh/ty). Updates `orjson` from 3.11.5 to 3.11.7
Release notes

Sourced from orjson's releases.

3.11.7

Changed

  • Use a faster library to serialize float. Users with byte-exact regression tests should note positive exponents are now written using a +, e.g., 1.2e+30 instead of 1.2e30. Both formats are spec-compliant.
  • ABI compatibility with CPython 3.15 alpha 5 free-threading.

3.11.6

Changed

  • orjson now includes code licensed under the Mozilla Public License 2.0 (MPL-2.0).
  • Drop support for Python 3.9.
  • ABI compatibility with CPython 3.15 alpha 5.
  • Build now depends on Rust 1.89 or later instead of 1.85.

Fixed

  • Fix sporadic crash serializing deeply nested list of dict.
Changelog

Sourced from orjson's changelog.

3.11.7 - 2026-02-02

Changed

  • Use a faster library to serialize float. Users with byte-exact regression tests should note positive exponents are now written using a +, e.g., 1.2e+30 instead of 1.2e30. Both formats are spec-compliant.
  • ABI compatibility with CPython 3.15 alpha 5 free-threading.

3.11.6 - 2026-01-29

Changed

  • orjson now includes code licensed under the Mozilla Public License 2.0 (MPL-2.0).
  • Drop support for Python 3.9.
  • ABI compatibility with CPython 3.15 alpha 5.
  • Build now depends on Rust 1.89 or later instead of 1.85.

Fixed

  • Fix sporadic crash serializing deeply nested list of dict.
Commits

Updates `ruff` from 0.14.11 to 0.15.1
Release notes

Sourced from ruff's releases.

0.15.1

Release Notes

Released on 2026-02-12.

Preview features

  • [airflow] Add ruff rules to catch deprecated Airflow imports for Airflow 3.1 (AIR321) (#22376)
  • [airflow] Third positional parameter not named ti_key should be flagged for BaseOperatorLink.get_link (AIR303) (#22828)
  • [flake8-gettext] Fix false negatives for plural argument of ngettext (INT001, INT002, INT003) (#21078)
  • [pyflakes] Fix infinite loop in preview fix for unused-import (F401) (#23038)
  • [pygrep-hooks] Detect non-existent mock methods in standalone expressions (PGH005) (#22830)
  • [pylint] Allow dunder submodules and improve diagnostic range (PLC2701) (#22804)
  • [pyupgrade] Improve diagnostic range for tuples (UP024) (#23013)
  • [refurb] Check subscripts in tuple do not use lambda parameters in reimplemented-operator (FURB118) (#23079)
  • [ruff] Detect mutable defaults in field calls (RUF008) (#23046)
  • [ruff] Ignore std cmath.inf (RUF069) (#23120)
  • [ruff] New rule float-equality-comparison (RUF069) (#20585)
  • Don't format unlabeled Markdown code blocks (#23106)
  • Markdown formatting support in LSP (#23063)
  • Support Quarto Markdown language markers (#22947)
  • Support formatting pycon Markdown code blocks (#23112)
  • Use extension mapping to select Markdown code block language (#22934)

Bug fixes

  • Avoid false positive for undefined variables in FAST001 (#23224)
  • Avoid introducing syntax errors for FAST003 autofix (#23227)
  • Avoid suggesting InitVar for __post_init__ that references PEP 695 type parameters (#23226)
  • Deduplicate type variables in generic functions (#23225)
  • Fix exception handler parenthesis removal for Python 3.14+ (#23126)
  • Fix f-string middle panic when parsing t-strings (#23232)
  • Wrap RUF020 target for multiline fixes (#23210)
  • Wrap UP007 target for multiline fixes (#23208)
  • Fix missing diagnostics for last range suppression in file (#23242)
  • [pyupgrade] Fix syntax error on string with newline escape and comment (UP037) (#22968)

Rule changes

  • Use ruff instead of Ruff as the program name in GitHub output format (#23240)
  • [PT006] Fix syntax error when unpacking nested tuples in parametrize fixes (#22441) (#22464)
  • [airflow] Catch deprecated attribute access from context key for Airflow 3.0 (AIR301) (#22850)
  • [airflow] Capture deprecated arguments and a decorator (AIR301) (#23170)
  • [flake8-boolean-trap] Add multiprocessing.Value to excluded functions for FBT003 (#23010)
  • [flake8-bugbear] Add a secondary annotation showing the previous occurrence (B033) (#22634)
  • [flake8-type-checking] Add sub-diagnostic showing the runtime use of an annotation (TC004) (#23091)
  • [isort] Support configurable import section heading comments (#23151)
  • [ruff] Improve the diagnostic for RUF012 (#23202)

Formatter

... (truncated)

Changelog

Sourced from ruff's changelog.

0.15.1

Released on 2026-02-12.

Preview features

  • [airflow] Add ruff rules to catch deprecated Airflow imports for Airflow 3.1 (AIR321) (#22376)
  • [airflow] Third positional parameter not named ti_key should be flagged for BaseOperatorLink.get_link (AIR303) (#22828)
  • [flake8-gettext] Fix false negatives for plural argument of ngettext (INT001, INT002, INT003) (#21078)
  • [pyflakes] Fix infinite loop in preview fix for unused-import (F401) (#23038)
  • [pygrep-hooks] Detect non-existent mock methods in standalone expressions (PGH005) (#22830)
  • [pylint] Allow dunder submodules and improve diagnostic range (PLC2701) (#22804)
  • [pyupgrade] Improve diagnostic range for tuples (UP024) (#23013)
  • [refurb] Check subscripts in tuple do not use lambda parameters in reimplemented-operator (FURB118) (#23079)
  • [ruff] Detect mutable defaults in field calls (RUF008) (#23046)
  • [ruff] Ignore std cmath.inf (RUF069) (#23120)
  • [ruff] New rule float-equality-comparison (RUF069) (#20585)
  • Don't format unlabeled Markdown code blocks (#23106)
  • Markdown formatting support in LSP (#23063)
  • Support Quarto Markdown language markers (#22947)
  • Support formatting pycon Markdown code blocks (#23112)
  • Use extension mapping to select Markdown code block language (#22934)

Bug fixes

  • Avoid false positive for undefined variables in FAST001 (#23224)
  • Avoid introducing syntax errors for FAST003 autofix (#23227)
  • Avoid suggesting InitVar for __post_init__ that references PEP 695 type parameters (#23226)
  • Deduplicate type variables in generic functions (#23225)
  • Fix exception handler parenthesis removal for Python 3.14+ (#23126)
  • Fix f-string middle panic when parsing t-strings (#23232)
  • Wrap RUF020 target for multiline fixes (#23210)
  • Wrap UP007 target for multiline fixes (#23208)
  • Fix missing diagnostics for last range suppression in file (#23242)
  • [pyupgrade] Fix syntax error on string with newline escape and comment (UP037) (#22968)

Rule changes

  • Use ruff instead of Ruff as the program name in GitHub output format (#23240)
  • [PT006] Fix syntax error when unpacking nested tuples in parametrize fixes (#22441) (#22464)
  • [airflow] Catch deprecated attribute access from context key for Airflow 3.0 (AIR301) (#22850)
  • [airflow] Capture deprecated arguments and a decorator (AIR301) (#23170)
  • [flake8-boolean-trap] Add multiprocessing.Value to excluded functions for FBT003 (#23010)
  • [flake8-bugbear] Add a secondary annotation showing the previous occurrence (B033) (#22634)
  • [flake8-type-checking] Add sub-diagnostic showing the runtime use of an annotation (TC004) (#23091)
  • [isort] Support configurable import section heading comments (#23151)
  • [ruff] Improve the diagnostic for RUF012 (#23202)

Formatter

... (truncated)

Commits
  • a2f11d2 Prepare for 0.15.1 (#23253)
  • d29628e Remove docker-run-action (#23254)
  • 8a04266 [ty] Allow discovering dependencies in system Python environments (#22994)
  • 55d06c8 Ensure pending suppression diagnostics are reported (#23242)
  • d056a9f [isort] support for configurable import section heading comments (#23151)
  • e22fa4f [ty] Fix method calls on subclasses of Any (#23248)
  • fa56c15 [ty] Fix bound method access on None (#23246)
  • 4fd07d0 Make range suppression test snapshot actually useful (#23251)
  • 8c63bce [ty] Include conditional symbols (like datetime.UTC) in auto-import in more...
  • 46be943 Exclude WASM artifacts from GitHub releases (#23221)
  • Additional commits viewable in compare view

Updates `mypy` from 1.19.0 to 1.19.1
Changelog

Sourced from mypy's changelog.

Mypy 1.19.1

  • Fix noncommutative joins with bounded TypeVars (Shantanu, PR 20345)
  • Respect output format for cached runs by serializing raw errors in cache metas (Ivan Levkivskyi, PR 20372)
  • Allow types.NoneType in match cases (A5rocks, PR 20383)
  • Fix mypyc generator regression with empty tuple (BobTheBuidler, PR 20371)
  • Fix crash involving Unpack-ed TypeVarTuple (Shantanu, PR 20323)
  • Fix crash on star import of redefinition (Ivan Levkivskyi, PR 20333)
  • Fix crash on typevar with forward ref used in other module (Ivan Levkivskyi, PR 20334)
  • Fail with an explicit error on PyPy (Ivan Levkivskyi, PR 20389)

Acknowledgements

Thanks to all mypy contributors who contributed to this release:

  • A5rocks
  • BobTheBuidler
  • bzoracler
  • Chainfire
  • Christoph Tyralla
  • David Foster
  • Frank Dana
  • Guo Ci
  • iap
  • Ivan Levkivskyi
  • James Hilton-Balfe
  • jhance
  • Joren Hammudoglu
  • Jukka Lehtosalo
  • KarelKenens
  • Kevin Kannammalil
  • Marc Mueller
  • Michael Carlstrom
  • Michael J. Sullivan
  • Piotr Sawicki
  • Randolf Scholz
  • Shantanu
  • Sigve Sebastian Farstad
  • sobolevn
  • Stanislav Terliakov
  • Stephen Morton
  • Theodore Ando
  • Thiago J. Barbalho
  • wyattscarpenter

I’d also like to thank my employer, Dropbox, for supporting mypy development.

Mypy 1.18

We’ve just uploaded mypy 1.18.1 to the Python Package Index (PyPI). Mypy is a static type checker for Python. This release includes new features, performance

... (truncated)

Commits

Updates `ty` from 0.0.1a27 to 0.0.17
Release notes

Sourced from ty's releases.

0.0.17

Release Notes

Released on 2026-02-13.

Bug fixes

  • Avoid Literal promotion for constrained TypeVars with Literal bounds (#23209)
  • Fix false positives in TypeVar shadowing checks (#23222)

Core type checking

  • Support generic protocols (#21902)
  • Perform control-flow analysis in loops (#22794)
  • Support typing.Self in attribute annotations (#23108)
  • Support type narrowing in situations with calls to NoReturn functions (#23109)
  • Support type narrowing and reachability analysis based on os.name checks (#23230)
  • Detect overrides of Final class variables in subclasses (#23180)
  • Fix bound method access on None (#23246)
  • Fix method calls on subclasses of Any (#23248)
  • Disallow type variables within PEP-695 type variable bounds and constraints (#22982)
  • Emit error for attribute access on union where some elements lack the attribute (#23042)
  • Emit error for invalid typevar defaults (#23194)
  • Improve display of ParamSpecs in some situations (#23211)

LSP server

  • Add hover and go-to-declaration support for subscript literals (#22837)
  • Assign lower completion ranking to deprecated names in auto import (#23188)
  • Improve spans of references to submodules imported in an __init__.py (#21795)
  • Include conditional symbols (like datetime.UTC) in auto-import in more cases (#23249)
  • Support auto-import for symbols in inlay hints (#22111)
  • Include overload declarations in find-references (#23215)

Performance

  • Avoid UnionBuilder overhead when creating a new union from the filtered elements of an existing union (#22352)

Other changes

  • Allow discovering dependencies in system Python environments (#22994)
  • Apply workspace settings to virtual files (#23228)
  • Add support for --output-format=junit (#22125)
  • Use a smaller diagnostic range for inconsistent-mro diagnostics (#23213)

Contributors

... (truncated)

Changelog

Sourced from ty's changelog.

0.0.17

Released on 2026-02-13.

Bug fixes

  • Avoid Literal promotion for constrained TypeVars with Literal bounds (#23209)
  • Fix false positives in TypeVar shadowing checks (#23222)

Core type checking

  • Support generic protocols (#21902)
  • Perform control-flow analysis in loops (#22794)
  • Support typing.Self in attribute annotations (#23108)
  • Support type narrowing in situations with calls to NoReturn functions (#23109)
  • Support type narrowing and reachability analysis based on os.name checks (#23230)
  • Detect overrides of Final class variables in subclasses (#23180)
  • Fix bound method access on None (#23246)
  • Fix method calls on subclasses of Any (#23248)
  • Disallow type variables within PEP-695 type variable bounds and constraints (#22982)
  • Emit error for attribute access on union where some elements lack the attribute (#23042)
  • Emit error for invalid typevar defaults (#23194)
  • Improve display of ParamSpecs in some situations (#23211)

LSP server

  • Add hover and go-to-declaration support for subscript literals (#22837)
  • Assign lower completion ranking to deprecated names in auto import (#23188)
  • Improve spans of references to submodules imported in an __init__.py (#21795)
  • Include conditional symbols (like datetime.UTC) in auto-import in more cases (#23249)
  • Support auto-import for symbols in inlay hints (#22111)
  • Include overload declarations in find-references (#23215)

Performance

  • Avoid UnionBuilder overhead when creating a new union from the filtered elements of an existing union (#22352)

Other changes

  • Allow discovering dependencies in system Python environments (#22994)
  • Apply workspace settings to virtual files (#23228)
  • Add support for --output-format=junit (#22125)
  • Use a smaller diagnostic range for inconsistent-mro diagnostics (#23213)

Contributors

... (truncated)

Commits

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: John Kennedy <65985482+jkennedyvz@users.noreply.github.com> --- libs/sdk-py/pyproject.toml | 6 +- libs/sdk-py/uv.lock | 306 ++++++++++++++++++------------------- 2 files changed, 155 insertions(+), 157 deletions(-) diff --git a/libs/sdk-py/pyproject.toml b/libs/sdk-py/pyproject.toml index d5cef8b78..9d6f2fe07 100644 --- a/libs/sdk-py/pyproject.toml +++ b/libs/sdk-py/pyproject.toml @@ -30,10 +30,10 @@ test = [ "pytest-watch", ] lint = [ - "ruff==0.14.11", + "ruff==0.15.1", "codespell", - "mypy==1.19.0", - "ty==0.0.1a27", + "mypy==1.19.1", + "ty==0.0.17", "starlette", ] dev = [ diff --git a/libs/sdk-py/uv.lock b/libs/sdk-py/uv.lock index 67e40046d..b384bfcd7 100644 --- a/libs/sdk-py/uv.lock +++ b/libs/sdk-py/uv.lock @@ -491,22 +491,22 @@ requires-dist = [ dev = [ { name = "codespell" }, { name = "langgraph", editable = "../langgraph" }, - { name = "mypy", specifier = "==1.19.0" }, + { name = "mypy", specifier = "==1.19.1" }, { name = "pydantic", specifier = ">=2.12.4" }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-mock" }, { name = "pytest-watch" }, - { name = "ruff", specifier = "==0.14.11" }, + { name = "ruff", specifier = "==0.15.1" }, { name = "starlette" }, - { name = "ty", specifier = "==0.0.1a27" }, + { name = "ty", specifier = "==0.0.17" }, ] lint = [ { name = "codespell" }, - { name = "mypy", specifier = "==1.19.0" }, - { name = "ruff", specifier = "==0.14.11" }, + { name = "mypy", specifier = "==1.19.1" }, + { name = "ruff", specifier = "==0.15.1" }, { name = "starlette" }, - { name = "ty", specifier = "==0.0.1a27" }, + { name = "ty", specifier = "==0.0.17" }, ] test = [ { name = "pytest" }, @@ -610,48 +610,48 @@ wheels = [ [[package]] name = "mypy" -version = "1.19.0" +version = "1.19.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "librt" }, + { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, { name = "mypy-extensions" }, { name = "pathspec" }, { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f9/b5/b58cdc25fadd424552804bf410855d52324183112aa004f0732c5f6324cf/mypy-1.19.0.tar.gz", hash = "sha256:f6b874ca77f733222641e5c46e4711648c4037ea13646fd0cdc814c2eaec2528", size = 3579025, upload-time = "2025-11-28T15:49:01.26Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/db/4efed9504bc01309ab9c2da7e352cc223569f05478012b5d9ece38fd44d2/mypy-1.19.1.tar.gz", hash = "sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba", size = 3582404, upload-time = "2025-12-15T05:03:48.42Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/8f/55fb488c2b7dabd76e3f30c10f7ab0f6190c1fcbc3e97b1e588ec625bbe2/mypy-1.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6148ede033982a8c5ca1143de34c71836a09f105068aaa8b7d5edab2b053e6c8", size = 13093239, upload-time = "2025-11-28T15:45:11.342Z" }, - { url = "https://files.pythonhosted.org/packages/72/1b/278beea978456c56b3262266274f335c3ba5ff2c8108b3b31bec1ffa4c1d/mypy-1.19.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a9ac09e52bb0f7fb912f5d2a783345c72441a08ef56ce3e17c1752af36340a39", size = 12156128, upload-time = "2025-11-28T15:46:02.566Z" }, - { url = "https://files.pythonhosted.org/packages/21/f8/e06f951902e136ff74fd7a4dc4ef9d884faeb2f8eb9c49461235714f079f/mypy-1.19.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11f7254c15ab3f8ed68f8e8f5cbe88757848df793e31c36aaa4d4f9783fd08ab", size = 12753508, upload-time = "2025-11-28T15:44:47.538Z" }, - { url = "https://files.pythonhosted.org/packages/67/5a/d035c534ad86e09cee274d53cf0fd769c0b29ca6ed5b32e205be3c06878c/mypy-1.19.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318ba74f75899b0e78b847d8c50821e4c9637c79d9a59680fc1259f29338cb3e", size = 13507553, upload-time = "2025-11-28T15:44:39.26Z" }, - { url = "https://files.pythonhosted.org/packages/6a/17/c4a5498e00071ef29e483a01558b285d086825b61cf1fb2629fbdd019d94/mypy-1.19.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cf7d84f497f78b682edd407f14a7b6e1a2212b433eedb054e2081380b7395aa3", size = 13792898, upload-time = "2025-11-28T15:44:31.102Z" }, - { url = "https://files.pythonhosted.org/packages/67/f6/bb542422b3ee4399ae1cdc463300d2d91515ab834c6233f2fd1d52fa21e0/mypy-1.19.0-cp310-cp310-win_amd64.whl", hash = "sha256:c3385246593ac2b97f155a0e9639be906e73534630f663747c71908dfbf26134", size = 10048835, upload-time = "2025-11-28T15:48:15.744Z" }, - { url = "https://files.pythonhosted.org/packages/0f/d2/010fb171ae5ac4a01cc34fbacd7544531e5ace95c35ca166dd8fd1b901d0/mypy-1.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a31e4c28e8ddb042c84c5e977e28a21195d086aaffaf08b016b78e19c9ef8106", size = 13010563, upload-time = "2025-11-28T15:48:23.975Z" }, - { url = "https://files.pythonhosted.org/packages/41/6b/63f095c9f1ce584fdeb595d663d49e0980c735a1d2004720ccec252c5d47/mypy-1.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34ec1ac66d31644f194b7c163d7f8b8434f1b49719d403a5d26c87fff7e913f7", size = 12077037, upload-time = "2025-11-28T15:47:51.582Z" }, - { url = "https://files.pythonhosted.org/packages/d7/83/6cb93d289038d809023ec20eb0b48bbb1d80af40511fa077da78af6ff7c7/mypy-1.19.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cb64b0ba5980466a0f3f9990d1c582bcab8db12e29815ecb57f1408d99b4bff7", size = 12680255, upload-time = "2025-11-28T15:46:57.628Z" }, - { url = "https://files.pythonhosted.org/packages/99/db/d217815705987d2cbace2edd9100926196d6f85bcb9b5af05058d6e3c8ad/mypy-1.19.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:120cffe120cca5c23c03c77f84abc0c14c5d2e03736f6c312480020082f1994b", size = 13421472, upload-time = "2025-11-28T15:47:59.655Z" }, - { url = "https://files.pythonhosted.org/packages/4e/51/d2beaca7c497944b07594f3f8aad8d2f0e8fc53677059848ae5d6f4d193e/mypy-1.19.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7a500ab5c444268a70565e374fc803972bfd1f09545b13418a5174e29883dab7", size = 13651823, upload-time = "2025-11-28T15:45:29.318Z" }, - { url = "https://files.pythonhosted.org/packages/aa/d1/7883dcf7644db3b69490f37b51029e0870aac4a7ad34d09ceae709a3df44/mypy-1.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:c14a98bc63fd867530e8ec82f217dae29d0550c86e70debc9667fff1ec83284e", size = 10049077, upload-time = "2025-11-28T15:45:39.818Z" }, - { url = "https://files.pythonhosted.org/packages/11/7e/1afa8fb188b876abeaa14460dc4983f909aaacaa4bf5718c00b2c7e0b3d5/mypy-1.19.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0fb3115cb8fa7c5f887c8a8d81ccdcb94cff334684980d847e5a62e926910e1d", size = 13207728, upload-time = "2025-11-28T15:46:26.463Z" }, - { url = "https://files.pythonhosted.org/packages/b2/13/f103d04962bcbefb1644f5ccb235998b32c337d6c13145ea390b9da47f3e/mypy-1.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3e19e3b897562276bb331074d64c076dbdd3e79213f36eed4e592272dabd760", size = 12202945, upload-time = "2025-11-28T15:48:49.143Z" }, - { url = "https://files.pythonhosted.org/packages/e4/93/a86a5608f74a22284a8ccea8592f6e270b61f95b8588951110ad797c2ddd/mypy-1.19.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b9d491295825182fba01b6ffe2c6fe4e5a49dbf4e2bb4d1217b6ced3b4797bc6", size = 12718673, upload-time = "2025-11-28T15:47:37.193Z" }, - { url = "https://files.pythonhosted.org/packages/3d/58/cf08fff9ced0423b858f2a7495001fda28dc058136818ee9dffc31534ea9/mypy-1.19.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6016c52ab209919b46169651b362068f632efcd5eb8ef9d1735f6f86da7853b2", size = 13608336, upload-time = "2025-11-28T15:48:32.625Z" }, - { url = "https://files.pythonhosted.org/packages/64/ed/9c509105c5a6d4b73bb08733102a3ea62c25bc02c51bca85e3134bf912d3/mypy-1.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f188dcf16483b3e59f9278c4ed939ec0254aa8a60e8fc100648d9ab5ee95a431", size = 13833174, upload-time = "2025-11-28T15:45:48.091Z" }, - { url = "https://files.pythonhosted.org/packages/cd/71/01939b66e35c6f8cb3e6fdf0b657f0fd24de2f8ba5e523625c8e72328208/mypy-1.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:0e3c3d1e1d62e678c339e7ade72746a9e0325de42cd2cccc51616c7b2ed1a018", size = 10112208, upload-time = "2025-11-28T15:46:41.702Z" }, - { url = "https://files.pythonhosted.org/packages/cb/0d/a1357e6bb49e37ce26fcf7e3cc55679ce9f4ebee0cd8b6ee3a0e301a9210/mypy-1.19.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7686ed65dbabd24d20066f3115018d2dce030d8fa9db01aa9f0a59b6813e9f9e", size = 13191993, upload-time = "2025-11-28T15:47:22.336Z" }, - { url = "https://files.pythonhosted.org/packages/5d/75/8e5d492a879ec4490e6ba664b5154e48c46c85b5ac9785792a5ec6a4d58f/mypy-1.19.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fd4a985b2e32f23bead72e2fb4bbe5d6aceee176be471243bd831d5b2644672d", size = 12174411, upload-time = "2025-11-28T15:44:55.492Z" }, - { url = "https://files.pythonhosted.org/packages/71/31/ad5dcee9bfe226e8eaba777e9d9d251c292650130f0450a280aec3485370/mypy-1.19.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fc51a5b864f73a3a182584b1ac75c404396a17eced54341629d8bdcb644a5bba", size = 12727751, upload-time = "2025-11-28T15:44:14.169Z" }, - { url = "https://files.pythonhosted.org/packages/77/06/b6b8994ce07405f6039701f4b66e9d23f499d0b41c6dd46ec28f96d57ec3/mypy-1.19.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:37af5166f9475872034b56c5efdcf65ee25394e9e1d172907b84577120714364", size = 13593323, upload-time = "2025-11-28T15:46:34.699Z" }, - { url = "https://files.pythonhosted.org/packages/68/b1/126e274484cccdf099a8e328d4fda1c7bdb98a5e888fa6010b00e1bbf330/mypy-1.19.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:510c014b722308c9bd377993bcbf9a07d7e0692e5fa8fc70e639c1eb19fc6bee", size = 13818032, upload-time = "2025-11-28T15:46:18.286Z" }, - { url = "https://files.pythonhosted.org/packages/f8/56/53a8f70f562dfc466c766469133a8a4909f6c0012d83993143f2a9d48d2d/mypy-1.19.0-cp313-cp313-win_amd64.whl", hash = "sha256:cabbee74f29aa9cd3b444ec2f1e4fa5a9d0d746ce7567a6a609e224429781f53", size = 10120644, upload-time = "2025-11-28T15:47:43.99Z" }, - { url = "https://files.pythonhosted.org/packages/b0/f4/7751f32f56916f7f8c229fe902cbdba3e4dd3f3ea9e8b872be97e7fc546d/mypy-1.19.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f2e36bed3c6d9b5f35d28b63ca4b727cb0228e480826ffc8953d1892ddc8999d", size = 13185236, upload-time = "2025-11-28T15:45:20.696Z" }, - { url = "https://files.pythonhosted.org/packages/35/31/871a9531f09e78e8d145032355890384f8a5b38c95a2c7732d226b93242e/mypy-1.19.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a18d8abdda14035c5718acb748faec09571432811af129bf0d9e7b2d6699bf18", size = 12213902, upload-time = "2025-11-28T15:46:10.117Z" }, - { url = "https://files.pythonhosted.org/packages/58/b8/af221910dd40eeefa2077a59107e611550167b9994693fc5926a0b0f87c0/mypy-1.19.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f75e60aca3723a23511948539b0d7ed514dda194bc3755eae0bfc7a6b4887aa7", size = 12738600, upload-time = "2025-11-28T15:44:22.521Z" }, - { url = "https://files.pythonhosted.org/packages/11/9f/c39e89a3e319c1d9c734dedec1183b2cc3aefbab066ec611619002abb932/mypy-1.19.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f44f2ae3c58421ee05fe609160343c25f70e3967f6e32792b5a78006a9d850f", size = 13592639, upload-time = "2025-11-28T15:48:08.55Z" }, - { url = "https://files.pythonhosted.org/packages/97/6d/ffaf5f01f5e284d9033de1267e6c1b8f3783f2cf784465378a86122e884b/mypy-1.19.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:63ea6a00e4bd6822adbfc75b02ab3653a17c02c4347f5bb0cf1d5b9df3a05835", size = 13799132, upload-time = "2025-11-28T15:47:06.032Z" }, - { url = "https://files.pythonhosted.org/packages/fe/b0/c33921e73aaa0106224e5a34822411bea38046188eb781637f5a5b07e269/mypy-1.19.0-cp314-cp314-win_amd64.whl", hash = "sha256:3ad925b14a0bb99821ff6f734553294aa6a3440a8cb082fe1f5b84dfb662afb1", size = 10269832, upload-time = "2025-11-28T15:47:29.392Z" }, - { url = "https://files.pythonhosted.org/packages/09/0e/fe228ed5aeab470c6f4eb82481837fadb642a5aa95cc8215fd2214822c10/mypy-1.19.0-py3-none-any.whl", hash = "sha256:0c01c99d626380752e527d5ce8e69ffbba2046eb8a060db0329690849cf9b6f9", size = 2469714, upload-time = "2025-11-28T15:45:33.22Z" }, + { url = "https://files.pythonhosted.org/packages/2f/63/e499890d8e39b1ff2df4c0c6ce5d371b6844ee22b8250687a99fd2f657a8/mypy-1.19.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f05aa3d375b385734388e844bc01733bd33c644ab48e9684faa54e5389775ec", size = 13101333, upload-time = "2025-12-15T05:03:03.28Z" }, + { url = "https://files.pythonhosted.org/packages/72/4b/095626fc136fba96effc4fd4a82b41d688ab92124f8c4f7564bffe5cf1b0/mypy-1.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:022ea7279374af1a5d78dfcab853fe6a536eebfda4b59deab53cd21f6cd9f00b", size = 12164102, upload-time = "2025-12-15T05:02:33.611Z" }, + { url = "https://files.pythonhosted.org/packages/0c/5b/952928dd081bf88a83a5ccd49aaecfcd18fd0d2710c7ff07b8fb6f7032b9/mypy-1.19.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee4c11e460685c3e0c64a4c5de82ae143622410950d6be863303a1c4ba0e36d6", size = 12765799, upload-time = "2025-12-15T05:03:28.44Z" }, + { url = "https://files.pythonhosted.org/packages/2a/0d/93c2e4a287f74ef11a66fb6d49c7a9f05e47b0a4399040e6719b57f500d2/mypy-1.19.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de759aafbae8763283b2ee5869c7255391fbc4de3ff171f8f030b5ec48381b74", size = 13522149, upload-time = "2025-12-15T05:02:36.011Z" }, + { url = "https://files.pythonhosted.org/packages/7b/0e/33a294b56aaad2b338d203e3a1d8b453637ac36cb278b45005e0901cf148/mypy-1.19.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ab43590f9cd5108f41aacf9fca31841142c786827a74ab7cc8a2eacb634e09a1", size = 13810105, upload-time = "2025-12-15T05:02:40.327Z" }, + { url = "https://files.pythonhosted.org/packages/0e/fd/3e82603a0cb66b67c5e7abababce6bf1a929ddf67bf445e652684af5c5a0/mypy-1.19.1-cp310-cp310-win_amd64.whl", hash = "sha256:2899753e2f61e571b3971747e302d5f420c3fd09650e1951e99f823bc3089dac", size = 10057200, upload-time = "2025-12-15T05:02:51.012Z" }, + { url = "https://files.pythonhosted.org/packages/ef/47/6b3ebabd5474d9cdc170d1342fbf9dddc1b0ec13ec90bf9004ee6f391c31/mypy-1.19.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d8dfc6ab58ca7dda47d9237349157500468e404b17213d44fc1cb77bce532288", size = 13028539, upload-time = "2025-12-15T05:03:44.129Z" }, + { url = "https://files.pythonhosted.org/packages/5c/a6/ac7c7a88a3c9c54334f53a941b765e6ec6c4ebd65d3fe8cdcfbe0d0fd7db/mypy-1.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e3f276d8493c3c97930e354b2595a44a21348b320d859fb4a2b9f66da9ed27ab", size = 12083163, upload-time = "2025-12-15T05:03:37.679Z" }, + { url = "https://files.pythonhosted.org/packages/67/af/3afa9cf880aa4a2c803798ac24f1d11ef72a0c8079689fac5cfd815e2830/mypy-1.19.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2abb24cf3f17864770d18d673c85235ba52456b36a06b6afc1e07c1fdcd3d0e6", size = 12687629, upload-time = "2025-12-15T05:02:31.526Z" }, + { url = "https://files.pythonhosted.org/packages/2d/46/20f8a7114a56484ab268b0ab372461cb3a8f7deed31ea96b83a4e4cfcfca/mypy-1.19.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a009ffa5a621762d0c926a078c2d639104becab69e79538a494bcccb62cc0331", size = 13436933, upload-time = "2025-12-15T05:03:15.606Z" }, + { url = "https://files.pythonhosted.org/packages/5b/f8/33b291ea85050a21f15da910002460f1f445f8007adb29230f0adea279cb/mypy-1.19.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f7cee03c9a2e2ee26ec07479f38ea9c884e301d42c6d43a19d20fb014e3ba925", size = 13661754, upload-time = "2025-12-15T05:02:26.731Z" }, + { url = "https://files.pythonhosted.org/packages/fd/a3/47cbd4e85bec4335a9cd80cf67dbc02be21b5d4c9c23ad6b95d6c5196bac/mypy-1.19.1-cp311-cp311-win_amd64.whl", hash = "sha256:4b84a7a18f41e167f7995200a1d07a4a6810e89d29859df936f1c3923d263042", size = 10055772, upload-time = "2025-12-15T05:03:26.179Z" }, + { url = "https://files.pythonhosted.org/packages/06/8a/19bfae96f6615aa8a0604915512e0289b1fad33d5909bf7244f02935d33a/mypy-1.19.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8174a03289288c1f6c46d55cef02379b478bfbc8e358e02047487cad44c6ca1", size = 13206053, upload-time = "2025-12-15T05:03:46.622Z" }, + { url = "https://files.pythonhosted.org/packages/a5/34/3e63879ab041602154ba2a9f99817bb0c85c4df19a23a1443c8986e4d565/mypy-1.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffcebe56eb09ff0c0885e750036a095e23793ba6c2e894e7e63f6d89ad51f22e", size = 12219134, upload-time = "2025-12-15T05:03:24.367Z" }, + { url = "https://files.pythonhosted.org/packages/89/cc/2db6f0e95366b630364e09845672dbee0cbf0bbe753a204b29a944967cd9/mypy-1.19.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2", size = 12731616, upload-time = "2025-12-15T05:02:44.725Z" }, + { url = "https://files.pythonhosted.org/packages/00/be/dd56c1fd4807bc1eba1cf18b2a850d0de7bacb55e158755eb79f77c41f8e/mypy-1.19.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c35d298c2c4bba75feb2195655dfea8124d855dfd7343bf8b8c055421eaf0cf8", size = 13620847, upload-time = "2025-12-15T05:03:39.633Z" }, + { url = "https://files.pythonhosted.org/packages/6d/42/332951aae42b79329f743bf1da088cd75d8d4d9acc18fbcbd84f26c1af4e/mypy-1.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34c81968774648ab5ac09c29a375fdede03ba253f8f8287847bd480782f73a6a", size = 13834976, upload-time = "2025-12-15T05:03:08.786Z" }, + { url = "https://files.pythonhosted.org/packages/6f/63/e7493e5f90e1e085c562bb06e2eb32cae27c5057b9653348d38b47daaecc/mypy-1.19.1-cp312-cp312-win_amd64.whl", hash = "sha256:b10e7c2cd7870ba4ad9b2d8a6102eb5ffc1f16ca35e3de6bfa390c1113029d13", size = 10118104, upload-time = "2025-12-15T05:03:10.834Z" }, + { url = "https://files.pythonhosted.org/packages/de/9f/a6abae693f7a0c697dbb435aac52e958dc8da44e92e08ba88d2e42326176/mypy-1.19.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e3157c7594ff2ef1634ee058aafc56a82db665c9438fd41b390f3bde1ab12250", size = 13201927, upload-time = "2025-12-15T05:02:29.138Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a4/45c35ccf6e1c65afc23a069f50e2c66f46bd3798cbe0d680c12d12935caa/mypy-1.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdb12f69bcc02700c2b47e070238f42cb87f18c0bc1fc4cdb4fb2bc5fd7a3b8b", size = 12206730, upload-time = "2025-12-15T05:03:01.325Z" }, + { url = "https://files.pythonhosted.org/packages/05/bb/cdcf89678e26b187650512620eec8368fded4cfd99cfcb431e4cdfd19dec/mypy-1.19.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f859fb09d9583a985be9a493d5cfc5515b56b08f7447759a0c5deaf68d80506e", size = 12724581, upload-time = "2025-12-15T05:03:20.087Z" }, + { url = "https://files.pythonhosted.org/packages/d1/32/dd260d52babf67bad8e6770f8e1102021877ce0edea106e72df5626bb0ec/mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9a6538e0415310aad77cb94004ca6482330fece18036b5f360b62c45814c4ef", size = 13616252, upload-time = "2025-12-15T05:02:49.036Z" }, + { url = "https://files.pythonhosted.org/packages/71/d0/5e60a9d2e3bd48432ae2b454b7ef2b62a960ab51292b1eda2a95edd78198/mypy-1.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:da4869fc5e7f62a88f3fe0b5c919d1d9f7ea3cef92d3689de2823fd27e40aa75", size = 13840848, upload-time = "2025-12-15T05:02:55.95Z" }, + { url = "https://files.pythonhosted.org/packages/98/76/d32051fa65ecf6cc8c6610956473abdc9b4c43301107476ac03559507843/mypy-1.19.1-cp313-cp313-win_amd64.whl", hash = "sha256:016f2246209095e8eda7538944daa1d60e1e8134d98983b9fc1e92c1fc0cb8dd", size = 10135510, upload-time = "2025-12-15T05:02:58.438Z" }, + { url = "https://files.pythonhosted.org/packages/de/eb/b83e75f4c820c4247a58580ef86fcd35165028f191e7e1ba57128c52782d/mypy-1.19.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06e6170bd5836770e8104c8fdd58e5e725cfeb309f0a6c681a811f557e97eac1", size = 13199744, upload-time = "2025-12-15T05:03:30.823Z" }, + { url = "https://files.pythonhosted.org/packages/94/28/52785ab7bfa165f87fcbb61547a93f98bb20e7f82f90f165a1f69bce7b3d/mypy-1.19.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:804bd67b8054a85447c8954215a906d6eff9cabeabe493fb6334b24f4bfff718", size = 12215815, upload-time = "2025-12-15T05:02:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/0a/c6/bdd60774a0dbfb05122e3e925f2e9e846c009e479dcec4821dad881f5b52/mypy-1.19.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21761006a7f497cb0d4de3d8ef4ca70532256688b0523eee02baf9eec895e27b", size = 12740047, upload-time = "2025-12-15T05:03:33.168Z" }, + { url = "https://files.pythonhosted.org/packages/32/2a/66ba933fe6c76bd40d1fe916a83f04fed253152f451a877520b3c4a5e41e/mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045", size = 13601998, upload-time = "2025-12-15T05:03:13.056Z" }, + { url = "https://files.pythonhosted.org/packages/e3/da/5055c63e377c5c2418760411fd6a63ee2b96cf95397259038756c042574f/mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957", size = 13807476, upload-time = "2025-12-15T05:03:17.977Z" }, + { url = "https://files.pythonhosted.org/packages/cd/09/4ebd873390a063176f06b0dbf1f7783dd87bd120eae7727fa4ae4179b685/mypy-1.19.1-cp314-cp314-win_amd64.whl", hash = "sha256:8bb5c6f6d043655e055be9b542aa5f3bdd30e4f3589163e85f93f3640060509f", size = 10281872, upload-time = "2025-12-15T05:03:05.549Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f4/4ce9a05ce5ded1de3ec1c1d96cf9f9504a04e54ce0ed55cfa38619a32b8d/mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247", size = 2471239, upload-time = "2025-12-15T05:03:07.248Z" }, ] [[package]] @@ -665,83 +665,83 @@ wheels = [ [[package]] name = "orjson" -version = "3.11.5" +version = "3.11.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/04/b8/333fdb27840f3bf04022d21b654a35f58e15407183aeb16f3b41aa053446/orjson-3.11.5.tar.gz", hash = "sha256:82393ab47b4fe44ffd0a7659fa9cfaacc717eb617c93cde83795f14af5c2e9d5", size = 5972347, upload-time = "2025-12-06T15:55:39.458Z" } +sdist = { url = "https://files.pythonhosted.org/packages/53/45/b268004f745ede84e5798b48ee12b05129d19235d0e15267aa57dcdb400b/orjson-3.11.7.tar.gz", hash = "sha256:9b1a67243945819ce55d24a30b59d6a168e86220452d2c96f4d1f093e71c0c49", size = 6144992, upload-time = "2026-02-02T15:38:49.29Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/79/19/b22cf9dad4db20c8737041046054cbd4f38bb5a2d0e4bb60487832ce3d76/orjson-3.11.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:df9eadb2a6386d5ea2bfd81309c505e125cfc9ba2b1b99a97e60985b0b3665d1", size = 245719, upload-time = "2025-12-06T15:53:43.877Z" }, - { url = "https://files.pythonhosted.org/packages/03/2e/b136dd6bf30ef5143fbe76a4c142828b55ccc618be490201e9073ad954a1/orjson-3.11.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc70da619744467d8f1f49a8cadae5ec7bbe054e5232d95f92ed8737f8c5870", size = 132467, upload-time = "2025-12-06T15:53:45.379Z" }, - { url = "https://files.pythonhosted.org/packages/ae/fc/ae99bfc1e1887d20a0268f0e2686eb5b13d0ea7bbe01de2b566febcd2130/orjson-3.11.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:073aab025294c2f6fc0807201c76fdaed86f8fc4be52c440fb78fbb759a1ac09", size = 130702, upload-time = "2025-12-06T15:53:46.659Z" }, - { url = "https://files.pythonhosted.org/packages/6e/43/ef7912144097765997170aca59249725c3ab8ef6079f93f9d708dd058df5/orjson-3.11.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:835f26fa24ba0bb8c53ae2a9328d1706135b74ec653ed933869b74b6909e63fd", size = 135907, upload-time = "2025-12-06T15:53:48.487Z" }, - { url = "https://files.pythonhosted.org/packages/3f/da/24d50e2d7f4092ddd4d784e37a3fa41f22ce8ed97abc9edd222901a96e74/orjson-3.11.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667c132f1f3651c14522a119e4dd631fad98761fa960c55e8e7430bb2a1ba4ac", size = 139935, upload-time = "2025-12-06T15:53:49.88Z" }, - { url = "https://files.pythonhosted.org/packages/02/4a/b4cb6fcbfff5b95a3a019a8648255a0fac9b221fbf6b6e72be8df2361feb/orjson-3.11.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42e8961196af655bb5e63ce6c60d25e8798cd4dfbc04f4203457fa3869322c2e", size = 137541, upload-time = "2025-12-06T15:53:51.226Z" }, - { url = "https://files.pythonhosted.org/packages/a5/99/a11bd129f18c2377c27b2846a9d9be04acec981f770d711ba0aaea563984/orjson-3.11.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75412ca06e20904c19170f8a24486c4e6c7887dea591ba18a1ab572f1300ee9f", size = 139031, upload-time = "2025-12-06T15:53:52.309Z" }, - { url = "https://files.pythonhosted.org/packages/64/29/d7b77d7911574733a036bb3e8ad7053ceb2b7d6ea42208b9dbc55b23b9ed/orjson-3.11.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6af8680328c69e15324b5af3ae38abbfcf9cbec37b5346ebfd52339c3d7e8a18", size = 141622, upload-time = "2025-12-06T15:53:53.606Z" }, - { url = "https://files.pythonhosted.org/packages/93/41/332db96c1de76b2feda4f453e91c27202cd092835936ce2b70828212f726/orjson-3.11.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a86fe4ff4ea523eac8f4b57fdac319faf037d3c1be12405e6a7e86b3fbc4756a", size = 413800, upload-time = "2025-12-06T15:53:54.866Z" }, - { url = "https://files.pythonhosted.org/packages/76/e1/5a0d148dd1f89ad2f9651df67835b209ab7fcb1118658cf353425d7563e9/orjson-3.11.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e607b49b1a106ee2086633167033afbd63f76f2999e9236f638b06b112b24ea7", size = 151198, upload-time = "2025-12-06T15:53:56.383Z" }, - { url = "https://files.pythonhosted.org/packages/0d/96/8db67430d317a01ae5cf7971914f6775affdcfe99f5bff9ef3da32492ecc/orjson-3.11.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7339f41c244d0eea251637727f016b3d20050636695bc78345cce9029b189401", size = 141984, upload-time = "2025-12-06T15:53:57.746Z" }, - { url = "https://files.pythonhosted.org/packages/71/49/40d21e1aa1ac569e521069228bb29c9b5a350344ccf922a0227d93c2ed44/orjson-3.11.5-cp310-cp310-win32.whl", hash = "sha256:8be318da8413cdbbce77b8c5fac8d13f6eb0f0db41b30bb598631412619572e8", size = 135272, upload-time = "2025-12-06T15:53:59.769Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7e/d0e31e78be0c100e08be64f48d2850b23bcb4d4c70d114f4e43b39f6895a/orjson-3.11.5-cp310-cp310-win_amd64.whl", hash = "sha256:b9f86d69ae822cabc2a0f6c099b43e8733dda788405cba2665595b7e8dd8d167", size = 133360, upload-time = "2025-12-06T15:54:01.25Z" }, - { url = "https://files.pythonhosted.org/packages/fd/68/6b3659daec3a81aed5ab47700adb1a577c76a5452d35b91c88efee89987f/orjson-3.11.5-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9c8494625ad60a923af6b2b0bd74107146efe9b55099e20d7740d995f338fcd8", size = 245318, upload-time = "2025-12-06T15:54:02.355Z" }, - { url = "https://files.pythonhosted.org/packages/e9/00/92db122261425f61803ccf0830699ea5567439d966cbc35856fe711bfe6b/orjson-3.11.5-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:7bb2ce0b82bc9fd1168a513ddae7a857994b780b2945a8c51db4ab1c4b751ebc", size = 129491, upload-time = "2025-12-06T15:54:03.877Z" }, - { url = "https://files.pythonhosted.org/packages/94/4f/ffdcb18356518809d944e1e1f77589845c278a1ebbb5a8297dfefcc4b4cb/orjson-3.11.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67394d3becd50b954c4ecd24ac90b5051ee7c903d167459f93e77fc6f5b4c968", size = 132167, upload-time = "2025-12-06T15:54:04.944Z" }, - { url = "https://files.pythonhosted.org/packages/97/c6/0a8caff96f4503f4f7dd44e40e90f4d14acf80d3b7a97cb88747bb712d3e/orjson-3.11.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:298d2451f375e5f17b897794bcc3e7b821c0f32b4788b9bcae47ada24d7f3cf7", size = 130516, upload-time = "2025-12-06T15:54:06.274Z" }, - { url = "https://files.pythonhosted.org/packages/4d/63/43d4dc9bd9954bff7052f700fdb501067f6fb134a003ddcea2a0bb3854ed/orjson-3.11.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa5e4244063db8e1d87e0f54c3f7522f14b2dc937e65d5241ef0076a096409fd", size = 135695, upload-time = "2025-12-06T15:54:07.702Z" }, - { url = "https://files.pythonhosted.org/packages/87/6f/27e2e76d110919cb7fcb72b26166ee676480a701bcf8fc53ac5d0edce32f/orjson-3.11.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1db2088b490761976c1b2e956d5d4e6409f3732e9d79cfa69f876c5248d1baf9", size = 139664, upload-time = "2025-12-06T15:54:08.828Z" }, - { url = "https://files.pythonhosted.org/packages/d4/f8/5966153a5f1be49b5fbb8ca619a529fde7bc71aa0a376f2bb83fed248bcd/orjson-3.11.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2ed66358f32c24e10ceea518e16eb3549e34f33a9d51f99ce23b0251776a1ef", size = 137289, upload-time = "2025-12-06T15:54:09.898Z" }, - { url = "https://files.pythonhosted.org/packages/a7/34/8acb12ff0299385c8bbcbb19fbe40030f23f15a6de57a9c587ebf71483fb/orjson-3.11.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2021afda46c1ed64d74b555065dbd4c2558d510d8cec5ea6a53001b3e5e82a9", size = 138784, upload-time = "2025-12-06T15:54:11.022Z" }, - { url = "https://files.pythonhosted.org/packages/ee/27/910421ea6e34a527f73d8f4ee7bdffa48357ff79c7b8d6eb6f7b82dd1176/orjson-3.11.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b42ffbed9128e547a1647a3e50bc88ab28ae9daa61713962e0d3dd35e820c125", size = 141322, upload-time = "2025-12-06T15:54:12.427Z" }, - { url = "https://files.pythonhosted.org/packages/87/a3/4b703edd1a05555d4bb1753d6ce44e1a05b7a6d7c164d5b332c795c63d70/orjson-3.11.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8d5f16195bb671a5dd3d1dbea758918bada8f6cc27de72bd64adfbd748770814", size = 413612, upload-time = "2025-12-06T15:54:13.858Z" }, - { url = "https://files.pythonhosted.org/packages/1b/36/034177f11d7eeea16d3d2c42a1883b0373978e08bc9dad387f5074c786d8/orjson-3.11.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c0e5d9f7a0227df2927d343a6e3859bebf9208b427c79bd31949abcc2fa32fa5", size = 150993, upload-time = "2025-12-06T15:54:15.189Z" }, - { url = "https://files.pythonhosted.org/packages/44/2f/ea8b24ee046a50a7d141c0227c4496b1180b215e728e3b640684f0ea448d/orjson-3.11.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:23d04c4543e78f724c4dfe656b3791b5f98e4c9253e13b2636f1af5d90e4a880", size = 141774, upload-time = "2025-12-06T15:54:16.451Z" }, - { url = "https://files.pythonhosted.org/packages/8a/12/cc440554bf8200eb23348a5744a575a342497b65261cd65ef3b28332510a/orjson-3.11.5-cp311-cp311-win32.whl", hash = "sha256:c404603df4865f8e0afe981aa3c4b62b406e6d06049564d58934860b62b7f91d", size = 135109, upload-time = "2025-12-06T15:54:17.73Z" }, - { url = "https://files.pythonhosted.org/packages/a3/83/e0c5aa06ba73a6760134b169f11fb970caa1525fa4461f94d76e692299d9/orjson-3.11.5-cp311-cp311-win_amd64.whl", hash = "sha256:9645ef655735a74da4990c24ffbd6894828fbfa117bc97c1edd98c282ecb52e1", size = 133193, upload-time = "2025-12-06T15:54:19.426Z" }, - { url = "https://files.pythonhosted.org/packages/cb/35/5b77eaebc60d735e832c5b1a20b155667645d123f09d471db0a78280fb49/orjson-3.11.5-cp311-cp311-win_arm64.whl", hash = "sha256:1cbf2735722623fcdee8e712cbaaab9e372bbcb0c7924ad711b261c2eccf4a5c", size = 126830, upload-time = "2025-12-06T15:54:20.836Z" }, - { url = "https://files.pythonhosted.org/packages/ef/a4/8052a029029b096a78955eadd68ab594ce2197e24ec50e6b6d2ab3f4e33b/orjson-3.11.5-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:334e5b4bff9ad101237c2d799d9fd45737752929753bf4faf4b207335a416b7d", size = 245347, upload-time = "2025-12-06T15:54:22.061Z" }, - { url = "https://files.pythonhosted.org/packages/64/67/574a7732bd9d9d79ac620c8790b4cfe0717a3d5a6eb2b539e6e8995e24a0/orjson-3.11.5-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:ff770589960a86eae279f5d8aa536196ebda8273a2a07db2a54e82b93bc86626", size = 129435, upload-time = "2025-12-06T15:54:23.615Z" }, - { url = "https://files.pythonhosted.org/packages/52/8d/544e77d7a29d90cf4d9eecd0ae801c688e7f3d1adfa2ebae5e1e94d38ab9/orjson-3.11.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed24250e55efbcb0b35bed7caaec8cedf858ab2f9f2201f17b8938c618c8ca6f", size = 132074, upload-time = "2025-12-06T15:54:24.694Z" }, - { url = "https://files.pythonhosted.org/packages/6e/57/b9f5b5b6fbff9c26f77e785baf56ae8460ef74acdb3eae4931c25b8f5ba9/orjson-3.11.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a66d7769e98a08a12a139049aac2f0ca3adae989817f8c43337455fbc7669b85", size = 130520, upload-time = "2025-12-06T15:54:26.185Z" }, - { url = "https://files.pythonhosted.org/packages/f6/6d/d34970bf9eb33f9ec7c979a262cad86076814859e54eb9a059a52f6dc13d/orjson-3.11.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86cfc555bfd5794d24c6a1903e558b50644e5e68e6471d66502ce5cb5fdef3f9", size = 136209, upload-time = "2025-12-06T15:54:27.264Z" }, - { url = "https://files.pythonhosted.org/packages/e7/39/bc373b63cc0e117a105ea12e57280f83ae52fdee426890d57412432d63b3/orjson-3.11.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a230065027bc2a025e944f9d4714976a81e7ecfa940923283bca7bbc1f10f626", size = 139837, upload-time = "2025-12-06T15:54:28.75Z" }, - { url = "https://files.pythonhosted.org/packages/cb/aa/7c4818c8d7d324da220f4f1af55c343956003aa4d1ce1857bdc1d396ba69/orjson-3.11.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b29d36b60e606df01959c4b982729c8845c69d1963f88686608be9ced96dbfaa", size = 137307, upload-time = "2025-12-06T15:54:29.856Z" }, - { url = "https://files.pythonhosted.org/packages/46/bf/0993b5a056759ba65145effe3a79dd5a939d4a070eaa5da2ee3180fbb13f/orjson-3.11.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c74099c6b230d4261fdc3169d50efc09abf38ace1a42ea2f9994b1d79153d477", size = 139020, upload-time = "2025-12-06T15:54:31.024Z" }, - { url = "https://files.pythonhosted.org/packages/65/e8/83a6c95db3039e504eda60fc388f9faedbb4f6472f5aba7084e06552d9aa/orjson-3.11.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e697d06ad57dd0c7a737771d470eedc18e68dfdefcdd3b7de7f33dfda5b6212e", size = 141099, upload-time = "2025-12-06T15:54:32.196Z" }, - { url = "https://files.pythonhosted.org/packages/b9/b4/24fdc024abfce31c2f6812973b0a693688037ece5dc64b7a60c1ce69e2f2/orjson-3.11.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e08ca8a6c851e95aaecc32bc44a5aa75d0ad26af8cdac7c77e4ed93acf3d5b69", size = 413540, upload-time = "2025-12-06T15:54:33.361Z" }, - { url = "https://files.pythonhosted.org/packages/d9/37/01c0ec95d55ed0c11e4cae3e10427e479bba40c77312b63e1f9665e0737d/orjson-3.11.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e8b5f96c05fce7d0218df3fdfeb962d6b8cfff7e3e20264306b46dd8b217c0f3", size = 151530, upload-time = "2025-12-06T15:54:34.6Z" }, - { url = "https://files.pythonhosted.org/packages/f9/d4/f9ebc57182705bb4bbe63f5bbe14af43722a2533135e1d2fb7affa0c355d/orjson-3.11.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ddbfdb5099b3e6ba6d6ea818f61997bb66de14b411357d24c4612cf1ebad08ca", size = 141863, upload-time = "2025-12-06T15:54:35.801Z" }, - { url = "https://files.pythonhosted.org/packages/0d/04/02102b8d19fdcb009d72d622bb5781e8f3fae1646bf3e18c53d1bc8115b5/orjson-3.11.5-cp312-cp312-win32.whl", hash = "sha256:9172578c4eb09dbfcf1657d43198de59b6cef4054de385365060ed50c458ac98", size = 135255, upload-time = "2025-12-06T15:54:37.209Z" }, - { url = "https://files.pythonhosted.org/packages/d4/fb/f05646c43d5450492cb387de5549f6de90a71001682c17882d9f66476af5/orjson-3.11.5-cp312-cp312-win_amd64.whl", hash = "sha256:2b91126e7b470ff2e75746f6f6ee32b9ab67b7a93c8ba1d15d3a0caaf16ec875", size = 133252, upload-time = "2025-12-06T15:54:38.401Z" }, - { url = "https://files.pythonhosted.org/packages/dc/a6/7b8c0b26ba18c793533ac1cd145e131e46fcf43952aa94c109b5b913c1f0/orjson-3.11.5-cp312-cp312-win_arm64.whl", hash = "sha256:acbc5fac7e06777555b0722b8ad5f574739e99ffe99467ed63da98f97f9ca0fe", size = 126777, upload-time = "2025-12-06T15:54:39.515Z" }, - { url = "https://files.pythonhosted.org/packages/10/43/61a77040ce59f1569edf38f0b9faadc90c8cf7e9bec2e0df51d0132c6bb7/orjson-3.11.5-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3b01799262081a4c47c035dd77c1301d40f568f77cc7ec1bb7db5d63b0a01629", size = 245271, upload-time = "2025-12-06T15:54:40.878Z" }, - { url = "https://files.pythonhosted.org/packages/55/f9/0f79be617388227866d50edd2fd320cb8fb94dc1501184bb1620981a0aba/orjson-3.11.5-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:61de247948108484779f57a9f406e4c84d636fa5a59e411e6352484985e8a7c3", size = 129422, upload-time = "2025-12-06T15:54:42.403Z" }, - { url = "https://files.pythonhosted.org/packages/77/42/f1bf1549b432d4a78bfa95735b79b5dac75b65b5bb815bba86ad406ead0a/orjson-3.11.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:894aea2e63d4f24a7f04a1908307c738d0dce992e9249e744b8f4e8dd9197f39", size = 132060, upload-time = "2025-12-06T15:54:43.531Z" }, - { url = "https://files.pythonhosted.org/packages/25/49/825aa6b929f1a6ed244c78acd7b22c1481fd7e5fda047dc8bf4c1a807eb6/orjson-3.11.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ddc21521598dbe369d83d4d40338e23d4101dad21dae0e79fa20465dbace019f", size = 130391, upload-time = "2025-12-06T15:54:45.059Z" }, - { url = "https://files.pythonhosted.org/packages/42/ec/de55391858b49e16e1aa8f0bbbb7e5997b7345d8e984a2dec3746d13065b/orjson-3.11.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cce16ae2f5fb2c53c3eafdd1706cb7b6530a67cc1c17abe8ec747f5cd7c0c51", size = 135964, upload-time = "2025-12-06T15:54:46.576Z" }, - { url = "https://files.pythonhosted.org/packages/1c/40/820bc63121d2d28818556a2d0a09384a9f0262407cf9fa305e091a8048df/orjson-3.11.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e46c762d9f0e1cfb4ccc8515de7f349abbc95b59cb5a2bd68df5973fdef913f8", size = 139817, upload-time = "2025-12-06T15:54:48.084Z" }, - { url = "https://files.pythonhosted.org/packages/09/c7/3a445ca9a84a0d59d26365fd8898ff52bdfcdcb825bcc6519830371d2364/orjson-3.11.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7345c759276b798ccd6d77a87136029e71e66a8bbf2d2755cbdde1d82e78706", size = 137336, upload-time = "2025-12-06T15:54:49.426Z" }, - { url = "https://files.pythonhosted.org/packages/9a/b3/dc0d3771f2e5d1f13368f56b339c6782f955c6a20b50465a91acb79fe961/orjson-3.11.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75bc2e59e6a2ac1dd28901d07115abdebc4563b5b07dd612bf64260a201b1c7f", size = 138993, upload-time = "2025-12-06T15:54:50.939Z" }, - { url = "https://files.pythonhosted.org/packages/d1/a2/65267e959de6abe23444659b6e19c888f242bf7725ff927e2292776f6b89/orjson-3.11.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:54aae9b654554c3b4edd61896b978568c6daa16af96fa4681c9b5babd469f863", size = 141070, upload-time = "2025-12-06T15:54:52.414Z" }, - { url = "https://files.pythonhosted.org/packages/63/c9/da44a321b288727a322c6ab17e1754195708786a04f4f9d2220a5076a649/orjson-3.11.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4bdd8d164a871c4ec773f9de0f6fe8769c2d6727879c37a9666ba4183b7f8228", size = 413505, upload-time = "2025-12-06T15:54:53.67Z" }, - { url = "https://files.pythonhosted.org/packages/7f/17/68dc14fa7000eefb3d4d6d7326a190c99bb65e319f02747ef3ebf2452f12/orjson-3.11.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a261fef929bcf98a60713bf5e95ad067cea16ae345d9a35034e73c3990e927d2", size = 151342, upload-time = "2025-12-06T15:54:55.113Z" }, - { url = "https://files.pythonhosted.org/packages/c4/c5/ccee774b67225bed630a57478529fc026eda33d94fe4c0eac8fe58d4aa52/orjson-3.11.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c028a394c766693c5c9909dec76b24f37e6a1b91999e8d0c0d5feecbe93c3e05", size = 141823, upload-time = "2025-12-06T15:54:56.331Z" }, - { url = "https://files.pythonhosted.org/packages/67/80/5d00e4155d0cd7390ae2087130637671da713959bb558db9bac5e6f6b042/orjson-3.11.5-cp313-cp313-win32.whl", hash = "sha256:2cc79aaad1dfabe1bd2d50ee09814a1253164b3da4c00a78c458d82d04b3bdef", size = 135236, upload-time = "2025-12-06T15:54:57.507Z" }, - { url = "https://files.pythonhosted.org/packages/95/fe/792cc06a84808dbdc20ac6eab6811c53091b42f8e51ecebf14b540e9cfe4/orjson-3.11.5-cp313-cp313-win_amd64.whl", hash = "sha256:ff7877d376add4e16b274e35a3f58b7f37b362abf4aa31863dadacdd20e3a583", size = 133167, upload-time = "2025-12-06T15:54:58.71Z" }, - { url = "https://files.pythonhosted.org/packages/46/2c/d158bd8b50e3b1cfdcf406a7e463f6ffe3f0d167b99634717acdaf5e299f/orjson-3.11.5-cp313-cp313-win_arm64.whl", hash = "sha256:59ac72ea775c88b163ba8d21b0177628bd015c5dd060647bbab6e22da3aad287", size = 126712, upload-time = "2025-12-06T15:54:59.892Z" }, - { url = "https://files.pythonhosted.org/packages/c2/60/77d7b839e317ead7bb225d55bb50f7ea75f47afc489c81199befc5435b50/orjson-3.11.5-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e446a8ea0a4c366ceafc7d97067bfd55292969143b57e3c846d87fc701e797a0", size = 245252, upload-time = "2025-12-06T15:55:01.127Z" }, - { url = "https://files.pythonhosted.org/packages/f1/aa/d4639163b400f8044cef0fb9aa51b0337be0da3a27187a20d1166e742370/orjson-3.11.5-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:53deb5addae9c22bbe3739298f5f2196afa881ea75944e7720681c7080909a81", size = 129419, upload-time = "2025-12-06T15:55:02.723Z" }, - { url = "https://files.pythonhosted.org/packages/30/94/9eabf94f2e11c671111139edf5ec410d2f21e6feee717804f7e8872d883f/orjson-3.11.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cd00d49d6063d2b8791da5d4f9d20539c5951f965e45ccf4e96d33505ce68f", size = 132050, upload-time = "2025-12-06T15:55:03.918Z" }, - { url = "https://files.pythonhosted.org/packages/3d/c8/ca10f5c5322f341ea9a9f1097e140be17a88f88d1cfdd29df522970d9744/orjson-3.11.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3fd15f9fc8c203aeceff4fda211157fad114dde66e92e24097b3647a08f4ee9e", size = 130370, upload-time = "2025-12-06T15:55:05.173Z" }, - { url = "https://files.pythonhosted.org/packages/25/d4/e96824476d361ee2edd5c6290ceb8d7edf88d81148a6ce172fc00278ca7f/orjson-3.11.5-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9df95000fbe6777bf9820ae82ab7578e8662051bb5f83d71a28992f539d2cda7", size = 136012, upload-time = "2025-12-06T15:55:06.402Z" }, - { url = "https://files.pythonhosted.org/packages/85/8e/9bc3423308c425c588903f2d103cfcfe2539e07a25d6522900645a6f257f/orjson-3.11.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92a8d676748fca47ade5bc3da7430ed7767afe51b2f8100e3cd65e151c0eaceb", size = 139809, upload-time = "2025-12-06T15:55:07.656Z" }, - { url = "https://files.pythonhosted.org/packages/e9/3c/b404e94e0b02a232b957c54643ce68d0268dacb67ac33ffdee24008c8b27/orjson-3.11.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa0f513be38b40234c77975e68805506cad5d57b3dfd8fe3baa7f4f4051e15b4", size = 137332, upload-time = "2025-12-06T15:55:08.961Z" }, - { url = "https://files.pythonhosted.org/packages/51/30/cc2d69d5ce0ad9b84811cdf4a0cd5362ac27205a921da524ff42f26d65e0/orjson-3.11.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1863e75b92891f553b7922ce4ee10ed06db061e104f2b7815de80cdcb135ad", size = 138983, upload-time = "2025-12-06T15:55:10.595Z" }, - { url = "https://files.pythonhosted.org/packages/0e/87/de3223944a3e297d4707d2fe3b1ffb71437550e165eaf0ca8bbe43ccbcb1/orjson-3.11.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4be86b58e9ea262617b8ca6251a2f0d63cc132a6da4b5fcc8e0a4128782c829", size = 141069, upload-time = "2025-12-06T15:55:11.832Z" }, - { url = "https://files.pythonhosted.org/packages/65/30/81d5087ae74be33bcae3ff2d80f5ccaa4a8fedc6d39bf65a427a95b8977f/orjson-3.11.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:b923c1c13fa02084eb38c9c065afd860a5cff58026813319a06949c3af5732ac", size = 413491, upload-time = "2025-12-06T15:55:13.314Z" }, - { url = "https://files.pythonhosted.org/packages/d0/6f/f6058c21e2fc1efaf918986dbc2da5cd38044f1a2d4b7b91ad17c4acf786/orjson-3.11.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:1b6bd351202b2cd987f35a13b5e16471cf4d952b42a73c391cc537974c43ef6d", size = 151375, upload-time = "2025-12-06T15:55:14.715Z" }, - { url = "https://files.pythonhosted.org/packages/54/92/c6921f17d45e110892899a7a563a925b2273d929959ce2ad89e2525b885b/orjson-3.11.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bb150d529637d541e6af06bbe3d02f5498d628b7f98267ff87647584293ab439", size = 141850, upload-time = "2025-12-06T15:55:15.94Z" }, - { url = "https://files.pythonhosted.org/packages/88/86/cdecb0140a05e1a477b81f24739da93b25070ee01ce7f7242f44a6437594/orjson-3.11.5-cp314-cp314-win32.whl", hash = "sha256:9cc1e55c884921434a84a0c3dd2699eb9f92e7b441d7f53f3941079ec6ce7499", size = 135278, upload-time = "2025-12-06T15:55:17.202Z" }, - { url = "https://files.pythonhosted.org/packages/e4/97/b638d69b1e947d24f6109216997e38922d54dcdcdb1b11c18d7efd2d3c59/orjson-3.11.5-cp314-cp314-win_amd64.whl", hash = "sha256:a4f3cb2d874e03bc7767c8f88adaa1a9a05cecea3712649c3b58589ec7317310", size = 133170, upload-time = "2025-12-06T15:55:18.468Z" }, - { url = "https://files.pythonhosted.org/packages/8f/dd/f4fff4a6fe601b4f8f3ba3aa6da8ac33d17d124491a3b804c662a70e1636/orjson-3.11.5-cp314-cp314-win_arm64.whl", hash = "sha256:38b22f476c351f9a1c43e5b07d8b5a02eb24a6ab8e75f700f7d479d4568346a5", size = 126713, upload-time = "2025-12-06T15:55:19.738Z" }, + { url = "https://files.pythonhosted.org/packages/de/1a/a373746fa6d0e116dd9e54371a7b54622c44d12296d5d0f3ad5e3ff33490/orjson-3.11.7-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a02c833f38f36546ba65a452127633afce4cf0dd7296b753d3bb54e55e5c0174", size = 229140, upload-time = "2026-02-02T15:37:06.082Z" }, + { url = "https://files.pythonhosted.org/packages/52/a2/fa129e749d500f9b183e8a3446a193818a25f60261e9ce143ad61e975208/orjson-3.11.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b63c6e6738d7c3470ad01601e23376aa511e50e1f3931395b9f9c722406d1a67", size = 128670, upload-time = "2026-02-02T15:37:08.002Z" }, + { url = "https://files.pythonhosted.org/packages/08/93/1e82011cd1e0bd051ef9d35bed1aa7fb4ea1f0a055dc2c841b46b43a9ebd/orjson-3.11.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:043d3006b7d32c7e233b8cfb1f01c651013ea079e08dcef7189a29abd8befe11", size = 123832, upload-time = "2026-02-02T15:37:09.191Z" }, + { url = "https://files.pythonhosted.org/packages/fe/d8/a26b431ef962c7d55736674dddade876822f3e33223c1f47a36879350d04/orjson-3.11.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57036b27ac8a25d81112eb0cc9835cd4833c5b16e1467816adc0015f59e870dc", size = 129171, upload-time = "2026-02-02T15:37:11.112Z" }, + { url = "https://files.pythonhosted.org/packages/a7/19/f47819b84a580f490da260c3ee9ade214cf4cf78ac9ce8c1c758f80fdfc9/orjson-3.11.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:733ae23ada68b804b222c44affed76b39e30806d38660bf1eb200520d259cc16", size = 141967, upload-time = "2026-02-02T15:37:12.282Z" }, + { url = "https://files.pythonhosted.org/packages/5b/cd/37ece39a0777ba077fdcdbe4cccae3be8ed00290c14bf8afdc548befc260/orjson-3.11.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5fdfad2093bdd08245f2e204d977facd5f871c88c4a71230d5bcbd0e43bf6222", size = 130991, upload-time = "2026-02-02T15:37:13.465Z" }, + { url = "https://files.pythonhosted.org/packages/8f/ed/f2b5d66aa9b6b5c02ff5f120efc7b38c7c4962b21e6be0f00fd99a5c348e/orjson-3.11.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cededd6738e1c153530793998e31c05086582b08315db48ab66649768f326baa", size = 133674, upload-time = "2026-02-02T15:37:14.694Z" }, + { url = "https://files.pythonhosted.org/packages/c4/6e/baa83e68d1aa09fa8c3e5b2c087d01d0a0bd45256de719ed7bc22c07052d/orjson-3.11.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:14f440c7268c8f8633d1b3d443a434bd70cb15686117ea6beff8fdc8f5917a1e", size = 138722, upload-time = "2026-02-02T15:37:16.501Z" }, + { url = "https://files.pythonhosted.org/packages/0c/47/7f8ef4963b772cd56999b535e553f7eb5cd27e9dd6c049baee6f18bfa05d/orjson-3.11.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3a2479753bbb95b0ebcf7969f562cdb9668e6d12416a35b0dda79febf89cdea2", size = 409056, upload-time = "2026-02-02T15:37:17.895Z" }, + { url = "https://files.pythonhosted.org/packages/38/eb/2df104dd2244b3618f25325a656f85cc3277f74bbd91224752410a78f3c7/orjson-3.11.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:71924496986275a737f38e3f22b4e0878882b3f7a310d2ff4dc96e812789120c", size = 144196, upload-time = "2026-02-02T15:37:19.349Z" }, + { url = "https://files.pythonhosted.org/packages/b6/2a/ee41de0aa3a6686598661eae2b4ebdff1340c65bfb17fcff8b87138aab21/orjson-3.11.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4a9eefdc70bf8bf9857f0290f973dec534ac84c35cd6a7f4083be43e7170a8f", size = 134979, upload-time = "2026-02-02T15:37:20.906Z" }, + { url = "https://files.pythonhosted.org/packages/4c/fa/92fc5d3d402b87a8b28277a9ed35386218a6a5287c7fe5ee9b9f02c53fb2/orjson-3.11.7-cp310-cp310-win32.whl", hash = "sha256:ae9e0b37a834cef7ce8f99de6498f8fad4a2c0bf6bfc3d02abd8ed56aa15b2de", size = 127968, upload-time = "2026-02-02T15:37:23.178Z" }, + { url = "https://files.pythonhosted.org/packages/07/29/a576bf36d73d60df06904d3844a9df08e25d59eba64363aaf8ec2f9bff41/orjson-3.11.7-cp310-cp310-win_amd64.whl", hash = "sha256:d772afdb22555f0c58cfc741bdae44180122b3616faa1ecadb595cd526e4c993", size = 125128, upload-time = "2026-02-02T15:37:24.329Z" }, + { url = "https://files.pythonhosted.org/packages/37/02/da6cb01fc6087048d7f61522c327edf4250f1683a58a839fdcc435746dd5/orjson-3.11.7-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9487abc2c2086e7c8eb9a211d2ce8855bae0e92586279d0d27b341d5ad76c85c", size = 228664, upload-time = "2026-02-02T15:37:25.542Z" }, + { url = "https://files.pythonhosted.org/packages/c1/c2/5885e7a5881dba9a9af51bc564e8967225a642b3e03d089289a35054e749/orjson-3.11.7-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:79cacb0b52f6004caf92405a7e1f11e6e2de8bdf9019e4f76b44ba045125cd6b", size = 125344, upload-time = "2026-02-02T15:37:26.92Z" }, + { url = "https://files.pythonhosted.org/packages/a4/1d/4e7688de0a92d1caf600dfd5fb70b4c5bfff51dfa61ac555072ef2d0d32a/orjson-3.11.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2e85fe4698b6a56d5e2ebf7ae87544d668eb6bde1ad1226c13f44663f20ec9e", size = 128404, upload-time = "2026-02-02T15:37:28.108Z" }, + { url = "https://files.pythonhosted.org/packages/2f/b2/ec04b74ae03a125db7bd69cffd014b227b7f341e3261bf75b5eb88a1aa92/orjson-3.11.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8d14b71c0b12963fe8a62aac87119f1afdf4cb88a400f61ca5ae581449efcb5", size = 123677, upload-time = "2026-02-02T15:37:30.287Z" }, + { url = "https://files.pythonhosted.org/packages/4c/69/f95bdf960605f08f827f6e3291fe243d8aa9c5c9ff017a8d7232209184c3/orjson-3.11.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91c81ef070c8f3220054115e1ef468b1c9ce8497b4e526cb9f68ab4dc0a7ac62", size = 128950, upload-time = "2026-02-02T15:37:31.595Z" }, + { url = "https://files.pythonhosted.org/packages/a4/1b/de59c57bae1d148ef298852abd31909ac3089cff370dfd4cd84cc99cbc42/orjson-3.11.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:411ebaf34d735e25e358a6d9e7978954a9c9d58cfb47bc6683cdc3964cd2f910", size = 141756, upload-time = "2026-02-02T15:37:32.985Z" }, + { url = "https://files.pythonhosted.org/packages/ee/9e/9decc59f4499f695f65c650f6cfa6cd4c37a3fbe8fa235a0a3614cb54386/orjson-3.11.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a16bcd08ab0bcdfc7e8801d9c4a9cc17e58418e4d48ddc6ded4e9e4b1a94062b", size = 130812, upload-time = "2026-02-02T15:37:34.204Z" }, + { url = "https://files.pythonhosted.org/packages/28/e6/59f932bcabd1eac44e334fe8e3281a92eacfcb450586e1f4bde0423728d8/orjson-3.11.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c0b51672e466fd7e56230ffbae7f1639e18d0ce023351fb75da21b71bc2c960", size = 133444, upload-time = "2026-02-02T15:37:35.446Z" }, + { url = "https://files.pythonhosted.org/packages/f1/36/b0f05c0eaa7ca30bc965e37e6a2956b0d67adb87a9872942d3568da846ae/orjson-3.11.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:136dcd6a2e796dfd9ffca9fc027d778567b0b7c9968d092842d3c323cef88aa8", size = 138609, upload-time = "2026-02-02T15:37:36.657Z" }, + { url = "https://files.pythonhosted.org/packages/b8/03/58ec7d302b8d86944c60c7b4b82975d5161fcce4c9bc8c6cb1d6741b6115/orjson-3.11.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:7ba61079379b0ae29e117db13bda5f28d939766e410d321ec1624afc6a0b0504", size = 408918, upload-time = "2026-02-02T15:37:38.076Z" }, + { url = "https://files.pythonhosted.org/packages/06/3a/868d65ef9a8b99be723bd510de491349618abd9f62c826cf206d962db295/orjson-3.11.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0527a4510c300e3b406591b0ba69b5dc50031895b0a93743526a3fc45f59d26e", size = 143998, upload-time = "2026-02-02T15:37:39.706Z" }, + { url = "https://files.pythonhosted.org/packages/5b/c7/1e18e1c83afe3349f4f6dc9e14910f0ae5f82eac756d1412ea4018938535/orjson-3.11.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a709e881723c9b18acddcfb8ba357322491ad553e277cf467e1e7e20e2d90561", size = 134802, upload-time = "2026-02-02T15:37:41.002Z" }, + { url = "https://files.pythonhosted.org/packages/d4/0b/ccb7ee1a65b37e8eeb8b267dc953561d72370e85185e459616d4345bab34/orjson-3.11.7-cp311-cp311-win32.whl", hash = "sha256:c43b8b5bab288b6b90dac410cca7e986a4fa747a2e8f94615aea407da706980d", size = 127828, upload-time = "2026-02-02T15:37:42.241Z" }, + { url = "https://files.pythonhosted.org/packages/af/9e/55c776dffda3f381e0f07d010a4f5f3902bf48eaba1bb7684d301acd4924/orjson-3.11.7-cp311-cp311-win_amd64.whl", hash = "sha256:6543001328aa857187f905308a028935864aefe9968af3848401b6fe80dbb471", size = 124941, upload-time = "2026-02-02T15:37:43.444Z" }, + { url = "https://files.pythonhosted.org/packages/aa/8e/424a620fa7d263b880162505fb107ef5e0afaa765b5b06a88312ac291560/orjson-3.11.7-cp311-cp311-win_arm64.whl", hash = "sha256:1ee5cc7160a821dfe14f130bc8e63e7611051f964b463d9e2a3a573204446a4d", size = 126245, upload-time = "2026-02-02T15:37:45.18Z" }, + { url = "https://files.pythonhosted.org/packages/80/bf/76f4f1665f6983385938f0e2a5d7efa12a58171b8456c252f3bae8a4cf75/orjson-3.11.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bd03ea7606833655048dab1a00734a2875e3e86c276e1d772b2a02556f0d895f", size = 228545, upload-time = "2026-02-02T15:37:46.376Z" }, + { url = "https://files.pythonhosted.org/packages/79/53/6c72c002cb13b5a978a068add59b25a8bdf2800ac1c9c8ecdb26d6d97064/orjson-3.11.7-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:89e440ebc74ce8ab5c7bc4ce6757b4a6b1041becb127df818f6997b5c71aa60b", size = 125224, upload-time = "2026-02-02T15:37:47.697Z" }, + { url = "https://files.pythonhosted.org/packages/2c/83/10e48852865e5dd151bdfe652c06f7da484578ed02c5fca938e3632cb0b8/orjson-3.11.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ede977b5fe5ac91b1dffc0a517ca4542d2ec8a6a4ff7b2652d94f640796342a", size = 128154, upload-time = "2026-02-02T15:37:48.954Z" }, + { url = "https://files.pythonhosted.org/packages/6e/52/a66e22a2b9abaa374b4a081d410edab6d1e30024707b87eab7c734afe28d/orjson-3.11.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b7b1dae39230a393df353827c855a5f176271c23434cfd2db74e0e424e693e10", size = 123548, upload-time = "2026-02-02T15:37:50.187Z" }, + { url = "https://files.pythonhosted.org/packages/de/38/605d371417021359f4910c496f764c48ceb8997605f8c25bf1dfe58c0ebe/orjson-3.11.7-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed46f17096e28fb28d2975834836a639af7278aa87c84f68ab08fbe5b8bd75fa", size = 129000, upload-time = "2026-02-02T15:37:51.426Z" }, + { url = "https://files.pythonhosted.org/packages/44/98/af32e842b0ffd2335c89714d48ca4e3917b42f5d6ee5537832e069a4b3ac/orjson-3.11.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3726be79e36e526e3d9c1aceaadbfb4a04ee80a72ab47b3f3c17fefb9812e7b8", size = 141686, upload-time = "2026-02-02T15:37:52.607Z" }, + { url = "https://files.pythonhosted.org/packages/96/0b/fc793858dfa54be6feee940c1463370ece34b3c39c1ca0aa3845f5ba9892/orjson-3.11.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0724e265bc548af1dedebd9cb3d24b4e1c1e685a343be43e87ba922a5c5fff2f", size = 130812, upload-time = "2026-02-02T15:37:53.944Z" }, + { url = "https://files.pythonhosted.org/packages/dc/91/98a52415059db3f374757d0b7f0f16e3b5cd5976c90d1c2b56acaea039e6/orjson-3.11.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7745312efa9e11c17fbd3cb3097262d079da26930ae9ae7ba28fb738367cbad", size = 133440, upload-time = "2026-02-02T15:37:55.615Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b6/cb540117bda61791f46381f8c26c8f93e802892830a6055748d3bb1925ab/orjson-3.11.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f904c24bdeabd4298f7a977ef14ca2a022ca921ed670b92ecd16ab6f3d01f867", size = 138386, upload-time = "2026-02-02T15:37:56.814Z" }, + { url = "https://files.pythonhosted.org/packages/63/1a/50a3201c334a7f17c231eee5f841342190723794e3b06293f26e7cf87d31/orjson-3.11.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b9fc4d0f81f394689e0814617aadc4f2ea0e8025f38c226cbf22d3b5ddbf025d", size = 408853, upload-time = "2026-02-02T15:37:58.291Z" }, + { url = "https://files.pythonhosted.org/packages/87/cd/8de1c67d0be44fdc22701e5989c0d015a2adf391498ad42c4dc589cd3013/orjson-3.11.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:849e38203e5be40b776ed2718e587faf204d184fc9a008ae441f9442320c0cab", size = 144130, upload-time = "2026-02-02T15:38:00.163Z" }, + { url = "https://files.pythonhosted.org/packages/0f/fe/d605d700c35dd55f51710d159fc54516a280923cd1b7e47508982fbb387d/orjson-3.11.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4682d1db3bcebd2b64757e0ddf9e87ae5f00d29d16c5cdf3a62f561d08cc3dd2", size = 134818, upload-time = "2026-02-02T15:38:01.507Z" }, + { url = "https://files.pythonhosted.org/packages/e4/e4/15ecc67edb3ddb3e2f46ae04475f2d294e8b60c1825fbe28a428b93b3fbd/orjson-3.11.7-cp312-cp312-win32.whl", hash = "sha256:f4f7c956b5215d949a1f65334cf9d7612dde38f20a95f2315deef167def91a6f", size = 127923, upload-time = "2026-02-02T15:38:02.75Z" }, + { url = "https://files.pythonhosted.org/packages/34/70/2e0855361f76198a3965273048c8e50a9695d88cd75811a5b46444895845/orjson-3.11.7-cp312-cp312-win_amd64.whl", hash = "sha256:bf742e149121dc5648ba0a08ea0871e87b660467ef168a3a5e53bc1fbd64bb74", size = 125007, upload-time = "2026-02-02T15:38:04.032Z" }, + { url = "https://files.pythonhosted.org/packages/68/40/c2051bd19fc467610fed469dc29e43ac65891571138f476834ca192bc290/orjson-3.11.7-cp312-cp312-win_arm64.whl", hash = "sha256:26c3b9132f783b7d7903bf1efb095fed8d4a3a85ec0d334ee8beff3d7a4749d5", size = 126089, upload-time = "2026-02-02T15:38:05.297Z" }, + { url = "https://files.pythonhosted.org/packages/89/25/6e0e52cac5aab51d7b6dcd257e855e1dec1c2060f6b28566c509b4665f62/orjson-3.11.7-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1d98b30cc1313d52d4af17d9c3d307b08389752ec5f2e5febdfada70b0f8c733", size = 228390, upload-time = "2026-02-02T15:38:06.8Z" }, + { url = "https://files.pythonhosted.org/packages/a5/29/a77f48d2fc8a05bbc529e5ff481fb43d914f9e383ea2469d4f3d51df3d00/orjson-3.11.7-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:d897e81f8d0cbd2abb82226d1860ad2e1ab3ff16d7b08c96ca00df9d45409ef4", size = 125189, upload-time = "2026-02-02T15:38:08.181Z" }, + { url = "https://files.pythonhosted.org/packages/89/25/0a16e0729a0e6a1504f9d1a13cdd365f030068aab64cec6958396b9969d7/orjson-3.11.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:814be4b49b228cfc0b3c565acf642dd7d13538f966e3ccde61f4f55be3e20785", size = 128106, upload-time = "2026-02-02T15:38:09.41Z" }, + { url = "https://files.pythonhosted.org/packages/66/da/a2e505469d60666a05ab373f1a6322eb671cb2ba3a0ccfc7d4bc97196787/orjson-3.11.7-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d06e5c5fed5caedd2e540d62e5b1c25e8c82431b9e577c33537e5fa4aa909539", size = 123363, upload-time = "2026-02-02T15:38:10.73Z" }, + { url = "https://files.pythonhosted.org/packages/23/bf/ed73f88396ea35c71b38961734ea4a4746f7ca0768bf28fd551d37e48dd0/orjson-3.11.7-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31c80ce534ac4ea3739c5ee751270646cbc46e45aea7576a38ffec040b4029a1", size = 129007, upload-time = "2026-02-02T15:38:12.138Z" }, + { url = "https://files.pythonhosted.org/packages/73/3c/b05d80716f0225fc9008fbf8ab22841dcc268a626aa550561743714ce3bf/orjson-3.11.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f50979824bde13d32b4320eedd513431c921102796d86be3eee0b58e58a3ecd1", size = 141667, upload-time = "2026-02-02T15:38:13.398Z" }, + { url = "https://files.pythonhosted.org/packages/61/e8/0be9b0addd9bf86abfc938e97441dcd0375d494594b1c8ad10fe57479617/orjson-3.11.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e54f3808e2b6b945078c41aa8d9b5834b28c50843846e97807e5adb75fa9705", size = 130832, upload-time = "2026-02-02T15:38:14.698Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ec/c68e3b9021a31d9ec15a94931db1410136af862955854ed5dd7e7e4f5bff/orjson-3.11.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12b80df61aab7b98b490fe9e4879925ba666fccdfcd175252ce4d9035865ace", size = 133373, upload-time = "2026-02-02T15:38:16.109Z" }, + { url = "https://files.pythonhosted.org/packages/d2/45/f3466739aaafa570cc8e77c6dbb853c48bf56e3b43738020e2661e08b0ac/orjson-3.11.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:996b65230271f1a97026fd0e6a753f51fbc0c335d2ad0c6201f711b0da32693b", size = 138307, upload-time = "2026-02-02T15:38:17.453Z" }, + { url = "https://files.pythonhosted.org/packages/e1/84/9f7f02288da1ffb31405c1be07657afd1eecbcb4b64ee2817b6fe0f785fa/orjson-3.11.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ab49d4b2a6a1d415ddb9f37a21e02e0d5dbfe10b7870b21bf779fc21e9156157", size = 408695, upload-time = "2026-02-02T15:38:18.831Z" }, + { url = "https://files.pythonhosted.org/packages/18/07/9dd2f0c0104f1a0295ffbe912bc8d63307a539b900dd9e2c48ef7810d971/orjson-3.11.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:390a1dce0c055ddf8adb6aa94a73b45a4a7d7177b5c584b8d1c1947f2ba60fb3", size = 144099, upload-time = "2026-02-02T15:38:20.28Z" }, + { url = "https://files.pythonhosted.org/packages/a5/66/857a8e4a3292e1f7b1b202883bcdeb43a91566cf59a93f97c53b44bd6801/orjson-3.11.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1eb80451a9c351a71dfaf5b7ccc13ad065405217726b59fdbeadbcc544f9d223", size = 134806, upload-time = "2026-02-02T15:38:22.186Z" }, + { url = "https://files.pythonhosted.org/packages/0a/5b/6ebcf3defc1aab3a338ca777214966851e92efb1f30dc7fc8285216e6d1b/orjson-3.11.7-cp313-cp313-win32.whl", hash = "sha256:7477aa6a6ec6139c5cb1cc7b214643592169a5494d200397c7fc95d740d5fcf3", size = 127914, upload-time = "2026-02-02T15:38:23.511Z" }, + { url = "https://files.pythonhosted.org/packages/00/04/c6f72daca5092e3117840a1b1e88dfc809cc1470cf0734890d0366b684a1/orjson-3.11.7-cp313-cp313-win_amd64.whl", hash = "sha256:b9f95dcdea9d4f805daa9ddf02617a89e484c6985fa03055459f90e87d7a0757", size = 124986, upload-time = "2026-02-02T15:38:24.836Z" }, + { url = "https://files.pythonhosted.org/packages/03/ba/077a0f6f1085d6b806937246860fafbd5b17f3919c70ee3f3d8d9c713f38/orjson-3.11.7-cp313-cp313-win_arm64.whl", hash = "sha256:800988273a014a0541483dc81021247d7eacb0c845a9d1a34a422bc718f41539", size = 126045, upload-time = "2026-02-02T15:38:26.216Z" }, + { url = "https://files.pythonhosted.org/packages/e9/1e/745565dca749813db9a093c5ebc4bac1a9475c64d54b95654336ac3ed961/orjson-3.11.7-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:de0a37f21d0d364954ad5de1970491d7fbd0fb1ef7417d4d56a36dc01ba0c0a0", size = 228391, upload-time = "2026-02-02T15:38:27.757Z" }, + { url = "https://files.pythonhosted.org/packages/46/19/e40f6225da4d3aa0c8dc6e5219c5e87c2063a560fe0d72a88deb59776794/orjson-3.11.7-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:c2428d358d85e8da9d37cba18b8c4047c55222007a84f97156a5b22028dfbfc0", size = 125188, upload-time = "2026-02-02T15:38:29.241Z" }, + { url = "https://files.pythonhosted.org/packages/9d/7e/c4de2babef2c0817fd1f048fd176aa48c37bec8aef53d2fa932983032cce/orjson-3.11.7-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4bc6c6ac52cdaa267552544c73e486fecbd710b7ac09bc024d5a78555a22f6", size = 128097, upload-time = "2026-02-02T15:38:30.618Z" }, + { url = "https://files.pythonhosted.org/packages/eb/74/233d360632bafd2197f217eee7fb9c9d0229eac0c18128aee5b35b0014fe/orjson-3.11.7-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd0d68edd7dfca1b2eca9361a44ac9f24b078de3481003159929a0573f21a6bf", size = 123364, upload-time = "2026-02-02T15:38:32.363Z" }, + { url = "https://files.pythonhosted.org/packages/79/51/af79504981dd31efe20a9e360eb49c15f06df2b40e7f25a0a52d9ae888e8/orjson-3.11.7-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:623ad1b9548ef63886319c16fa317848e465a21513b31a6ad7b57443c3e0dcf5", size = 129076, upload-time = "2026-02-02T15:38:33.68Z" }, + { url = "https://files.pythonhosted.org/packages/67/e2/da898eb68b72304f8de05ca6715870d09d603ee98d30a27e8a9629abc64b/orjson-3.11.7-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6e776b998ac37c0396093d10290e60283f59cfe0fc3fccbd0ccc4bd04dd19892", size = 141705, upload-time = "2026-02-02T15:38:34.989Z" }, + { url = "https://files.pythonhosted.org/packages/c5/89/15364d92acb3d903b029e28d834edb8780c2b97404cbf7929aa6b9abdb24/orjson-3.11.7-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c6c3af76716f4a9c290371ba2e390ede06f6603edb277b481daf37f6f464e", size = 130855, upload-time = "2026-02-02T15:38:36.379Z" }, + { url = "https://files.pythonhosted.org/packages/c2/8b/ecdad52d0b38d4b8f514be603e69ccd5eacf4e7241f972e37e79792212ec/orjson-3.11.7-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a56df3239294ea5964adf074c54bcc4f0ccd21636049a2cf3ca9cf03b5d03cf1", size = 133386, upload-time = "2026-02-02T15:38:37.704Z" }, + { url = "https://files.pythonhosted.org/packages/b9/0e/45e1dcf10e17d0924b7c9162f87ec7b4ca79e28a0548acf6a71788d3e108/orjson-3.11.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bda117c4148e81f746655d5a3239ae9bd00cb7bc3ca178b5fc5a5997e9744183", size = 138295, upload-time = "2026-02-02T15:38:39.096Z" }, + { url = "https://files.pythonhosted.org/packages/63/d7/4d2e8b03561257af0450f2845b91fbd111d7e526ccdf737267108075e0ba/orjson-3.11.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:23d6c20517a97a9daf1d48b580fcdc6f0516c6f4b5038823426033690b4d2650", size = 408720, upload-time = "2026-02-02T15:38:40.634Z" }, + { url = "https://files.pythonhosted.org/packages/78/cf/d45343518282108b29c12a65892445fc51f9319dc3c552ceb51bb5905ed2/orjson-3.11.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:8ff206156006da5b847c9304b6308a01e8cdbc8cce824e2779a5ba71c3def141", size = 144152, upload-time = "2026-02-02T15:38:42.262Z" }, + { url = "https://files.pythonhosted.org/packages/a9/3a/d6001f51a7275aacd342e77b735c71fa04125a3f93c36fee4526bc8c654e/orjson-3.11.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:962d046ee1765f74a1da723f4b33e3b228fe3a48bd307acce5021dfefe0e29b2", size = 134814, upload-time = "2026-02-02T15:38:43.627Z" }, + { url = "https://files.pythonhosted.org/packages/1d/d3/f19b47ce16820cc2c480f7f1723e17f6d411b3a295c60c8ad3aa9ff1c96a/orjson-3.11.7-cp314-cp314-win32.whl", hash = "sha256:89e13dd3f89f1c38a9c9eba5fbf7cdc2d1feca82f5f290864b4b7a6aac704576", size = 127997, upload-time = "2026-02-02T15:38:45.06Z" }, + { url = "https://files.pythonhosted.org/packages/12/df/172771902943af54bf661a8d102bdf2e7f932127968080632bda6054b62c/orjson-3.11.7-cp314-cp314-win_amd64.whl", hash = "sha256:845c3e0d8ded9c9271cd79596b9b552448b885b97110f628fb687aee2eed11c1", size = 124985, upload-time = "2026-02-02T15:38:46.388Z" }, + { url = "https://files.pythonhosted.org/packages/6f/1c/f2a8d8a1b17514660a614ce5f7aac74b934e69f5abc2700cc7ced882a009/orjson-3.11.7-cp314-cp314-win_arm64.whl", hash = "sha256:4a2e9c5be347b937a2e0203866f12bba36082e89b402ddb9e927d5822e43088d", size = 126038, upload-time = "2026-02-02T15:38:47.703Z" }, ] [[package]] @@ -1118,28 +1118,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.14.11" +version = "0.15.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/77/9a7fe084d268f8855d493e5031ea03fa0af8cc05887f638bf1c4e3363eb8/ruff-0.14.11.tar.gz", hash = "sha256:f6dc463bfa5c07a59b1ff2c3b9767373e541346ea105503b4c0369c520a66958", size = 5993417, upload-time = "2026-01-08T19:11:58.322Z" } +sdist = { url = "https://files.pythonhosted.org/packages/04/dc/4e6ac71b511b141cf626357a3946679abeba4cf67bc7cc5a17920f31e10d/ruff-0.15.1.tar.gz", hash = "sha256:c590fe13fb57c97141ae975c03a1aedb3d3156030cabd740d6ff0b0d601e203f", size = 4540855, upload-time = "2026-02-12T23:09:09.998Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f0/a6/a4c40a5aaa7e331f245d2dc1ac8ece306681f52b636b40ef87c88b9f7afd/ruff-0.14.11-py3-none-linux_armv6l.whl", hash = "sha256:f6ff2d95cbd335841a7217bdfd9c1d2e44eac2c584197ab1385579d55ff8830e", size = 12951208, upload-time = "2026-01-08T19:12:09.218Z" }, - { url = "https://files.pythonhosted.org/packages/5c/5c/360a35cb7204b328b685d3129c08aca24765ff92b5a7efedbdd6c150d555/ruff-0.14.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6f6eb5c1c8033680f4172ea9c8d3706c156223010b8b97b05e82c59bdc774ee6", size = 13330075, upload-time = "2026-01-08T19:12:02.549Z" }, - { url = "https://files.pythonhosted.org/packages/1b/9e/0cc2f1be7a7d33cae541824cf3f95b4ff40d03557b575912b5b70273c9ec/ruff-0.14.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f2fc34cc896f90080fca01259f96c566f74069a04b25b6205d55379d12a6855e", size = 12257809, upload-time = "2026-01-08T19:12:00.366Z" }, - { url = "https://files.pythonhosted.org/packages/a7/e5/5faab97c15bb75228d9f74637e775d26ac703cc2b4898564c01ab3637c02/ruff-0.14.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53386375001773ae812b43205d6064dae49ff0968774e6befe16a994fc233caa", size = 12678447, upload-time = "2026-01-08T19:12:13.899Z" }, - { url = "https://files.pythonhosted.org/packages/1b/33/e9767f60a2bef779fb5855cab0af76c488e0ce90f7bb7b8a45c8a2ba4178/ruff-0.14.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a697737dce1ca97a0a55b5ff0434ee7205943d4874d638fe3ae66166ff46edbe", size = 12758560, upload-time = "2026-01-08T19:11:42.55Z" }, - { url = "https://files.pythonhosted.org/packages/eb/84/4c6cf627a21462bb5102f7be2a320b084228ff26e105510cd2255ea868e5/ruff-0.14.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6845ca1da8ab81ab1dce755a32ad13f1db72e7fba27c486d5d90d65e04d17b8f", size = 13599296, upload-time = "2026-01-08T19:11:30.371Z" }, - { url = "https://files.pythonhosted.org/packages/88/e1/92b5ed7ea66d849f6157e695dc23d5d6d982bd6aa8d077895652c38a7cae/ruff-0.14.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e36ce2fd31b54065ec6f76cb08d60159e1b32bdf08507862e32f47e6dde8bcbf", size = 15048981, upload-time = "2026-01-08T19:12:04.742Z" }, - { url = "https://files.pythonhosted.org/packages/61/df/c1bd30992615ac17c2fb64b8a7376ca22c04a70555b5d05b8f717163cf9f/ruff-0.14.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:590bcc0e2097ecf74e62a5c10a6b71f008ad82eb97b0a0079e85defe19fe74d9", size = 14633183, upload-time = "2026-01-08T19:11:40.069Z" }, - { url = "https://files.pythonhosted.org/packages/04/e9/fe552902f25013dd28a5428a42347d9ad20c4b534834a325a28305747d64/ruff-0.14.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:53fe71125fc158210d57fe4da26e622c9c294022988d08d9347ec1cf782adafe", size = 14050453, upload-time = "2026-01-08T19:11:37.555Z" }, - { url = "https://files.pythonhosted.org/packages/ae/93/f36d89fa021543187f98991609ce6e47e24f35f008dfe1af01379d248a41/ruff-0.14.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a35c9da08562f1598ded8470fcfef2afb5cf881996e6c0a502ceb61f4bc9c8a3", size = 13757889, upload-time = "2026-01-08T19:12:07.094Z" }, - { url = "https://files.pythonhosted.org/packages/b7/9f/c7fb6ecf554f28709a6a1f2a7f74750d400979e8cd47ed29feeaa1bd4db8/ruff-0.14.11-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:0f3727189a52179393ecf92ec7057c2210203e6af2676f08d92140d3e1ee72c1", size = 13955832, upload-time = "2026-01-08T19:11:55.064Z" }, - { url = "https://files.pythonhosted.org/packages/db/a0/153315310f250f76900a98278cf878c64dfb6d044e184491dd3289796734/ruff-0.14.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:eb09f849bd37147a789b85995ff734a6c4a095bed5fd1608c4f56afc3634cde2", size = 12586522, upload-time = "2026-01-08T19:11:35.356Z" }, - { url = "https://files.pythonhosted.org/packages/2f/2b/a73a2b6e6d2df1d74bf2b78098be1572191e54bec0e59e29382d13c3adc5/ruff-0.14.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:c61782543c1231bf71041461c1f28c64b961d457d0f238ac388e2ab173d7ecb7", size = 12724637, upload-time = "2026-01-08T19:11:47.796Z" }, - { url = "https://files.pythonhosted.org/packages/f0/41/09100590320394401cd3c48fc718a8ba71c7ddb1ffd07e0ad6576b3a3df2/ruff-0.14.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:82ff352ea68fb6766140381748e1f67f83c39860b6446966cff48a315c3e2491", size = 13145837, upload-time = "2026-01-08T19:11:32.87Z" }, - { url = "https://files.pythonhosted.org/packages/3b/d8/e035db859d1d3edf909381eb8ff3e89a672d6572e9454093538fe6f164b0/ruff-0.14.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:728e56879df4ca5b62a9dde2dd0eb0edda2a55160c0ea28c4025f18c03f86984", size = 13850469, upload-time = "2026-01-08T19:12:11.694Z" }, - { url = "https://files.pythonhosted.org/packages/4e/02/bb3ff8b6e6d02ce9e3740f4c17dfbbfb55f34c789c139e9cd91985f356c7/ruff-0.14.11-py3-none-win32.whl", hash = "sha256:337c5dd11f16ee52ae217757d9b82a26400be7efac883e9e852646f1557ed841", size = 12851094, upload-time = "2026-01-08T19:11:45.163Z" }, - { url = "https://files.pythonhosted.org/packages/58/f1/90ddc533918d3a2ad628bc3044cdfc094949e6d4b929220c3f0eb8a1c998/ruff-0.14.11-py3-none-win_amd64.whl", hash = "sha256:f981cea63d08456b2c070e64b79cb62f951aa1305282974d4d5216e6e0178ae6", size = 14001379, upload-time = "2026-01-08T19:11:52.591Z" }, - { url = "https://files.pythonhosted.org/packages/c4/1c/1dbe51782c0e1e9cfce1d1004752672d2d4629ea46945d19d731ad772b3b/ruff-0.14.11-py3-none-win_arm64.whl", hash = "sha256:649fb6c9edd7f751db276ef42df1f3df41c38d67d199570ae2a7bd6cbc3590f0", size = 12938644, upload-time = "2026-01-08T19:11:50.027Z" }, + { url = "https://files.pythonhosted.org/packages/23/bf/e6e4324238c17f9d9120a9d60aa99a7daaa21204c07fcd84e2ef03bb5fd1/ruff-0.15.1-py3-none-linux_armv6l.whl", hash = "sha256:b101ed7cf4615bda6ffe65bdb59f964e9f4a0d3f85cbf0e54f0ab76d7b90228a", size = 10367819, upload-time = "2026-02-12T23:09:03.598Z" }, + { url = "https://files.pythonhosted.org/packages/b3/ea/c8f89d32e7912269d38c58f3649e453ac32c528f93bb7f4219258be2e7ed/ruff-0.15.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:939c995e9277e63ea632cc8d3fae17aa758526f49a9a850d2e7e758bfef46602", size = 10798618, upload-time = "2026-02-12T23:09:22.928Z" }, + { url = "https://files.pythonhosted.org/packages/5e/0f/1d0d88bc862624247d82c20c10d4c0f6bb2f346559d8af281674cf327f15/ruff-0.15.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1d83466455fdefe60b8d9c8df81d3c1bbb2115cede53549d3b522ce2bc703899", size = 10148518, upload-time = "2026-02-12T23:08:58.339Z" }, + { url = "https://files.pythonhosted.org/packages/f5/c8/291c49cefaa4a9248e986256df2ade7add79388fe179e0691be06fae6f37/ruff-0.15.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9457e3c3291024866222b96108ab2d8265b477e5b1534c7ddb1810904858d16", size = 10518811, upload-time = "2026-02-12T23:09:31.865Z" }, + { url = "https://files.pythonhosted.org/packages/c3/1a/f5707440e5ae43ffa5365cac8bbb91e9665f4a883f560893829cf16a606b/ruff-0.15.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:92c92b003e9d4f7fbd33b1867bb15a1b785b1735069108dfc23821ba045b29bc", size = 10196169, upload-time = "2026-02-12T23:09:17.306Z" }, + { url = "https://files.pythonhosted.org/packages/2a/ff/26ddc8c4da04c8fd3ee65a89c9fb99eaa5c30394269d424461467be2271f/ruff-0.15.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fe5c41ab43e3a06778844c586251eb5a510f67125427625f9eb2b9526535779", size = 10990491, upload-time = "2026-02-12T23:09:25.503Z" }, + { url = "https://files.pythonhosted.org/packages/fc/00/50920cb385b89413f7cdb4bb9bc8fc59c1b0f30028d8bccc294189a54955/ruff-0.15.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66a6dd6df4d80dc382c6484f8ce1bcceb55c32e9f27a8b94c32f6c7331bf14fb", size = 11843280, upload-time = "2026-02-12T23:09:19.88Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6d/2f5cad8380caf5632a15460c323ae326f1e1a2b5b90a6ee7519017a017ca/ruff-0.15.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a4a42cbb8af0bda9bcd7606b064d7c0bc311a88d141d02f78920be6acb5aa83", size = 11274336, upload-time = "2026-02-12T23:09:14.907Z" }, + { url = "https://files.pythonhosted.org/packages/a3/1d/5f56cae1d6c40b8a318513599b35ea4b075d7dc1cd1d04449578c29d1d75/ruff-0.15.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ab064052c31dddada35079901592dfba2e05f5b1e43af3954aafcbc1096a5b2", size = 11137288, upload-time = "2026-02-12T23:09:07.475Z" }, + { url = "https://files.pythonhosted.org/packages/cd/20/6f8d7d8f768c93b0382b33b9306b3b999918816da46537d5a61635514635/ruff-0.15.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:5631c940fe9fe91f817a4c2ea4e81f47bee3ca4aa646134a24374f3c19ad9454", size = 11070681, upload-time = "2026-02-12T23:08:55.43Z" }, + { url = "https://files.pythonhosted.org/packages/9a/67/d640ac76069f64cdea59dba02af2e00b1fa30e2103c7f8d049c0cff4cafd/ruff-0.15.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:68138a4ba184b4691ccdc39f7795c66b3c68160c586519e7e8444cf5a53e1b4c", size = 10486401, upload-time = "2026-02-12T23:09:27.927Z" }, + { url = "https://files.pythonhosted.org/packages/65/3d/e1429f64a3ff89297497916b88c32a5cc88eeca7e9c787072d0e7f1d3e1e/ruff-0.15.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:518f9af03bfc33c03bdb4cb63fabc935341bb7f54af500f92ac309ecfbba6330", size = 10197452, upload-time = "2026-02-12T23:09:12.147Z" }, + { url = "https://files.pythonhosted.org/packages/78/83/e2c3bade17dad63bf1e1c2ffaf11490603b760be149e1419b07049b36ef2/ruff-0.15.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:da79f4d6a826caaea95de0237a67e33b81e6ec2e25fc7e1993a4015dffca7c61", size = 10693900, upload-time = "2026-02-12T23:09:34.418Z" }, + { url = "https://files.pythonhosted.org/packages/a1/27/fdc0e11a813e6338e0706e8b39bb7a1d61ea5b36873b351acee7e524a72a/ruff-0.15.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3dd86dccb83cd7d4dcfac303ffc277e6048600dfc22e38158afa208e8bf94a1f", size = 11227302, upload-time = "2026-02-12T23:09:36.536Z" }, + { url = "https://files.pythonhosted.org/packages/f6/58/ac864a75067dcbd3b95be5ab4eb2b601d7fbc3d3d736a27e391a4f92a5c1/ruff-0.15.1-py3-none-win32.whl", hash = "sha256:660975d9cb49b5d5278b12b03bb9951d554543a90b74ed5d366b20e2c57c2098", size = 10462555, upload-time = "2026-02-12T23:09:29.899Z" }, + { url = "https://files.pythonhosted.org/packages/e0/5e/d4ccc8a27ecdb78116feac4935dfc39d1304536f4296168f91ed3ec00cd2/ruff-0.15.1-py3-none-win_amd64.whl", hash = "sha256:c820fef9dd5d4172a6570e5721704a96c6679b80cf7be41659ed439653f62336", size = 11599956, upload-time = "2026-02-12T23:09:01.157Z" }, + { url = "https://files.pythonhosted.org/packages/2a/07/5bda6a85b220c64c65686bc85bd0bbb23b29c62b3a9f9433fa55f17cda93/ruff-0.15.1-py3-none-win_arm64.whl", hash = "sha256:5ff7d5f0f88567850f45081fac8f4ec212be8d0b963e385c3f7d0d2eb4899416", size = 10874604, upload-time = "2026-02-12T23:09:05.515Z" }, ] [[package]] @@ -1220,27 +1219,26 @@ wheels = [ [[package]] name = "ty" -version = "0.0.1a27" +version = "0.0.17" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8f/65/3592d7c73d80664378fc90d0a00c33449a99cbf13b984433c883815245f3/ty-0.0.1a27.tar.gz", hash = "sha256:d34fe04979f2c912700cbf0919e8f9b4eeaa10c4a2aff7450e5e4c90f998bc28", size = 4516059, upload-time = "2025-11-18T21:55:18.381Z" } +sdist = { url = "https://files.pythonhosted.org/packages/66/c3/41ae6346443eedb65b96761abfab890a48ce2aa5a8a27af69c5c5d99064d/ty-0.0.17.tar.gz", hash = "sha256:847ed6c120913e280bf9b54d8eaa7a1049708acb8824ad234e71498e8ad09f97", size = 5167209, upload-time = "2026-02-13T13:26:36.835Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/05/7945aa97356446fd53ed3ddc7ee02a88d8ad394217acd9428f472d6b109d/ty-0.0.1a27-py3-none-linux_armv6l.whl", hash = "sha256:3cbb735f5ecb3a7a5f5b82fb24da17912788c109086df4e97d454c8fb236fbc5", size = 9375047, upload-time = "2025-11-18T21:54:31.577Z" }, - { url = "https://files.pythonhosted.org/packages/69/4e/89b167a03de0e9ec329dc89bc02e8694768e4576337ef6c0699987681342/ty-0.0.1a27-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:4a6367236dc456ba2416563301d498aef8c6f8959be88777ef7ba5ac1bf15f0b", size = 9169540, upload-time = "2025-11-18T21:54:34.036Z" }, - { url = "https://files.pythonhosted.org/packages/38/07/e62009ab9cc242e1becb2bd992097c80a133fce0d4f055fba6576150d08a/ty-0.0.1a27-py3-none-macosx_11_0_arm64.whl", hash = "sha256:8e93e231a1bcde964cdb062d2d5e549c24493fb1638eecae8fcc42b81e9463a4", size = 8711942, upload-time = "2025-11-18T21:54:36.3Z" }, - { url = "https://files.pythonhosted.org/packages/b5/43/f35716ec15406f13085db52e762a3cc663c651531a8124481d0ba602eca0/ty-0.0.1a27-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5b6a8166b60117da1179851a3d719cc798bf7e61f91b35d76242f0059e9ae1d", size = 8984208, upload-time = "2025-11-18T21:54:39.453Z" }, - { url = "https://files.pythonhosted.org/packages/2d/79/486a3374809523172379768de882c7a369861165802990177fe81489b85f/ty-0.0.1a27-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bfbe8b0e831c072b79a078d6c126d7f4d48ca17f64a103de1b93aeda32265dc5", size = 9157209, upload-time = "2025-11-18T21:54:42.664Z" }, - { url = "https://files.pythonhosted.org/packages/ff/08/9a7c8efcb327197d7d347c548850ef4b54de1c254981b65e8cd0672dc327/ty-0.0.1a27-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:90e09678331552e7c25d7eb47868b0910dc5b9b212ae22c8ce71a52d6576ddbb", size = 9519207, upload-time = "2025-11-18T21:54:45.311Z" }, - { url = "https://files.pythonhosted.org/packages/e0/9d/7b4680683e83204b9edec551bb91c21c789ebc586b949c5218157ee474b7/ty-0.0.1a27-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:88c03e4beeca79d85a5618921e44b3a6ea957e0453e08b1cdd418b51da645939", size = 10148794, upload-time = "2025-11-18T21:54:48.329Z" }, - { url = "https://files.pythonhosted.org/packages/89/21/8b961b0ab00c28223f06b33222427a8e31aa04f39d1b236acc93021c626c/ty-0.0.1a27-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ece5811322789fefe22fc088ed36c5879489cd39e913f9c1ff2a7678f089c61", size = 9900563, upload-time = "2025-11-18T21:54:51.214Z" }, - { url = "https://files.pythonhosted.org/packages/85/eb/95e1f0b426c2ea8d443aa923fcab509059c467bbe64a15baaf573fea1203/ty-0.0.1a27-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f2ccb4f0fddcd6e2017c268dfce2489e9a36cb82a5900afe6425835248b1086", size = 9926355, upload-time = "2025-11-18T21:54:53.927Z" }, - { url = "https://files.pythonhosted.org/packages/f5/78/40e7f072049e63c414f2845df780be3a494d92198c87c2ffa65e63aecf3f/ty-0.0.1a27-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33450528312e41d003e96a1647780b2783ab7569bbc29c04fc76f2d1908061e3", size = 9480580, upload-time = "2025-11-18T21:54:56.617Z" }, - { url = "https://files.pythonhosted.org/packages/18/da/f4a2dfedab39096808ddf7475f35ceb750d9a9da840bee4afd47b871742f/ty-0.0.1a27-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a0a9ac635deaa2b15947701197ede40cdecd13f89f19351872d16f9ccd773fa1", size = 8957524, upload-time = "2025-11-18T21:54:59.085Z" }, - { url = "https://files.pythonhosted.org/packages/21/ea/26fee9a20cf77a157316fd3ab9c6db8ad5a0b20b2d38a43f3452622587ac/ty-0.0.1a27-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:797fb2cd49b6b9b3ac9f2f0e401fb02d3aa155badc05a8591d048d38d28f1e0c", size = 9201098, upload-time = "2025-11-18T21:55:01.845Z" }, - { url = "https://files.pythonhosted.org/packages/b0/53/e14591d1275108c9ae28f97ac5d4b93adcc2c8a4b1b9a880dfa9d07c15f8/ty-0.0.1a27-py3-none-musllinux_1_2_i686.whl", hash = "sha256:7fe81679a0941f85e98187d444604e24b15bde0a85874957c945751756314d03", size = 9275470, upload-time = "2025-11-18T21:55:04.23Z" }, - { url = "https://files.pythonhosted.org/packages/37/44/e2c9acecac70bf06fb41de285e7be2433c2c9828f71e3bf0e886fc85c4fd/ty-0.0.1a27-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:355f651d0cdb85535a82bd9f0583f77b28e3fd7bba7b7da33dcee5a576eff28b", size = 9592394, upload-time = "2025-11-18T21:55:06.542Z" }, - { url = "https://files.pythonhosted.org/packages/ee/a7/4636369731b24ed07c2b4c7805b8d990283d677180662c532d82e4ef1a36/ty-0.0.1a27-py3-none-win32.whl", hash = "sha256:61782e5f40e6df622093847b34c366634b75d53f839986f1bf4481672ad6cb55", size = 8783816, upload-time = "2025-11-18T21:55:09.648Z" }, - { url = "https://files.pythonhosted.org/packages/a7/1d/b76487725628d9e81d9047dc0033a5e167e0d10f27893d04de67fe1a9763/ty-0.0.1a27-py3-none-win_amd64.whl", hash = "sha256:c682b238085d3191acddcf66ef22641562946b1bba2a7f316012d5b2a2f4de11", size = 9616833, upload-time = "2025-11-18T21:55:12.457Z" }, - { url = "https://files.pythonhosted.org/packages/3a/db/c7cd5276c8f336a3cf87992b75ba9d486a7cf54e753fcd42495b3bc56fb7/ty-0.0.1a27-py3-none-win_arm64.whl", hash = "sha256:e146dfa32cbb0ac6afb0cb65659e87e4e313715e68d76fe5ae0a4b3d5b912ce8", size = 9137796, upload-time = "2025-11-18T21:55:15.897Z" }, + { url = "https://files.pythonhosted.org/packages/c0/01/0ef15c22a1c54b0f728ceff3f62d478dbf8b0dcf8ff7b80b954f79584f3e/ty-0.0.17-py3-none-linux_armv6l.whl", hash = "sha256:64a9a16555cc8867d35c2647c2f1afbd3cae55f68fd95283a574d1bb04fe93e0", size = 10192793, upload-time = "2026-02-13T13:27:13.943Z" }, + { url = "https://files.pythonhosted.org/packages/0f/2c/f4c322d9cded56edc016b1092c14b95cf58c8a33b4787316ea752bb9418e/ty-0.0.17-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:eb2dbd8acd5c5a55f4af0d479523e7c7265a88542efe73ed3d696eb1ba7b6454", size = 10051977, upload-time = "2026-02-13T13:26:57.741Z" }, + { url = "https://files.pythonhosted.org/packages/4c/a5/43746c1ff81e784f5fc303afc61fe5bcd85d0fcf3ef65cb2cef78c7486c7/ty-0.0.17-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f18f5fd927bc628deb9ea2df40f06b5f79c5ccf355db732025a3e8e7152801f6", size = 9564639, upload-time = "2026-02-13T13:26:42.781Z" }, + { url = "https://files.pythonhosted.org/packages/d6/b8/280b04e14a9c0474af574f929fba2398b5e1c123c1e7735893b4cd73d13c/ty-0.0.17-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5383814d1d7a5cc53b3b07661856bab04bb2aac7a677c8d33c55169acdaa83df", size = 10061204, upload-time = "2026-02-13T13:27:00.152Z" }, + { url = "https://files.pythonhosted.org/packages/2a/d7/493e1607d8dfe48288d8a768a2adc38ee27ef50e57f0af41ff273987cda0/ty-0.0.17-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c20423b8744b484f93e7bf2ef8a9724bca2657873593f9f41d08bd9f83444c9", size = 10013116, upload-time = "2026-02-13T13:26:34.543Z" }, + { url = "https://files.pythonhosted.org/packages/80/ef/22f3ed401520afac90dbdf1f9b8b7755d85b0d5c35c1cb35cf5bd11b59c2/ty-0.0.17-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6f5b1aba97db9af86517b911674b02f5bc310750485dc47603a105bd0e83ddd", size = 10533623, upload-time = "2026-02-13T13:26:31.449Z" }, + { url = "https://files.pythonhosted.org/packages/75/ce/744b15279a11ac7138832e3a55595706b4a8a209c9f878e3ab8e571d9032/ty-0.0.17-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:488bce1a9bea80b851a97cd34c4d2ffcd69593d6c3f54a72ae02e5c6e47f3d0c", size = 11069750, upload-time = "2026-02-13T13:26:48.638Z" }, + { url = "https://files.pythonhosted.org/packages/f2/be/1133c91f15a0e00d466c24f80df486d630d95d1b2af63296941f7473812f/ty-0.0.17-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8df66b91ec84239420985ec215e7f7549bfda2ac036a3b3c065f119d1c06825a", size = 10870862, upload-time = "2026-02-13T13:26:54.715Z" }, + { url = "https://files.pythonhosted.org/packages/3e/4a/a2ed209ef215b62b2d3246e07e833081e07d913adf7e0448fc204be443d6/ty-0.0.17-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:002139e807c53002790dfefe6e2f45ab0e04012e76db3d7c8286f96ec121af8f", size = 10628118, upload-time = "2026-02-13T13:26:45.439Z" }, + { url = "https://files.pythonhosted.org/packages/b3/0c/87476004cb5228e9719b98afffad82c3ef1f84334bde8527bcacba7b18cb/ty-0.0.17-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6c4e01f05ce82e5d489ab3900ca0899a56c4ccb52659453780c83e5b19e2b64c", size = 10038185, upload-time = "2026-02-13T13:27:02.693Z" }, + { url = "https://files.pythonhosted.org/packages/46/4b/98f0b3ba9aef53c1f0305519536967a4aa793a69ed72677b0a625c5313ac/ty-0.0.17-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2b226dd1e99c0d2152d218c7e440150d1a47ce3c431871f0efa073bbf899e881", size = 10047644, upload-time = "2026-02-13T13:27:05.474Z" }, + { url = "https://files.pythonhosted.org/packages/93/e0/06737bb80aa1a9103b8651d2eb691a7e53f1ed54111152be25f4a02745db/ty-0.0.17-py3-none-musllinux_1_2_i686.whl", hash = "sha256:8b11f1da7859e0ad69e84b3c5ef9a7b055ceed376a432fad44231bdfc48061c2", size = 10231140, upload-time = "2026-02-13T13:27:10.844Z" }, + { url = "https://files.pythonhosted.org/packages/7c/79/e2a606bd8852383ba9abfdd578f4a227bd18504145381a10a5f886b4e751/ty-0.0.17-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c04e196809ff570559054d3e011425fd7c04161529eb551b3625654e5f2434cb", size = 10718344, upload-time = "2026-02-13T13:26:51.66Z" }, + { url = "https://files.pythonhosted.org/packages/c5/2d/2663984ac11de6d78f74432b8b14ba64d170b45194312852b7543cf7fd56/ty-0.0.17-py3-none-win32.whl", hash = "sha256:305b6ed150b2740d00a817b193373d21f0767e10f94ac47abfc3b2e5a5aec809", size = 9672932, upload-time = "2026-02-13T13:27:08.522Z" }, + { url = "https://files.pythonhosted.org/packages/de/b5/39be78f30b31ee9f5a585969930c7248354db90494ff5e3d0756560fb731/ty-0.0.17-py3-none-win_amd64.whl", hash = "sha256:531828267527aee7a63e972f54e5eee21d9281b72baf18e5c2850c6b862add83", size = 10542138, upload-time = "2026-02-13T13:27:17.084Z" }, + { url = "https://files.pythonhosted.org/packages/40/b7/f875c729c5d0079640c75bad2c7e5d43edc90f16ba242f28a11966df8f65/ty-0.0.17-py3-none-win_arm64.whl", hash = "sha256:de9810234c0c8d75073457e10a84825b9cd72e6629826b7f01c7a0b266ae25b1", size = 10023068, upload-time = "2026-02-13T13:26:39.637Z" }, ] [[package]] From 5da9a1d844554d35c67aa20d0dd69f6753bcb8f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 09:21:54 -0800 Subject: [PATCH 21/41] chore(deps): bump the all-dependencies group in /libs/cli/js-monorepo-example with 13 updates (#6813) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the all-dependencies group in /libs/cli/js-monorepo-example with 13 updates: | Package | From | To | | --- | --- | --- | | [turbo](https://github.com/vercel/turborepo) | `2.5.6` | `2.8.8` | | [typescript](https://github.com/microsoft/TypeScript) | `5.9.2` | `5.9.3` | | [@tsconfig/recommended](https://github.com/tsconfig/bases/tree/HEAD/bases) | `1.0.10` | `1.0.13` | | [@eslint/eslintrc](https://github.com/eslint/eslintrc) | `3.3.1` | `3.3.3` | | [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) | `9.34.0` | `10.0.1` | | [eslint](https://github.com/eslint/eslint) | `8.57.1` | `10.0.0` | | [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) | `8.10.2` | `10.1.8` | | [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier) | `4.2.5` | `5.5.5` | | [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) | `5.62.0` | `8.55.0` | | [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `5.62.0` | `8.55.0` | | [prettier](https://github.com/prettier/prettier) | `3.6.2` | `3.8.1` | | [@langchain/core](https://github.com/langchain-ai/langchainjs) | `0.3.72` | `1.1.24` | | [@langchain/langgraph](https://github.com/langchain-ai/langgraphjs/tree/HEAD/libs/langgraph-core) | `0.2.74` | `1.1.4` | Updates `turbo` from 2.5.6 to 2.8.8
Release notes

Sourced from turbo's releases.

Turborepo v2.8.8-canary.7

What's Changed

Changelog

Full Changelog: https://github.com/vercel/turborepo/compare/v2.8.8-canary.6...v2.8.8-canary.7

Turborepo v2.8.8-canary.6

Full Changelog: https://github.com/vercel/turborepo/compare/v2.8.8-canary.5...v2.8.8-canary.6

Turborepo v2.8.8-canary.5

What's Changed

Changelog

Full Changelog: https://github.com/vercel/turborepo/compare/v2.8.8-canary.4...v2.8.8-canary.5

Turborepo v2.8.8-canary.4

What's Changed

Examples

New Contributors

Full Changelog: https://github.com/vercel/turborepo/compare/v2.8.8-canary.3...v2.8.8-canary.4

Turborepo v2.8.8-canary.3

What's Changed

Changelog

Full Changelog: https://github.com/vercel/turborepo/compare/v2.8.8-canary.2...v2.8.8-canary.3

... (truncated)

Commits
Maintainer changes

This version was pushed to npm by [GitHub Actions](https://www.npmjs.com/~GitHub Actions), a new releaser for turbo since your current version.


Updates `typescript` from 5.9.2 to 5.9.3
Release notes

Sourced from typescript's releases.

TypeScript 5.9.3

Note: this tag was recreated to point at the correct commit. The npm package contained the correct content.

For release notes, check out the release announcement

Downloads are available on:

Commits
  • c63de15 Bump version to 5.9.3 and LKG
  • 8428ca4 🤖 Pick PR #62438 (Fix incorrectly ignored dts file fr...) into release-5.9 (#...
  • a131cac 🤖 Pick PR #62351 (Add missing Float16Array constructo...) into release-5.9 (#...
  • 0424333 🤖 Pick PR #62423 (Revert PR 61928) into release-5.9 (#62425)
  • bdb641a 🤖 Pick PR #62311 (Fix parenthesizer rules for manuall...) into release-5.9 (#...
  • 0d9b9b9 🤖 Pick PR #61978 (Restructure CI to prepare for requi...) into release-5.9 (#...
  • 2dce0c5 Intentionally regress one buggy declaration output to an older version (#62163)
  • See full diff in compare view

Updates `@tsconfig/recommended` from 1.0.10 to 1.0.13
Commits

Updates `@eslint/eslintrc` from 3.3.1 to 3.3.3
Release notes

Sourced from @​eslint/eslintrc's releases.

eslintrc: v3.3.3

3.3.3 (2025-11-28)

Bug Fixes

  • release v3.3.3 because publishing v3.3.2 failed (#211) (8aa555a)

eslintrc: v3.3.2

3.3.2 (2025-11-25)

Bug Fixes

  • Remove name property from all and recommended configs (#200) (344da49)
Changelog

Sourced from @​eslint/eslintrc's changelog.

3.3.3 (2025-11-28)

Bug Fixes

  • release v3.3.3 because publishing v3.3.2 failed (#211) (8aa555a)

3.3.2 (2025-11-25)

Bug Fixes

  • Remove name property from all and recommended configs (#200) (344da49)
Commits
  • fdb5298 chore: release 3.3.3 🚀 (#212)
  • 8aa555a fix: release v3.3.3 because publishing v3.3.2 failed (#211)
  • a8b773d chore: release 3.3.2 🚀 (#204)
  • 85244bb chore: switch to googleapis/release-please-action (#208)
  • d356360 docs: Update README sponsors
  • 116bf03 chore: update js-yaml to version 4.1.1 (#207)
  • 16e8d20 docs: Update README sponsors
  • 3b089ac chore: update .gitignore to exclude shared workflows (#206)
  • 1f6e2d1 docs: Update README sponsors
  • 785c00b docs: Update README sponsors
  • Additional commits viewable in compare view
Maintainer changes

This version was pushed to npm by [GitHub Actions](https://www.npmjs.com/~GitHub Actions), a new releaser for @​eslint/eslintrc since your current version.


Updates `@eslint/js` from 9.34.0 to 10.0.1
Release notes

Sourced from @​eslint/js's releases.

v10.0.0

Breaking Changes

  • f9e54f4 feat!: estimate rule-tester failure location (#20420) (ST-DDT)
  • a176319 feat!: replace chalk with styleText and add color to ResultsMeta (#20227) (루밀LuMir)
  • c7046e6 feat!: enable JSX reference tracking (#20152) (Pixel998)
  • fa31a60 feat!: add name to configs (#20015) (Kirk Waiblinger)
  • 3383e7e fix!: remove deprecated SourceCode methods (#20137) (Pixel998)
  • 501abd0 feat!: update dependency minimatch to v10 (#20246) (renovate[bot])
  • ca4d3b4 fix!: stricter rule tester assertions for valid test cases (#20125) (唯然)
  • 96512a6 fix!: Remove deprecated rule context methods (#20086) (Nicholas C. Zakas)
  • c69fdac feat!: remove eslintrc support (#20037) (Francesco Trotta)
  • 208b5cc feat!: Use ScopeManager#addGlobals() (#20132) (Milos Djermanovic)
  • a2ee188 fix!: add uniqueItems: true in no-invalid-regexp option (#20155) (Tanuj Kanti)
  • a89059d feat!: Program range span entire source text (#20133) (Pixel998)
  • 39a6424 fix!: assert 'text' is a string across all RuleFixer methods (#20082) (Pixel998)
  • f28fbf8 fix!: Deprecate "always" and "as-needed" options of the radix rule (#20223) (Milos Djermanovic)
  • aa3fb2b fix!: tighten func-names schema (#20119) (Pixel998)
  • f6c0ed0 feat!: report eslint-env comments as errors (#20128) (Francesco Trotta)
  • 4bf739f fix!: remove deprecated LintMessage#nodeType and TestCaseError#type (#20096) (Pixel998)
  • 523c076 feat!: drop support for jiti < 2.2.0 (#20016) (michael faith)
  • 454a292 feat!: update eslint:recommended configuration (#20210) (Pixel998)
  • 4f880ee feat!: remove v10_* and inactive unstable_* flags (#20225) (sethamus)
  • f18115c feat!: no-shadow-restricted-names report globalThis by default (#20027) (sethamus)
  • c6358c3 feat!: Require Node.js ^20.19.0 || ^22.13.0 || >=24 (#20160) (Milos Djermanovic)

Features

  • bff9091 feat: handle Array.fromAsync in array-callback-return (#20457) (Francesco Trotta)
  • 290c594 feat: add self to no-implied-eval rule (#20468) (sethamus)
  • 43677de feat: fix handling of function and class expression names in no-shadow (#20432) (Milos Djermanovic)
  • f0cafe5 feat: rule tester add assertion option requireData (#20409) (fnx)
  • f7ab693 feat: output RuleTester test case failure index (#19976) (ST-DDT)
  • 7cbcbf9 feat: add countThis option to max-params (#20236) (Gerkin)
  • f148a5e feat: add error assertion options (#20247) (ST-DDT)
  • 09e6654 feat: update error loc of require-yield and no-useless-constructor (#20267) (Tanuj Kanti)

Bug Fixes

  • 436b82f fix: update eslint (#20473) (renovate[bot])
  • 1d29d22 fix: detect default this binding in Array.fromAsync callbacks (#20456) (Francesco Trotta)
  • 727451e fix: fix regression of global mode report range in strict rule (#20462) (ntnyq)
  • e80485f fix: remove fake FlatESLint and LegacyESLint exports (#20460) (Francesco Trotta)
  • 9eeff3b fix: update esquery (#20423) (cryptnix)
  • b34b938 fix: use Error.prepareStackTrace to estimate failing test location (#20436) (Francesco Trotta)
  • 51aab53 fix: update eslint (#20443) (renovate[bot])
  • 23490b2 fix: handle space before colon in RuleTester location estimation (#20433) (Francesco Trotta)
  • f244dbf fix: use MessagePlaceholderData type from @eslint/core (#20348) (루밀LuMir)
  • d186f8c fix: update eslint (#20427) (renovate[bot])
  • 2332262 fix: error location should not modify error message in RuleTester (#20421) (Milos Djermanovic)
  • ab99b21 fix: ensure filename is passed as third argument to verifyAndFix() (#20405) (루밀LuMir)
  • 8a60f3b fix: remove ecmaVersion and sourceType from ParserOptions type (#20415) (Pixel998)
  • eafd727 fix: remove TDZ scope type (#20231) (jaymarvelz)

... (truncated)

Commits

Updates `eslint` from 8.57.1 to 10.0.0
Release notes

Sourced from eslint's releases.

v10.0.0

Breaking Changes

  • f9e54f4 feat!: estimate rule-tester failure location (#20420) (ST-DDT)
  • a176319 feat!: replace chalk with styleText and add color to ResultsMeta (#20227) (루밀LuMir)
  • c7046e6 feat!: enable JSX reference tracking (#20152) (Pixel998)
  • fa31a60 feat!: add name to configs (#20015) (Kirk Waiblinger)
  • 3383e7e fix!: remove deprecated SourceCode methods (#20137) (Pixel998)
  • 501abd0 feat!: update dependency minimatch to v10 (#20246) (renovate[bot])
  • ca4d3b4 fix!: stricter rule tester assertions for valid test cases (#20125) (唯然)
  • 96512a6 fix!: Remove deprecated rule context methods (#20086) (Nicholas C. Zakas)
  • c69fdac feat!: remove eslintrc support (#20037) (Francesco Trotta)
  • 208b5cc feat!: Use ScopeManager#addGlobals() (#20132) (Milos Djermanovic)
  • a2ee188 fix!: add uniqueItems: true in no-invalid-regexp option (#20155) (Tanuj Kanti)
  • a89059d feat!: Program range span entire source text (#20133) (Pixel998)
  • 39a6424 fix!: assert 'text' is a string across all RuleFixer methods (#20082) (Pixel998)
  • f28fbf8 fix!: Deprecate "always" and "as-needed" options of the radix rule (#20223) (Milos Djermanovic)
  • aa3fb2b fix!: tighten func-names schema (#20119) (Pixel998)
  • f6c0ed0 feat!: report eslint-env comments as errors (#20128) (Francesco Trotta)
  • 4bf739f fix!: remove deprecated LintMessage#nodeType and TestCaseError#type (#20096) (Pixel998)
  • 523c076 feat!: drop support for jiti < 2.2.0 (#20016) (michael faith)
  • 454a292 feat!: update eslint:recommended configuration (#20210) (Pixel998)
  • 4f880ee feat!: remove v10_* and inactive unstable_* flags (#20225) (sethamus)
  • f18115c feat!: no-shadow-restricted-names report globalThis by default (#20027) (sethamus)
  • c6358c3 feat!: Require Node.js ^20.19.0 || ^22.13.0 || >=24 (#20160) (Milos Djermanovic)

Features

  • bff9091 feat: handle Array.fromAsync in array-callback-return (#20457) (Francesco Trotta)
  • 290c594 feat: add self to no-implied-eval rule (#20468) (sethamus)
  • 43677de feat: fix handling of function and class expression names in no-shadow (#20432) (Milos Djermanovic)
  • f0cafe5 feat: rule tester add assertion option requireData (#20409) (fnx)
  • f7ab693 feat: output RuleTester test case failure index (#19976) (ST-DDT)
  • 7cbcbf9 feat: add countThis option to max-params (#20236) (Gerkin)
  • f148a5e feat: add error assertion options (#20247) (ST-DDT)
  • 09e6654 feat: update error loc of require-yield and no-useless-constructor (#20267) (Tanuj Kanti)

Bug Fixes

  • 436b82f fix: update eslint (#20473) (renovate[bot])
  • 1d29d22 fix: detect default this binding in Array.fromAsync callbacks (#20456) (Francesco Trotta)
  • 727451e fix: fix regression of global mode report range in strict rule (#20462) (ntnyq)
  • e80485f fix: remove fake FlatESLint and LegacyESLint exports (#20460) (Francesco Trotta)
  • 9eeff3b fix: update esquery (#20423) (cryptnix)
  • b34b938 fix: use Error.prepareStackTrace to estimate failing test location (#20436) (Francesco Trotta)
  • 51aab53 fix: update eslint (#20443) (renovate[bot])
  • 23490b2 fix: handle space before colon in RuleTester location estimation (#20433) (Francesco Trotta)
  • f244dbf fix: use MessagePlaceholderData type from @eslint/core (#20348) (루밀LuMir)
  • d186f8c fix: update eslint (#20427) (renovate[bot])
  • 2332262 fix: error location should not modify error message in RuleTester (#20421) (Milos Djermanovic)
  • ab99b21 fix: ensure filename is passed as third argument to verifyAndFix() (#20405) (루밀LuMir)
  • 8a60f3b fix: remove ecmaVersion and sourceType from ParserOptions type (#20415) (Pixel998)
  • eafd727 fix: remove TDZ scope type (#20231) (jaymarvelz)

... (truncated)

Commits
  • 4e6c4ac 10.0.0
  • ddd8a22 Build: changelog update for 10.0.0
  • bff9091 feat: handle Array.fromAsync in array-callback-return (#20457)
  • 1ece282 chore: ignore /docs/v9.x in link checker (#20452)
  • 034e139 ci: add type integration test for @html-eslint/eslint-plugin (#20345)
  • f3fbc2f chore: set @eslint/js version to 10.0.0 to skip releasing it (#20466)
  • e978dda docs: Update README
  • 4cecf83 docs: Update README
  • c79f0ab docs: Update README
  • afc0681 chore: remove scopeManager.addGlobals patch for typescript-eslint parser (#20...
  • Additional commits viewable in compare view

Updates `eslint-config-prettier` from 8.10.2 to 10.1.8
Release notes

Sourced from eslint-config-prettier's releases.

v10.1.8

republish latest version

Full Changelog: https://github.com/prettier/eslint-config-prettier/compare/v10.1.5...v10.1.8

v10.1.5

Patch Changes

Full Changelog: https://github.com/prettier/eslint-config-prettier/compare/v10.1.4...v10.1.5

v10.1.4

Patch Changes

Full Changelog: https://github.com/prettier/eslint-config-prettier/compare/v10.1.3...v10.1.4

v10.1.3

Patch Changes

New Contributors

Full Changelog: https://github.com/prettier/eslint-config-prettier/compare/v10.1.2...v10.1.3

v10.1.2

Patch Changes

v10.1.1

Patch Changes

  • #309 eb56a5e Thanks @​JounQin! - fix: separate the /flat entry for compatibility

    For flat config users, the previous "eslint-config-prettier" entry still works, but "eslint-config-prettier/flat" adds a new name property for config-inspector, we just can't add it for the default entry for compatibility.

    See also prettier/eslint-config-prettier#308

    // before
    import eslintConfigPrettier from "eslint-config-prettier";
    

    // after
    import eslintConfigPrettier from "eslint-config-prettier/flat";

... (truncated)

Changelog

Sourced from eslint-config-prettier's changelog.

eslint-config-prettier

10.1.5

Patch Changes

10.1.4

Patch Changes

10.1.3

Patch Changes

10.1.2

Patch Changes

10.1.1

Patch Changes

  • #309 eb56a5e Thanks @​JounQin! - fix: separate the /flat entry for compatibility

    For flat config users, the previous "eslint-config-prettier" entry still works, but "eslint-config-prettier/flat" adds a new name property for config-inspector, we just can't add it for the default entry for compatibility.

    See also prettier/eslint-config-prettier#308

    // before
    import eslintConfigPrettier from "eslint-config-prettier";
    

    // after
    import eslintConfigPrettier from "eslint-config-prettier/flat";

10.1.0

Minor Changes

... (truncated)

Commits

Updates `eslint-plugin-prettier` from 4.2.5 to 5.5.5
Release notes

Sourced from eslint-plugin-prettier's releases.

v5.5.5

Patch Changes

v5.5.4

Patch Changes

v5.5.3

republish the latest version

Full Changelog: https://github.com/prettier/eslint-plugin-prettier/compare/v5.5.2...v5.5.3

v5.5.2

republish the latest version

Full Changelog: https://github.com/prettier/eslint-plugin-prettier/compare/v5.5.1...v5.5.2

v5.5.1

Patch Changes

Full Changelog: https://github.com/prettier/eslint-plugin-prettier/compare/v5.5.0...v5.5.1

v5.5.0

Minor Changes

  • #743 92f2c9c Thanks @​dotcarmen! - feat: support non-js languages like css for @eslint/css and json for @eslint/json

New Contributors

Full Changelog: https://github.com/prettier/eslint-plugin-prettier/compare/v5.4.1...v5.5.0

v5.4.1

Patch Changes

  • #740 c21521f Thanks @​JounQin! - fix(deps): bump synckit to v0.11.7 to fix potential TypeError: Cannot read properties of undefined (reading 'message') error

Full Changelog: https://github.com/prettier/eslint-plugin-prettier/compare/v5.4.0...v5.4.1

v5.4.0

Minor Changes

... (truncated)

Changelog

Sourced from eslint-plugin-prettier's changelog.

5.5.5

Patch Changes

5.5.4

Patch Changes

5.5.1

Patch Changes

5.5.0

Minor Changes

  • #743 92f2c9c Thanks @​dotcarmen! - feat: support non-js languages like css for @eslint/css and json for @eslint/json

5.4.1

Patch Changes

  • #740 c21521f Thanks @​JounQin! - fix(deps): bump synckit to v0.11.7 to fix potential TypeError: Cannot read properties of undefined (reading 'message') error

5.4.0

Minor Changes

5.3.1

Patch Changes

5.3.0

Minor Changes

... (truncated)

Commits
  • e2c154a chore: release eslint-plugin-prettier (#773)
  • 6795c1a build(deps): Bump the actions group across 1 directory with 2 updates (#774)
  • 77651a3 fix: bump synckit for yarn PnP ESM issue (#776)
  • 7264ed0 chore: bump prettier-linter-helpers to v1.0.1 (#772)
  • e11a5b7 build(deps): Bump the actions group across 1 directory with 3 updates (#769)
  • befda88 ci: enable trusted publishing (#757)
  • e2c31d2 chore: release eslint-plugin-prettier (#756)
  • 98a8bfd chore(deps): update all dependencies (#750)
  • cf52b30 fix: disallow extra properties in rule options (#751)
  • 723f7a8 fix: add 'oxc', 'oxc-ts' and 'hermes' parsers to parserBlocklist (#755)
  • Additional commits viewable in compare view
Maintainer changes

This version was pushed to npm by [GitHub Actions](https://www.npmjs.com/~GitHub Actions), a new releaser for eslint-plugin-prettier since your current version.


Updates `@typescript-eslint/eslint-plugin` from 5.62.0 to 8.55.0
Release notes

Sourced from @​typescript-eslint/eslint-plugin's releases.

v8.55.0

8.55.0 (2026-02-09)

🚀 Features

  • utils: deprecate defaultOptions in favor of meta.defaultOptions (#11992)

🩹 Fixes

  • eslint-plugin: [no-unused-vars] remove trailing newline when removing entire import (#11990)
  • eslint-plugin: [no-useless-default-assignment] require strictNullChecks (#11966, #12000)
  • eslint-plugin: [no-useless-default-assignment] report unnecessary defaults in ternary expressions (#11984)
  • eslint-plugin: [no-useless-default-assignment] reduce param index to ts this handling (#11949)
  • typescript-estree: forbid invalid modifier in object expression (#11931)

❤️ Thank You

See GitHub Releases for more information.

You can read about our versioning strategy and releases on our website.

v8.54.0

8.54.0 (2026-01-26)

🚀 Features