Compare commits

..
Author SHA1 Message Date
Quanzheng LongandClaude Opus 4.8 8e77945f40 fix: preserve updated_channels shape in update_state delta path
The supersteps-based delta history walk requires update_state to write
counters_since_delta_snapshot metadata, but passing updated_channels to
create_checkpoint also overrode checkpoint["updated_channels"] (was None),
breaking deferred-node triggering on resume for non-delta graphs
(test_in_one_fan_out_state_graph_defer_node). Keep updated_channels at its
default so resume/trigger semantics are unchanged; still write the counter
metadata and snapshot delta channels that hit their cadence.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 10:59:45 -07:00
Quanzheng Long 728fb748be fix 2026-06-30 21:22:00 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>ClaudeJohn Kennedyopen-swe[bot] <open-swe@users.noreply.github.com>
d2f97191ab chore(deps): bump redis in /libs/langgraph (#7976)
## Description
Updates the langgraph lockfile against current `main`, carrying forward
the streaming timing test relaxation and resolving stale
pyproject/lockfile conflicts. Redis now resolves to 8.0.1; Starlette is
already 1.3.1 on `main`.

## Test Plan
- [x] `cd libs/langgraph && uv lock --check && make format && make lint`
- [x] `cd libs/langgraph && NO_DOCKER=true
TEST="tests/test_pregel.py::test_sync_streaming_with_functional_api -q
--no-header --disable-warnings" make test`
- [x] `cd libs/langgraph && NO_DOCKER=true
TEST="tests/test_pregel.py::test_in_one_fan_out_state_graph_waiting_edge_plus_regular
-q --no-header --disable-warnings" make test`

Made by [Open
SWE](https://openswe.vercel.app/agents/75b64102-20de-8a57-3a60-beb9c32bf681)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: John Kennedy <65985482+jkennedyvz@users.noreply.github.com>
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-27 23:12:55 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c1aad8b460 chore(deps-dev): bump starlette from 1.0.1 to 1.3.1 in /libs/sdk-py (#8104)
Bumps [starlette](https://github.com/Kludex/starlette) from 1.0.1 to
1.3.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/Kludex/starlette/releases">starlette's
releases</a>.</em></p>
<blockquote>
<h2>Version 1.3.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Use <code>StarletteDeprecationWarning</code> instead of
<code>DeprecationWarning</code> by <a
href="https://github.com/Kludex"><code>@​Kludex</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3119">Kludex/starlette#3119</a></li>
<li>Enforce <code>max_fields</code> and <code>max_part_size</code> in
<code>FormParser</code> by <a
href="https://github.com/Kludex"><code>@​Kludex</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3329">Kludex/starlette#3329</a></li>
<li>Enforce <code>FormParser</code> limits in parser callbacks by <a
href="https://github.com/Kludex"><code>@​Kludex</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3331">Kludex/starlette#3331</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Kludex/starlette/compare/1.3.0...1.3.1">https://github.com/Kludex/starlette/compare/1.3.0...1.3.1</a></p>
<h2>Version 1.3.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Clamp oversized suffix ranges in <code>FileResponse</code> by <a
href="https://github.com/jiyujie2006"><code>@​jiyujie2006</code></a> in
<a
href="https://redirect.github.com/Kludex/starlette/pull/3307">Kludex/starlette#3307</a></li>
<li>Catch <code>OSError</code> alongside <code>MultiPartException</code>
when closing temp files by <a
href="https://github.com/N3XT3R1337"><code>@​N3XT3R1337</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3191">Kludex/starlette#3191</a></li>
<li>Add <code>httpx2</code> to the <code>full</code> extra by <a
href="https://github.com/Kludex"><code>@​Kludex</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3323">Kludex/starlette#3323</a></li>
<li>Adjust testclient typing and warnings by <a
href="https://github.com/waketzheng"><code>@​waketzheng</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3322">Kludex/starlette#3322</a></li>
<li>Fix IndexError in URL.replace() on a URL with no authority by <a
href="https://github.com/LeSingh1"><code>@​LeSingh1</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3317">Kludex/starlette#3317</a></li>
<li>Annotate URLPath protocol parameter with Literal by <a
href="https://github.com/Chang-LeHung"><code>@​Chang-LeHung</code></a>
in <a
href="https://redirect.github.com/Kludex/starlette/pull/3285">Kludex/starlette#3285</a></li>
<li>avoid collapsing exception groups from user code by <a
href="https://github.com/graingert"><code>@​graingert</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/2830">Kludex/starlette#2830</a></li>
<li>Use <code>removeprefix</code> to strip weak ETag indicator in
<code>is_not_modified</code> by <a
href="https://github.com/gnosyslambda"><code>@​gnosyslambda</code></a>
in <a
href="https://redirect.github.com/Kludex/starlette/pull/3193">Kludex/starlette#3193</a></li>
<li>Build <code>request.url</code> from structured components by <a
href="https://github.com/Kludex"><code>@​Kludex</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3326">Kludex/starlette#3326</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/jiyujie2006"><code>@​jiyujie2006</code></a>
made their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3307">Kludex/starlette#3307</a></li>
<li><a
href="https://github.com/N3XT3R1337"><code>@​N3XT3R1337</code></a> made
their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3191">Kludex/starlette#3191</a></li>
<li><a
href="https://github.com/leestana01"><code>@​leestana01</code></a> made
their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3319">Kludex/starlette#3319</a></li>
<li><a href="https://github.com/LeSingh1"><code>@​LeSingh1</code></a>
made their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3317">Kludex/starlette#3317</a></li>
<li><a
href="https://github.com/EmmanuelNiyonshuti"><code>@​EmmanuelNiyonshuti</code></a>
made their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3204">Kludex/starlette#3204</a></li>
<li><a
href="https://github.com/Chang-LeHung"><code>@​Chang-LeHung</code></a>
made their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3285">Kludex/starlette#3285</a></li>
<li><a
href="https://github.com/gnosyslambda"><code>@​gnosyslambda</code></a>
made their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3193">Kludex/starlette#3193</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Kludex/starlette/compare/1.2.1...1.3.0">https://github.com/Kludex/starlette/compare/1.2.1...1.3.0</a></p>
<h2>Version 1.2.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Use <code>httpx2</code> for type checking in the
<code>testclient</code> module by <a
href="https://github.com/leifwar"><code>@​leifwar</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3304">Kludex/starlette#3304</a></li>
<li>Add assert error for requires() when request param is not Request
type by <a
href="https://github.com/KeeganOP"><code>@​KeeganOP</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3298">Kludex/starlette#3298</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/leifwar"><code>@​leifwar</code></a> made
their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3304">Kludex/starlette#3304</a></li>
<li><a href="https://github.com/diskeu"><code>@​diskeu</code></a> made
their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3243">Kludex/starlette#3243</a></li>
<li><a href="https://github.com/KeeganOP"><code>@​KeeganOP</code></a>
made their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3298">Kludex/starlette#3298</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Kludex/starlette/compare/1.2.0...1.2.1">https://github.com/Kludex/starlette/compare/1.2.0...1.2.1</a></p>
<h2>Version 1.2.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Support httpx2 in the test client by <a
href="https://github.com/Kludex"><code>@​Kludex</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3291">Kludex/starlette#3291</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Kludex/starlette/compare/1.1.0...1.2.0">https://github.com/Kludex/starlette/compare/1.1.0...1.2.0</a></p>
<h2>Version 1.1.0</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/Kludex/starlette/blob/main/docs/release-notes.md">starlette's
changelog</a>.</em></p>
<blockquote>
<h2>1.3.1 (June 12, 2026)</h2>
<h4>Fixed</h4>
<ul>
<li>Enforce <code>max_fields</code> and <code>max_part_size</code> in
<code>FormParser</code> <a
href="https://redirect.github.com/encode/starlette/pull/3329">#3329</a>.</li>
<li>Enforce <code>FormParser</code> limits in parser callbacks <a
href="https://redirect.github.com/encode/starlette/pull/3331">#3331</a>.</li>
</ul>
<h2>1.3.0 (June 11, 2026)</h2>
<h4>Added</h4>
<ul>
<li>Add <code>httpx2</code> to the <code>full</code> extra <a
href="https://redirect.github.com/encode/starlette/pull/3323">#3323</a>.</li>
<li>Annotate the <code>URLPath</code> <code>protocol</code> parameter
with <code>Literal</code> <a
href="https://redirect.github.com/encode/starlette/pull/3285">#3285</a>.</li>
</ul>
<h4>Fixed</h4>
<ul>
<li>Build <code>request.url</code> from structured components <a
href="https://redirect.github.com/encode/starlette/pull/3326">#3326</a>.</li>
<li>Clamp oversized suffix ranges in <code>FileResponse</code> <a
href="https://redirect.github.com/encode/starlette/pull/3307">#3307</a>.</li>
<li>Catch <code>OSError</code> alongside <code>MultiPartException</code>
when closing temp files <a
href="https://redirect.github.com/encode/starlette/pull/3191">#3191</a>.</li>
<li>Avoid collapsing exception groups raised from user code <a
href="https://redirect.github.com/encode/starlette/pull/2830">#2830</a>.</li>
<li>Use <code>removeprefix</code> to strip the weak <code>ETag</code>
indicator in <code>is_not_modified</code> <a
href="https://redirect.github.com/encode/starlette/pull/3193">#3193</a>.</li>
<li>Fix <code>IndexError</code> in <code>URL.replace()</code> on a URL
with no authority <a
href="https://redirect.github.com/encode/starlette/pull/3317">#3317</a>.</li>
<li>Adjust <code>testclient</code> typing and warnings <a
href="https://redirect.github.com/encode/starlette/pull/3322">#3322</a>.</li>
</ul>
<h2>1.2.1 (May 31, 2026)</h2>
<h4>Fixed</h4>
<ul>
<li>Use <code>httpx2</code> for type checking in the
<code>testclient</code> module <a
href="https://redirect.github.com/encode/starlette/pull/3304">#3304</a>.</li>
<li>Add assert error for <code>requires()</code> when the request
parameter is not a <code>Request</code> type <a
href="https://redirect.github.com/encode/starlette/pull/3298">#3298</a>.</li>
</ul>
<h2>1.2.0 (May 28, 2026)</h2>
<h4>Added</h4>
<ul>
<li>Support httpx2 in the test client <a
href="https://redirect.github.com/encode/starlette/pull/3291">#3291</a>.</li>
</ul>
<h2>1.1.0 (May 23, 2026)</h2>
<h4>Added</h4>
<ul>
<li>Use <code>&quot;application/octet-stream&quot;</code> as the
<code>FileResponse</code> media type fallback <a
href="https://redirect.github.com/encode/starlette/pull/3283">#3283</a>.</li>
</ul>
<h4>Fixed</h4>
<ul>
<li>Only dispatch standard HTTP verbs in <code>HTTPEndpoint</code> <a
href="https://redirect.github.com/encode/starlette/pull/3286">#3286</a>.</li>
<li>Reject absolute paths in <code>StaticFiles.lookup_path</code> <a
href="https://redirect.github.com/encode/starlette/pull/3287">#3287</a>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/Kludex/starlette/commit/8ebffd0678570ddd5d5bb11c6f3c3c7fd4682ab9"><code>8ebffd0</code></a>
Version 1.3.1 (<a
href="https://redirect.github.com/Kludex/starlette/issues/3330">#3330</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/25b8e179d8d7ed86769c02f648772dd5fb43dc3c"><code>25b8e17</code></a>
Enforce <code>FormParser</code> limits in parser callbacks (<a
href="https://redirect.github.com/Kludex/starlette/issues/3331">#3331</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/dba1c4babc4f99ad2622bb913d87045775dda735"><code>dba1c4b</code></a>
Enforce <code>max_fields</code> and <code>max_part_size</code> in
<code>FormParser</code> (<a
href="https://redirect.github.com/Kludex/starlette/issues/3329">#3329</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/45e51dcf99f3a270b0bcec1aec5410b4345863a9"><code>45e51dc</code></a>
Use <code>StarletteDeprecationWarning</code> instead of
<code>DeprecationWarning</code> (<a
href="https://redirect.github.com/Kludex/starlette/issues/3119">#3119</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/5f8610c386e13de1d80d36efa961e1486a1d2d01"><code>5f8610c</code></a>
Version 1.3.0 (<a
href="https://redirect.github.com/Kludex/starlette/issues/3327">#3327</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/167b5850e809f38b27fbfed62d58bf6442855975"><code>167b585</code></a>
Build <code>request.url</code> from structured components (<a
href="https://redirect.github.com/Kludex/starlette/issues/3326">#3326</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/37309255b4c1b9c381a2d24a1eaf83100984a16a"><code>3730925</code></a>
Use <code>removeprefix</code> to strip weak ETag indicator in
<code>is_not_modified</code> (<a
href="https://redirect.github.com/Kludex/starlette/issues/3193">#3193</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/e6f7ad1ab85efb27ab7910d8007b3f4531f7b083"><code>e6f7ad1</code></a>
avoid collapsing exception groups from user code (<a
href="https://redirect.github.com/Kludex/starlette/issues/2830">#2830</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/115228fcdca0e0ef5bf4a95a40ddce5a9fced428"><code>115228f</code></a>
Annotate URLPath protocol parameter with Literal (<a
href="https://redirect.github.com/Kludex/starlette/issues/3285">#3285</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/113f193a34353c9153857028c1074351d22fad07"><code>113f193</code></a>
docs: replace inline ASGI server list with link to canonical implemen…
(<a
href="https://redirect.github.com/Kludex/starlette/issues/3204">#3204</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/Kludex/starlette/compare/1.0.1...1.3.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=starlette&package-manager=uv&previous-version=1.0.1&new-version=1.3.1)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-27 18:22:23 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
d5dfeaf033 chore(deps): bump starlette from 1.0.1 to 1.3.1 in /libs/cli (#8105)
Bumps [starlette](https://github.com/Kludex/starlette) from 1.0.1 to
1.3.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/Kludex/starlette/releases">starlette's
releases</a>.</em></p>
<blockquote>
<h2>Version 1.3.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Use <code>StarletteDeprecationWarning</code> instead of
<code>DeprecationWarning</code> by <a
href="https://github.com/Kludex"><code>@​Kludex</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3119">Kludex/starlette#3119</a></li>
<li>Enforce <code>max_fields</code> and <code>max_part_size</code> in
<code>FormParser</code> by <a
href="https://github.com/Kludex"><code>@​Kludex</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3329">Kludex/starlette#3329</a></li>
<li>Enforce <code>FormParser</code> limits in parser callbacks by <a
href="https://github.com/Kludex"><code>@​Kludex</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3331">Kludex/starlette#3331</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Kludex/starlette/compare/1.3.0...1.3.1">https://github.com/Kludex/starlette/compare/1.3.0...1.3.1</a></p>
<h2>Version 1.3.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Clamp oversized suffix ranges in <code>FileResponse</code> by <a
href="https://github.com/jiyujie2006"><code>@​jiyujie2006</code></a> in
<a
href="https://redirect.github.com/Kludex/starlette/pull/3307">Kludex/starlette#3307</a></li>
<li>Catch <code>OSError</code> alongside <code>MultiPartException</code>
when closing temp files by <a
href="https://github.com/N3XT3R1337"><code>@​N3XT3R1337</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3191">Kludex/starlette#3191</a></li>
<li>Add <code>httpx2</code> to the <code>full</code> extra by <a
href="https://github.com/Kludex"><code>@​Kludex</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3323">Kludex/starlette#3323</a></li>
<li>Adjust testclient typing and warnings by <a
href="https://github.com/waketzheng"><code>@​waketzheng</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3322">Kludex/starlette#3322</a></li>
<li>Fix IndexError in URL.replace() on a URL with no authority by <a
href="https://github.com/LeSingh1"><code>@​LeSingh1</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3317">Kludex/starlette#3317</a></li>
<li>Annotate URLPath protocol parameter with Literal by <a
href="https://github.com/Chang-LeHung"><code>@​Chang-LeHung</code></a>
in <a
href="https://redirect.github.com/Kludex/starlette/pull/3285">Kludex/starlette#3285</a></li>
<li>avoid collapsing exception groups from user code by <a
href="https://github.com/graingert"><code>@​graingert</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/2830">Kludex/starlette#2830</a></li>
<li>Use <code>removeprefix</code> to strip weak ETag indicator in
<code>is_not_modified</code> by <a
href="https://github.com/gnosyslambda"><code>@​gnosyslambda</code></a>
in <a
href="https://redirect.github.com/Kludex/starlette/pull/3193">Kludex/starlette#3193</a></li>
<li>Build <code>request.url</code> from structured components by <a
href="https://github.com/Kludex"><code>@​Kludex</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3326">Kludex/starlette#3326</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/jiyujie2006"><code>@​jiyujie2006</code></a>
made their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3307">Kludex/starlette#3307</a></li>
<li><a
href="https://github.com/N3XT3R1337"><code>@​N3XT3R1337</code></a> made
their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3191">Kludex/starlette#3191</a></li>
<li><a
href="https://github.com/leestana01"><code>@​leestana01</code></a> made
their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3319">Kludex/starlette#3319</a></li>
<li><a href="https://github.com/LeSingh1"><code>@​LeSingh1</code></a>
made their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3317">Kludex/starlette#3317</a></li>
<li><a
href="https://github.com/EmmanuelNiyonshuti"><code>@​EmmanuelNiyonshuti</code></a>
made their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3204">Kludex/starlette#3204</a></li>
<li><a
href="https://github.com/Chang-LeHung"><code>@​Chang-LeHung</code></a>
made their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3285">Kludex/starlette#3285</a></li>
<li><a
href="https://github.com/gnosyslambda"><code>@​gnosyslambda</code></a>
made their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3193">Kludex/starlette#3193</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Kludex/starlette/compare/1.2.1...1.3.0">https://github.com/Kludex/starlette/compare/1.2.1...1.3.0</a></p>
<h2>Version 1.2.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Use <code>httpx2</code> for type checking in the
<code>testclient</code> module by <a
href="https://github.com/leifwar"><code>@​leifwar</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3304">Kludex/starlette#3304</a></li>
<li>Add assert error for requires() when request param is not Request
type by <a
href="https://github.com/KeeganOP"><code>@​KeeganOP</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3298">Kludex/starlette#3298</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/leifwar"><code>@​leifwar</code></a> made
their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3304">Kludex/starlette#3304</a></li>
<li><a href="https://github.com/diskeu"><code>@​diskeu</code></a> made
their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3243">Kludex/starlette#3243</a></li>
<li><a href="https://github.com/KeeganOP"><code>@​KeeganOP</code></a>
made their first contribution in <a
href="https://redirect.github.com/Kludex/starlette/pull/3298">Kludex/starlette#3298</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Kludex/starlette/compare/1.2.0...1.2.1">https://github.com/Kludex/starlette/compare/1.2.0...1.2.1</a></p>
<h2>Version 1.2.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Support httpx2 in the test client by <a
href="https://github.com/Kludex"><code>@​Kludex</code></a> in <a
href="https://redirect.github.com/Kludex/starlette/pull/3291">Kludex/starlette#3291</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Kludex/starlette/compare/1.1.0...1.2.0">https://github.com/Kludex/starlette/compare/1.1.0...1.2.0</a></p>
<h2>Version 1.1.0</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/Kludex/starlette/blob/main/docs/release-notes.md">starlette's
changelog</a>.</em></p>
<blockquote>
<h2>1.3.1 (June 12, 2026)</h2>
<h4>Fixed</h4>
<ul>
<li>Enforce <code>max_fields</code> and <code>max_part_size</code> in
<code>FormParser</code> <a
href="https://redirect.github.com/encode/starlette/pull/3329">#3329</a>.</li>
<li>Enforce <code>FormParser</code> limits in parser callbacks <a
href="https://redirect.github.com/encode/starlette/pull/3331">#3331</a>.</li>
</ul>
<h2>1.3.0 (June 11, 2026)</h2>
<h4>Added</h4>
<ul>
<li>Add <code>httpx2</code> to the <code>full</code> extra <a
href="https://redirect.github.com/encode/starlette/pull/3323">#3323</a>.</li>
<li>Annotate the <code>URLPath</code> <code>protocol</code> parameter
with <code>Literal</code> <a
href="https://redirect.github.com/encode/starlette/pull/3285">#3285</a>.</li>
</ul>
<h4>Fixed</h4>
<ul>
<li>Build <code>request.url</code> from structured components <a
href="https://redirect.github.com/encode/starlette/pull/3326">#3326</a>.</li>
<li>Clamp oversized suffix ranges in <code>FileResponse</code> <a
href="https://redirect.github.com/encode/starlette/pull/3307">#3307</a>.</li>
<li>Catch <code>OSError</code> alongside <code>MultiPartException</code>
when closing temp files <a
href="https://redirect.github.com/encode/starlette/pull/3191">#3191</a>.</li>
<li>Avoid collapsing exception groups raised from user code <a
href="https://redirect.github.com/encode/starlette/pull/2830">#2830</a>.</li>
<li>Use <code>removeprefix</code> to strip the weak <code>ETag</code>
indicator in <code>is_not_modified</code> <a
href="https://redirect.github.com/encode/starlette/pull/3193">#3193</a>.</li>
<li>Fix <code>IndexError</code> in <code>URL.replace()</code> on a URL
with no authority <a
href="https://redirect.github.com/encode/starlette/pull/3317">#3317</a>.</li>
<li>Adjust <code>testclient</code> typing and warnings <a
href="https://redirect.github.com/encode/starlette/pull/3322">#3322</a>.</li>
</ul>
<h2>1.2.1 (May 31, 2026)</h2>
<h4>Fixed</h4>
<ul>
<li>Use <code>httpx2</code> for type checking in the
<code>testclient</code> module <a
href="https://redirect.github.com/encode/starlette/pull/3304">#3304</a>.</li>
<li>Add assert error for <code>requires()</code> when the request
parameter is not a <code>Request</code> type <a
href="https://redirect.github.com/encode/starlette/pull/3298">#3298</a>.</li>
</ul>
<h2>1.2.0 (May 28, 2026)</h2>
<h4>Added</h4>
<ul>
<li>Support httpx2 in the test client <a
href="https://redirect.github.com/encode/starlette/pull/3291">#3291</a>.</li>
</ul>
<h2>1.1.0 (May 23, 2026)</h2>
<h4>Added</h4>
<ul>
<li>Use <code>&quot;application/octet-stream&quot;</code> as the
<code>FileResponse</code> media type fallback <a
href="https://redirect.github.com/encode/starlette/pull/3283">#3283</a>.</li>
</ul>
<h4>Fixed</h4>
<ul>
<li>Only dispatch standard HTTP verbs in <code>HTTPEndpoint</code> <a
href="https://redirect.github.com/encode/starlette/pull/3286">#3286</a>.</li>
<li>Reject absolute paths in <code>StaticFiles.lookup_path</code> <a
href="https://redirect.github.com/encode/starlette/pull/3287">#3287</a>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/Kludex/starlette/commit/8ebffd0678570ddd5d5bb11c6f3c3c7fd4682ab9"><code>8ebffd0</code></a>
Version 1.3.1 (<a
href="https://redirect.github.com/Kludex/starlette/issues/3330">#3330</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/25b8e179d8d7ed86769c02f648772dd5fb43dc3c"><code>25b8e17</code></a>
Enforce <code>FormParser</code> limits in parser callbacks (<a
href="https://redirect.github.com/Kludex/starlette/issues/3331">#3331</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/dba1c4babc4f99ad2622bb913d87045775dda735"><code>dba1c4b</code></a>
Enforce <code>max_fields</code> and <code>max_part_size</code> in
<code>FormParser</code> (<a
href="https://redirect.github.com/Kludex/starlette/issues/3329">#3329</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/45e51dcf99f3a270b0bcec1aec5410b4345863a9"><code>45e51dc</code></a>
Use <code>StarletteDeprecationWarning</code> instead of
<code>DeprecationWarning</code> (<a
href="https://redirect.github.com/Kludex/starlette/issues/3119">#3119</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/5f8610c386e13de1d80d36efa961e1486a1d2d01"><code>5f8610c</code></a>
Version 1.3.0 (<a
href="https://redirect.github.com/Kludex/starlette/issues/3327">#3327</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/167b5850e809f38b27fbfed62d58bf6442855975"><code>167b585</code></a>
Build <code>request.url</code> from structured components (<a
href="https://redirect.github.com/Kludex/starlette/issues/3326">#3326</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/37309255b4c1b9c381a2d24a1eaf83100984a16a"><code>3730925</code></a>
Use <code>removeprefix</code> to strip weak ETag indicator in
<code>is_not_modified</code> (<a
href="https://redirect.github.com/Kludex/starlette/issues/3193">#3193</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/e6f7ad1ab85efb27ab7910d8007b3f4531f7b083"><code>e6f7ad1</code></a>
avoid collapsing exception groups from user code (<a
href="https://redirect.github.com/Kludex/starlette/issues/2830">#2830</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/115228fcdca0e0ef5bf4a95a40ddce5a9fced428"><code>115228f</code></a>
Annotate URLPath protocol parameter with Literal (<a
href="https://redirect.github.com/Kludex/starlette/issues/3285">#3285</a>)</li>
<li><a
href="https://github.com/Kludex/starlette/commit/113f193a34353c9153857028c1074351d22fad07"><code>113f193</code></a>
docs: replace inline ASGI server list with link to canonical implemen…
(<a
href="https://redirect.github.com/Kludex/starlette/issues/3204">#3204</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/Kludex/starlette/compare/1.0.1...1.3.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=starlette&package-manager=uv&previous-version=1.0.1&new-version=1.3.1)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-27 18:12:22 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
bdb323efbb chore(deps): bump langsmith from 0.8.0 to 0.8.18 in /libs/checkpoint-sqlite (#8177)
Bumps [langsmith](https://github.com/langchain-ai/langsmith-sdk) from
0.8.0 to 0.8.18.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/langchain-ai/langsmith-sdk/releases">langsmith's
releases</a>.</em></p>
<blockquote>
<h2>v0.8.18</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps-dev): bump vitest from 3.2.4 to 3.2.6 in /js by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3002">langchain-ai/langsmith-sdk#3002</a></li>
<li>chore(deps): bump pyjwt from 2.12.1 to 2.13.0 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3030">langchain-ai/langsmith-sdk#3030</a></li>
<li>chore(deps): bump python-multipart from 0.0.27 to 0.0.31 in /python
by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3036">langchain-ai/langsmith-sdk#3036</a></li>
<li>chore(deps): bump aiohttp from 3.14.0 to 3.14.1 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3037">langchain-ai/langsmith-sdk#3037</a></li>
<li>chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /python by
<a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3038">langchain-ai/langsmith-sdk#3038</a></li>
<li>chore(deps): bump starlette from 1.0.1 to 1.3.1 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3039">langchain-ai/langsmith-sdk#3039</a></li>
<li>chore(deps-dev): bump langchain-anthropic from 1.4.4 to 1.4.6 in
/python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3044">langchain-ai/langsmith-sdk#3044</a></li>
<li>chore(deps): bump the npm_and_yarn group across 4 directories with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3046">langchain-ai/langsmith-sdk#3046</a></li>
<li>chore(deps): bump the npm_and_yarn group across 2 directories with 2
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3060">langchain-ai/langsmith-sdk#3060</a></li>
<li>test(python): fix integration assertions for updated attachment
error message by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3061">langchain-ai/langsmith-sdk#3061</a></li>
<li>chore: reconcile bumpversion config and mandate release process for
agents by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3062">langchain-ai/langsmith-sdk#3062</a></li>
<li>release(py): 0.8.18 by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3063">langchain-ai/langsmith-sdk#3063</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.17...v0.8.18">https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.17...v0.8.18</a></p>
<h2>v0.8.17</h2>
<h2>What's Changed</h2>
<ul>
<li>feat: expose the resources from the generated openapi client in the
langsmith client by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3018">langchain-ai/langsmith-sdk#3018</a></li>
<li>feat(js): port <code>isTracingEnabled</code> utility from Python by
<a href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3032">langchain-ai/langsmith-sdk#3032</a></li>
<li>Add sandbox mount support to JS SDK by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3010">langchain-ai/langsmith-sdk#3010</a></li>
<li>release(js): bump to 0.7.9 by <a
href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3035">langchain-ai/langsmith-sdk#3035</a></li>
<li>Add sandbox mount support to Python SDK by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3009">langchain-ai/langsmith-sdk#3009</a></li>
<li>docs: note that _openapi_client directories are auto-generated by <a
href="https://github.com/KiewanVillatel"><code>@​KiewanVillatel</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3034">langchain-ai/langsmith-sdk#3034</a></li>
<li>fix: update JS SDK type declarations with skipLibCheck disabled by
<a href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3043">langchain-ai/langsmith-sdk#3043</a></li>
<li>release(js): 0.7.10 by <a
href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3045">langchain-ai/langsmith-sdk#3045</a></li>
<li>feat: adding python async for online evals by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3048">langchain-ai/langsmith-sdk#3048</a></li>
<li>Add sandbox Git mount SDK helpers by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3040">langchain-ai/langsmith-sdk#3040</a></li>
<li>fix: use insights tab in sdk report links [closes LSO-2936] by <a
href="https://github.com/eric-langchain"><code>@​eric-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3050">langchain-ai/langsmith-sdk#3050</a></li>
<li>feat(client): warn when backend version is below minimum required by
<a
href="https://github.com/KiewanVillatel"><code>@​KiewanVillatel</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3041">langchain-ai/langsmith-sdk#3041</a></li>
<li>chore: bump _MIN_BACKEND_VERSION to 0.16.5rc1 by <a
href="https://github.com/langtions-bot"><code>@​langtions-bot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3053">langchain-ai/langsmith-sdk#3053</a></li>
<li>fix(sandbox): use built-in gcp auth host matching by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3055">langchain-ai/langsmith-sdk#3055</a></li>
<li>chore(python): py to 0.8.17 by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3056">langchain-ai/langsmith-sdk#3056</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a>
made their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3018">langchain-ai/langsmith-sdk#3018</a></li>
<li><a
href="https://github.com/eric-langchain"><code>@​eric-langchain</code></a>
made their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3050">langchain-ai/langsmith-sdk#3050</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.16...v0.8.17">https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.16...v0.8.17</a></p>
<h2>v0.8.16</h2>
<h2>What's Changed</h2>
<ul>
<li>feat(py): add sync/async conversion for Sandbox and SandboxClient
[INF-0000] by <a
href="https://github.com/ramon-langchain"><code>@​ramon-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3019">langchain-ai/langsmith-sdk#3019</a></li>
<li>fix(experiments): extract keys from wrapped evaluator function by <a
href="https://github.com/shamikkarkhanis"><code>@​shamikkarkhanis</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3014">langchain-ai/langsmith-sdk#3014</a></li>
<li>chore: repoint <a
href="mailto:support@langchain.dev">support@langchain.dev</a> mentions
to the Support Portal by <a
href="https://github.com/lutan-langchain"><code>@​lutan-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3024">langchain-ai/langsmith-sdk#3024</a></li>
<li>fix(python): derive create_child run id from start_time [LSDK-220]
by <a
href="https://github.com/harisaiharish"><code>@​harisaiharish</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3027">langchain-ai/langsmith-sdk#3027</a></li>
<li>chore: sync langsmith_api by <a
href="https://github.com/langtions-bot"><code>@​langtions-bot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3020">langchain-ai/langsmith-sdk#3020</a></li>
<li>chore: js to 0.7.8 and py to 0.8.16 by <a
href="https://github.com/shamikkarkhanis"><code>@​shamikkarkhanis</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3029">langchain-ai/langsmith-sdk#3029</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/31c2bf650b84a44577d8b4443298fb7e78025b8f"><code>31c2bf6</code></a>
release(py): 0.8.18 (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3063">#3063</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/8955b688689fdf47871d44013787410a42ea13fd"><code>8955b68</code></a>
chore: reconcile bumpversion config and mandate release process for
agents (#...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/411401f6ca5ff401c29772ed097c9c9ed97f994c"><code>411401f</code></a>
test(python): fix integration assertions for updated attachment error
message...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/9c5515620f9bfa2145fc65d6f4353c4c8a3e96b6"><code>9c55156</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/5b2bd8db3c50d3f19e98f41288c87d9c0ac0b136"><code>5b2bd8d</code></a>
chore(deps): bump the npm_and_yarn group across 2 directories with 2
updates ...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/d8642f9099a48025d00c7283ad3cd2ce56fec775"><code>d8642f9</code></a>
chore(deps): bump the npm_and_yarn group across 4 directories with 4
updates ...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/953c2e5e25e41ecb4dba428adbac1c446c0a0071"><code>953c2e5</code></a>
chore(deps-dev): bump langchain-anthropic from 1.4.4 to 1.4.6 in /python
(<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3044">#3044</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/5513699e2d25c2147e02c296bc3b90f7d0923d8a"><code>5513699</code></a>
chore(deps): bump starlette from 1.0.1 to 1.3.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3039">#3039</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/8becdefdf422a02e03f78cf3ebb4c62c136b7cf3"><code>8becdef</code></a>
chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3038">#3038</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/1a9c522febbf313bbe649ca75c39158fec048934"><code>1a9c522</code></a>
chore(deps): bump aiohttp from 3.14.0 to 3.14.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3037">#3037</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.0...v0.8.18">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=langsmith&package-manager=uv&previous-version=0.8.0&new-version=0.8.18)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-25 20:51:26 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
31f69551b7 chore(deps): bump langsmith from 0.8.0 to 0.8.18 in /libs/checkpoint-postgres (#8171)
Bumps [langsmith](https://github.com/langchain-ai/langsmith-sdk) from
0.8.0 to 0.8.18.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/langchain-ai/langsmith-sdk/releases">langsmith's
releases</a>.</em></p>
<blockquote>
<h2>v0.8.18</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps-dev): bump vitest from 3.2.4 to 3.2.6 in /js by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3002">langchain-ai/langsmith-sdk#3002</a></li>
<li>chore(deps): bump pyjwt from 2.12.1 to 2.13.0 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3030">langchain-ai/langsmith-sdk#3030</a></li>
<li>chore(deps): bump python-multipart from 0.0.27 to 0.0.31 in /python
by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3036">langchain-ai/langsmith-sdk#3036</a></li>
<li>chore(deps): bump aiohttp from 3.14.0 to 3.14.1 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3037">langchain-ai/langsmith-sdk#3037</a></li>
<li>chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /python by
<a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3038">langchain-ai/langsmith-sdk#3038</a></li>
<li>chore(deps): bump starlette from 1.0.1 to 1.3.1 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3039">langchain-ai/langsmith-sdk#3039</a></li>
<li>chore(deps-dev): bump langchain-anthropic from 1.4.4 to 1.4.6 in
/python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3044">langchain-ai/langsmith-sdk#3044</a></li>
<li>chore(deps): bump the npm_and_yarn group across 4 directories with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3046">langchain-ai/langsmith-sdk#3046</a></li>
<li>chore(deps): bump the npm_and_yarn group across 2 directories with 2
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3060">langchain-ai/langsmith-sdk#3060</a></li>
<li>test(python): fix integration assertions for updated attachment
error message by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3061">langchain-ai/langsmith-sdk#3061</a></li>
<li>chore: reconcile bumpversion config and mandate release process for
agents by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3062">langchain-ai/langsmith-sdk#3062</a></li>
<li>release(py): 0.8.18 by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3063">langchain-ai/langsmith-sdk#3063</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.17...v0.8.18">https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.17...v0.8.18</a></p>
<h2>v0.8.17</h2>
<h2>What's Changed</h2>
<ul>
<li>feat: expose the resources from the generated openapi client in the
langsmith client by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3018">langchain-ai/langsmith-sdk#3018</a></li>
<li>feat(js): port <code>isTracingEnabled</code> utility from Python by
<a href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3032">langchain-ai/langsmith-sdk#3032</a></li>
<li>Add sandbox mount support to JS SDK by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3010">langchain-ai/langsmith-sdk#3010</a></li>
<li>release(js): bump to 0.7.9 by <a
href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3035">langchain-ai/langsmith-sdk#3035</a></li>
<li>Add sandbox mount support to Python SDK by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3009">langchain-ai/langsmith-sdk#3009</a></li>
<li>docs: note that _openapi_client directories are auto-generated by <a
href="https://github.com/KiewanVillatel"><code>@​KiewanVillatel</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3034">langchain-ai/langsmith-sdk#3034</a></li>
<li>fix: update JS SDK type declarations with skipLibCheck disabled by
<a href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3043">langchain-ai/langsmith-sdk#3043</a></li>
<li>release(js): 0.7.10 by <a
href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3045">langchain-ai/langsmith-sdk#3045</a></li>
<li>feat: adding python async for online evals by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3048">langchain-ai/langsmith-sdk#3048</a></li>
<li>Add sandbox Git mount SDK helpers by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3040">langchain-ai/langsmith-sdk#3040</a></li>
<li>fix: use insights tab in sdk report links [closes LSO-2936] by <a
href="https://github.com/eric-langchain"><code>@​eric-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3050">langchain-ai/langsmith-sdk#3050</a></li>
<li>feat(client): warn when backend version is below minimum required by
<a
href="https://github.com/KiewanVillatel"><code>@​KiewanVillatel</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3041">langchain-ai/langsmith-sdk#3041</a></li>
<li>chore: bump _MIN_BACKEND_VERSION to 0.16.5rc1 by <a
href="https://github.com/langtions-bot"><code>@​langtions-bot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3053">langchain-ai/langsmith-sdk#3053</a></li>
<li>fix(sandbox): use built-in gcp auth host matching by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3055">langchain-ai/langsmith-sdk#3055</a></li>
<li>chore(python): py to 0.8.17 by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3056">langchain-ai/langsmith-sdk#3056</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a>
made their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3018">langchain-ai/langsmith-sdk#3018</a></li>
<li><a
href="https://github.com/eric-langchain"><code>@​eric-langchain</code></a>
made their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3050">langchain-ai/langsmith-sdk#3050</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.16...v0.8.17">https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.16...v0.8.17</a></p>
<h2>v0.8.16</h2>
<h2>What's Changed</h2>
<ul>
<li>feat(py): add sync/async conversion for Sandbox and SandboxClient
[INF-0000] by <a
href="https://github.com/ramon-langchain"><code>@​ramon-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3019">langchain-ai/langsmith-sdk#3019</a></li>
<li>fix(experiments): extract keys from wrapped evaluator function by <a
href="https://github.com/shamikkarkhanis"><code>@​shamikkarkhanis</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3014">langchain-ai/langsmith-sdk#3014</a></li>
<li>chore: repoint <a
href="mailto:support@langchain.dev">support@langchain.dev</a> mentions
to the Support Portal by <a
href="https://github.com/lutan-langchain"><code>@​lutan-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3024">langchain-ai/langsmith-sdk#3024</a></li>
<li>fix(python): derive create_child run id from start_time [LSDK-220]
by <a
href="https://github.com/harisaiharish"><code>@​harisaiharish</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3027">langchain-ai/langsmith-sdk#3027</a></li>
<li>chore: sync langsmith_api by <a
href="https://github.com/langtions-bot"><code>@​langtions-bot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3020">langchain-ai/langsmith-sdk#3020</a></li>
<li>chore: js to 0.7.8 and py to 0.8.16 by <a
href="https://github.com/shamikkarkhanis"><code>@​shamikkarkhanis</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3029">langchain-ai/langsmith-sdk#3029</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/31c2bf650b84a44577d8b4443298fb7e78025b8f"><code>31c2bf6</code></a>
release(py): 0.8.18 (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3063">#3063</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/8955b688689fdf47871d44013787410a42ea13fd"><code>8955b68</code></a>
chore: reconcile bumpversion config and mandate release process for
agents (#...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/411401f6ca5ff401c29772ed097c9c9ed97f994c"><code>411401f</code></a>
test(python): fix integration assertions for updated attachment error
message...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/9c5515620f9bfa2145fc65d6f4353c4c8a3e96b6"><code>9c55156</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/5b2bd8db3c50d3f19e98f41288c87d9c0ac0b136"><code>5b2bd8d</code></a>
chore(deps): bump the npm_and_yarn group across 2 directories with 2
updates ...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/d8642f9099a48025d00c7283ad3cd2ce56fec775"><code>d8642f9</code></a>
chore(deps): bump the npm_and_yarn group across 4 directories with 4
updates ...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/953c2e5e25e41ecb4dba428adbac1c446c0a0071"><code>953c2e5</code></a>
chore(deps-dev): bump langchain-anthropic from 1.4.4 to 1.4.6 in /python
(<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3044">#3044</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/5513699e2d25c2147e02c296bc3b90f7d0923d8a"><code>5513699</code></a>
chore(deps): bump starlette from 1.0.1 to 1.3.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3039">#3039</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/8becdefdf422a02e03f78cf3ebb4c62c136b7cf3"><code>8becdef</code></a>
chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3038">#3038</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/1a9c522febbf313bbe649ca75c39158fec048934"><code>1a9c522</code></a>
chore(deps): bump aiohttp from 3.14.0 to 3.14.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3037">#3037</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.0...v0.8.18">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=langsmith&package-manager=uv&previous-version=0.8.0&new-version=0.8.18)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-25 20:50:44 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6b767dea5f chore(deps): bump langsmith from 0.8.2 to 0.8.18 in /libs/checkpoint-conformance (#8178)
Bumps [langsmith](https://github.com/langchain-ai/langsmith-sdk) from
0.8.2 to 0.8.18.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/langchain-ai/langsmith-sdk/releases">langsmith's
releases</a>.</em></p>
<blockquote>
<h2>v0.8.18</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps-dev): bump vitest from 3.2.4 to 3.2.6 in /js by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3002">langchain-ai/langsmith-sdk#3002</a></li>
<li>chore(deps): bump pyjwt from 2.12.1 to 2.13.0 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3030">langchain-ai/langsmith-sdk#3030</a></li>
<li>chore(deps): bump python-multipart from 0.0.27 to 0.0.31 in /python
by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3036">langchain-ai/langsmith-sdk#3036</a></li>
<li>chore(deps): bump aiohttp from 3.14.0 to 3.14.1 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3037">langchain-ai/langsmith-sdk#3037</a></li>
<li>chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /python by
<a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3038">langchain-ai/langsmith-sdk#3038</a></li>
<li>chore(deps): bump starlette from 1.0.1 to 1.3.1 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3039">langchain-ai/langsmith-sdk#3039</a></li>
<li>chore(deps-dev): bump langchain-anthropic from 1.4.4 to 1.4.6 in
/python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3044">langchain-ai/langsmith-sdk#3044</a></li>
<li>chore(deps): bump the npm_and_yarn group across 4 directories with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3046">langchain-ai/langsmith-sdk#3046</a></li>
<li>chore(deps): bump the npm_and_yarn group across 2 directories with 2
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3060">langchain-ai/langsmith-sdk#3060</a></li>
<li>test(python): fix integration assertions for updated attachment
error message by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3061">langchain-ai/langsmith-sdk#3061</a></li>
<li>chore: reconcile bumpversion config and mandate release process for
agents by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3062">langchain-ai/langsmith-sdk#3062</a></li>
<li>release(py): 0.8.18 by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3063">langchain-ai/langsmith-sdk#3063</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.17...v0.8.18">https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.17...v0.8.18</a></p>
<h2>v0.8.17</h2>
<h2>What's Changed</h2>
<ul>
<li>feat: expose the resources from the generated openapi client in the
langsmith client by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3018">langchain-ai/langsmith-sdk#3018</a></li>
<li>feat(js): port <code>isTracingEnabled</code> utility from Python by
<a href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3032">langchain-ai/langsmith-sdk#3032</a></li>
<li>Add sandbox mount support to JS SDK by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3010">langchain-ai/langsmith-sdk#3010</a></li>
<li>release(js): bump to 0.7.9 by <a
href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3035">langchain-ai/langsmith-sdk#3035</a></li>
<li>Add sandbox mount support to Python SDK by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3009">langchain-ai/langsmith-sdk#3009</a></li>
<li>docs: note that _openapi_client directories are auto-generated by <a
href="https://github.com/KiewanVillatel"><code>@​KiewanVillatel</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3034">langchain-ai/langsmith-sdk#3034</a></li>
<li>fix: update JS SDK type declarations with skipLibCheck disabled by
<a href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3043">langchain-ai/langsmith-sdk#3043</a></li>
<li>release(js): 0.7.10 by <a
href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3045">langchain-ai/langsmith-sdk#3045</a></li>
<li>feat: adding python async for online evals by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3048">langchain-ai/langsmith-sdk#3048</a></li>
<li>Add sandbox Git mount SDK helpers by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3040">langchain-ai/langsmith-sdk#3040</a></li>
<li>fix: use insights tab in sdk report links [closes LSO-2936] by <a
href="https://github.com/eric-langchain"><code>@​eric-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3050">langchain-ai/langsmith-sdk#3050</a></li>
<li>feat(client): warn when backend version is below minimum required by
<a
href="https://github.com/KiewanVillatel"><code>@​KiewanVillatel</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3041">langchain-ai/langsmith-sdk#3041</a></li>
<li>chore: bump _MIN_BACKEND_VERSION to 0.16.5rc1 by <a
href="https://github.com/langtions-bot"><code>@​langtions-bot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3053">langchain-ai/langsmith-sdk#3053</a></li>
<li>fix(sandbox): use built-in gcp auth host matching by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3055">langchain-ai/langsmith-sdk#3055</a></li>
<li>chore(python): py to 0.8.17 by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3056">langchain-ai/langsmith-sdk#3056</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a>
made their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3018">langchain-ai/langsmith-sdk#3018</a></li>
<li><a
href="https://github.com/eric-langchain"><code>@​eric-langchain</code></a>
made their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3050">langchain-ai/langsmith-sdk#3050</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.16...v0.8.17">https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.16...v0.8.17</a></p>
<h2>v0.8.16</h2>
<h2>What's Changed</h2>
<ul>
<li>feat(py): add sync/async conversion for Sandbox and SandboxClient
[INF-0000] by <a
href="https://github.com/ramon-langchain"><code>@​ramon-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3019">langchain-ai/langsmith-sdk#3019</a></li>
<li>fix(experiments): extract keys from wrapped evaluator function by <a
href="https://github.com/shamikkarkhanis"><code>@​shamikkarkhanis</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3014">langchain-ai/langsmith-sdk#3014</a></li>
<li>chore: repoint <a
href="mailto:support@langchain.dev">support@langchain.dev</a> mentions
to the Support Portal by <a
href="https://github.com/lutan-langchain"><code>@​lutan-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3024">langchain-ai/langsmith-sdk#3024</a></li>
<li>fix(python): derive create_child run id from start_time [LSDK-220]
by <a
href="https://github.com/harisaiharish"><code>@​harisaiharish</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3027">langchain-ai/langsmith-sdk#3027</a></li>
<li>chore: sync langsmith_api by <a
href="https://github.com/langtions-bot"><code>@​langtions-bot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3020">langchain-ai/langsmith-sdk#3020</a></li>
<li>chore: js to 0.7.8 and py to 0.8.16 by <a
href="https://github.com/shamikkarkhanis"><code>@​shamikkarkhanis</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3029">langchain-ai/langsmith-sdk#3029</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/31c2bf650b84a44577d8b4443298fb7e78025b8f"><code>31c2bf6</code></a>
release(py): 0.8.18 (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3063">#3063</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/8955b688689fdf47871d44013787410a42ea13fd"><code>8955b68</code></a>
chore: reconcile bumpversion config and mandate release process for
agents (#...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/411401f6ca5ff401c29772ed097c9c9ed97f994c"><code>411401f</code></a>
test(python): fix integration assertions for updated attachment error
message...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/9c5515620f9bfa2145fc65d6f4353c4c8a3e96b6"><code>9c55156</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/5b2bd8db3c50d3f19e98f41288c87d9c0ac0b136"><code>5b2bd8d</code></a>
chore(deps): bump the npm_and_yarn group across 2 directories with 2
updates ...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/d8642f9099a48025d00c7283ad3cd2ce56fec775"><code>d8642f9</code></a>
chore(deps): bump the npm_and_yarn group across 4 directories with 4
updates ...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/953c2e5e25e41ecb4dba428adbac1c446c0a0071"><code>953c2e5</code></a>
chore(deps-dev): bump langchain-anthropic from 1.4.4 to 1.4.6 in /python
(<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3044">#3044</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/5513699e2d25c2147e02c296bc3b90f7d0923d8a"><code>5513699</code></a>
chore(deps): bump starlette from 1.0.1 to 1.3.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3039">#3039</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/8becdefdf422a02e03f78cf3ebb4c62c136b7cf3"><code>8becdef</code></a>
chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3038">#3038</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/1a9c522febbf313bbe649ca75c39158fec048934"><code>1a9c522</code></a>
chore(deps): bump aiohttp from 3.14.0 to 3.14.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3037">#3037</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.2...v0.8.18">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=langsmith&package-manager=uv&previous-version=0.8.2&new-version=0.8.18)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-25 13:45:44 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
e6574a854f chore(deps): bump langsmith from 0.8.0 to 0.8.18 in /libs/cli (#8172)
Bumps [langsmith](https://github.com/langchain-ai/langsmith-sdk) from
0.8.0 to 0.8.18.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/langchain-ai/langsmith-sdk/releases">langsmith's
releases</a>.</em></p>
<blockquote>
<h2>v0.8.18</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps-dev): bump vitest from 3.2.4 to 3.2.6 in /js by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3002">langchain-ai/langsmith-sdk#3002</a></li>
<li>chore(deps): bump pyjwt from 2.12.1 to 2.13.0 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3030">langchain-ai/langsmith-sdk#3030</a></li>
<li>chore(deps): bump python-multipart from 0.0.27 to 0.0.31 in /python
by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3036">langchain-ai/langsmith-sdk#3036</a></li>
<li>chore(deps): bump aiohttp from 3.14.0 to 3.14.1 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3037">langchain-ai/langsmith-sdk#3037</a></li>
<li>chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /python by
<a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3038">langchain-ai/langsmith-sdk#3038</a></li>
<li>chore(deps): bump starlette from 1.0.1 to 1.3.1 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3039">langchain-ai/langsmith-sdk#3039</a></li>
<li>chore(deps-dev): bump langchain-anthropic from 1.4.4 to 1.4.6 in
/python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3044">langchain-ai/langsmith-sdk#3044</a></li>
<li>chore(deps): bump the npm_and_yarn group across 4 directories with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3046">langchain-ai/langsmith-sdk#3046</a></li>
<li>chore(deps): bump the npm_and_yarn group across 2 directories with 2
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3060">langchain-ai/langsmith-sdk#3060</a></li>
<li>test(python): fix integration assertions for updated attachment
error message by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3061">langchain-ai/langsmith-sdk#3061</a></li>
<li>chore: reconcile bumpversion config and mandate release process for
agents by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3062">langchain-ai/langsmith-sdk#3062</a></li>
<li>release(py): 0.8.18 by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3063">langchain-ai/langsmith-sdk#3063</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.17...v0.8.18">https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.17...v0.8.18</a></p>
<h2>v0.8.17</h2>
<h2>What's Changed</h2>
<ul>
<li>feat: expose the resources from the generated openapi client in the
langsmith client by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3018">langchain-ai/langsmith-sdk#3018</a></li>
<li>feat(js): port <code>isTracingEnabled</code> utility from Python by
<a href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3032">langchain-ai/langsmith-sdk#3032</a></li>
<li>Add sandbox mount support to JS SDK by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3010">langchain-ai/langsmith-sdk#3010</a></li>
<li>release(js): bump to 0.7.9 by <a
href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3035">langchain-ai/langsmith-sdk#3035</a></li>
<li>Add sandbox mount support to Python SDK by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3009">langchain-ai/langsmith-sdk#3009</a></li>
<li>docs: note that _openapi_client directories are auto-generated by <a
href="https://github.com/KiewanVillatel"><code>@​KiewanVillatel</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3034">langchain-ai/langsmith-sdk#3034</a></li>
<li>fix: update JS SDK type declarations with skipLibCheck disabled by
<a href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3043">langchain-ai/langsmith-sdk#3043</a></li>
<li>release(js): 0.7.10 by <a
href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3045">langchain-ai/langsmith-sdk#3045</a></li>
<li>feat: adding python async for online evals by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3048">langchain-ai/langsmith-sdk#3048</a></li>
<li>Add sandbox Git mount SDK helpers by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3040">langchain-ai/langsmith-sdk#3040</a></li>
<li>fix: use insights tab in sdk report links [closes LSO-2936] by <a
href="https://github.com/eric-langchain"><code>@​eric-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3050">langchain-ai/langsmith-sdk#3050</a></li>
<li>feat(client): warn when backend version is below minimum required by
<a
href="https://github.com/KiewanVillatel"><code>@​KiewanVillatel</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3041">langchain-ai/langsmith-sdk#3041</a></li>
<li>chore: bump _MIN_BACKEND_VERSION to 0.16.5rc1 by <a
href="https://github.com/langtions-bot"><code>@​langtions-bot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3053">langchain-ai/langsmith-sdk#3053</a></li>
<li>fix(sandbox): use built-in gcp auth host matching by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3055">langchain-ai/langsmith-sdk#3055</a></li>
<li>chore(python): py to 0.8.17 by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3056">langchain-ai/langsmith-sdk#3056</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a>
made their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3018">langchain-ai/langsmith-sdk#3018</a></li>
<li><a
href="https://github.com/eric-langchain"><code>@​eric-langchain</code></a>
made their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3050">langchain-ai/langsmith-sdk#3050</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.16...v0.8.17">https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.16...v0.8.17</a></p>
<h2>v0.8.16</h2>
<h2>What's Changed</h2>
<ul>
<li>feat(py): add sync/async conversion for Sandbox and SandboxClient
[INF-0000] by <a
href="https://github.com/ramon-langchain"><code>@​ramon-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3019">langchain-ai/langsmith-sdk#3019</a></li>
<li>fix(experiments): extract keys from wrapped evaluator function by <a
href="https://github.com/shamikkarkhanis"><code>@​shamikkarkhanis</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3014">langchain-ai/langsmith-sdk#3014</a></li>
<li>chore: repoint <a
href="mailto:support@langchain.dev">support@langchain.dev</a> mentions
to the Support Portal by <a
href="https://github.com/lutan-langchain"><code>@​lutan-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3024">langchain-ai/langsmith-sdk#3024</a></li>
<li>fix(python): derive create_child run id from start_time [LSDK-220]
by <a
href="https://github.com/harisaiharish"><code>@​harisaiharish</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3027">langchain-ai/langsmith-sdk#3027</a></li>
<li>chore: sync langsmith_api by <a
href="https://github.com/langtions-bot"><code>@​langtions-bot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3020">langchain-ai/langsmith-sdk#3020</a></li>
<li>chore: js to 0.7.8 and py to 0.8.16 by <a
href="https://github.com/shamikkarkhanis"><code>@​shamikkarkhanis</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3029">langchain-ai/langsmith-sdk#3029</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/31c2bf650b84a44577d8b4443298fb7e78025b8f"><code>31c2bf6</code></a>
release(py): 0.8.18 (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3063">#3063</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/8955b688689fdf47871d44013787410a42ea13fd"><code>8955b68</code></a>
chore: reconcile bumpversion config and mandate release process for
agents (#...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/411401f6ca5ff401c29772ed097c9c9ed97f994c"><code>411401f</code></a>
test(python): fix integration assertions for updated attachment error
message...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/9c5515620f9bfa2145fc65d6f4353c4c8a3e96b6"><code>9c55156</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/5b2bd8db3c50d3f19e98f41288c87d9c0ac0b136"><code>5b2bd8d</code></a>
chore(deps): bump the npm_and_yarn group across 2 directories with 2
updates ...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/d8642f9099a48025d00c7283ad3cd2ce56fec775"><code>d8642f9</code></a>
chore(deps): bump the npm_and_yarn group across 4 directories with 4
updates ...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/953c2e5e25e41ecb4dba428adbac1c446c0a0071"><code>953c2e5</code></a>
chore(deps-dev): bump langchain-anthropic from 1.4.4 to 1.4.6 in /python
(<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3044">#3044</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/5513699e2d25c2147e02c296bc3b90f7d0923d8a"><code>5513699</code></a>
chore(deps): bump starlette from 1.0.1 to 1.3.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3039">#3039</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/8becdefdf422a02e03f78cf3ebb4c62c136b7cf3"><code>8becdef</code></a>
chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3038">#3038</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/1a9c522febbf313bbe649ca75c39158fec048934"><code>1a9c522</code></a>
chore(deps): bump aiohttp from 3.14.0 to 3.14.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3037">#3037</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.0...v0.8.18">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=langsmith&package-manager=uv&previous-version=0.8.0&new-version=0.8.18)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-25 13:45:24 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
49110176c4 chore(deps): bump langsmith from 0.8.0 to 0.8.18 in /libs/sdk-py (#8174)
Bumps [langsmith](https://github.com/langchain-ai/langsmith-sdk) from
0.8.0 to 0.8.18.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/langchain-ai/langsmith-sdk/releases">langsmith's
releases</a>.</em></p>
<blockquote>
<h2>v0.8.18</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps-dev): bump vitest from 3.2.4 to 3.2.6 in /js by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3002">langchain-ai/langsmith-sdk#3002</a></li>
<li>chore(deps): bump pyjwt from 2.12.1 to 2.13.0 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3030">langchain-ai/langsmith-sdk#3030</a></li>
<li>chore(deps): bump python-multipart from 0.0.27 to 0.0.31 in /python
by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3036">langchain-ai/langsmith-sdk#3036</a></li>
<li>chore(deps): bump aiohttp from 3.14.0 to 3.14.1 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3037">langchain-ai/langsmith-sdk#3037</a></li>
<li>chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /python by
<a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3038">langchain-ai/langsmith-sdk#3038</a></li>
<li>chore(deps): bump starlette from 1.0.1 to 1.3.1 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3039">langchain-ai/langsmith-sdk#3039</a></li>
<li>chore(deps-dev): bump langchain-anthropic from 1.4.4 to 1.4.6 in
/python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3044">langchain-ai/langsmith-sdk#3044</a></li>
<li>chore(deps): bump the npm_and_yarn group across 4 directories with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3046">langchain-ai/langsmith-sdk#3046</a></li>
<li>chore(deps): bump the npm_and_yarn group across 2 directories with 2
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3060">langchain-ai/langsmith-sdk#3060</a></li>
<li>test(python): fix integration assertions for updated attachment
error message by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3061">langchain-ai/langsmith-sdk#3061</a></li>
<li>chore: reconcile bumpversion config and mandate release process for
agents by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3062">langchain-ai/langsmith-sdk#3062</a></li>
<li>release(py): 0.8.18 by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3063">langchain-ai/langsmith-sdk#3063</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.17...v0.8.18">https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.17...v0.8.18</a></p>
<h2>v0.8.17</h2>
<h2>What's Changed</h2>
<ul>
<li>feat: expose the resources from the generated openapi client in the
langsmith client by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3018">langchain-ai/langsmith-sdk#3018</a></li>
<li>feat(js): port <code>isTracingEnabled</code> utility from Python by
<a href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3032">langchain-ai/langsmith-sdk#3032</a></li>
<li>Add sandbox mount support to JS SDK by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3010">langchain-ai/langsmith-sdk#3010</a></li>
<li>release(js): bump to 0.7.9 by <a
href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3035">langchain-ai/langsmith-sdk#3035</a></li>
<li>Add sandbox mount support to Python SDK by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3009">langchain-ai/langsmith-sdk#3009</a></li>
<li>docs: note that _openapi_client directories are auto-generated by <a
href="https://github.com/KiewanVillatel"><code>@​KiewanVillatel</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3034">langchain-ai/langsmith-sdk#3034</a></li>
<li>fix: update JS SDK type declarations with skipLibCheck disabled by
<a href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3043">langchain-ai/langsmith-sdk#3043</a></li>
<li>release(js): 0.7.10 by <a
href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3045">langchain-ai/langsmith-sdk#3045</a></li>
<li>feat: adding python async for online evals by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3048">langchain-ai/langsmith-sdk#3048</a></li>
<li>Add sandbox Git mount SDK helpers by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3040">langchain-ai/langsmith-sdk#3040</a></li>
<li>fix: use insights tab in sdk report links [closes LSO-2936] by <a
href="https://github.com/eric-langchain"><code>@​eric-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3050">langchain-ai/langsmith-sdk#3050</a></li>
<li>feat(client): warn when backend version is below minimum required by
<a
href="https://github.com/KiewanVillatel"><code>@​KiewanVillatel</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3041">langchain-ai/langsmith-sdk#3041</a></li>
<li>chore: bump _MIN_BACKEND_VERSION to 0.16.5rc1 by <a
href="https://github.com/langtions-bot"><code>@​langtions-bot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3053">langchain-ai/langsmith-sdk#3053</a></li>
<li>fix(sandbox): use built-in gcp auth host matching by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3055">langchain-ai/langsmith-sdk#3055</a></li>
<li>chore(python): py to 0.8.17 by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3056">langchain-ai/langsmith-sdk#3056</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a>
made their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3018">langchain-ai/langsmith-sdk#3018</a></li>
<li><a
href="https://github.com/eric-langchain"><code>@​eric-langchain</code></a>
made their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3050">langchain-ai/langsmith-sdk#3050</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.16...v0.8.17">https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.16...v0.8.17</a></p>
<h2>v0.8.16</h2>
<h2>What's Changed</h2>
<ul>
<li>feat(py): add sync/async conversion for Sandbox and SandboxClient
[INF-0000] by <a
href="https://github.com/ramon-langchain"><code>@​ramon-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3019">langchain-ai/langsmith-sdk#3019</a></li>
<li>fix(experiments): extract keys from wrapped evaluator function by <a
href="https://github.com/shamikkarkhanis"><code>@​shamikkarkhanis</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3014">langchain-ai/langsmith-sdk#3014</a></li>
<li>chore: repoint <a
href="mailto:support@langchain.dev">support@langchain.dev</a> mentions
to the Support Portal by <a
href="https://github.com/lutan-langchain"><code>@​lutan-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3024">langchain-ai/langsmith-sdk#3024</a></li>
<li>fix(python): derive create_child run id from start_time [LSDK-220]
by <a
href="https://github.com/harisaiharish"><code>@​harisaiharish</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3027">langchain-ai/langsmith-sdk#3027</a></li>
<li>chore: sync langsmith_api by <a
href="https://github.com/langtions-bot"><code>@​langtions-bot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3020">langchain-ai/langsmith-sdk#3020</a></li>
<li>chore: js to 0.7.8 and py to 0.8.16 by <a
href="https://github.com/shamikkarkhanis"><code>@​shamikkarkhanis</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3029">langchain-ai/langsmith-sdk#3029</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/31c2bf650b84a44577d8b4443298fb7e78025b8f"><code>31c2bf6</code></a>
release(py): 0.8.18 (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3063">#3063</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/8955b688689fdf47871d44013787410a42ea13fd"><code>8955b68</code></a>
chore: reconcile bumpversion config and mandate release process for
agents (#...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/411401f6ca5ff401c29772ed097c9c9ed97f994c"><code>411401f</code></a>
test(python): fix integration assertions for updated attachment error
message...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/9c5515620f9bfa2145fc65d6f4353c4c8a3e96b6"><code>9c55156</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/5b2bd8db3c50d3f19e98f41288c87d9c0ac0b136"><code>5b2bd8d</code></a>
chore(deps): bump the npm_and_yarn group across 2 directories with 2
updates ...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/d8642f9099a48025d00c7283ad3cd2ce56fec775"><code>d8642f9</code></a>
chore(deps): bump the npm_and_yarn group across 4 directories with 4
updates ...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/953c2e5e25e41ecb4dba428adbac1c446c0a0071"><code>953c2e5</code></a>
chore(deps-dev): bump langchain-anthropic from 1.4.4 to 1.4.6 in /python
(<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3044">#3044</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/5513699e2d25c2147e02c296bc3b90f7d0923d8a"><code>5513699</code></a>
chore(deps): bump starlette from 1.0.1 to 1.3.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3039">#3039</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/8becdefdf422a02e03f78cf3ebb4c62c136b7cf3"><code>8becdef</code></a>
chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3038">#3038</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/1a9c522febbf313bbe649ca75c39158fec048934"><code>1a9c522</code></a>
chore(deps): bump aiohttp from 3.14.0 to 3.14.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3037">#3037</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.0...v0.8.18">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=langsmith&package-manager=uv&previous-version=0.8.0&new-version=0.8.18)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-25 13:45:10 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6f438b441a chore(deps): bump langsmith from 0.8.0 to 0.8.18 in /libs/langgraph (#8176)
Bumps [langsmith](https://github.com/langchain-ai/langsmith-sdk) from
0.8.0 to 0.8.18.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/langchain-ai/langsmith-sdk/releases">langsmith's
releases</a>.</em></p>
<blockquote>
<h2>v0.8.18</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps-dev): bump vitest from 3.2.4 to 3.2.6 in /js by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3002">langchain-ai/langsmith-sdk#3002</a></li>
<li>chore(deps): bump pyjwt from 2.12.1 to 2.13.0 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3030">langchain-ai/langsmith-sdk#3030</a></li>
<li>chore(deps): bump python-multipart from 0.0.27 to 0.0.31 in /python
by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3036">langchain-ai/langsmith-sdk#3036</a></li>
<li>chore(deps): bump aiohttp from 3.14.0 to 3.14.1 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3037">langchain-ai/langsmith-sdk#3037</a></li>
<li>chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /python by
<a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3038">langchain-ai/langsmith-sdk#3038</a></li>
<li>chore(deps): bump starlette from 1.0.1 to 1.3.1 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3039">langchain-ai/langsmith-sdk#3039</a></li>
<li>chore(deps-dev): bump langchain-anthropic from 1.4.4 to 1.4.6 in
/python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3044">langchain-ai/langsmith-sdk#3044</a></li>
<li>chore(deps): bump the npm_and_yarn group across 4 directories with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3046">langchain-ai/langsmith-sdk#3046</a></li>
<li>chore(deps): bump the npm_and_yarn group across 2 directories with 2
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3060">langchain-ai/langsmith-sdk#3060</a></li>
<li>test(python): fix integration assertions for updated attachment
error message by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3061">langchain-ai/langsmith-sdk#3061</a></li>
<li>chore: reconcile bumpversion config and mandate release process for
agents by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3062">langchain-ai/langsmith-sdk#3062</a></li>
<li>release(py): 0.8.18 by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3063">langchain-ai/langsmith-sdk#3063</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.17...v0.8.18">https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.17...v0.8.18</a></p>
<h2>v0.8.17</h2>
<h2>What's Changed</h2>
<ul>
<li>feat: expose the resources from the generated openapi client in the
langsmith client by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3018">langchain-ai/langsmith-sdk#3018</a></li>
<li>feat(js): port <code>isTracingEnabled</code> utility from Python by
<a href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3032">langchain-ai/langsmith-sdk#3032</a></li>
<li>Add sandbox mount support to JS SDK by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3010">langchain-ai/langsmith-sdk#3010</a></li>
<li>release(js): bump to 0.7.9 by <a
href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3035">langchain-ai/langsmith-sdk#3035</a></li>
<li>Add sandbox mount support to Python SDK by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3009">langchain-ai/langsmith-sdk#3009</a></li>
<li>docs: note that _openapi_client directories are auto-generated by <a
href="https://github.com/KiewanVillatel"><code>@​KiewanVillatel</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3034">langchain-ai/langsmith-sdk#3034</a></li>
<li>fix: update JS SDK type declarations with skipLibCheck disabled by
<a href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3043">langchain-ai/langsmith-sdk#3043</a></li>
<li>release(js): 0.7.10 by <a
href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3045">langchain-ai/langsmith-sdk#3045</a></li>
<li>feat: adding python async for online evals by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3048">langchain-ai/langsmith-sdk#3048</a></li>
<li>Add sandbox Git mount SDK helpers by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3040">langchain-ai/langsmith-sdk#3040</a></li>
<li>fix: use insights tab in sdk report links [closes LSO-2936] by <a
href="https://github.com/eric-langchain"><code>@​eric-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3050">langchain-ai/langsmith-sdk#3050</a></li>
<li>feat(client): warn when backend version is below minimum required by
<a
href="https://github.com/KiewanVillatel"><code>@​KiewanVillatel</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3041">langchain-ai/langsmith-sdk#3041</a></li>
<li>chore: bump _MIN_BACKEND_VERSION to 0.16.5rc1 by <a
href="https://github.com/langtions-bot"><code>@​langtions-bot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3053">langchain-ai/langsmith-sdk#3053</a></li>
<li>fix(sandbox): use built-in gcp auth host matching by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3055">langchain-ai/langsmith-sdk#3055</a></li>
<li>chore(python): py to 0.8.17 by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3056">langchain-ai/langsmith-sdk#3056</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a>
made their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3018">langchain-ai/langsmith-sdk#3018</a></li>
<li><a
href="https://github.com/eric-langchain"><code>@​eric-langchain</code></a>
made their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3050">langchain-ai/langsmith-sdk#3050</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.16...v0.8.17">https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.16...v0.8.17</a></p>
<h2>v0.8.16</h2>
<h2>What's Changed</h2>
<ul>
<li>feat(py): add sync/async conversion for Sandbox and SandboxClient
[INF-0000] by <a
href="https://github.com/ramon-langchain"><code>@​ramon-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3019">langchain-ai/langsmith-sdk#3019</a></li>
<li>fix(experiments): extract keys from wrapped evaluator function by <a
href="https://github.com/shamikkarkhanis"><code>@​shamikkarkhanis</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3014">langchain-ai/langsmith-sdk#3014</a></li>
<li>chore: repoint <a
href="mailto:support@langchain.dev">support@langchain.dev</a> mentions
to the Support Portal by <a
href="https://github.com/lutan-langchain"><code>@​lutan-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3024">langchain-ai/langsmith-sdk#3024</a></li>
<li>fix(python): derive create_child run id from start_time [LSDK-220]
by <a
href="https://github.com/harisaiharish"><code>@​harisaiharish</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3027">langchain-ai/langsmith-sdk#3027</a></li>
<li>chore: sync langsmith_api by <a
href="https://github.com/langtions-bot"><code>@​langtions-bot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3020">langchain-ai/langsmith-sdk#3020</a></li>
<li>chore: js to 0.7.8 and py to 0.8.16 by <a
href="https://github.com/shamikkarkhanis"><code>@​shamikkarkhanis</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3029">langchain-ai/langsmith-sdk#3029</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/31c2bf650b84a44577d8b4443298fb7e78025b8f"><code>31c2bf6</code></a>
release(py): 0.8.18 (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3063">#3063</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/8955b688689fdf47871d44013787410a42ea13fd"><code>8955b68</code></a>
chore: reconcile bumpversion config and mandate release process for
agents (#...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/411401f6ca5ff401c29772ed097c9c9ed97f994c"><code>411401f</code></a>
test(python): fix integration assertions for updated attachment error
message...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/9c5515620f9bfa2145fc65d6f4353c4c8a3e96b6"><code>9c55156</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/5b2bd8db3c50d3f19e98f41288c87d9c0ac0b136"><code>5b2bd8d</code></a>
chore(deps): bump the npm_and_yarn group across 2 directories with 2
updates ...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/d8642f9099a48025d00c7283ad3cd2ce56fec775"><code>d8642f9</code></a>
chore(deps): bump the npm_and_yarn group across 4 directories with 4
updates ...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/953c2e5e25e41ecb4dba428adbac1c446c0a0071"><code>953c2e5</code></a>
chore(deps-dev): bump langchain-anthropic from 1.4.4 to 1.4.6 in /python
(<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3044">#3044</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/5513699e2d25c2147e02c296bc3b90f7d0923d8a"><code>5513699</code></a>
chore(deps): bump starlette from 1.0.1 to 1.3.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3039">#3039</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/8becdefdf422a02e03f78cf3ebb4c62c136b7cf3"><code>8becdef</code></a>
chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3038">#3038</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/1a9c522febbf313bbe649ca75c39158fec048934"><code>1a9c522</code></a>
chore(deps): bump aiohttp from 3.14.0 to 3.14.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3037">#3037</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.0...v0.8.18">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=langsmith&package-manager=uv&previous-version=0.8.0&new-version=0.8.18)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-25 13:45:07 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
9f0c60ad50 chore(deps): bump langsmith from 0.8.0 to 0.8.18 in /libs/prebuilt (#8175)
Bumps [langsmith](https://github.com/langchain-ai/langsmith-sdk) from
0.8.0 to 0.8.18.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/langchain-ai/langsmith-sdk/releases">langsmith's
releases</a>.</em></p>
<blockquote>
<h2>v0.8.18</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps-dev): bump vitest from 3.2.4 to 3.2.6 in /js by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3002">langchain-ai/langsmith-sdk#3002</a></li>
<li>chore(deps): bump pyjwt from 2.12.1 to 2.13.0 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3030">langchain-ai/langsmith-sdk#3030</a></li>
<li>chore(deps): bump python-multipart from 0.0.27 to 0.0.31 in /python
by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3036">langchain-ai/langsmith-sdk#3036</a></li>
<li>chore(deps): bump aiohttp from 3.14.0 to 3.14.1 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3037">langchain-ai/langsmith-sdk#3037</a></li>
<li>chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /python by
<a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3038">langchain-ai/langsmith-sdk#3038</a></li>
<li>chore(deps): bump starlette from 1.0.1 to 1.3.1 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3039">langchain-ai/langsmith-sdk#3039</a></li>
<li>chore(deps-dev): bump langchain-anthropic from 1.4.4 to 1.4.6 in
/python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3044">langchain-ai/langsmith-sdk#3044</a></li>
<li>chore(deps): bump the npm_and_yarn group across 4 directories with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3046">langchain-ai/langsmith-sdk#3046</a></li>
<li>chore(deps): bump the npm_and_yarn group across 2 directories with 2
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3060">langchain-ai/langsmith-sdk#3060</a></li>
<li>test(python): fix integration assertions for updated attachment
error message by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3061">langchain-ai/langsmith-sdk#3061</a></li>
<li>chore: reconcile bumpversion config and mandate release process for
agents by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3062">langchain-ai/langsmith-sdk#3062</a></li>
<li>release(py): 0.8.18 by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3063">langchain-ai/langsmith-sdk#3063</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.17...v0.8.18">https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.17...v0.8.18</a></p>
<h2>v0.8.17</h2>
<h2>What's Changed</h2>
<ul>
<li>feat: expose the resources from the generated openapi client in the
langsmith client by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3018">langchain-ai/langsmith-sdk#3018</a></li>
<li>feat(js): port <code>isTracingEnabled</code> utility from Python by
<a href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3032">langchain-ai/langsmith-sdk#3032</a></li>
<li>Add sandbox mount support to JS SDK by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3010">langchain-ai/langsmith-sdk#3010</a></li>
<li>release(js): bump to 0.7.9 by <a
href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3035">langchain-ai/langsmith-sdk#3035</a></li>
<li>Add sandbox mount support to Python SDK by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3009">langchain-ai/langsmith-sdk#3009</a></li>
<li>docs: note that _openapi_client directories are auto-generated by <a
href="https://github.com/KiewanVillatel"><code>@​KiewanVillatel</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3034">langchain-ai/langsmith-sdk#3034</a></li>
<li>fix: update JS SDK type declarations with skipLibCheck disabled by
<a href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3043">langchain-ai/langsmith-sdk#3043</a></li>
<li>release(js): 0.7.10 by <a
href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3045">langchain-ai/langsmith-sdk#3045</a></li>
<li>feat: adding python async for online evals by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3048">langchain-ai/langsmith-sdk#3048</a></li>
<li>Add sandbox Git mount SDK helpers by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3040">langchain-ai/langsmith-sdk#3040</a></li>
<li>fix: use insights tab in sdk report links [closes LSO-2936] by <a
href="https://github.com/eric-langchain"><code>@​eric-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3050">langchain-ai/langsmith-sdk#3050</a></li>
<li>feat(client): warn when backend version is below minimum required by
<a
href="https://github.com/KiewanVillatel"><code>@​KiewanVillatel</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3041">langchain-ai/langsmith-sdk#3041</a></li>
<li>chore: bump _MIN_BACKEND_VERSION to 0.16.5rc1 by <a
href="https://github.com/langtions-bot"><code>@​langtions-bot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3053">langchain-ai/langsmith-sdk#3053</a></li>
<li>fix(sandbox): use built-in gcp auth host matching by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3055">langchain-ai/langsmith-sdk#3055</a></li>
<li>chore(python): py to 0.8.17 by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3056">langchain-ai/langsmith-sdk#3056</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a>
made their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3018">langchain-ai/langsmith-sdk#3018</a></li>
<li><a
href="https://github.com/eric-langchain"><code>@​eric-langchain</code></a>
made their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3050">langchain-ai/langsmith-sdk#3050</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.16...v0.8.17">https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.16...v0.8.17</a></p>
<h2>v0.8.16</h2>
<h2>What's Changed</h2>
<ul>
<li>feat(py): add sync/async conversion for Sandbox and SandboxClient
[INF-0000] by <a
href="https://github.com/ramon-langchain"><code>@​ramon-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3019">langchain-ai/langsmith-sdk#3019</a></li>
<li>fix(experiments): extract keys from wrapped evaluator function by <a
href="https://github.com/shamikkarkhanis"><code>@​shamikkarkhanis</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3014">langchain-ai/langsmith-sdk#3014</a></li>
<li>chore: repoint <a
href="mailto:support@langchain.dev">support@langchain.dev</a> mentions
to the Support Portal by <a
href="https://github.com/lutan-langchain"><code>@​lutan-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3024">langchain-ai/langsmith-sdk#3024</a></li>
<li>fix(python): derive create_child run id from start_time [LSDK-220]
by <a
href="https://github.com/harisaiharish"><code>@​harisaiharish</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3027">langchain-ai/langsmith-sdk#3027</a></li>
<li>chore: sync langsmith_api by <a
href="https://github.com/langtions-bot"><code>@​langtions-bot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3020">langchain-ai/langsmith-sdk#3020</a></li>
<li>chore: js to 0.7.8 and py to 0.8.16 by <a
href="https://github.com/shamikkarkhanis"><code>@​shamikkarkhanis</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3029">langchain-ai/langsmith-sdk#3029</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/31c2bf650b84a44577d8b4443298fb7e78025b8f"><code>31c2bf6</code></a>
release(py): 0.8.18 (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3063">#3063</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/8955b688689fdf47871d44013787410a42ea13fd"><code>8955b68</code></a>
chore: reconcile bumpversion config and mandate release process for
agents (#...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/411401f6ca5ff401c29772ed097c9c9ed97f994c"><code>411401f</code></a>
test(python): fix integration assertions for updated attachment error
message...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/9c5515620f9bfa2145fc65d6f4353c4c8a3e96b6"><code>9c55156</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/5b2bd8db3c50d3f19e98f41288c87d9c0ac0b136"><code>5b2bd8d</code></a>
chore(deps): bump the npm_and_yarn group across 2 directories with 2
updates ...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/d8642f9099a48025d00c7283ad3cd2ce56fec775"><code>d8642f9</code></a>
chore(deps): bump the npm_and_yarn group across 4 directories with 4
updates ...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/953c2e5e25e41ecb4dba428adbac1c446c0a0071"><code>953c2e5</code></a>
chore(deps-dev): bump langchain-anthropic from 1.4.4 to 1.4.6 in /python
(<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3044">#3044</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/5513699e2d25c2147e02c296bc3b90f7d0923d8a"><code>5513699</code></a>
chore(deps): bump starlette from 1.0.1 to 1.3.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3039">#3039</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/8becdefdf422a02e03f78cf3ebb4c62c136b7cf3"><code>8becdef</code></a>
chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3038">#3038</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/1a9c522febbf313bbe649ca75c39158fec048934"><code>1a9c522</code></a>
chore(deps): bump aiohttp from 3.14.0 to 3.14.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3037">#3037</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.0...v0.8.18">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=langsmith&package-manager=uv&previous-version=0.8.0&new-version=0.8.18)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-25 13:44:50 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
0ee6b367da chore(deps): bump langsmith from 0.8.0 to 0.8.18 in /libs/checkpoint (#8173)
Bumps [langsmith](https://github.com/langchain-ai/langsmith-sdk) from
0.8.0 to 0.8.18.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/langchain-ai/langsmith-sdk/releases">langsmith's
releases</a>.</em></p>
<blockquote>
<h2>v0.8.18</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps-dev): bump vitest from 3.2.4 to 3.2.6 in /js by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3002">langchain-ai/langsmith-sdk#3002</a></li>
<li>chore(deps): bump pyjwt from 2.12.1 to 2.13.0 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3030">langchain-ai/langsmith-sdk#3030</a></li>
<li>chore(deps): bump python-multipart from 0.0.27 to 0.0.31 in /python
by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3036">langchain-ai/langsmith-sdk#3036</a></li>
<li>chore(deps): bump aiohttp from 3.14.0 to 3.14.1 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3037">langchain-ai/langsmith-sdk#3037</a></li>
<li>chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /python by
<a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3038">langchain-ai/langsmith-sdk#3038</a></li>
<li>chore(deps): bump starlette from 1.0.1 to 1.3.1 in /python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3039">langchain-ai/langsmith-sdk#3039</a></li>
<li>chore(deps-dev): bump langchain-anthropic from 1.4.4 to 1.4.6 in
/python by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3044">langchain-ai/langsmith-sdk#3044</a></li>
<li>chore(deps): bump the npm_and_yarn group across 4 directories with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3046">langchain-ai/langsmith-sdk#3046</a></li>
<li>chore(deps): bump the npm_and_yarn group across 2 directories with 2
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3060">langchain-ai/langsmith-sdk#3060</a></li>
<li>test(python): fix integration assertions for updated attachment
error message by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3061">langchain-ai/langsmith-sdk#3061</a></li>
<li>chore: reconcile bumpversion config and mandate release process for
agents by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3062">langchain-ai/langsmith-sdk#3062</a></li>
<li>release(py): 0.8.18 by <a
href="https://github.com/QuentinBrosse"><code>@​QuentinBrosse</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3063">langchain-ai/langsmith-sdk#3063</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.17...v0.8.18">https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.17...v0.8.18</a></p>
<h2>v0.8.17</h2>
<h2>What's Changed</h2>
<ul>
<li>feat: expose the resources from the generated openapi client in the
langsmith client by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3018">langchain-ai/langsmith-sdk#3018</a></li>
<li>feat(js): port <code>isTracingEnabled</code> utility from Python by
<a href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3032">langchain-ai/langsmith-sdk#3032</a></li>
<li>Add sandbox mount support to JS SDK by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3010">langchain-ai/langsmith-sdk#3010</a></li>
<li>release(js): bump to 0.7.9 by <a
href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3035">langchain-ai/langsmith-sdk#3035</a></li>
<li>Add sandbox mount support to Python SDK by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3009">langchain-ai/langsmith-sdk#3009</a></li>
<li>docs: note that _openapi_client directories are auto-generated by <a
href="https://github.com/KiewanVillatel"><code>@​KiewanVillatel</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3034">langchain-ai/langsmith-sdk#3034</a></li>
<li>fix: update JS SDK type declarations with skipLibCheck disabled by
<a href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3043">langchain-ai/langsmith-sdk#3043</a></li>
<li>release(js): 0.7.10 by <a
href="https://github.com/dqbd"><code>@​dqbd</code></a> in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3045">langchain-ai/langsmith-sdk#3045</a></li>
<li>feat: adding python async for online evals by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3048">langchain-ai/langsmith-sdk#3048</a></li>
<li>Add sandbox Git mount SDK helpers by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3040">langchain-ai/langsmith-sdk#3040</a></li>
<li>fix: use insights tab in sdk report links [closes LSO-2936] by <a
href="https://github.com/eric-langchain"><code>@​eric-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3050">langchain-ai/langsmith-sdk#3050</a></li>
<li>feat(client): warn when backend version is below minimum required by
<a
href="https://github.com/KiewanVillatel"><code>@​KiewanVillatel</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3041">langchain-ai/langsmith-sdk#3041</a></li>
<li>chore: bump _MIN_BACKEND_VERSION to 0.16.5rc1 by <a
href="https://github.com/langtions-bot"><code>@​langtions-bot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3053">langchain-ai/langsmith-sdk#3053</a></li>
<li>fix(sandbox): use built-in gcp auth host matching by <a
href="https://github.com/DanielKneipp"><code>@​DanielKneipp</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3055">langchain-ai/langsmith-sdk#3055</a></li>
<li>chore(python): py to 0.8.17 by <a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a> in
<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3056">langchain-ai/langsmith-sdk#3056</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/sineha-mani"><code>@​sineha-mani</code></a>
made their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3018">langchain-ai/langsmith-sdk#3018</a></li>
<li><a
href="https://github.com/eric-langchain"><code>@​eric-langchain</code></a>
made their first contribution in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3050">langchain-ai/langsmith-sdk#3050</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.16...v0.8.17">https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.16...v0.8.17</a></p>
<h2>v0.8.16</h2>
<h2>What's Changed</h2>
<ul>
<li>feat(py): add sync/async conversion for Sandbox and SandboxClient
[INF-0000] by <a
href="https://github.com/ramon-langchain"><code>@​ramon-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3019">langchain-ai/langsmith-sdk#3019</a></li>
<li>fix(experiments): extract keys from wrapped evaluator function by <a
href="https://github.com/shamikkarkhanis"><code>@​shamikkarkhanis</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3014">langchain-ai/langsmith-sdk#3014</a></li>
<li>chore: repoint <a
href="mailto:support@langchain.dev">support@langchain.dev</a> mentions
to the Support Portal by <a
href="https://github.com/lutan-langchain"><code>@​lutan-langchain</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3024">langchain-ai/langsmith-sdk#3024</a></li>
<li>fix(python): derive create_child run id from start_time [LSDK-220]
by <a
href="https://github.com/harisaiharish"><code>@​harisaiharish</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3027">langchain-ai/langsmith-sdk#3027</a></li>
<li>chore: sync langsmith_api by <a
href="https://github.com/langtions-bot"><code>@​langtions-bot</code></a>[bot]
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3020">langchain-ai/langsmith-sdk#3020</a></li>
<li>chore: js to 0.7.8 and py to 0.8.16 by <a
href="https://github.com/shamikkarkhanis"><code>@​shamikkarkhanis</code></a>
in <a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/pull/3029">langchain-ai/langsmith-sdk#3029</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/31c2bf650b84a44577d8b4443298fb7e78025b8f"><code>31c2bf6</code></a>
release(py): 0.8.18 (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3063">#3063</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/8955b688689fdf47871d44013787410a42ea13fd"><code>8955b68</code></a>
chore: reconcile bumpversion config and mandate release process for
agents (#...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/411401f6ca5ff401c29772ed097c9c9ed97f994c"><code>411401f</code></a>
test(python): fix integration assertions for updated attachment error
message...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/9c5515620f9bfa2145fc65d6f4353c4c8a3e96b6"><code>9c55156</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/5b2bd8db3c50d3f19e98f41288c87d9c0ac0b136"><code>5b2bd8d</code></a>
chore(deps): bump the npm_and_yarn group across 2 directories with 2
updates ...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/d8642f9099a48025d00c7283ad3cd2ce56fec775"><code>d8642f9</code></a>
chore(deps): bump the npm_and_yarn group across 4 directories with 4
updates ...</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/953c2e5e25e41ecb4dba428adbac1c446c0a0071"><code>953c2e5</code></a>
chore(deps-dev): bump langchain-anthropic from 1.4.4 to 1.4.6 in /python
(<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3044">#3044</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/5513699e2d25c2147e02c296bc3b90f7d0923d8a"><code>5513699</code></a>
chore(deps): bump starlette from 1.0.1 to 1.3.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3039">#3039</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/8becdefdf422a02e03f78cf3ebb4c62c136b7cf3"><code>8becdef</code></a>
chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3038">#3038</a>)</li>
<li><a
href="https://github.com/langchain-ai/langsmith-sdk/commit/1a9c522febbf313bbe649ca75c39158fec048934"><code>1a9c522</code></a>
chore(deps): bump aiohttp from 3.14.0 to 3.14.1 in /python (<a
href="https://redirect.github.com/langchain-ai/langsmith-sdk/issues/3037">#3037</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/langchain-ai/langsmith-sdk/compare/v0.8.0...v0.8.18">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=langsmith&package-manager=uv&previous-version=0.8.0&new-version=0.8.18)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-25 13:44:32 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
7aee194a91 chore(deps): bump jupyterlab from 4.5.7 to 4.5.9 in /libs/langgraph (#8164)
[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=jupyterlab&package-manager=uv&previous-version=4.5.7&new-version=4.5.9)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-25 13:44:12 -07:00
hari-dhanushkodiGitHubhari-dhanushkodiopen-swe[bot] <open-swe@users.noreply.github.com>
3df6f50ad5 feat(cli): allow prebuild images for langgraph deploy (#8100)
Fixes #

adds a --image flag to `langgraph deploy`, allows a user to `langgraph
build` a custom image and then deploy this specific image with
`langgraph deploy`.

---------

Co-authored-by: hari-dhanushkodi <203702815+hari-dhanushkodi@users.noreply.github.com>
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-25 03:32:42 +00:00
Quanzheng LongGitHubopen-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>
8c9d59c842 fix(langgraph): emit valid UUIDs for exit-mode delta task_ids for langgraph-api (#8165)
Fix exit-mode DeltaChannel `PutWrites` task IDs so they remain valid RFC
UUIDs while preserving superstep ordering for `ORDER BY task_id, idx`.

Follow-up to #7730: `_put_exit_delta_writes` used `f"{step:08d}-{tid}"`,
which produces a 6-segment string Postgres rejects for
`checkpoint_writes.task_id uuid` (e.g. `invalid input syntax for type
uuid`) in LangGraph-API.

This new `exit_delta_task_id()` helper embeds the superstep in the first
UUID group and keeps the original task UUID in the remaining segments
(e.g. `00000001-0270-bf16-1ef8-fb321bef9f3d`).

**Breaking changes:** None.

**Verification:**
- `cd libs/langgraph && make format && make lint && make test
TEST="tests/test_delta_channel_exit_mode.py"` (12 passed)
- New unit test asserts synthetic IDs parse as UUID, sort by superstep,
and that the old format is invalid

---------

Signed-off-by: Quanzheng Long <prclqz@gmail.com>
Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com>
2026-06-23 11:56:11 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
711b315502 chore(deps): bump langchain-anthropic from 1.0.0a5 to 1.4.6 in /libs/cli/examples/graph_prerelease_reqs in the pip group across 1 directory (#8145)
Bumps the pip group with 1 update in the
/libs/cli/examples/graph_prerelease_reqs directory:
[langchain-anthropic](https://github.com/langchain-ai/langchain).

Updates `langchain-anthropic` from 1.0.0a5 to 1.4.6
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/langchain-ai/langchain/releases">langchain-anthropic's
releases</a>.</em></p>
<blockquote>
<h2>langchain-anthropic==1.4.6</h2>
<p>Changes since langchain-anthropic==1.4.5</p>
<p>release(anthropic): 1.4.6 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/38105">#38105</a>)
fix(langchain,anthropic): confine file-search results and tighten
anthropic <code>allowed_prefixes</code> (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/38106">#38106</a>)
release(core): 1.4.6 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/38061">#38061</a>)
feat(core,partners): add package version tracking to tracing metadata
(<a
href="https://redirect.github.com/langchain-ai/langchain/issues/35295">#35295</a>)
chore(infra): bump mypy to 2.1 and unify type-check config across the
monorepo (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/36470">#36470</a>)
feat(standard-tests): validate tool call chunks during streaming (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/34707">#34707</a>)
test(anthropic): make expected warnings explicit (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/38044">#38044</a>)
test(anthropic): make tests robust to gateway base URL (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/38043">#38043</a>)</p>
<h2>langchain-anthropic==1.4.5</h2>
<p>Changes since langchain-anthropic==1.4.4</p>
<p>release(anthropic): 1.4.5 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/38036">#38036</a>)
fix(core): support content block tokens in callbacks (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/34739">#34739</a>)
chore(model-profiles): refresh model profile data (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/38012">#38012</a>)
hotfix(openai): min core dep (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37990">#37990</a>)
test(langchain,partners): disable pytest-benchmark under xdist to
silence <code>PytestBenchmarkWarning</code> (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37901">#37901</a>)
chore(model-profiles): refresh model profile data (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37895">#37895</a>)
chore(model-profiles): refresh model profile data (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37771">#37771</a>)</p>
<h2>langchain-anthropic==1.4.4</h2>
<p>Changes since langchain-anthropic==1.4.3</p>
<p>release(anthropic): 1.4.4 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37757">#37757</a>)
fix(anthropic): normalize cross-provider tool-call IDs (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37756">#37756</a>)
test(anthropic): retry integration tests on transient failures (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37697">#37697</a>)
chore(infra): bump <code>langchain-tests</code> floor to 1.1.9 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37610">#37610</a>)
chore: bump langsmith from 0.8.3 to 0.8.5 in /libs/partners/anthropic
(<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37564">#37564</a>)
chore: bump idna from 3.11 to 3.15 in /libs/partners/anthropic (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37565">#37565</a>)
ci(infra): harden Dependabot version-bound preservation (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37510">#37510</a>)
chore(infra): merge v1.4 into master (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37350">#37350</a>)
chore: bump urllib3 from 2.6.3 to 2.7.0 in /libs/partners/anthropic (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37343">#37343</a>)
chore: bump requests from 2.33.0 to 2.33.1 in /libs/partners/anthropic
(<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37286">#37286</a>)
chore: bump langsmith from 0.7.31 to 0.8.3 in /libs/partners/anthropic
(<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37287">#37287</a>)
chore: bump langchain-core from 1.3.2 to 1.3.3 in
/libs/partners/anthropic (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37288">#37288</a>)</p>
<h2>langchain-anthropic==1.4.3</h2>
<p>Changes since langchain-anthropic==1.4.2</p>
<p>release(anthropic): 1.4.3 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37166">#37166</a>)
refactor(langchain-classic): retarget deprecations to
<code>create_agent</code>, other chores (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37164">#37164</a>)
chore(docs): update x handle references (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37081">#37081</a>)
fix(anthropic): guard httpx finalizers (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/37064">#37064</a>)</p>
<h2>langchain-anthropic==1.4.2</h2>
<p>Changes since langchain-anthropic==1.4.1</p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/langchain-ai/langchain/commit/c9f98c1bcd00a923e674d691c963a5c3ca584692"><code>c9f98c1</code></a>
release(anthropic): 1.4.6 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/38105">#38105</a>)</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/3bfb6a33e788aaca1626a7c09cbdbdbef6977012"><code>3bfb6a3</code></a>
release(langchain): 1.3.9 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/38104">#38104</a>)</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/dcaf7795a3e6590af55c3ff7bda6add6355e9ea6"><code>dcaf779</code></a>
fix(langchain,anthropic): confine file-search results and tighten
anthropic `...</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/0392b6bae4bdfc0b7ed5aeb2e9e414bbb7ea643b"><code>0392b6b</code></a>
fix(core): fix Pydantic v1 support in tools/runnable (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/33698">#33698</a>)</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/f6d63bc9f344b2949e91a6904d301553376b4f10"><code>f6d63bc</code></a>
release(langchain): 1.3.8 (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/38096">#38096</a>)</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/5d20596d73789020f53c622b22c0a9893ba09606"><code>5d20596</code></a>
style(core,langchain,langchain-classic,partners): replace double
backticks in...</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/fb55c6660a2ac26038a64dac1534048294bc51ab"><code>fb55c66</code></a>
chore: bump langsmith from 0.8.9 to 0.8.14 in /libs/partners/huggingface
(<a
href="https://redirect.github.com/langchain-ai/langchain/issues/38">#38</a>...</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/51daae5c139712f6f1347b5a801f672680ba1eba"><code>51daae5</code></a>
chore: bump langsmith from 0.8.9 to 0.8.14 in /libs/partners/chroma (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/38092">#38092</a>)</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/70e9579e433043321fb8e93a8a51770c946363d0"><code>70e9579</code></a>
chore: bump langsmith from 0.8.9 to 0.8.14 in /libs/partners/fireworks
(<a
href="https://redirect.github.com/langchain-ai/langchain/issues/38093">#38093</a>)</li>
<li><a
href="https://github.com/langchain-ai/langchain/commit/6c0e9af3246e3bbf98838e4b9ec563ad563dd748"><code>6c0e9af</code></a>
chore: bump langsmith from 0.8.9 to 0.8.14 in /libs/partners/xai (<a
href="https://redirect.github.com/langchain-ai/langchain/issues/38094">#38094</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/langchain-ai/langchain/compare/langchain-anthropic==1.0.0a5...langchain-anthropic==1.4.6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=langchain-anthropic&package-manager=pip&previous-version=1.0.0a5&new-version=1.4.6)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> 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 <dependency name> 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 <dependency name>` 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 <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/langchain-ai/langgraph/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-19 10:05:18 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
e308ae99da chore(deps): bump @babel/core from 7.25.2 to 7.29.7 in /libs/cli/js-examples (#8144)
Bumps
[@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core)
from 7.25.2 to 7.29.7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/babel/babel/releases">@​babel/core's
releases</a>.</em></p>
<blockquote>
<h2>v7.29.7 (2026-05-25)</h2>
<p>Re-release all packages with npm provenance attestations</p>
<h2>v7.29.6 (2026-05-25)</h2>
<h4>🐛 Bug Fix</h4>
<ul>
<li><code>babel-generator</code>
<ul>
<li><a
href="https://redirect.github.com/babel/babel/pull/18014">#18014</a>
Catchup source map position in preserveFormat (<a
href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
<li><code>babel-core</code>
<ul>
<li><a
href="https://redirect.github.com/babel/babel/pull/18001">#18001</a>
[7.x packport]Improve input source map handling (<a
href="https://github.com/JLHwung"><code>@​JLHwung</code></a>)</li>
</ul>
</li>
<li><code>babel-core</code>, <code>babel-generator</code>
<ul>
<li><a
href="https://redirect.github.com/babel/babel/pull/17998">#17998</a>
Preserve original identifier names from input sourcemaps (<a
href="https://github.com/babel/babel/tree/HEAD/packages/babel-core/issues/17992">#17992</a>)
(<a href="https://github.com/Andarist"><code>@​Andarist</code></a>)</li>
</ul>
</li>
</ul>
<h4>Committers: 3</h4>
<ul>
<li>Huáng Jùnliàng (<a
href="https://github.com/JLHwung"><code>@​JLHwung</code></a>)</li>
<li>Mateusz Burzyński (<a
href="https://github.com/Andarist"><code>@​Andarist</code></a>)</li>
<li>Nicolò Ribaudo (<a
href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
<h2>v7.29.5 (2026-05-05)</h2>
<h4>🏠  Internal</h4>
<ul>
<li><code>babel-preset-env</code>
<ul>
<li>Update <code>@babel/*</code> dependencies</li>
</ul>
</li>
</ul>
<h2>v7.29.4 (2026-05-05)</h2>
<h4>🐛 Bug Fix</h4>
<ul>
<li><code>babel-plugin-transform-modules-systemjs</code>
<ul>
<li><a
href="https://redirect.github.com/babel/babel/pull/17974">#17974</a>
[7.x backport]fix(systemjs): improve module string name support (<a
href="https://github.com/JLHwung"><code>@​JLHwung</code></a>)</li>
</ul>
</li>
</ul>
<h4>Committers: 1</h4>
<ul>
<li>Huáng Jùnliàng (<a
href="https://github.com/JLHwung"><code>@​JLHwung</code></a>)</li>
</ul>
<h2>v7.29.3 (2026-04-30)</h2>
<h4>👓 Spec Compliance</h4>
<ul>
<li><code>babel-parser</code>
<ul>
<li><a
href="https://redirect.github.com/babel/babel/pull/17923">#17923</a>
Support flow extends bound (<a
href="https://github.com/JLHwung"><code>@​JLHwung</code></a>)</li>
</ul>
</li>
</ul>
<h4>🐛 Bug Fix</h4>
<ul>
<li><code>babel-helper-create-class-features-plugin</code>,
<code>babel-plugin-proposal-decorators</code>
<ul>
<li><a
href="https://redirect.github.com/babel/babel/pull/17931">#17931</a>
fix(decorators): replace super within all removed static elements (<a
href="https://github.com/JLHwung"><code>@​JLHwung</code></a>)</li>
</ul>
</li>
<li><code>babel-register</code>
<ul>
<li><a
href="https://redirect.github.com/babel/babel/pull/17915">#17915</a> Fix
thread synchronization issues in <code>@babel/register</code> (<a
href="https://github.com/liuxingbaoyu"><code>@​liuxingbaoyu</code></a>)</li>
</ul>
</li>
<li><code>babel-compat-data</code>,
<code>babel-plugin-bugfix-safari-rest-destructuring-rhs-array</code>,
<code>babel-preset-env</code>
<ul>
<li><a
href="https://redirect.github.com/babel/babel/pull/17788">#17788</a> Add
bugfix plugin for Safari array rest destructuring bug (<a
href="https://github.com/JLHwung"><code>@​JLHwung</code></a>)</li>
</ul>
</li>
</ul>
<h4>💅 Polish</h4>
<ul>
<li><code>babel-parser</code></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/babel/babel/commit/4fba7541180bf5f58256d8e358b544e3831ad090"><code>4fba754</code></a>
v7.29.7</li>
<li><a
href="https://github.com/babel/babel/commit/04ea6b27fdac8f40c3481aec2080ac9678779509"><code>04ea6b2</code></a>
v7.29.6</li>
<li><a
href="https://github.com/babel/babel/commit/99f498a9b9fa0b900d603fbe8f6601bb3b9e42bb"><code>99f498a</code></a>
[7.x packport]Improve input source map handling (<a
href="https://github.com/babel/babel/tree/HEAD/packages/babel-core/issues/18001">#18001</a>)</li>
<li><a
href="https://github.com/babel/babel/commit/feba0a3654c596bd369d1ef1231f5d56666d56dc"><code>feba0a3</code></a>
Preserve original identifier names from input sourcemaps (<a
href="https://github.com/babel/babel/tree/HEAD/packages/babel-core/issues/17992">#17992</a>)
(<a
href="https://github.com/babel/babel/tree/HEAD/packages/babel-core/issues/17998">#17998</a>)</li>
<li><a
href="https://github.com/babel/babel/commit/aa8394e454337d118ac3d40bfa3ee1a3cb3f3ed2"><code>aa8394e</code></a>
v7.29.0</li>
<li><a
href="https://github.com/babel/babel/commit/ad0d03f0c92404a60ec6b1c12f15febd38e2397a"><code>ad0d03f</code></a>
[7.x backport] feat: Allow specifying startLine in code frame (<a
href="https://github.com/babel/babel/tree/HEAD/packages/babel-core/issues/17739">#17739</a>)</li>
<li><a
href="https://github.com/babel/babel/commit/d7f400889567ae18ef9ac41b024b5120f6060e17"><code>d7f4008</code></a>
v7.28.6</li>
<li><a
href="https://github.com/babel/babel/commit/e130225028e93e106135586f344cfa44c4aac847"><code>e130225</code></a>
Polish(standalone): improve message on invalid preset/plugin (<a
href="https://github.com/babel/babel/tree/HEAD/packages/babel-core/issues/17606">#17606</a>)</li>
<li><a
href="https://github.com/babel/babel/commit/99dcba5e71de3bd81ce14077cfa5b6df58e9b177"><code>99dcba5</code></a>
chore: enable some ts-eslint rules (<a
href="https://github.com/babel/babel/tree/HEAD/packages/babel-core/issues/17592">#17592</a>)</li>
<li><a
href="https://github.com/babel/babel/commit/c92c4919771105140015167f25f7bacac77c90d9"><code>c92c491</code></a>
Improve Unicode handling in code-frame tokenizer (<a
href="https://github.com/babel/babel/tree/HEAD/packages/babel-core/issues/17589">#17589</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/babel/babel/commits/v7.29.7/packages/babel-core">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new
releaser for <code>@​babel/core</code> since your current version.</p>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@babel/core&package-manager=npm_and_yarn&previous-version=7.25.2&new-version=7.29.7)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-19 02:56:16 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c6eb0a2058 chore(deps): bump js-yaml from 4.1.1 to 4.2.0 in /libs/cli/js-monorepo-example (#8143)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.1 to 4.2.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md">js-yaml's
changelog</a>.</em></p>
<blockquote>
<h2>[4.2.0] - 2026-06-01</h2>
<h3>Added</h3>
<ul>
<li>Added <code>docs/safety.md</code> with notes about processing
untrusted YAML.</li>
<li>Added <code>maxDepth</code> (100) loader option. Not a problem, but
gives a better
exception instead of RangeError on stack overflow.</li>
<li>Added <code>maxMergeSeqLength</code> (20) loader option. Not a
problem after <code>merge</code> fix,
but an additional restriction for safety.</li>
<li>Added sourcemaps to <code>dist/</code> builds.</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Stop resolving numbers with underscores as numeric scalars, <a
href="https://redirect.github.com/nodeca/js-yaml/issues/627">#627</a>.</li>
<li>Switched dev toolchains to Vite / neostandard.</li>
<li>Updated demo.</li>
<li>Reorganized tests.</li>
<li><code>dist/</code> files are no longer kept in the repository.</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fix parsing of properties on the first implicit block mapping key,
<a
href="https://redirect.github.com/nodeca/js-yaml/issues/62">#62</a>.</li>
<li>Fix trailing whitespace handling when folding flow scalar lines, <a
href="https://redirect.github.com/nodeca/js-yaml/issues/307">#307</a>.</li>
<li>Reject top-level block scalars without content indentation, <a
href="https://redirect.github.com/nodeca/js-yaml/issues/280">#280</a>.</li>
<li>Ensure numbers survive round-trip, <a
href="https://redirect.github.com/nodeca/js-yaml/issues/737">#737</a>.</li>
<li>Fix test coverage for issue <a
href="https://redirect.github.com/nodeca/js-yaml/issues/221">#221</a>.</li>
<li>Fix flow scalar trailing whitespace folding, <a
href="https://redirect.github.com/nodeca/js-yaml/issues/307">#307</a>.</li>
<li>Fix digits in YAML named tag handles.</li>
</ul>
<h3>Security</h3>
<ul>
<li>Fix potential DoS via quadratic complexity in merge - deduplicate
repeated
elements (makes sense for malformed files &gt; 10K).</li>
</ul>
<h2>[3.14.2] - 2025-11-15</h2>
<h3>Security</h3>
<ul>
<li>Backported v4.1.1 fix to v3</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/nodeca/js-yaml/commits">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=js-yaml&package-manager=npm_and_yarn&previous-version=4.1.1&new-version=4.2.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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-19 02:56:06 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
db3f4d7255 chore(deps): bump bleach from 6.3.0 to 6.4.0 in /libs/langgraph (#8107)
Bumps [bleach](https://github.com/mozilla/bleach) from 6.3.0 to 6.4.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/mozilla/bleach/blob/main/CHANGES">bleach's
changelog</a>.</em></p>
<blockquote>
<h2>Version 6.4.0 (June 5th, 2026)</h2>
<p><strong>NOTE: 2026-06-05: Bleach is no longer maintained. There will
be no future
releases including for security issues.</strong>
See issue:
<code>&lt;https://github.com/mozilla/bleach/issues/698&gt;</code>__</p>
<p><strong>Backwards incompatible changes</strong></p>
<ul>
<li>Dropped support for pypy 3.10. (<a
href="https://redirect.github.com/mozilla/bleach/issues/764">#764</a>)</li>
</ul>
<p><strong>Security fixes</strong></p>
<ul>
<li>
<p>Fix bug 2023812 / GHSA-8rfp-98v4-mmr6.</p>
<p>Fix XSS issue with sanitize_uri_value where disallowed schemes with
Unicode invisible characters wouldn't be rejected.</p>
<p>For example::</p>
<p>import bleach
payload1 = '<!-- raw HTML omitted -->Click<!-- raw HTML omitted -->'
result1 = bleach.clean(payload1)
print(repr(result1))</p>
<p>outputs::</p>
<p>'<!-- raw HTML omitted -->Click<!-- raw HTML omitted -->'</p>
<p>See the advisory for details.</p>
</li>
<li>
<p>Fix GHSA-gj48-438w-jh9v.</p>
<p>Fix issue where URI sanitization wasn't happening in formaction
attributes.</p>
<p>See the advisory for details.</p>
</li>
</ul>
<p><strong>Bug fixes</strong></p>
<ul>
<li>
<p>Add support for pypy 3.11. (<a
href="https://redirect.github.com/mozilla/bleach/issues/764">#764</a>)</p>
</li>
<li>
<p>Drop version max in tinycss2 pin. (<a
href="https://redirect.github.com/mozilla/bleach/issues/772">#772</a>)</p>
<p>This removes one of the things we had to keep checking and updating.
Users
now own the responsibility for correctness with the version of tinycss2
they're using.</p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/mozilla/bleach/commit/f0355a7af00500482c5292c6c83290c6a178068d"><code>f0355a7</code></a>
fix: fix last release date in CHANGES</li>
<li><a
href="https://github.com/mozilla/bleach/commit/ae4e8a26706516ad01b92e66321b480208a440da"><code>ae4e8a2</code></a>
chore: bleach 6.4.0 and final release</li>
<li><a
href="https://github.com/mozilla/bleach/commit/970df58e9f0c55cc52244f3f0106e473a40d886d"><code>970df58</code></a>
fix: uri-sanitization in formaction attributes</li>
<li><a
href="https://github.com/mozilla/bleach/commit/7c4867c32344d1c961107fae62240a6f0dc680dc"><code>7c4867c</code></a>
fix: xss bypass in allowed protocol test using unicode invisible
characters</li>
<li><a
href="https://github.com/mozilla/bleach/commit/913ab75992b845e2c9c060c41f24d46921db4693"><code>913ab75</code></a>
fix: reduce redundancy in workflow jobs</li>
<li><a
href="https://github.com/mozilla/bleach/commit/218c15af455c8dec14f98fcb2e235f8680e93930"><code>218c15a</code></a>
fix: rework pip caching</li>
<li><a
href="https://github.com/mozilla/bleach/commit/4f0b097bf80548a022050e2f71f024d755a9f154"><code>4f0b097</code></a>
fix: fix tox platform restrictions</li>
<li><a
href="https://github.com/mozilla/bleach/commit/e95a79d07bb5d792425c2bc0ef5dd03f6614f3bb"><code>e95a79d</code></a>
chore: update pytest</li>
<li><a
href="https://github.com/mozilla/bleach/commit/91539d4e80d4685b8f2bedc79076ff0ff6c1b911"><code>91539d4</code></a>
Bump actions/cache from 5.0.3 to 5.0.4</li>
<li><a
href="https://github.com/mozilla/bleach/commit/cd47b4ce495859065da23c2116f651e591e1e90d"><code>cd47b4c</code></a>
fix: handle left-angle-bracket that's not a tag (<a
href="https://redirect.github.com/mozilla/bleach/issues/733">#733</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/mozilla/bleach/compare/v6.3.0...v6.4.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=bleach&package-manager=uv&previous-version=6.3.0&new-version=6.4.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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-19 08:34:16 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
4401ae03e0 chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /libs/langgraph (#8106)
Bumps [cryptography](https://github.com/pyca/cryptography) from 46.0.7
to 48.0.1.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst">cryptography's
changelog</a>.</em></p>
<blockquote>
<p>48.0.1 - 2026-06-09</p>
<pre><code>
* Updated Windows, macOS, and Linux wheels to be compiled with OpenSSL
4.0.1.
<p>.. _v48-0-0:</p>
<p>48.0.0 - 2026-05-04<br />
</code></pre></p>
<ul>
<li>
<p><strong>BACKWARDS INCOMPATIBLE:</strong> Support for Python 3.8 has
been removed.
<code>cryptography</code> now requires Python 3.9 or later.</p>
</li>
<li>
<p><strong>BACKWARDS INCOMPATIBLE:</strong> Loading an X.509 CRL whose
inner
<code>TBSCertList.signature</code> algorithm does not match the outer
<code>signatureAlgorithm</code> now raises <code>ValueError</code>.
Previously, such CRLs
were parsed successfully and only rejected during signature
validation.</p>
</li>
<li>
<p>Added support for
:doc:<code>/hazmat/primitives/asymmetric/mlkem</code> and
:doc:<code>/hazmat/primitives/asymmetric/mldsa</code> when using OpenSSL
3.5.0 or
later, in addition to the existing AWS-LC and BoringSSL support. This
means
post-quantum algorithms are now available to users of our wheels.</p>
<ul>
<li><strong>Note:</strong> Going forward, we do not guarantee that all
functionality
in <code>cryptography</code> will be available when building against
OpenSSL. See :doc:<code>/statements/state-of-openssl</code> for more
information.</li>
</ul>
</li>
</ul>
<p>.. _v47-0-0:</p>
<p>47.0.0 - 2026-04-24</p>
<pre><code>
* Support for Python 3.8 is deprecated and will be removed in the next
  ``cryptography`` release.
* **BACKWARDS INCOMPATIBLE:** Support for binary elliptic curves
  (``SECT*`` classes) has been removed. These curves are rarely used and
  have additional security considerations that make them undesirable.
* **BACKWARDS INCOMPATIBLE:** Support for OpenSSL 1.1.x has been
removed.
OpenSSL 3.0.0 or later is now required. LibreSSL, BoringSSL, and AWS-LC
  continue to be supported.
* **BACKWARDS INCOMPATIBLE:** Dropped support for LibreSSL &lt; 4.1.
* **BACKWARDS INCOMPATIBLE:** Loading keys with unsupported algorithms
or
  keys with unsupported explicit curve encodings now raises
  :class:`~cryptography.exceptions.UnsupportedAlgorithm` instead of
  ``ValueError``. This change affects

:func:`~cryptography.hazmat.primitives.serialization.load_pem_private_key`,

:func:`~cryptography.hazmat.primitives.serialization.load_der_private_key`,

:func:`~cryptography.hazmat.primitives.serialization.load_pem_public_key`,

:func:`~cryptography.hazmat.primitives.serialization.load_der_public_key`,
  and :meth:`~cryptography.x509.Certificate.public_key` when called on
  certificates with unsupported public key algorithms.
&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/pyca/cryptography/commit/de987ce48ccfeb1abca41efa23b2bf73ec704f74"><code>de987ce</code></a>
48.0.1 version bump and changelog (<a
href="https://redirect.github.com/pyca/cryptography/issues/14996">#14996</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/8e03e30e3aae01632a697e903e3593c924f0139d"><code>8e03e30</code></a>
bump for 48.0.0 release (<a
href="https://redirect.github.com/pyca/cryptography/issues/14796">#14796</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/295e0d254ef31ab864730aa41312ec355416ee71"><code>295e0d2</code></a>
Add AGENTS.md with CLAUDE.md symlink (<a
href="https://redirect.github.com/pyca/cryptography/issues/14794">#14794</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/104a2de19e268a433e6da92be9cb872dcf0003c8"><code>104a2de</code></a>
Bump BoringSSL, OpenSSL, AWS-LC in CI (<a
href="https://redirect.github.com/pyca/cryptography/issues/14793">#14793</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/67ec1e51988195e17993d2edef5258b27509b926"><code>67ec1e5</code></a>
call check_length early on AesSiv::encrypt (<a
href="https://redirect.github.com/pyca/cryptography/issues/14792">#14792</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/b2da57a0d9e4bfd2b95364299091a18f74127b26"><code>b2da57a</code></a>
changelog for mldsa/mlkem for openssl (<a
href="https://redirect.github.com/pyca/cryptography/issues/14791">#14791</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/3cf44adee25c368d4a136e072fa9f80465d91eb0"><code>3cf44ad</code></a>
ML-KEM OpenSSL support (<a
href="https://redirect.github.com/pyca/cryptography/issues/14781">#14781</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/2e31639666766f846fbab2c605879db0fa64fe83"><code>2e31639</code></a>
ML-DSA OpenSSL support (<a
href="https://redirect.github.com/pyca/cryptography/issues/14773">#14773</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/5affe5a286a986fdf512c4a5cb280d28a96c10e3"><code>5affe5a</code></a>
fix rust nightly clippy (<a
href="https://redirect.github.com/pyca/cryptography/issues/14790">#14790</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/2e73ca448eaf64b6f0d4ffbb794cf96170cef5ec"><code>2e73ca4</code></a>
bump rust-openssl dep and update EcPoint::mul_generator to
mul_generator2 (<a
href="https://redirect.github.com/pyca/cryptography/issues/1">#1</a>...</li>
<li>Additional commits viewable in <a
href="https://github.com/pyca/cryptography/compare/46.0.7...48.0.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=cryptography&package-manager=uv&previous-version=46.0.7&new-version=48.0.1)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-19 08:33:28 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
871d6fc804 chore(deps): bump cryptography from 46.0.7 to 48.0.1 in /libs/cli (#8103)
Bumps [cryptography](https://github.com/pyca/cryptography) from 46.0.7
to 48.0.1.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst">cryptography's
changelog</a>.</em></p>
<blockquote>
<p>48.0.1 - 2026-06-09</p>
<pre><code>
* Updated Windows, macOS, and Linux wheels to be compiled with OpenSSL
4.0.1.
<p>.. _v48-0-0:</p>
<p>48.0.0 - 2026-05-04<br />
</code></pre></p>
<ul>
<li>
<p><strong>BACKWARDS INCOMPATIBLE:</strong> Support for Python 3.8 has
been removed.
<code>cryptography</code> now requires Python 3.9 or later.</p>
</li>
<li>
<p><strong>BACKWARDS INCOMPATIBLE:</strong> Loading an X.509 CRL whose
inner
<code>TBSCertList.signature</code> algorithm does not match the outer
<code>signatureAlgorithm</code> now raises <code>ValueError</code>.
Previously, such CRLs
were parsed successfully and only rejected during signature
validation.</p>
</li>
<li>
<p>Added support for
:doc:<code>/hazmat/primitives/asymmetric/mlkem</code> and
:doc:<code>/hazmat/primitives/asymmetric/mldsa</code> when using OpenSSL
3.5.0 or
later, in addition to the existing AWS-LC and BoringSSL support. This
means
post-quantum algorithms are now available to users of our wheels.</p>
<ul>
<li><strong>Note:</strong> Going forward, we do not guarantee that all
functionality
in <code>cryptography</code> will be available when building against
OpenSSL. See :doc:<code>/statements/state-of-openssl</code> for more
information.</li>
</ul>
</li>
</ul>
<p>.. _v47-0-0:</p>
<p>47.0.0 - 2026-04-24</p>
<pre><code>
* Support for Python 3.8 is deprecated and will be removed in the next
  ``cryptography`` release.
* **BACKWARDS INCOMPATIBLE:** Support for binary elliptic curves
  (``SECT*`` classes) has been removed. These curves are rarely used and
  have additional security considerations that make them undesirable.
* **BACKWARDS INCOMPATIBLE:** Support for OpenSSL 1.1.x has been
removed.
OpenSSL 3.0.0 or later is now required. LibreSSL, BoringSSL, and AWS-LC
  continue to be supported.
* **BACKWARDS INCOMPATIBLE:** Dropped support for LibreSSL &lt; 4.1.
* **BACKWARDS INCOMPATIBLE:** Loading keys with unsupported algorithms
or
  keys with unsupported explicit curve encodings now raises
  :class:`~cryptography.exceptions.UnsupportedAlgorithm` instead of
  ``ValueError``. This change affects

:func:`~cryptography.hazmat.primitives.serialization.load_pem_private_key`,

:func:`~cryptography.hazmat.primitives.serialization.load_der_private_key`,

:func:`~cryptography.hazmat.primitives.serialization.load_pem_public_key`,

:func:`~cryptography.hazmat.primitives.serialization.load_der_public_key`,
  and :meth:`~cryptography.x509.Certificate.public_key` when called on
  certificates with unsupported public key algorithms.
&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/pyca/cryptography/commit/de987ce48ccfeb1abca41efa23b2bf73ec704f74"><code>de987ce</code></a>
48.0.1 version bump and changelog (<a
href="https://redirect.github.com/pyca/cryptography/issues/14996">#14996</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/8e03e30e3aae01632a697e903e3593c924f0139d"><code>8e03e30</code></a>
bump for 48.0.0 release (<a
href="https://redirect.github.com/pyca/cryptography/issues/14796">#14796</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/295e0d254ef31ab864730aa41312ec355416ee71"><code>295e0d2</code></a>
Add AGENTS.md with CLAUDE.md symlink (<a
href="https://redirect.github.com/pyca/cryptography/issues/14794">#14794</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/104a2de19e268a433e6da92be9cb872dcf0003c8"><code>104a2de</code></a>
Bump BoringSSL, OpenSSL, AWS-LC in CI (<a
href="https://redirect.github.com/pyca/cryptography/issues/14793">#14793</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/67ec1e51988195e17993d2edef5258b27509b926"><code>67ec1e5</code></a>
call check_length early on AesSiv::encrypt (<a
href="https://redirect.github.com/pyca/cryptography/issues/14792">#14792</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/b2da57a0d9e4bfd2b95364299091a18f74127b26"><code>b2da57a</code></a>
changelog for mldsa/mlkem for openssl (<a
href="https://redirect.github.com/pyca/cryptography/issues/14791">#14791</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/3cf44adee25c368d4a136e072fa9f80465d91eb0"><code>3cf44ad</code></a>
ML-KEM OpenSSL support (<a
href="https://redirect.github.com/pyca/cryptography/issues/14781">#14781</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/2e31639666766f846fbab2c605879db0fa64fe83"><code>2e31639</code></a>
ML-DSA OpenSSL support (<a
href="https://redirect.github.com/pyca/cryptography/issues/14773">#14773</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/5affe5a286a986fdf512c4a5cb280d28a96c10e3"><code>5affe5a</code></a>
fix rust nightly clippy (<a
href="https://redirect.github.com/pyca/cryptography/issues/14790">#14790</a>)</li>
<li><a
href="https://github.com/pyca/cryptography/commit/2e73ca448eaf64b6f0d4ffbb794cf96170cef5ec"><code>2e73ca4</code></a>
bump rust-openssl dep and update EcPoint::mul_generator to
mul_generator2 (<a
href="https://redirect.github.com/pyca/cryptography/issues/1">#1</a>...</li>
<li>Additional commits viewable in <a
href="https://github.com/pyca/cryptography/compare/46.0.7...48.0.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=cryptography&package-manager=uv&previous-version=46.0.7&new-version=48.0.1)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-19 08:32:58 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
b42e83780f chore(deps): bump pyjwt from 2.12.1 to 2.13.0 in /libs/cli (#8093)
Bumps [pyjwt](https://github.com/jpadilla/pyjwt) from 2.12.1 to 2.13.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/jpadilla/pyjwt/releases">pyjwt's
releases</a>.</em></p>
<blockquote>
<h2>2.13.0</h2>
<h1>PyJWT 2.13.0 — Security Release</h1>
<p>This release bundles five security fixes plus three additional
hardening / spec-compliance changes. We recommend all users upgrade.</p>
<h2>Security</h2>
<ul>
<li>
<p><strong><a
href="https://github.com/jpadilla/pyjwt/security/advisories/GHSA-xgmm-8j9v-c9wx"><code>GHSA-xgmm-8j9v-c9wx</code></a>
— JWK JSON accepted as HMAC secret (algorithm confusion).</strong>
<code>HMACAlgorithm.prepare_key</code> previously rejected PEM- and
SSH-formatted asymmetric keys but did not catch a JWK passed as a raw
JSON string. In a verifier configured with both symmetric and asymmetric
algorithms in <code>algorithms=[…]</code> and a raw-JSON JWK as the key,
an attacker could forge HS256 tokens using the JWK text as the HMAC
secret. The guard has been extended to reject any JWK-shaped JSON.
<em>Reported by <a
href="https://github.com/aradona91"><code>@​aradona91</code></a>.</em></p>
</li>
<li>
<p><strong><a
href="https://github.com/jpadilla/pyjwt/security/advisories/GHSA-jq35-7prp-9v3f"><code>GHSA-jq35-7prp-9v3f</code></a>
— Algorithm allow-list bypass with <code>PyJWK</code> /
<code>PyJWKClient</code>.</strong> When verifying with a
<code>PyJWK</code>, the caller's <code>algorithms=[…]</code> allow-list
was checked against the token header <code>alg</code> as a string only;
actual verification used the algorithm bound to the <code>PyJWK</code>.
An attacker who controlled a registered JWKS key could sign with one
algorithm and advertise another on the header. PyJWT now requires the
token header <code>alg</code> to match the <code>PyJWK</code>'s
algorithm before verification. <em>Reported by <a
href="https://github.com/sushi-gif"><code>@​sushi-gif</code></a>.</em></p>
</li>
<li>
<p><strong><a
href="https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w7vc-732c-9m39"><code>GHSA-w7vc-732c-9m39</code></a>
— DoS via base64 decode of unused payload segment when
<code>b64=false</code>.</strong> For detached-payload JWS
(<code>b64=false</code>), the compact-form payload segment was
base64-decoded before being discarded in favor of the caller-supplied
<code>detached_payload</code>. An attacker could inflate the unused
segment to force CPU + memory cost without holding a valid signature.
The segment is now required to be empty per RFC 7515 Appendix F, and is
no longer decoded. <em>Reported by <a
href="https://github.com/thesmartshadow"><code>@​thesmartshadow</code></a>.</em></p>
</li>
<li>
<p><strong><a
href="https://github.com/jpadilla/pyjwt/security/advisories/GHSA-993g-76c3-p5m4"><code>GHSA-993g-76c3-p5m4</code></a>
— <code>PyJWKClient</code> accepts non-HTTP(S) URIs.</strong>
<code>PyJWKClient.fetch_data</code> passed its URI to
<code>urllib.request.urlopen</code>, which by default also handles
<code>file://</code>, <code>ftp://</code>, and <code>data:</code>
schemes. An application that fed an attacker-influenced URI into
<code>PyJWKClient</code> could be coerced into reading local files or
reaching other unintended schemes. <code>PyJWKClient</code> now rejects
any URI whose scheme isn't <code>http</code> or <code>https</code>.
<em>Reported by <a
href="https://github.com/KEIJOT"><code>@​KEIJOT</code></a>.</em></p>
</li>
<li>
<p><strong><a
href="https://github.com/jpadilla/pyjwt/security/advisories/GHSA-fhv5-28vv-h8m8"><code>GHSA-fhv5-28vv-h8m8</code></a>
— <code>PyJWKClient</code> cache wiped on fetch error.</strong> A
<code>finally</code>-block <code>put(jwk_set=None)</code> cleared the
JWK Set cache whenever a fetch raised, turning a transient JWKS-endpoint
outage into application-wide auth failure. The cache write was moved
into the success path; transient errors no longer evict valid cached
keys. <em>Reported by <a
href="https://github.com/eddieran"><code>@​eddieran</code></a>.</em></p>
</li>
</ul>
<h2>Fixed</h2>
<ul>
<li>Reject empty HMAC keys outright in
<code>HMACAlgorithm.prepare_key</code> with <code>InvalidKeyError</code>
instead of accepting them with only a warning. Defends against the
<code>os.getenv(&quot;JWT_SECRET&quot;, &quot;&quot;)</code> footgun.
<em>Thanks to <a
href="https://github.com/SnailSploit"><code>@​SnailSploit</code></a> and
<a href="https://github.com/spartan8806"><code>@​spartan8806</code></a>
for the reports.</em></li>
<li>Forward per-call <code>options</code> (including
<code>enforce_minimum_key_length</code>) from <code>PyJWT.decode</code>
through to <code>PyJWS._verify_signature</code>. The option was
previously silently dropped between the two layers, so it only took
effect when set on the <code>PyJWT</code> instance. <em>Thanks to <a
href="https://github.com/WLUB"><code>@​WLUB</code></a> for the
report.</em></li>
<li><strong>RFC 7797 §3 compliance for <code>b64=false</code>:</strong>
the encoder now auto-adds <code>&quot;b64&quot;</code> to
<code>crit</code>, and the decoder rejects tokens that set
<code>b64=false</code> without listing it in <code>crit</code>.
<em>Thanks to <a
href="https://github.com/MachineLearning-Nerd"><code>@​MachineLearning-Nerd</code></a>
for the report.</em></li>
</ul>
<h2>Changed</h2>
<ul>
<li>Migrate the <code>dev</code>, <code>docs</code>, and
<code>tests</code> package extras to dependency groups, by <a
href="https://github.com/kurtmckee"><code>@​kurtmckee</code></a> in <a
href="https://redirect.github.com/jpadilla/pyjwt/pull/1152">#1152</a>.</li>
</ul>
<h2>Upgrade notes</h2>
<p>Most fixes are invisible to correctly-configured callers. A few
behavioral changes you may encounter:</p>
<ul>
<li><strong>Empty HMAC keys now raise.</strong> If your app passed
<code>&quot;&quot;</code> or <code>b&quot;&quot;</code> as a secret
(often via a missing env var, e.g.
<code>os.getenv(&quot;JWT_SECRET&quot;, &quot;&quot;)</code>),
<code>encode</code>/<code>decode</code> will now raise
<code>InvalidKeyError</code>. This is the intended behavior — fix the
configuration.</li>
<li><strong><code>PyJWK</code> decoding now requires the token's
<code>alg</code> to match the JWK's algorithm.</strong> Previously a
mismatch was silently honored if the header <code>alg</code> appeared in
the allow-list. Tokens that relied on this mismatch will now fail with
<code>InvalidAlgorithmError</code>.</li>
<li><strong><code>PyJWKClient</code> now rejects non-HTTP(S) URIs at
construction time.</strong> Tests or dev environments that fetched JWKS
from <code>file://</code> URIs need to switch to a local HTTP server or
load the JWKS by other means (e.g. construct
<code>PyJWKSet.from_dict(...)</code> directly).</li>
<li><strong><code>b64=false</code> tokens are now strictly RFC 7515 /
7797 compliant.</strong> Tokens with a non-empty compact-form payload
segment, or that omit <code>&quot;b64&quot;</code> from
<code>crit</code>, will be rejected. PyJWT-produced tokens always
satisfy both invariants, so round-trips through PyJWT are
unaffected.</li>
<li><strong><code>enforce_minimum_key_length</code> set per-call now
takes effect.</strong> Callers who passed
<code>options={&quot;enforce_minimum_key_length&quot;: True}</code> to
<code>jwt.decode()</code> previously got no enforcement; they will now
get <code>InvalidKeyError</code> on undersized keys, as documented.</li>
</ul>
<p><strong>Full changelog:</strong> <a
href="https://github.com/jpadilla/pyjwt/compare/2.12.1...2.13.0">https://github.com/jpadilla/pyjwt/compare/2.12.1...2.13.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst">pyjwt's
changelog</a>.</em></p>
<blockquote>
<h2><code>v2.13.0
&lt;https://github.com/jpadilla/pyjwt/compare/2.12.1...2.13.0&gt;</code>__</h2>
<p>Security</p>
<pre><code>
- Reject JWK JSON documents passed as raw HMAC secrets in
  ``HMACAlgorithm.prepare_key`` to close an algorithm-confusion gap that
  the existing PEM/SSH guard did not cover. Reported by @aradona91 in
`GHSA-xgmm-8j9v-c9wx
&lt;https://github.com/jpadilla/pyjwt/security/advisories/GHSA-xgmm-8j9v-c9wx&gt;`__.
- Bind the JWT header ``alg`` to ``PyJWK.algorithm_name`` during
  verification so the caller's ``algorithms=[...]`` allow-list cannot be
bypassed when decoding with a ``PyJWK`` / ``PyJWKClient`` key. Reported
by @sushi-gif in `GHSA-jq35-7prp-9v3f
&lt;https://github.com/jpadilla/pyjwt/security/advisories/GHSA-jq35-7prp-9v3f&gt;`__.
- Reject non-``http(s)`` URI schemes in ``PyJWKClient`` so attacker-
influenced URIs cannot read local files or reach unintended schemes via
urllib's default ``file://`` / ``ftp://`` / ``data:`` handlers. Reported
by @KEIJOT in `GHSA-993g-76c3-p5m4
&lt;https://github.com/jpadilla/pyjwt/security/advisories/GHSA-993g-76c3-p5m4&gt;`__.
- Preserve the cached JWK Set on fetch errors in
``PyJWKClient.fetch_data``.
  The previous ``finally``-block ``put(None)`` pattern cleared the cache
on any transient outage, turning one bad JWKS request into application-
wide auth failure. Reported by @eddieran in `GHSA-fhv5-28vv-h8m8
&lt;https://github.com/jpadilla/pyjwt/security/advisories/GHSA-fhv5-28vv-h8m8&gt;`__.
- Skip the unconditional base64 decode of the compact-form payload
segment
  when ``b64=false`` is set in the protected header, and require that
  segment to be empty (RFC 7515 Appendix F detached form). Closes an
  unauthenticated DoS amplifier. Reported by @thesmartshadow in
`GHSA-w7vc-732c-9m39
&lt;https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w7vc-732c-9m39&gt;`__.
<p>Fixed</p>
<pre><code>
- Reject empty HMAC keys outright in ``HMACAlgorithm.prepare_key`` with
  ``InvalidKeyError`` instead of accepting them with only a warning.
  Thanks to @SnailSploit and @spartan8806 for independently flagging the
  footgun.
- Forward per-call ``options`` (including
``enforce_minimum_key_length``)
  from ``PyJWT.decode`` through to ``PyJWS._verify_signature`` so the
option actually takes effect when set at the call site rather than only
  on the ``PyJWT`` instance. Thanks to @WLUB for the report.
- RFC 7797 §3 compliance for ``b64=false``: the encoder now auto-adds
``&amp;quot;b64&amp;quot;`` to the ``crit`` header parameter, and the
decoder rejects
tokens that set ``b64=false`` without listing it in ``crit``. Thanks to
  @MachineLearning-Nerd for the report.

Changed
</code></pre>
<ul>
<li>Migrate the <code>dev</code>, <code>docs</code>, and
<code>tests</code> package extras to dependency groups by <a
href="https://github.com/kurtmckee"><code>@​kurtmckee</code></a> in
<code>[#1152](https://github.com/jpadilla/pyjwt/issues/1152)
&amp;lt;https://github.com/jpadilla/pyjwt/pull/1152&amp;gt;</code>__
</code></pre></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/7144e4534c34810f4525dc4578a32addd8212cff"><code>7144e45</code></a>
Apply ruff format</li>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/d2f4bec4963897c0ef96ef64a875894f2c8542ab"><code>d2f4bec</code></a>
Restore <code>cast()</code> calls with cross-version <code>type:
ignore</code> for <code>prepare_key</code></li>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/22f478cebddd8294259c30f037ecb92b0b348774"><code>22f478c</code></a>
Remove redundant casts in <code>RSAAlgorithm.prepare_key</code> and
`ECAlgorithm.prepare...</li>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/95791b1759b8aa4f2203575d344d5c78564cdc81"><code>95791b1</code></a>
Bundle security fixes and hardening into 2.13.0</li>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/dcc27a9d3182a2349c30b160758785c6ce7a6508"><code>dcc27a9</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/jpadilla/pyjwt/issues/1155">#1155</a>)</li>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/9d08a9a1896845ed8eaf88e6f6ac61e5800c3e7a"><code>9d08a9a</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/jpadilla/pyjwt/issues/1146">#1146</a>)</li>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/b87c10014d4109f0214fea188d00faaaf8a80e64"><code>b87c100</code></a>
Bump codecov/codecov-action from 5 to 6 (<a
href="https://redirect.github.com/jpadilla/pyjwt/issues/1154">#1154</a>)</li>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/40e3147eb5f790d8d041772e5fc00728a176c812"><code>40e3147</code></a>
Migrate development extras to dependency groups (<a
href="https://redirect.github.com/jpadilla/pyjwt/issues/1152">#1152</a>)</li>
<li>See full diff in <a
href="https://github.com/jpadilla/pyjwt/compare/2.12.1...2.13.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=pyjwt&package-manager=uv&previous-version=2.12.1&new-version=2.13.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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-19 08:32:37 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
587daa31d9 chore(deps): bump jupyter-server from 2.18.0 to 2.20.0 in /libs/langgraph (#8134)
Bumps [jupyter-server](https://github.com/jupyter-server/jupyter_server)
from 2.18.0 to 2.20.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/jupyter-server/jupyter_server/releases">jupyter-server's
releases</a>.</em></p>
<blockquote>
<h2>v2.20.0</h2>
<h2>2.20.0</h2>
<p>(<a
href="https://github.com/jupyter-server/jupyter_server/compare/v2.19.0...333e700119ee0bcc0b5fcd4c158213d7c275c778">Full
Changelog</a>)</p>
<h3>Security fixes</h3>
<ul>
<li>CVE-2026-44727 <a
href="https://github.com/jupyter-server/jupyter_server/security/advisories/GHSA-fcw5-x6j4-ccmp">GHSA-fcw5-x6j4-ccmp</a></li>
</ul>
<h3>Enhancements made</h3>
<ul>
<li>Fix confusing terminal output when using ServerApp.ip=0.0.0.0 <a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1643">#1643</a>
(<a href="https://github.com/Yann-P"><code>@​Yann-P</code></a>, <a
href="https://github.com/minrk"><code>@​minrk</code></a>)</li>
<li>Add a toggle to enable curve encryption for all kernels that support
it <a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1638">#1638</a>
(<a href="https://github.com/krassowski"><code>@​krassowski</code></a>,
<a href="https://github.com/Carreau"><code>@​Carreau</code></a>, <a
href="https://github.com/ianthomas23"><code>@​ianthomas23</code></a>, <a
href="https://github.com/minrk"><code>@​minrk</code></a>)</li>
</ul>
<h3>Bugs fixed</h3>
<ul>
<li>Grab the port from <code>bind_sockets</code> in case its different
<a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1651">#1651</a>
(<a href="https://github.com/choldgraf"><code>@​choldgraf</code></a>, <a
href="https://github.com/krassowski"><code>@​krassowski</code></a>)</li>
</ul>
<h3>Maintenance and upkeep improvements</h3>
<ul>
<li>Fix <code>test_authorizer</code> having a spurious comma in params
<a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1664">#1664</a>
(<a
href="https://github.com/krassowski"><code>@​krassowski</code></a>)</li>
<li>Add a reminder to merge GHSA before release <a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1659">#1659</a>
(<a href="https://github.com/Yann-P"><code>@​Yann-P</code></a>, <a
href="https://github.com/Carreau"><code>@​Carreau</code></a>)</li>
<li>Exclude problematic <code>pywinpty</code> 3.0.4 version <a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1658">#1658</a>
(<a
href="https://github.com/krassowski"><code>@​krassowski</code></a>)</li>
<li>ci: explicitly pass base-setup inputs to fix strict validation
failures <a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1626">#1626</a>
(<a href="https://github.com/Carreau"><code>@​Carreau</code></a>, <a
href="https://github.com/Copilot"><code>@​Copilot</code></a>)</li>
</ul>
<h3>Documentation improvements</h3>
<ul>
<li>Align docs for curve encryption with latest JEP version <a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1660">#1660</a>
(<a href="https://github.com/krassowski"><code>@​krassowski</code></a>,
<a href="https://github.com/Carreau"><code>@​Carreau</code></a>)</li>
<li>Remove PGP key from docs <a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1653">#1653</a>
(<a href="https://github.com/Yann-P"><code>@​Yann-P</code></a>, <a
href="https://github.com/krassowski"><code>@​krassowski</code></a>)</li>
</ul>
<h3>Contributors to this release</h3>
<p>The following people contributed discussions, new ideas, code and
documentation contributions, and review.
See <a
href="https://github-activity.readthedocs.io/en/latest/use/#how-does-this-tool-define-contributions-in-the-reports">our
definition of contributors</a>.</p>
<p>(<a
href="https://github.com/jupyter-server/jupyter_server/graphs/contributors?from=2026-05-29&amp;to=2026-06-17&amp;type=c">GitHub
contributors page for this release</a>)</p>
<p><a href="https://github.com/Carreau"><code>@​Carreau</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3ACarreau+updated%3A2026-05-29..2026-06-17&amp;type=Issues">activity</a>)
| <a href="https://github.com/choldgraf"><code>@​choldgraf</code></a>
(<a
href="https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Acholdgraf+updated%3A2026-05-29..2026-06-17&amp;type=Issues">activity</a>)
| <a href="https://github.com/Copilot"><code>@​Copilot</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3ACopilot+updated%3A2026-05-29..2026-06-17&amp;type=Issues">activity</a>)
| <a
href="https://github.com/ianthomas23"><code>@​ianthomas23</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Aianthomas23+updated%3A2026-05-29..2026-06-17&amp;type=Issues">activity</a>)
| <a href="https://github.com/krassowski"><code>@​krassowski</code></a>
(<a
href="https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Akrassowski+updated%3A2026-05-29..2026-06-17&amp;type=Issues">activity</a>)
| <a href="https://github.com/minrk"><code>@​minrk</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Aminrk+updated%3A2026-05-29..2026-06-17&amp;type=Issues">activity</a>)
| <a href="https://github.com/Yann-P"><code>@​Yann-P</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3AYann-P+updated%3A2026-05-29..2026-06-17&amp;type=Issues">activity</a>)</p>
<h2>v2.19.0</h2>
<h2>2.19.0</h2>
<p>(<a
href="https://github.com/jupyter-server/jupyter_server/compare/v2.18.2...664e2255c71efe963f397b9f803dbcf503b5a920">Full
Changelog</a>)</p>
<h3>Enhancements made</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/jupyter-server/jupyter_server/blob/main/CHANGELOG.md">jupyter-server's
changelog</a>.</em></p>
<blockquote>
<h2>2.20.0</h2>
<p>(<a
href="https://github.com/jupyter-server/jupyter_server/compare/v2.19.0...333e700119ee0bcc0b5fcd4c158213d7c275c778">Full
Changelog</a>)</p>
<h3>Enhancements made</h3>
<ul>
<li>Fix confusing terminal output when using ServerApp.ip=0.0.0.0 <a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1643">#1643</a>
(<a href="https://github.com/Yann-P"><code>@​Yann-P</code></a>, <a
href="https://github.com/minrk"><code>@​minrk</code></a>)</li>
<li>Add a toggle to enable curve encryption for all kernels that support
it <a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1638">#1638</a>
(<a href="https://github.com/krassowski"><code>@​krassowski</code></a>,
<a href="https://github.com/Carreau"><code>@​Carreau</code></a>, <a
href="https://github.com/ianthomas23"><code>@​ianthomas23</code></a>, <a
href="https://github.com/minrk"><code>@​minrk</code></a>)</li>
</ul>
<h3>Bugs fixed</h3>
<ul>
<li>Grab the port from <code>bind_sockets</code> in case its different
<a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1651">#1651</a>
(<a href="https://github.com/choldgraf"><code>@​choldgraf</code></a>, <a
href="https://github.com/krassowski"><code>@​krassowski</code></a>)</li>
</ul>
<h3>Maintenance and upkeep improvements</h3>
<ul>
<li>Fix <code>test_authorizer</code> having a spurious comma in params
<a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1664">#1664</a>
(<a
href="https://github.com/krassowski"><code>@​krassowski</code></a>)</li>
<li>Add a reminder to merge GHSA before release <a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1659">#1659</a>
(<a href="https://github.com/Yann-P"><code>@​Yann-P</code></a>, <a
href="https://github.com/Carreau"><code>@​Carreau</code></a>)</li>
<li>Exclude problematic <code>pywinpty</code> 3.0.4 version <a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1658">#1658</a>
(<a
href="https://github.com/krassowski"><code>@​krassowski</code></a>)</li>
<li>ci: explicitly pass base-setup inputs to fix strict validation
failures <a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1626">#1626</a>
(<a href="https://github.com/Carreau"><code>@​Carreau</code></a>, <a
href="https://github.com/Copilot"><code>@​Copilot</code></a>)</li>
</ul>
<h3>Documentation improvements</h3>
<ul>
<li>Align docs for curve encryption with latest JEP version <a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1660">#1660</a>
(<a href="https://github.com/krassowski"><code>@​krassowski</code></a>,
<a href="https://github.com/Carreau"><code>@​Carreau</code></a>)</li>
<li>Remove PGP key from docs <a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1653">#1653</a>
(<a href="https://github.com/Yann-P"><code>@​Yann-P</code></a>, <a
href="https://github.com/krassowski"><code>@​krassowski</code></a>)</li>
</ul>
<h3>Contributors to this release</h3>
<p>The following people contributed discussions, new ideas, code and
documentation contributions, and review.
See <a
href="https://github-activity.readthedocs.io/en/latest/use/#how-does-this-tool-define-contributions-in-the-reports">our
definition of contributors</a>.</p>
<p>(<a
href="https://github.com/jupyter-server/jupyter_server/graphs/contributors?from=2026-05-29&amp;to=2026-06-17&amp;type=c">GitHub
contributors page for this release</a>)</p>
<p><a href="https://github.com/Carreau"><code>@​Carreau</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3ACarreau+updated%3A2026-05-29..2026-06-17&amp;type=Issues">activity</a>)
| <a href="https://github.com/choldgraf"><code>@​choldgraf</code></a>
(<a
href="https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Acholdgraf+updated%3A2026-05-29..2026-06-17&amp;type=Issues">activity</a>)
| <a href="https://github.com/Copilot"><code>@​Copilot</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3ACopilot+updated%3A2026-05-29..2026-06-17&amp;type=Issues">activity</a>)
| <a
href="https://github.com/ianthomas23"><code>@​ianthomas23</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Aianthomas23+updated%3A2026-05-29..2026-06-17&amp;type=Issues">activity</a>)
| <a href="https://github.com/krassowski"><code>@​krassowski</code></a>
(<a
href="https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Akrassowski+updated%3A2026-05-29..2026-06-17&amp;type=Issues">activity</a>)
| <a href="https://github.com/minrk"><code>@​minrk</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Aminrk+updated%3A2026-05-29..2026-06-17&amp;type=Issues">activity</a>)
| <a href="https://github.com/Yann-P"><code>@​Yann-P</code></a> (<a
href="https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3AYann-P+updated%3A2026-05-29..2026-06-17&amp;type=Issues">activity</a>)</p>
<!-- raw HTML omitted -->
<h2>2.19.0</h2>
<p>(<a
href="https://github.com/jupyter-server/jupyter_server/compare/v2.18.2...664e2255c71efe963f397b9f803dbcf503b5a920">Full
Changelog</a>)</p>
<h3>Enhancements made</h3>
<ul>
<li>Return <code>unresolved</code> stanza when kernel scope is
unavailable for <code>resolvePath</code> (instead of failing with 404)
<a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1641">#1641</a>
(<a href="https://github.com/MUFFANUJ"><code>@​MUFFANUJ</code></a>, <a
href="https://github.com/Carreau"><code>@​Carreau</code></a>, <a
href="https://github.com/krassowski"><code>@​krassowski</code></a>)</li>
</ul>
<h3>Bugs fixed</h3>
<ul>
<li>Recreate notary store on failure to prevent save deadlock and data
loss <a
href="https://redirect.github.com/jupyter-server/jupyter_server/pull/1640">#1640</a>
(<a href="https://github.com/krassowski"><code>@​krassowski</code></a>,
<a href="https://github.com/Carreau"><code>@​Carreau</code></a>)</li>
</ul>
<h3>Maintenance and upkeep improvements</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/jupyter-server/jupyter_server/commit/05a78ad879e69ef87e91b2714a8ebeb5ff9628a7"><code>05a78ad</code></a>
Publish 2.20.0</li>
<li><a
href="https://github.com/jupyter-server/jupyter_server/commit/6cbee8d65e71abac851c4492fea987ad080580bd"><code>6cbee8d</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/jupyter-server/jupyter_server/commit/333e700119ee0bcc0b5fcd4c158213d7c275c778"><code>333e700</code></a>
Fix <code>test_authorizer</code> having a spurious comma in params (<a
href="https://redirect.github.com/jupyter-server/jupyter_server/issues/1664">#1664</a>)</li>
<li><a
href="https://github.com/jupyter-server/jupyter_server/commit/cccd543352d9be0365de56627b671cc8aa9cab0c"><code>cccd543</code></a>
Fix CI: explicitly pass base-setup inputs to avoid strict validation
failures</li>
<li><a
href="https://github.com/jupyter-server/jupyter_server/commit/cd16d715dfb1f84b2e5056317927fc930b811842"><code>cd16d71</code></a>
Align docs for curve encryption with latest JEP version (<a
href="https://redirect.github.com/jupyter-server/jupyter_server/issues/1660">#1660</a>)</li>
<li><a
href="https://github.com/jupyter-server/jupyter_server/commit/e458061e6ee50368bbdb74153092fc8400704ee0"><code>e458061</code></a>
Add a toggle to enable curve encryption for all kernels that support it
(<a
href="https://redirect.github.com/jupyter-server/jupyter_server/issues/1638">#1638</a>)</li>
<li><a
href="https://github.com/jupyter-server/jupyter_server/commit/0ceeb4fb61be1deaaa7c1ff01325f7dd47db1c46"><code>0ceeb4f</code></a>
Add note in RELEASE.md</li>
<li><a
href="https://github.com/jupyter-server/jupyter_server/commit/b13f8a241b1111e402457e1d0b1cce252d8e1e5e"><code>b13f8a2</code></a>
Markdown does not work.</li>
<li><a
href="https://github.com/jupyter-server/jupyter_server/commit/e885b10a26c11caf109007a901153d1ac373c14d"><code>e885b10</code></a>
Add GHSA reminder in prep-release</li>
<li><a
href="https://github.com/jupyter-server/jupyter_server/commit/0e28c901e8bc0953d61611fe8cb018460433288f"><code>0e28c90</code></a>
Exclude problematic <code>pywinpty</code> 3.0.4 version (<a
href="https://redirect.github.com/jupyter-server/jupyter_server/issues/1658">#1658</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/jupyter-server/jupyter_server/compare/v2.18.0...v2.20.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=jupyter-server&package-manager=uv&previous-version=2.18.0&new-version=2.20.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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-19 01:28:49 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
510d943362 chore(deps): bump tornado from 6.5.6 to 6.5.7 in /libs/langgraph (#8108)
Bumps [tornado](https://github.com/tornadoweb/tornado) from 6.5.6 to
6.5.7.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/tornadoweb/tornado/blob/master/docs/releases.rst">tornado's
changelog</a>.</em></p>
<blockquote>
<h1>Release notes</h1>
<p>.. toctree::
:maxdepth: 2</p>
<p>releases/v6.5.7
releases/v6.5.6
releases/v6.5.5
releases/v6.5.4
releases/v6.5.3
releases/v6.5.2
releases/v6.5.1
releases/v6.5.0
releases/v6.4.2
releases/v6.4.1
releases/v6.4.0
releases/v6.3.3
releases/v6.3.2
releases/v6.3.1
releases/v6.3.0
releases/v6.2.0
releases/v6.1.0
releases/v6.0.4
releases/v6.0.3
releases/v6.0.2
releases/v6.0.1
releases/v6.0.0
releases/v5.1.1
releases/v5.1.0
releases/v5.0.2
releases/v5.0.1
releases/v5.0.0
releases/v4.5.3
releases/v4.5.2
releases/v4.5.1
releases/v4.5.0
releases/v4.4.3
releases/v4.4.2
releases/v4.4.1
releases/v4.4.0
releases/v4.3.0
releases/v4.2.1
releases/v4.2.0
releases/v4.1.0
releases/v4.0.2
releases/v4.0.1
releases/v4.0.0
releases/v3.2.2
releases/v3.2.1</p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tornadoweb/tornado/commit/48fc2d43d1f48b8b3b0be5dcf6a7634c6f45b1c4"><code>48fc2d4</code></a>
Merge pull request <a
href="https://redirect.github.com/tornadoweb/tornado/issues/3633">#3633</a>
from bdarnell/curl-reset-65</li>
<li><a
href="https://github.com/tornadoweb/tornado/commit/4ae1ddd14245e56e9fb6fb14d4b9508301fbb841"><code>4ae1ddd</code></a>
Release notes and version bump for 6.5.7</li>
<li><a
href="https://github.com/tornadoweb/tornado/commit/3154caabc9a60cb0b6953d28877b2785fbd3ab43"><code>3154caa</code></a>
curl_httpclient: Reset the curl object before putting it on the
freelist</li>
<li><a
href="https://github.com/tornadoweb/tornado/commit/7d869c0739b264797ef92b6aa4a80c54b5993ea2"><code>7d869c0</code></a>
Merge pull request <a
href="https://redirect.github.com/tornadoweb/tornado/issues/3631">#3631</a>
from bdarnell/cve-links</li>
<li><a
href="https://github.com/tornadoweb/tornado/commit/288241f6812bb7204984573e55de21d17af951f3"><code>288241f</code></a>
docs: Use the correct link syntax</li>
<li><a
href="https://github.com/tornadoweb/tornado/commit/8da981c0f614f63d9d3b2cd5017db2b40e5642f6"><code>8da981c</code></a>
docs: Add CVE links to 6.5.6 release notes</li>
<li>See full diff in <a
href="https://github.com/tornadoweb/tornado/compare/v6.5.6...v6.5.7">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tornado&package-manager=uv&previous-version=6.5.6&new-version=6.5.7)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-19 01:28:38 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
a4157ef280 chore(deps): bump pyjwt from 2.12.0 to 2.13.0 in /libs/langgraph (#8092)
Bumps [pyjwt](https://github.com/jpadilla/pyjwt) from 2.12.0 to 2.13.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/jpadilla/pyjwt/releases">pyjwt's
releases</a>.</em></p>
<blockquote>
<h2>2.13.0</h2>
<h1>PyJWT 2.13.0 — Security Release</h1>
<p>This release bundles five security fixes plus three additional
hardening / spec-compliance changes. We recommend all users upgrade.</p>
<h2>Security</h2>
<ul>
<li>
<p><strong><a
href="https://github.com/jpadilla/pyjwt/security/advisories/GHSA-xgmm-8j9v-c9wx"><code>GHSA-xgmm-8j9v-c9wx</code></a>
— JWK JSON accepted as HMAC secret (algorithm confusion).</strong>
<code>HMACAlgorithm.prepare_key</code> previously rejected PEM- and
SSH-formatted asymmetric keys but did not catch a JWK passed as a raw
JSON string. In a verifier configured with both symmetric and asymmetric
algorithms in <code>algorithms=[…]</code> and a raw-JSON JWK as the key,
an attacker could forge HS256 tokens using the JWK text as the HMAC
secret. The guard has been extended to reject any JWK-shaped JSON.
<em>Reported by <a
href="https://github.com/aradona91"><code>@​aradona91</code></a>.</em></p>
</li>
<li>
<p><strong><a
href="https://github.com/jpadilla/pyjwt/security/advisories/GHSA-jq35-7prp-9v3f"><code>GHSA-jq35-7prp-9v3f</code></a>
— Algorithm allow-list bypass with <code>PyJWK</code> /
<code>PyJWKClient</code>.</strong> When verifying with a
<code>PyJWK</code>, the caller's <code>algorithms=[…]</code> allow-list
was checked against the token header <code>alg</code> as a string only;
actual verification used the algorithm bound to the <code>PyJWK</code>.
An attacker who controlled a registered JWKS key could sign with one
algorithm and advertise another on the header. PyJWT now requires the
token header <code>alg</code> to match the <code>PyJWK</code>'s
algorithm before verification. <em>Reported by <a
href="https://github.com/sushi-gif"><code>@​sushi-gif</code></a>.</em></p>
</li>
<li>
<p><strong><a
href="https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w7vc-732c-9m39"><code>GHSA-w7vc-732c-9m39</code></a>
— DoS via base64 decode of unused payload segment when
<code>b64=false</code>.</strong> For detached-payload JWS
(<code>b64=false</code>), the compact-form payload segment was
base64-decoded before being discarded in favor of the caller-supplied
<code>detached_payload</code>. An attacker could inflate the unused
segment to force CPU + memory cost without holding a valid signature.
The segment is now required to be empty per RFC 7515 Appendix F, and is
no longer decoded. <em>Reported by <a
href="https://github.com/thesmartshadow"><code>@​thesmartshadow</code></a>.</em></p>
</li>
<li>
<p><strong><a
href="https://github.com/jpadilla/pyjwt/security/advisories/GHSA-993g-76c3-p5m4"><code>GHSA-993g-76c3-p5m4</code></a>
— <code>PyJWKClient</code> accepts non-HTTP(S) URIs.</strong>
<code>PyJWKClient.fetch_data</code> passed its URI to
<code>urllib.request.urlopen</code>, which by default also handles
<code>file://</code>, <code>ftp://</code>, and <code>data:</code>
schemes. An application that fed an attacker-influenced URI into
<code>PyJWKClient</code> could be coerced into reading local files or
reaching other unintended schemes. <code>PyJWKClient</code> now rejects
any URI whose scheme isn't <code>http</code> or <code>https</code>.
<em>Reported by <a
href="https://github.com/KEIJOT"><code>@​KEIJOT</code></a>.</em></p>
</li>
<li>
<p><strong><a
href="https://github.com/jpadilla/pyjwt/security/advisories/GHSA-fhv5-28vv-h8m8"><code>GHSA-fhv5-28vv-h8m8</code></a>
— <code>PyJWKClient</code> cache wiped on fetch error.</strong> A
<code>finally</code>-block <code>put(jwk_set=None)</code> cleared the
JWK Set cache whenever a fetch raised, turning a transient JWKS-endpoint
outage into application-wide auth failure. The cache write was moved
into the success path; transient errors no longer evict valid cached
keys. <em>Reported by <a
href="https://github.com/eddieran"><code>@​eddieran</code></a>.</em></p>
</li>
</ul>
<h2>Fixed</h2>
<ul>
<li>Reject empty HMAC keys outright in
<code>HMACAlgorithm.prepare_key</code> with <code>InvalidKeyError</code>
instead of accepting them with only a warning. Defends against the
<code>os.getenv(&quot;JWT_SECRET&quot;, &quot;&quot;)</code> footgun.
<em>Thanks to <a
href="https://github.com/SnailSploit"><code>@​SnailSploit</code></a> and
<a href="https://github.com/spartan8806"><code>@​spartan8806</code></a>
for the reports.</em></li>
<li>Forward per-call <code>options</code> (including
<code>enforce_minimum_key_length</code>) from <code>PyJWT.decode</code>
through to <code>PyJWS._verify_signature</code>. The option was
previously silently dropped between the two layers, so it only took
effect when set on the <code>PyJWT</code> instance. <em>Thanks to <a
href="https://github.com/WLUB"><code>@​WLUB</code></a> for the
report.</em></li>
<li><strong>RFC 7797 §3 compliance for <code>b64=false</code>:</strong>
the encoder now auto-adds <code>&quot;b64&quot;</code> to
<code>crit</code>, and the decoder rejects tokens that set
<code>b64=false</code> without listing it in <code>crit</code>.
<em>Thanks to <a
href="https://github.com/MachineLearning-Nerd"><code>@​MachineLearning-Nerd</code></a>
for the report.</em></li>
</ul>
<h2>Changed</h2>
<ul>
<li>Migrate the <code>dev</code>, <code>docs</code>, and
<code>tests</code> package extras to dependency groups, by <a
href="https://github.com/kurtmckee"><code>@​kurtmckee</code></a> in <a
href="https://redirect.github.com/jpadilla/pyjwt/pull/1152">#1152</a>.</li>
</ul>
<h2>Upgrade notes</h2>
<p>Most fixes are invisible to correctly-configured callers. A few
behavioral changes you may encounter:</p>
<ul>
<li><strong>Empty HMAC keys now raise.</strong> If your app passed
<code>&quot;&quot;</code> or <code>b&quot;&quot;</code> as a secret
(often via a missing env var, e.g.
<code>os.getenv(&quot;JWT_SECRET&quot;, &quot;&quot;)</code>),
<code>encode</code>/<code>decode</code> will now raise
<code>InvalidKeyError</code>. This is the intended behavior — fix the
configuration.</li>
<li><strong><code>PyJWK</code> decoding now requires the token's
<code>alg</code> to match the JWK's algorithm.</strong> Previously a
mismatch was silently honored if the header <code>alg</code> appeared in
the allow-list. Tokens that relied on this mismatch will now fail with
<code>InvalidAlgorithmError</code>.</li>
<li><strong><code>PyJWKClient</code> now rejects non-HTTP(S) URIs at
construction time.</strong> Tests or dev environments that fetched JWKS
from <code>file://</code> URIs need to switch to a local HTTP server or
load the JWKS by other means (e.g. construct
<code>PyJWKSet.from_dict(...)</code> directly).</li>
<li><strong><code>b64=false</code> tokens are now strictly RFC 7515 /
7797 compliant.</strong> Tokens with a non-empty compact-form payload
segment, or that omit <code>&quot;b64&quot;</code> from
<code>crit</code>, will be rejected. PyJWT-produced tokens always
satisfy both invariants, so round-trips through PyJWT are
unaffected.</li>
<li><strong><code>enforce_minimum_key_length</code> set per-call now
takes effect.</strong> Callers who passed
<code>options={&quot;enforce_minimum_key_length&quot;: True}</code> to
<code>jwt.decode()</code> previously got no enforcement; they will now
get <code>InvalidKeyError</code> on undersized keys, as documented.</li>
</ul>
<p><strong>Full changelog:</strong> <a
href="https://github.com/jpadilla/pyjwt/compare/2.12.1...2.13.0">https://github.com/jpadilla/pyjwt/compare/2.12.1...2.13.0</a></p>
<h2>2.12.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Add typing_extensions dependency for Python &lt; 3.11 by <a
href="https://github.com/jpadilla"><code>@​jpadilla</code></a> in <a
href="https://redirect.github.com/jpadilla/pyjwt/pull/1151">jpadilla/pyjwt#1151</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/jpadilla/pyjwt/compare/2.12.0...2.12.1">https://github.com/jpadilla/pyjwt/compare/2.12.0...2.12.1</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst">pyjwt's
changelog</a>.</em></p>
<blockquote>
<h2><code>v2.13.0
&lt;https://github.com/jpadilla/pyjwt/compare/2.12.1...2.13.0&gt;</code>__</h2>
<p>Security</p>
<pre><code>
- Reject JWK JSON documents passed as raw HMAC secrets in
  ``HMACAlgorithm.prepare_key`` to close an algorithm-confusion gap that
  the existing PEM/SSH guard did not cover. Reported by @aradona91 in
`GHSA-xgmm-8j9v-c9wx
&lt;https://github.com/jpadilla/pyjwt/security/advisories/GHSA-xgmm-8j9v-c9wx&gt;`__.
- Bind the JWT header ``alg`` to ``PyJWK.algorithm_name`` during
  verification so the caller's ``algorithms=[...]`` allow-list cannot be
bypassed when decoding with a ``PyJWK`` / ``PyJWKClient`` key. Reported
by @sushi-gif in `GHSA-jq35-7prp-9v3f
&lt;https://github.com/jpadilla/pyjwt/security/advisories/GHSA-jq35-7prp-9v3f&gt;`__.
- Reject non-``http(s)`` URI schemes in ``PyJWKClient`` so attacker-
influenced URIs cannot read local files or reach unintended schemes via
urllib's default ``file://`` / ``ftp://`` / ``data:`` handlers. Reported
by @KEIJOT in `GHSA-993g-76c3-p5m4
&lt;https://github.com/jpadilla/pyjwt/security/advisories/GHSA-993g-76c3-p5m4&gt;`__.
- Preserve the cached JWK Set on fetch errors in
``PyJWKClient.fetch_data``.
  The previous ``finally``-block ``put(None)`` pattern cleared the cache
on any transient outage, turning one bad JWKS request into application-
wide auth failure. Reported by @eddieran in `GHSA-fhv5-28vv-h8m8
&lt;https://github.com/jpadilla/pyjwt/security/advisories/GHSA-fhv5-28vv-h8m8&gt;`__.
- Skip the unconditional base64 decode of the compact-form payload
segment
  when ``b64=false`` is set in the protected header, and require that
  segment to be empty (RFC 7515 Appendix F detached form). Closes an
  unauthenticated DoS amplifier. Reported by @thesmartshadow in
`GHSA-w7vc-732c-9m39
&lt;https://github.com/jpadilla/pyjwt/security/advisories/GHSA-w7vc-732c-9m39&gt;`__.
<p>Fixed</p>
<pre><code>
- Reject empty HMAC keys outright in ``HMACAlgorithm.prepare_key`` with
  ``InvalidKeyError`` instead of accepting them with only a warning.
  Thanks to @SnailSploit and @spartan8806 for independently flagging the
  footgun.
- Forward per-call ``options`` (including
``enforce_minimum_key_length``)
  from ``PyJWT.decode`` through to ``PyJWS._verify_signature`` so the
option actually takes effect when set at the call site rather than only
  on the ``PyJWT`` instance. Thanks to @WLUB for the report.
- RFC 7797 §3 compliance for ``b64=false``: the encoder now auto-adds
``&amp;quot;b64&amp;quot;`` to the ``crit`` header parameter, and the
decoder rejects
tokens that set ``b64=false`` without listing it in ``crit``. Thanks to
  @MachineLearning-Nerd for the report.

Changed
</code></pre>
<ul>
<li>Migrate the <code>dev</code>, <code>docs</code>, and
<code>tests</code> package extras to dependency groups by <a
href="https://github.com/kurtmckee"><code>@​kurtmckee</code></a> in
<code>[#1152](https://github.com/jpadilla/pyjwt/issues/1152)
&amp;lt;https://github.com/jpadilla/pyjwt/pull/1152&amp;gt;</code>__</li>
</ul>
<p><code>v2.12.1
&amp;lt;https://github.com/jpadilla/pyjwt/compare/2.12.0...2.12.1&amp;gt;</code>__
&lt;/tr&gt;&lt;/table&gt;
</code></pre></p>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/7144e4534c34810f4525dc4578a32addd8212cff"><code>7144e45</code></a>
Apply ruff format</li>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/d2f4bec4963897c0ef96ef64a875894f2c8542ab"><code>d2f4bec</code></a>
Restore <code>cast()</code> calls with cross-version <code>type:
ignore</code> for <code>prepare_key</code></li>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/22f478cebddd8294259c30f037ecb92b0b348774"><code>22f478c</code></a>
Remove redundant casts in <code>RSAAlgorithm.prepare_key</code> and
`ECAlgorithm.prepare...</li>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/95791b1759b8aa4f2203575d344d5c78564cdc81"><code>95791b1</code></a>
Bundle security fixes and hardening into 2.13.0</li>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/dcc27a9d3182a2349c30b160758785c6ce7a6508"><code>dcc27a9</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/jpadilla/pyjwt/issues/1155">#1155</a>)</li>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/9d08a9a1896845ed8eaf88e6f6ac61e5800c3e7a"><code>9d08a9a</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/jpadilla/pyjwt/issues/1146">#1146</a>)</li>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/b87c10014d4109f0214fea188d00faaaf8a80e64"><code>b87c100</code></a>
Bump codecov/codecov-action from 5 to 6 (<a
href="https://redirect.github.com/jpadilla/pyjwt/issues/1154">#1154</a>)</li>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/40e3147eb5f790d8d041772e5fc00728a176c812"><code>40e3147</code></a>
Migrate development extras to dependency groups (<a
href="https://redirect.github.com/jpadilla/pyjwt/issues/1152">#1152</a>)</li>
<li><a
href="https://github.com/jpadilla/pyjwt/commit/a4e1a3d1218b01c5806420b8f16d9308ac4adc30"><code>a4e1a3d</code></a>
Add typing_extensions dependency for Python &lt; 3.11 (<a
href="https://redirect.github.com/jpadilla/pyjwt/issues/1151">#1151</a>)</li>
<li>See full diff in <a
href="https://github.com/jpadilla/pyjwt/compare/2.12.0...2.13.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=pyjwt&package-manager=uv&previous-version=2.12.0&new-version=2.13.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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-19 01:25:58 -07:00
Nick HollonandGitHub ce6c8b2410 release(langgraph): 1.2.6 (#8139) 2026-06-18 16:53:47 -04:00
Quanzheng LongandGitHub 9100f2c682 feat: add delta-channel-dump recovery script as examples to dump from Postgres for deltaChannel rollback (#8109)
Add a standalone recovery tool at `examples/delta-channel-dump/` for
operators rolling back from langgraph >= 1.2 / deepagents 0.6.x to an
older runtime that does not understand `EXT_DELTA_SNAPSHOT` msgpack
blobs. Without this, channels like `messages` can appear empty after
rollback because the old reducer does not decode delta snapshots.

`dump.py` connects directly to Postgres, walks the checkpoint parent
chain (mirroring `aget_delta_channel_history`), decodes msgpack blobs
via `ormsgpack` with a hand-rolled EXT 0–7 hook (no langgraph imports),
and emits JSON with per-channel `seed` + oldest-to-newest `writes`. The
operator reduces and re-applies via `update_state` manually.

## Scope

- Postgres checkpointer only
- Deps: `psycopg[binary]`, `ormsgpack` (not added to repo
`pyproject.toml` — operator installs at runtime)
- No reducer application, no DB writes, no AES/custom encryption support
(fails loudly on encrypted blob types)

## How verified

- E2E against local Postgres: 15 runs of `delta_channel_messages_freq`
(`snapshot_frequency=10`)
- Asserted `delta_kind == "snapshot"`, `len(seed) == 10`, `len(writes)
== 5`, message ids `ai-0`..`ai-14`
- Confirmed portability: fresh venv with only `pip install
"psycopg[binary]" ormsgpack` produced identical output
2026-06-17 10:50:30 -07:00
Nick HollonGitHubNick Hollonopen-swe[bot] <open-swe@users.noreply.github.com>
79befe67ba fix: nested subgraph inherits parent checkpoint_ns (regression in 1.2.3) (#8053)
Closes #8038

## Description

The `ensure_config` merge introduced in #7926 caused a child graph
invoked inside a parent node to inherit the parent task's
`checkpoint_ns` from the ambient run context
(`var_child_runnable_config`), so the child's checkpoints were written
under an unreadable namespace and re-ran from scratch each turn (#8038).
The first explicitly passed `configurable` that carries a checkpoint
coordinate (a `thread_id`, or any
`checkpoint_ns`/`checkpoint_id`/`checkpoint_map`) now replaces the
ambient one, while subsequent explicit configs still shallow-merge —
preserving #7926's `with_config(...)` semantics.

## Contract

`ensure_config` merges an explicit `configurable` over the ambient run
context (`var_child_runnable_config`) with one rule: **an explicit
`configurable` that supplies its own checkpoint coordinate addresses its
own checkpoint lineage, so the ambient `configurable` is dropped rather
than merged over.** Coordinate keys are `thread_id`, `checkpoint_ns`,
`checkpoint_id`, and `checkpoint_map` (grouped as
`_CHECKPOINT_COORDINATE_KEYS`). A non-coordinate `configurable` keeps
the ambient and shallow-merges over it.

Below, each case shows the parent/child graph wiring that triggers it
and the resulting namespacing. The child is always a compiled subgraph
invoked from inside a parent node.

### 1. Subgraph invoked with no new config → ambient inherited

```python
child = StateGraph(ChildState).add_node("n", child_node).add_edge(START, "n").compile(checkpointer=checkpointer)

def parent_node(state):
    child.invoke({}, config=None)          # no explicit configurable
    return {"result": "ok"}

parent = StateGraph(ParentState).add_node("p", parent_node).add_edge(START, "p").compile(checkpointer=checkpointer)
parent.invoke({"result": ""}, config={"configurable": {"thread_id": "parent"}})
```
Child inherits the parent task's `checkpoint_ns` (`p:<parent-task>`);
its checkpoints are written as a discoverable child of the parent run.
Pre-#7926 behavior, unchanged.

### 2. Subgraph invoked with a new thread_id → ambient dropped

```python
child = StateGraph(ChildState).add_node("n", child_node).add_edge(START, "n").compile(checkpointer=checkpointer)
child_config = {"configurable": {"thread_id": str(uuid4())}}

def parent_node(state):
    child.invoke({}, config=child_config)  # explicit new thread_id
    return {"result": "ok"}

parent = StateGraph(ParentState).add_node("p", parent_node).add_edge(START, "p").compile(checkpointer=checkpointer)
parent.invoke({"result": ""}, config={"configurable": {"thread_id": "parent"}})
```
Child starts its own lineage on `child_config`'s thread; `checkpoint_ns
== ""`; `child.get_state(child_config)` reads back state across repeated
parent turns. Fixes #8038.

### 3. Subgraph invoked with the same thread_id as parent → ambient
still dropped

```python
child = StateGraph(ChildState).add_node("n", child_node).add_edge(START, "n").compile(checkpointer=checkpointer)

def parent_node(state):
    # reuses the parent's thread_id as the child's own
    child.invoke({}, config={"configurable": {"thread_id": state["parent_thread"]}})
    return {"result": "ok"}

parent = StateGraph(ParentState).add_node("p", parent_node).add_edge(START, "p").compile(checkpointer=checkpointer)
parent_thread = str(uuid4())
parent.invoke({"parent_thread": parent_thread, "result": ""}, config={"configurable": {"thread_id": parent_thread}})
```
Child addresses its own root namespace on the shared thread;
`checkpoint_ns == ""`. The parent task's `checkpoint_ns` must not leak
in, or `child.get_state({"configurable": {"thread_id": parent_thread}})`
returns empty state and the child re-runs from scratch each turn.

### 4. Subagent invoked with a non-coordinate key only → ambient
inherited

```python
child = StateGraph(ChildState).add_node("n", child_node).add_edge(START, "n").compile(checkpointer=checkpointer)

def parent_node(state):
    # ls_agent_type is not a checkpoint coordinate, so ambient is kept
    child.invoke({}, config={"configurable": {"ls_agent_type": "subagent"}})
    return {"result": "ok"}

parent = StateGraph(ParentState).add_node("p", parent_node).add_edge(START, "p").compile(checkpointer=checkpointer)
parent.invoke({"result": ""}, config={"configurable": {"thread_id": "parent"}})
```
Child remains a discoverable child of the parent run; ambient
`thread_id` and `checkpoint_ns` preserved (deepagents `task` tool
pattern).

### 5. with_config(...) + invoke-time thread_id → ambient dropped, then
merged

```python
# child compiled with a non-coordinate configurable via with_config
child = (
    StateGraph(ChildState)
    .add_node("n", child_node)
    .add_edge(START, "n")
    .compile(checkpointer=checkpointer)
    .with_config({"configurable": {"ls_agent_type": "root"}})
)

def parent_node(state):
    # invoke-time config supplies the thread_id; with_config's ls_agent_type survives
    child.invoke({}, config={"configurable": {"thread_id": "child"}})
    return {"result": "ok"}

parent = StateGraph(ParentState).add_node("p", parent_node).add_edge(START, "p").compile(checkpointer=checkpointer)
parent.invoke({"result": ""}, config={"configurable": {"thread_id": "parent"}})
```
First coordinate-bearing config (`thread_id`) drops the ambient;
subsequent explicit configs still shallow-merge, so `ls_agent_type`
survives alongside `thread_id`. Preserves #7926 `with_config(...)`
semantics.

### Regression note

Cases 1, 4, and 5 are the pre-#7926 behavior and are preserved
unchanged. Cases 2 and 3 fix the regression introduced by #7926: an
explicit `thread_id` resets the ambient even when it equals the ambient
thread id, because a child reusing the parent's thread id still
addresses its own root namespace on that thread, not the parent task's.

## Self-Hosted Release Note
Fix regression where a nested subgraph with its own `thread_id` invoked
inside a parent node lost its persisted state across turns.

## Test Plan
- [x] `pytest tests/test_subgraph_persistence.py -k
test_child_with_own_thread_id_keeps_namespace` (case 2)
- [x] `pytest tests/test_utils.py -k
ensure_config_explicit_configurable_replaces_ambient` (case 2)
- [x] `pytest tests/test_utils.py -k
ensure_config_ambient_inherited_when_no_explicit_configurable` (case 1)
- [x] `pytest tests/test_utils.py -k
ensure_config_non_coordinate_config_keeps_ambient_checkpoint_ns` (case
4)
- [x] `pytest tests/test_utils.py -k
ensure_config_explicit_configurables_still_merge_over_ambient` (case 5)
- [x] `pytest tests/test_utils.py -k
ensure_config_same_thread_id_still_clears_ambient` (case 3)

Made by [Open SWE](https://openswe.vercel.app)

---------

Co-authored-by: Nick Hollon <274035459+nick-hollon-lc@users.noreply.github.com>
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-17 10:29:31 -04:00
Nick HollonGitHubNick Hollonopen-swe[bot] <open-swe@users.noreply.github.com>
9af25217c3 fix: cancel running subgraphs on v3 stream abort [closes #8029] (#8057)
## Description
v3 event streaming's `stream.abort()` (sync and async) only closed the
mux and stopped pumping, leaving the underlying `astream`/`stream`
generator — and any running subgraphs — alive until they finished,
burning resources. The fix closes the underlying graph iterator so
`GeneratorExit` propagates into in-flight nodes/subgraphs and cancels
them, matching v2's `aclose()` behavior. Fixes #8029.

## Release Note
v3 streaming `stream.abort()` now cancels running subgraphs instead of
letting them run to completion.

## Test Plan
- [x] `TEST="tests/test_pregel_stream_events_v3.py -k abort" make test`
(new `test_abort_cancels_running_subgraph` asserts the looping subgraph
stops after abort)

Made by [Open SWE](https://openswe.vercel.app)

---------

Co-authored-by: Nick Hollon <274035459+nick-hollon-lc@users.noreply.github.com>
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-17 09:40:05 -04:00
Connor BraaandGitHub 1a9baae959 release(cli): 0.4.30 (#8101)
Bump langgraph-cli to 0.4.30 to cut a CLI release from
916025d2f6.

Also change the in-memory extra to require langgraph-api <0.12.0,
excluding 0.12.0.dev releases from normal pip resolution.

Refresh uv example lockfiles so they keep langchain-protocol compatible
with the stable API image used by CLI integration tests.

CI will verify the release change.
2026-06-16 12:43:04 -07:00
Connor BraaandGitHub 916025d2f6 feat(cli): support compatible api version ranges (#8023)
Adds `api_version` ranges for LangGraph API base image tags.
`~=0.11.0.dev5` resolves to the newest matching compatible image while
freezing later dev prereleases until rc/final/patch tags exist;
`>~=0.11.0.dev5` uses the same floor but can also float to future stable
releases while ignoring future prereleases.

Verified with `make format`, `make lint`, and `make test` from
`libs/cli`.

---------

Signed-off-by: Connor Braa <cwlbraa@langchain.dev>
2026-06-15 20:24:31 -04:00
Mason DaughertyandGitHub 97320843fe ci(deps): pin GitHub Actions to commit SHAs (#8065)
Every third-party GitHub Action in the workflows is now pinned to a full
commit SHA instead of a floating major tag, closing a supply-chain gap
where a mutable tag like `@v6` could be force-pushed to point at
malicious code. Seven actions were already SHA-pinned; this brings the
remaining first-party `actions/*` and `astral-sh/setup-uv` references in
line.

## Changes
- Pinned all previously tag-referenced actions to their current commit
SHA with the exact release as a trailing comment (the format Dependabot
reads and updates): `actions/checkout` → `v6.0.3`,
`actions/setup-python` → `v6.2.0`, `actions/github-script` → `v9.0.0`,
`actions/upload-artifact` → `v7.0.1`, `actions/download-artifact` →
`v8.0.1`, `actions/cache/{restore,save}` → `v5.0.5`,
`actions/configure-pages` → `v6.0.0`, `actions/deploy-pages` → `v5.0.0`,
`actions/upload-pages-artifact` → `v5.0.0`,
`actions/create-github-app-token` → `v3.2.0`, and `astral-sh/setup-uv` →
`v7.6.0`.
- Applied across all workflow files plus the `uv_setup` composite
action; local same-repo references (`./.github/workflows/_*.yml`,
`./.github/actions/uv_setup`) left as path refs since they resolve from
the same commit.
2026-06-12 21:29:40 -04:00
Mason DaughertyandGitHub 8558481859 docs: standardize package README.md structure (#8064)
Aligns the repository's package READMEs around a shared documentation
shape so users see consistent install, positioning, docs, release, and
contribution guidance across LangGraph packages.
2026-06-12 19:32:10 -04:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
4cf120df49 chore(deps): bump tornado from 6.5.5 to 6.5.6 in /libs/langgraph (#8063)
Bumps [tornado](https://github.com/tornadoweb/tornado) from 6.5.5 to
6.5.6.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/tornadoweb/tornado/blob/master/docs/releases.rst">tornado's
changelog</a>.</em></p>
<blockquote>
<h1>Release notes</h1>
<p>.. toctree::
:maxdepth: 2</p>
<p>releases/v6.5.7
releases/v6.5.6
releases/v6.5.5
releases/v6.5.4
releases/v6.5.3
releases/v6.5.2
releases/v6.5.1
releases/v6.5.0
releases/v6.4.2
releases/v6.4.1
releases/v6.4.0
releases/v6.3.3
releases/v6.3.2
releases/v6.3.1
releases/v6.3.0
releases/v6.2.0
releases/v6.1.0
releases/v6.0.4
releases/v6.0.3
releases/v6.0.2
releases/v6.0.1
releases/v6.0.0
releases/v5.1.1
releases/v5.1.0
releases/v5.0.2
releases/v5.0.1
releases/v5.0.0
releases/v4.5.3
releases/v4.5.2
releases/v4.5.1
releases/v4.5.0
releases/v4.4.3
releases/v4.4.2
releases/v4.4.1
releases/v4.4.0
releases/v4.3.0
releases/v4.2.1
releases/v4.2.0
releases/v4.1.0
releases/v4.0.2
releases/v4.0.1
releases/v4.0.0
releases/v3.2.2
releases/v3.2.1</p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/tornadoweb/tornado/commit/aba2569f7ed7a6bdbef816658fb6b7182531b751"><code>aba2569</code></a>
Merge pull request <a
href="https://redirect.github.com/tornadoweb/tornado/issues/3626">#3626</a>
from bdarnell/fixes-656</li>
<li><a
href="https://github.com/tornadoweb/tornado/commit/a24b260e0d22fd48acea1a2635526c1700e7ac09"><code>a24b260</code></a>
httpclient_test: Accept an additional error message variant</li>
<li><a
href="https://github.com/tornadoweb/tornado/commit/a74240a70268fe5cb40a127951cb21549ab9ff24"><code>a74240a</code></a>
Release notes and version bump for 6.5.6.</li>
<li><a
href="https://github.com/tornadoweb/tornado/commit/e8fc7edb238f1022e39f9d0b9d297fc7c21fb0a5"><code>e8fc7ed</code></a>
simple_httpclient: Strip auth headers on cross-origin redirects</li>
<li><a
href="https://github.com/tornadoweb/tornado/commit/96dc88c2a05705287856b2cd6b4b4034f9a6aaac"><code>96dc88c</code></a>
speedups: validate mask length</li>
<li><a
href="https://github.com/tornadoweb/tornado/commit/ff808b33adc52d89a549376a5e3628e92abbc8ff"><code>ff808b3</code></a>
http1connection: Enforce max_body_size in _GzipMessageDelegate</li>
<li><a
href="https://github.com/tornadoweb/tornado/commit/ede4e37f93c1edbc0bf749e9a57c9db2501cd54b"><code>ede4e37</code></a>
auth: Correctly parse check_authentication response</li>
<li><a
href="https://github.com/tornadoweb/tornado/commit/1c178bef88bbd29907eb94a2a649a4a6675681de"><code>1c178be</code></a>
Remove obsolete curl force_timeout workaround</li>
<li><a
href="https://github.com/tornadoweb/tornado/commit/c99d55bb6cc0c9da2c6696545ed4ee1d20b7fcf0"><code>c99d55b</code></a>
Replace deprecated pycurl IOCTLFUNCTION callback with SEEKFUNCTION</li>
<li><a
href="https://github.com/tornadoweb/tornado/commit/27614316ef8ad125fe18725cf96e384560ba0e14"><code>2761431</code></a>
Merge pull request <a
href="https://redirect.github.com/tornadoweb/tornado/issues/3587">#3587</a>
from bdarnell/fix-link</li>
<li>Additional commits viewable in <a
href="https://github.com/tornadoweb/tornado/compare/v6.5.5...v6.5.6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tornado&package-manager=uv&previous-version=6.5.5&new-version=6.5.6)](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)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

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 <dependency name> 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).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-12 17:24:58 -04:00
74 changed files with 4025 additions and 1508 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ runs:
using: composite
steps:
- name: Install uv and set the python version
uses: astral-sh/setup-uv@v7
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
with:
python-version: ${{ inputs.python-version }}
enable-cache: ${{ inputs.enable-cache }}
+3 -3
View File
@@ -37,7 +37,7 @@ jobs:
run:
working-directory: libs/cli
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Get changed files
id: changed-files
if: github.event_name != 'workflow_dispatch'
@@ -126,8 +126,8 @@ jobs:
exit 1
fi
LANGCHAIN_ANTHROPIC_VERSION=$(docker run --rm --entrypoint "" langgraph-test-h python -c "import sys; from importlib.metadata import version; v = version('langchain-anthropic'); print(v);")
if [ "$LANGCHAIN_ANTHROPIC_VERSION" != "1.0.0a5" ]; then
echo "LANGCHAIN_ANTHROPIC_VERSION != 1.0.0a5; $LANGCHAIN_ANTHROPIC_VERSION"
if [ "$LANGCHAIN_ANTHROPIC_VERSION" != "1.4.6" ]; then
echo "LANGCHAIN_ANTHROPIC_VERSION != 1.4.6; $LANGCHAIN_ANTHROPIC_VERSION"
exit 1
fi
+1 -1
View File
@@ -31,7 +31,7 @@ jobs:
- "3.12"
name: "lint #${{ matrix.python-version }}"
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Get changed files
id: changed-files
if: github.event_name != 'workflow_dispatch'
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
env:
HAS_LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY != '' }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python
uses: ./.github/actions/uv_setup
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
name: "test #${{ matrix.python-version }}"
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python ${{ matrix.python-version }}
uses: ./.github/actions/uv_setup
with:
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
working-directory: libs/langgraph
name: "test #${{ matrix.python-version }}"
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python ${{ matrix.python-version }}
uses: ./.github/actions/uv_setup
with:
+4 -4
View File
@@ -23,7 +23,7 @@ jobs:
version: ${{ steps.check-version.outputs.version }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: ./.github/actions/uv_setup
@@ -48,7 +48,7 @@ jobs:
working-directory: ${{ inputs.working-directory }}
- name: Upload build
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: test-dist
path: ${{ inputs.working-directory }}/dist/
@@ -74,9 +74,9 @@ jobs:
id-token: write
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/download-artifact@v8
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: test-dist
path: ${{ inputs.working-directory }}/dist/
+2 -2
View File
@@ -17,7 +17,7 @@ jobs:
run:
working-directory: libs/langgraph
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- run: SHA=$(git rev-parse HEAD) && echo "SHA=$SHA" >> $GITHUB_ENV
- name: Set up Python 3.11
uses: ./.github/actions/uv_setup
@@ -30,7 +30,7 @@ jobs:
- name: Run benchmarks
run: OUTPUT=out/benchmark-baseline.json make -s benchmark
- name: Save outputs
uses: actions/cache/save@v5
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
key: ${{ runner.os }}-benchmark-baseline-${{ env.SHA }}
path: |
+3 -3
View File
@@ -15,7 +15,7 @@ jobs:
run:
working-directory: libs/langgraph
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- id: files
name: Get changed files
uses: Ana06/get-changed-files@25f79e676e7ea1868813e21465014798211fad8c # v2.3.0
@@ -30,7 +30,7 @@ jobs:
- name: Install dependencies
run: uv sync --group test
- name: Download baseline
uses: actions/cache/restore@v5
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
key: ${{ runner.os }}-benchmark-baseline
restore-keys: |
@@ -57,7 +57,7 @@ jobs:
echo EOF
} >> "$GITHUB_OUTPUT"
- name: Annotation
uses: actions/github-script@v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
CHANGED_FILES: ${{ steps.files.outputs.added_modified_renamed }}
BENCHMARK_OUTPUT: ${{ steps.benchmark.outputs.OUTPUT }}
+4 -4
View File
@@ -30,7 +30,7 @@ jobs:
deps: ${{ steps.filter.outputs.deps || 'true' }}
sdk_py: ${{ steps.filter.outputs.sdk_py || 'true' }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4
if: github.event_name != 'workflow_dispatch'
id: filter
@@ -112,9 +112,9 @@ jobs:
name: "Check SDK methods matching"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python
uses: actions/setup-python@v6
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.11"
- name: Run check_sdk_methods script
@@ -130,7 +130,7 @@ jobs:
python-version:
- "3.13"
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python ${{ matrix.python-version }}
uses: ./.github/actions/uv_setup
with:
+5 -5
View File
@@ -26,10 +26,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Setup Python
uses: actions/setup-python@v6
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.11'
@@ -37,13 +37,13 @@ jobs:
run: python docs/generate_redirects.py
- name: Setup Pages
uses: actions/configure-pages@v6
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
- name: Upload artifact
uses: actions/upload-pages-artifact@v5
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: 'docs/_site'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v5
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
+8 -8
View File
@@ -25,7 +25,7 @@ jobs:
tag: ${{ steps.check-version.outputs.tag }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python
uses: ./.github/actions/uv_setup
@@ -51,7 +51,7 @@ jobs:
working-directory: ${{ inputs.working-directory }}
- name: Upload build
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: dist
path: ${{ inputs.working-directory }}/dist/
@@ -87,7 +87,7 @@ jobs:
outputs:
release-body: ${{ steps.generate-release-body.outputs.release-body }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
repository: langchain-ai/langgraph
path: langgraph
@@ -158,7 +158,7 @@ jobs:
- test-pypi-publish
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# We explicitly *don't* set up caching here. This ensures our tests are
# maximally sensitive to catching breakage.
@@ -262,7 +262,7 @@ jobs:
working-directory: ${{ inputs.working-directory }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python
uses: ./.github/actions/uv_setup
@@ -272,7 +272,7 @@ jobs:
enable-cache: false
working-directory: ${{ inputs.working-directory }}
- uses: actions/download-artifact@v8
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: dist
path: ${{ inputs.working-directory }}/dist/
@@ -304,7 +304,7 @@ jobs:
working-directory: ${{ inputs.working-directory }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up Python
uses: ./.github/actions/uv_setup
@@ -314,7 +314,7 @@ jobs:
enable-cache: false
working-directory: ${{ inputs.working-directory }}
- uses: actions/download-artifact@v8
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: dist
path: ${{ inputs.working-directory }}/dist/
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
steps:
- name: Find and reopen matching PRs
uses: actions/github-script@v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { owner, repo } = context.repo;
+4 -4
View File
@@ -50,7 +50,7 @@ jobs:
steps:
- name: Check for issue link and assignee
id: check-link
uses: actions/github-script@v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { owner, repo } = context.repo;
@@ -283,7 +283,7 @@ jobs:
if: >-
env.ENFORCE_ISSUE_LINK == 'true' &&
(steps.check-link.outputs.has-link != 'true' || steps.check-link.outputs.is-assigned != 'true')
uses: actions/github-script@v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { owner, repo } = context.repo;
@@ -312,7 +312,7 @@ jobs:
if: >-
env.ENFORCE_ISSUE_LINK == 'true' &&
steps.check-link.outputs.has-link == 'true' && steps.check-link.outputs.is-assigned == 'true'
uses: actions/github-script@v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { owner, repo } = context.repo;
@@ -366,7 +366,7 @@ jobs:
if: >-
env.ENFORCE_ISSUE_LINK == 'true' &&
(steps.check-link.outputs.has-link != 'true' || steps.check-link.outputs.is-assigned != 'true')
uses: actions/github-script@v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { owner, repo } = context.repo;
+7 -7
View File
@@ -55,7 +55,7 @@ jobs:
steps:
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v3
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.ORG_MEMBERSHIP_APP_ID }}
private-key: ${{ secrets.ORG_MEMBERSHIP_APP_PRIVATE_KEY }}
@@ -63,7 +63,7 @@ jobs:
- name: Check if contributor is external
if: steps.app-token.outcome == 'success'
id: check-membership
uses: actions/github-script@v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
@@ -102,7 +102,7 @@ jobs:
- name: Apply contributor tier label
if: steps.check-membership.outputs.is-external == 'true'
uses: actions/github-script@v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
@@ -155,7 +155,7 @@ jobs:
- name: Add external label
if: steps.check-membership.outputs.is-external == 'true'
uses: actions/github-script@v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
@@ -168,7 +168,7 @@ jobs:
- name: Add internal label
if: steps.check-membership.outputs.is-external == 'false'
uses: actions/github-script@v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
@@ -190,13 +190,13 @@ jobs:
steps:
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v3
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.ORG_MEMBERSHIP_APP_ID }}
private-key: ${{ secrets.ORG_MEMBERSHIP_APP_PRIVATE_KEY }}
- name: Backfill labels
uses: actions/github-script@v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
+5 -5
View File
@@ -40,7 +40,7 @@ jobs:
steps:
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v3
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.ORG_MEMBERSHIP_APP_ID }}
private-key: ${{ secrets.ORG_MEMBERSHIP_APP_PRIVATE_KEY }}
@@ -48,7 +48,7 @@ jobs:
- name: Check if contributor is external
if: steps.app-token.outcome == 'success'
id: check-membership
uses: actions/github-script@v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
@@ -90,7 +90,7 @@ jobs:
# event fires and triggers require_issue_link.yml.
- name: Apply contributor tier label
if: steps.check-membership.outputs.is-external == 'true'
uses: actions/github-script@v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
# Use App token so the "labeled" event propagates to downstream
# workflows (e.g. require_issue_link.yml).
@@ -145,7 +145,7 @@ jobs:
- name: Add external label
if: steps.check-membership.outputs.is-external == 'true'
uses: actions/github-script@v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
# Use App token so the "labeled" event propagates to downstream
# workflows (e.g. require_issue_link.yml). Events created by the
@@ -161,7 +161,7 @@ jobs:
- name: Add internal label
if: steps.check-membership.outputs.is-external == 'false'
uses: actions/github-script@v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Set up uv
uses: ./.github/actions/uv_setup
+9 -1
View File
@@ -1,3 +1,11 @@
# LangGraph examples
This directory is retained purely for archival purposes and is no longer updated. The examples previously found here have been moved to the newly [consolidated LangChain documentation](https://docs.langchain.com/oss/python/langgraph/overview). Please refer to the LangChain docs for the most up-to-date examples and usage guidelines for LangGraph.
This directory is retained purely for archival purposes and is no longer updated.
## 🤔 What is this?
The examples previously found here have been moved to the consolidated LangChain documentation. This directory remains available for historical reference, but new examples and usage guidance are published in the docs.
## 📖 Documentation
For up-to-date LangGraph examples, tutorials, and guides, see the [LangGraph Docs](https://docs.langchain.com/oss/python/langgraph/overview). Get started with the [LangGraph Quickstart](https://docs.langchain.com/oss/python/langgraph/quickstart).
+132
View File
@@ -0,0 +1,132 @@
# delta-channel-dump
Recover messages (and other channels) from a Postgres-backed LangGraph thread
written by **langgraph >= 1.2** (DeltaChannel format) — including **LangGraph
Server / langgraph-api** deployments on the Postgres runtime, **deepagents
0.6.x**, or any OSS app using `PostgresSaver` — before rolling back to an older
runtime such as **deepagents 0.5.x / langgraph < 1.2**.
langgraph-api uses the same `checkpoints` / `checkpoint_blobs` / `checkpoint_writes`
schema as OSS `checkpoint-postgres`; this script reads those tables directly.
On the older runtime, `add_messages` does not understand the `EXT_DELTA_SNAPSHOT`
msgpack ext code and silently returns an empty list for affected channels. This
tool reads the raw checkpoint blobs from Postgres and emits JSON you can inspect
and re-apply via `update_state` (LangGraph Server SDK) or `graph.update_state`
(OSS).
## Install
```bash
pip install "psycopg[binary]" ormsgpack
```
## Run
```bash
export DATABASE_URI=postgres://user:pass@host:5432/dbname
python3 dump.py \
--thread-id <uuid> \
--channel messages \
[--channel files ...] \
[--checkpoint-id <uuid>] \
[--checkpoint-ns ""] \
--output recovery.json
```
- `--thread-id` (required): thread UUID
- `--channel` (required, repeatable): channel names to recover
- `--checkpoint-id` (optional): target checkpoint; defaults to latest
- `--checkpoint-ns` (optional): namespace; defaults to `""`
- `--database-uri` (optional): Postgres URI; defaults to `DATABASE_URI` env var
- `--output` (optional): output file; defaults to stdout
## Output
```json
{
"thread_id": "...",
"checkpoint_ns": "",
"target_checkpoint_id": "...",
"parent_checkpoint_id": "...",
"channels": {
"messages": {
"delta_kind": "snapshot",
"seed_checkpoint_id": "...",
"seed_version": "...",
"seed": [{ "type": "ai", "content": "...", "id": "ai-0" }],
"writes": [
{
"checkpoint_id": "...",
"task_id": "...",
"idx": 0,
"value": [{ "type": "ai", "content": "...", "id": "ai-10" }]
}
]
}
}
}
```
`delta_kind` is one of:
- `snapshot` — DeltaChannel snapshot blob (`channel_values[ch] == true`)
- `legacy_plain` — pre-DeltaChannel inline or blob value
- `no_seed` — walked to root without finding a populated ancestor
`writes` are ordered oldest-to-newest (the order a reducer would replay them).
## Reducing back to a single list
For deepagents-style messages, combine seed and writes, then deduplicate:
```python
import json
data = json.load(open("recovery.json"))
ch = data["channels"]["messages"]
messages = list(ch["seed"] or [])
for w in ch["writes"]:
messages.extend(w["value"] or [])
# Dedup by id, keep last; drop RemoveMessage tombstones
by_id = {}
for m in messages:
if isinstance(m, dict) and m.get("type") == "remove":
by_id.pop(m.get("id"), None)
elif isinstance(m, dict) and m.get("id"):
by_id[m["id"]] = m
else:
by_id[id(m)] = m
reduced = list(by_id.values())
```
This approximates `_messages_delta_reducer` semantics; adjust for your graph.
## Re-applying
```python
from langgraph_sdk import get_client
client = get_client(url="http://localhost:8123")
await client.threads.update_state(
thread_id,
values={"messages": reduced},
)
```
Review the recovered JSON before calling `update_state`. This tool is
read-only and intentionally does not mutate the database.
## Scope / non-goals (v1)
- **Postgres only** — OSS `PostgresSaver` or langgraph-api Postgres runtime; not
inmem, gRPC core, Mongo, or Redis checkpointer backends
- **No AES decryption** (`LANGGRAPH_AES_KEY`) or custom encryption
- **No reducer** — raw seed + writes only
- **No automatic `update_state`** — operator applies manually
## Copying
`dump.py` is self-contained. Copy it anywhere; only `psycopg[binary]` and
`ormsgpack` are required at runtime. No langgraph imports.
+469
View File
@@ -0,0 +1,469 @@
#!/usr/bin/env python3
"""Recover delta-channel state from a Postgres-backed LangGraph thread.
Works with OSS ``PostgresSaver`` and LangGraph Server / langgraph-api on the
Postgres runtime (same checkpoint schema). Use after rolling back from
langgraph >= 1.2 / deepagents 0.6.x to an older runtime that does not
understand ``EXT_DELTA_SNAPSHOT`` msgpack blobs. The script walks the checkpoint
parent chain, decodes msgpack blobs, and emits a JSON dump of per-channel
``seed`` plus oldest-to-newest ``writes``. Apply the recovered values manually
via ``client.threads.update_state(...)`` (Server) or ``graph.update_state``
(OSS).
Install::
pip install "psycopg[binary]" ormsgpack
Run::
export DATABASE_URI=postgres://...
python3 dump.py --thread-id <uuid> --channel messages --output recovery.json
Scope (v1): Postgres only; no AES/custom encryption; no reducer application.
"""
from __future__ import annotations
import argparse
import base64
import json
import os
import sys
import uuid
from typing import Any
import ormsgpack
import psycopg
# LangGraph msgpack EXT type codes (langgraph/checkpoint/serde/jsonplus.py).
EXT_CONSTRUCTOR_SINGLE_ARG = 0
EXT_CONSTRUCTOR_POS_ARGS = 1
EXT_CONSTRUCTOR_KW_ARGS = 2
EXT_METHOD_SINGLE_ARG = 3
EXT_PYDANTIC_V1 = 4
EXT_PYDANTIC_V2 = 5
EXT_NUMPY_ARRAY = 6
EXT_DELTA_SNAPSHOT = 7
_MSGPACK_OPTION = ormsgpack.OPT_NON_STR_KEYS
def ext_hook(code: int, data: bytes) -> Any:
"""Decode LangGraph msgpack EXT payloads to JSON-friendly Python values."""
if code == EXT_DELTA_SNAPSHOT:
inner = ormsgpack.unpackb(data, ext_hook=ext_hook, option=_MSGPACK_OPTION)
return {"__delta_snapshot__": inner}
if code == EXT_CONSTRUCTOR_SINGLE_ARG:
try:
tup = ormsgpack.unpackb(data, ext_hook=ext_hook, option=_MSGPACK_OPTION)
if tup[0] == "uuid" and tup[1] == "UUID":
hex_ = tup[2]
return (
f"{hex_[:8]}-{hex_[8:12]}-{hex_[12:16]}-"
f"{hex_[16:20]}-{hex_[20:]}"
)
return tup[2]
except Exception:
return None
if code == EXT_CONSTRUCTOR_POS_ARGS:
try:
tup = ormsgpack.unpackb(data, ext_hook=ext_hook, option=_MSGPACK_OPTION)
if tup[0] == "langgraph.types" and tup[1] == "Send":
args = tup[2]
if len(args) == 2:
return {"__send__": {"node": args[0], "arg": args[1]}}
return {
"__send__": {
"node": args[0],
"arg": args[1],
"timeout": args[2],
}
}
return tup[2]
except Exception:
return None
if code in (EXT_CONSTRUCTOR_KW_ARGS, EXT_METHOD_SINGLE_ARG):
try:
tup = ormsgpack.unpackb(data, ext_hook=ext_hook, option=_MSGPACK_OPTION)
return tup[2]
except Exception:
return None
if code in (EXT_PYDANTIC_V1, EXT_PYDANTIC_V2):
try:
tup = ormsgpack.unpackb(data, ext_hook=ext_hook, option=_MSGPACK_OPTION)
return tup[2]
except Exception:
return None
if code == EXT_NUMPY_ARRAY:
try:
dtype_str, shape, order, buf = ormsgpack.unpackb(
data, ext_hook=ext_hook, option=_MSGPACK_OPTION
)
return {
"__numpy_array__": {
"dtype": dtype_str,
"shape": shape,
"order": order,
"data_b64": base64.b64encode(buf).decode("ascii"),
}
}
except Exception:
return None
return None
def decode_blob(blob_type: str, blob_bytes: bytes | None) -> Any:
if blob_type in ("empty", "null") or blob_bytes is None:
return None
if blob_type == "msgpack":
return ormsgpack.unpackb(
blob_bytes, ext_hook=ext_hook, option=_MSGPACK_OPTION
)
if blob_type in ("bytes", "bytearray"):
return base64.b64encode(blob_bytes).decode("ascii")
raise RuntimeError(
f"Unknown blob type {blob_type!r}. "
"AES/custom-encrypted deployments are out of scope for v1."
)
def delta_unwrap(value: Any) -> Any:
if isinstance(value, dict) and "__delta_snapshot__" in value:
return value["__delta_snapshot__"]
return value
def json_default(obj: Any) -> Any:
if isinstance(obj, (bytes, bytearray)):
return base64.b64encode(bytes(obj)).decode("ascii")
if isinstance(obj, uuid.UUID):
return str(obj)
raise TypeError(f"Object of type {type(obj).__name__} is not JSON serializable")
def resolve_target_checkpoint_id(
conn: psycopg.Connection[Any],
thread_id: str,
checkpoint_ns: str,
checkpoint_id: str | None,
) -> str:
if checkpoint_id is not None:
return checkpoint_id
row = conn.execute(
"""
SELECT checkpoint_id::text
FROM checkpoints
WHERE thread_id = %s AND checkpoint_ns = %s
ORDER BY checkpoint_id DESC
LIMIT 1
""",
(thread_id, checkpoint_ns),
).fetchone()
if row is None:
raise SystemExit(
f"No checkpoints found for thread_id={thread_id!r} "
f"checkpoint_ns={checkpoint_ns!r}"
)
return row[0]
def _load_checkpoint(
conn: psycopg.Connection[Any],
thread_id: str,
checkpoint_ns: str,
checkpoint_id: str,
) -> tuple[dict[str, Any], str | None] | None:
row = conn.execute(
"""
SELECT checkpoint, parent_checkpoint_id::text
FROM checkpoints
WHERE thread_id = %s AND checkpoint_ns = %s AND checkpoint_id = %s
""",
(thread_id, checkpoint_ns, checkpoint_id),
).fetchone()
if row is None:
return None
return row[0], row[1]
def _load_seed(
conn: psycopg.Connection[Any],
*,
thread_id: str,
checkpoint_ns: str,
channel: str,
checkpoint_id: str,
channel_values: dict[str, Any],
channel_versions: dict[str, str],
) -> dict[str, Any]:
cv = channel_values[channel]
version = channel_versions.get(channel)
if cv is True:
blob_row = conn.execute(
"""
SELECT type, blob
FROM checkpoint_blobs
WHERE thread_id = %s AND checkpoint_ns = %s
AND channel = %s AND version = %s
""",
(thread_id, checkpoint_ns, channel, version),
).fetchone()
seed_value = None
if blob_row is not None and blob_row[0] != "empty":
seed_value = delta_unwrap(decode_blob(blob_row[0], blob_row[1]))
return {
"delta_kind": "snapshot",
"seed_checkpoint_id": checkpoint_id,
"seed_version": version,
"seed": seed_value,
}
if isinstance(cv, (int, float, str, bool)) or cv is None:
return {
"delta_kind": "legacy_plain",
"seed_checkpoint_id": checkpoint_id,
"seed_version": version,
"seed": cv,
}
blob_row = conn.execute(
"""
SELECT type, blob
FROM checkpoint_blobs
WHERE thread_id = %s AND checkpoint_ns = %s
AND channel = %s AND version = %s
""",
(thread_id, checkpoint_ns, channel, version),
).fetchone()
seed_value = cv if blob_row is None else decode_blob(blob_row[0], blob_row[1])
return {
"delta_kind": "legacy_plain",
"seed_checkpoint_id": checkpoint_id,
"seed_version": version,
"seed": seed_value,
}
def _load_writes_for_checkpoint(
conn: psycopg.Connection[Any],
*,
thread_id: str,
checkpoint_ns: str,
checkpoint_id: str,
channel: str,
) -> list[dict[str, Any]]:
"""Load writes for one checkpoint, newest-first by ``(task_id, idx)``.
``walk_channel`` reverses the accumulated flat list before returning;
DESC here yields oldest-first within each checkpoint in the final output,
matching ``PostgresSaver._build_delta_channels_writes_history``.
"""
rows = conn.execute(
"""
SELECT task_id::text, idx, type, blob
FROM checkpoint_writes
WHERE thread_id = %s AND checkpoint_ns = %s
AND checkpoint_id = %s AND channel = %s
ORDER BY task_id DESC, idx DESC
""",
(thread_id, checkpoint_ns, checkpoint_id, channel),
).fetchall()
return [
{
"checkpoint_id": checkpoint_id,
"task_id": task_id,
"idx": idx,
"value": decode_blob(blob_type, blob_bytes),
}
for task_id, idx, blob_type, blob_bytes in rows
]
def walk_channel(
conn: psycopg.Connection[Any],
*,
thread_id: str,
checkpoint_ns: str,
start_checkpoint_id: str | None,
channel: str,
) -> dict[str, Any]:
"""Walk one channel's parent chain from target.parent backward to seed."""
chain_writes_newest_first: list[dict[str, Any]] = []
cur = start_checkpoint_id
while cur is not None:
loaded = _load_checkpoint(conn, thread_id, checkpoint_ns, cur)
if loaded is None:
break
checkpoint_json, parent_id = loaded
channel_values = checkpoint_json.get("channel_values") or {}
channel_versions = checkpoint_json.get("channel_versions") or {}
chain_writes_newest_first.extend(
_load_writes_for_checkpoint(
conn,
thread_id=thread_id,
checkpoint_ns=checkpoint_ns,
checkpoint_id=cur,
channel=channel,
)
)
if channel in channel_values:
seed = _load_seed(
conn,
thread_id=thread_id,
checkpoint_ns=checkpoint_ns,
channel=channel,
checkpoint_id=cur,
channel_values=channel_values,
channel_versions=channel_versions,
)
seed["writes"] = list(reversed(chain_writes_newest_first))
return seed
cur = parent_id
return {
"delta_kind": "no_seed",
"seed_checkpoint_id": None,
"seed_version": None,
"seed": None,
"writes": list(reversed(chain_writes_newest_first)),
}
def walk_parent_chain(
conn: psycopg.Connection[Any],
*,
thread_id: str,
checkpoint_ns: str,
target_checkpoint_id: str,
channels: list[str],
) -> tuple[str | None, dict[str, dict[str, Any]]]:
"""Walk parent chain and return per-channel seed + writes (oldest-first)."""
parent_row = conn.execute(
"""
SELECT parent_checkpoint_id::text
FROM checkpoints
WHERE thread_id = %s AND checkpoint_ns = %s AND checkpoint_id = %s
""",
(thread_id, checkpoint_ns, target_checkpoint_id),
).fetchone()
if parent_row is None:
raise SystemExit(
f"Checkpoint {target_checkpoint_id!r} not found for thread {thread_id!r}"
)
parent_checkpoint_id = parent_row[0]
result = {
ch: walk_channel(
conn,
thread_id=thread_id,
checkpoint_ns=checkpoint_ns,
start_checkpoint_id=parent_checkpoint_id,
channel=ch,
)
for ch in channels
}
return parent_checkpoint_id, result
def build_output(
*,
thread_id: str,
checkpoint_ns: str,
target_checkpoint_id: str,
parent_checkpoint_id: str | None,
channels: dict[str, dict[str, Any]],
) -> dict[str, Any]:
return {
"thread_id": thread_id,
"checkpoint_ns": checkpoint_ns,
"target_checkpoint_id": target_checkpoint_id,
"parent_checkpoint_id": parent_checkpoint_id,
"channels": channels,
}
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(
description=(
"Recover delta-channel seed + writes from Postgres checkpoint data."
),
)
parser.add_argument("--thread-id", required=True, help="Thread UUID")
parser.add_argument(
"--channel",
action="append",
required=True,
dest="channels",
help="Channel name (repeatable)",
)
parser.add_argument(
"--checkpoint-id",
default=None,
help="Target checkpoint UUID (default: latest for thread)",
)
parser.add_argument(
"--checkpoint-ns",
default="",
help='Checkpoint namespace (default: "")',
)
parser.add_argument(
"--database-uri",
default=os.environ.get("DATABASE_URI"),
help="Postgres URI (default: DATABASE_URI env var)",
)
parser.add_argument(
"--output",
default="-",
help="Output JSON file path (default: stdout)",
)
return parser.parse_args(argv)
def main(argv: list[str] | None = None) -> int:
args = parse_args(argv)
if not args.database_uri:
print(
"error: --database-uri or DATABASE_URI is required",
file=sys.stderr,
)
return 2
thread_id = str(uuid.UUID(args.thread_id))
channels = list(dict.fromkeys(args.channels))
with psycopg.connect(args.database_uri) as conn:
target_checkpoint_id = resolve_target_checkpoint_id(
conn,
thread_id,
args.checkpoint_ns,
args.checkpoint_id,
)
parent_checkpoint_id, channel_data = walk_parent_chain(
conn,
thread_id=thread_id,
checkpoint_ns=args.checkpoint_ns,
target_checkpoint_id=target_checkpoint_id,
channels=channels,
)
output = build_output(
thread_id=thread_id,
checkpoint_ns=args.checkpoint_ns,
target_checkpoint_id=target_checkpoint_id,
parent_checkpoint_id=parent_checkpoint_id,
channels=channel_data,
)
payload = json.dumps(output, indent=2, default=json_default)
if args.output == "-":
print(payload)
else:
with open(args.output, "w", encoding="utf-8") as f:
f.write(payload)
f.write("\n")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+27 -5
View File
@@ -1,15 +1,27 @@
# langgraph-checkpoint-conformance
# LangGraph Checkpoint Conformance
Conformance test suite for [LangGraph](https://github.com/langchain-ai/langgraph) checkpointer implementations.
[![PyPI - Version](https://img.shields.io/pypi/v/langgraph-checkpoint-conformance?label=%20)](https://pypi.org/project/langgraph-checkpoint-conformance/#history)
[![PyPI - License](https://img.shields.io/pypi/l/langgraph-checkpoint-conformance)](https://opensource.org/licenses/MIT)
[![PyPI - Downloads](https://img.shields.io/pepy/dt/langgraph-checkpoint-conformance)](https://pypistats.org/packages/langgraph-checkpoint-conformance)
[![Twitter](https://img.shields.io/twitter/url/https/twitter.com/langchain_oss.svg?style=social&label=Follow%20%40LangChain)](https://x.com/langchain_oss)
Validates that a `BaseCheckpointSaver` subclass correctly implements the checkpoint storage contract — blob round-trips, metadata preservation, namespace isolation, incremental channel updates, and more.
To help you ship LangGraph apps to production faster, check out [LangSmith](https://www.langchain.com/langsmith).
[LangSmith](https://www.langchain.com/langsmith) is a unified developer platform for building, testing, and monitoring LLM applications.
## Installation
## Quick Install
```bash
pip install langgraph-checkpoint-conformance
uv add langgraph-checkpoint-conformance
```
## 🤔 What is this?
This library provides a conformance test suite for [LangGraph](https://github.com/langchain-ai/langgraph) checkpointer implementations. It validates that a `BaseCheckpointSaver` subclass correctly implements the checkpoint storage contract — blob round-trips, metadata preservation, namespace isolation, incremental channel updates, and more.
## 📖 Documentation
For full documentation, see the [API reference](https://reference.langchain.com/python/langgraph/). For conceptual guides on persistence and memory, see the [LangGraph Docs](https://docs.langchain.com/oss/python/langgraph/overview).
## Quick start
Register your checkpointer with `@checkpointer_test` and run `validate()`:
@@ -110,3 +122,13 @@ async def pg_checkpointer():
async with PostgresSaver.from_conn_string(CONN_STRING) as saver:
yield saver
```
## 📕 Releases & Versioning
See our [Releases](https://docs.langchain.com/oss/python/release-policy) and [Versioning](https://docs.langchain.com/oss/python/versioning) policies.
## 💁 Contributing
As an open-source project in a rapidly developing field, we are extremely open to contributions, whether it be in the form of a new feature, improved infrastructure, or better documentation.
For detailed information on how to contribute, see the [Contributing Guide](https://docs.langchain.com/oss/python/contributing/overview).
@@ -54,6 +54,12 @@ async def build_delta_chain(
stored: list[RunnableConfig] = []
parent_cfg: RunnableConfig | None = None
# Track supersteps since the channel's last snapshot, mirroring Pregel's
# `counters_since_delta_snapshot` bookkeeping: every step increments the
# counter; a snapshot step resets it (and carries no counter entry, so
# the walk locates the seed exactly `supersteps` hops back).
supersteps_since_snapshot = 0
for step in range(total_steps):
config: RunnableConfig = {
"configurable": {
@@ -68,11 +74,19 @@ async def build_delta_chain(
channel_values: dict[str, Any] = {}
channel_versions: dict[str, int] = {}
supersteps_since_snapshot += 1
counters: dict[str, tuple[int, int]] = {}
if step in snapshot_set:
channel_values[channel] = _DeltaSnapshot(
write_value_fn(step),
)
channel_versions[channel] = step + 1
supersteps_since_snapshot = 0
else:
counters[channel] = (
supersteps_since_snapshot,
supersteps_since_snapshot,
)
cp = Checkpoint(
v=1,
@@ -84,9 +98,10 @@ async def build_delta_chain(
updated_channels=None,
)
new_versions = dict(channel_versions)
parent_cfg = await saver.aput(
config, cp, generate_metadata(step=step), new_versions
)
md = generate_metadata(step=step)
if counters:
md["counters_since_delta_snapshot"] = counters
parent_cfg = await saver.aput(config, cp, md, new_versions)
stored.append(parent_cfg)
# Write a pending write for non-snapshot steps so the walk has
@@ -87,6 +87,10 @@ async def test_history_multi_channel(
from langgraph.checkpoint.conformance.test_utils import generate_metadata
# Per-channel supersteps since last snapshot ("a" snapshots at step 1,
# "b" at step 3). Drives the per-channel walk depth from the head.
s_a = 0
s_b = 0
for step in range(5):
config = {"configurable": {"thread_id": tid, "checkpoint_ns": ""}}
if parent_cfg:
@@ -95,12 +99,21 @@ async def test_history_multi_channel(
]
cv: dict = {}
cvs: dict = {}
s_a += 1
s_b += 1
counters: dict = {}
if step == 1:
cv["a"] = _DeltaSnapshot("snap_a")
cvs["a"] = step + 1
s_a = 0
else:
counters["a"] = (s_a, s_a)
if step == 3:
cv["b"] = _DeltaSnapshot("snap_b")
cvs["b"] = step + 1
s_b = 0
else:
counters["b"] = (s_b, s_b)
cp = Checkpoint(
v=1,
id=str(uuid6(clock_seq=-1)),
@@ -110,7 +123,10 @@ async def test_history_multi_channel(
versions_seen={},
updated_channels=None,
)
parent_cfg = await saver.aput(config, cp, generate_metadata(step=step), cvs)
md = generate_metadata(step=step)
if counters:
md["counters_since_delta_snapshot"] = counters
parent_cfg = await saver.aput(config, cp, md, cvs)
configs.append(parent_cfg)
await saver.aput_writes(parent_cfg, [("a", step), ("b", step)], str(uuid4()))
@@ -148,7 +164,12 @@ async def test_history_walk_to_root_no_seed(
)
head = configs[-1]
result = await saver.aget_delta_channel_history(config=head, channels=["ch"])
# The head's supersteps counter (4) runs one hop past the real root —
# the snapshot checkpoint was never persisted (implicit empty baseline).
# No seed, and the full chain (steps 0..2) replays from empty.
assert "seed" not in result["ch"], f"Expected no seed, got {result['ch']}"
values = [w[2] for w in result["ch"]["writes"]]
assert values == [0, 1, 2], f"Expected full-chain writes [0,1,2], got {values}"
async def test_history_migration_plain_value_as_seed(
@@ -170,6 +191,10 @@ async def test_history_migration_plain_value_as_seed(
configs: list = []
parent_cfg = None
# The channel was a non-delta channel through step 1 (plain value, no
# delta counter), then migrated to DeltaChannel at step 2. Supersteps
# count from the migration boundary: step 2 -> 1, step 3 -> 2, so the
# head (step 3) walks 2 hops back to the plain-value seed at step 1.
for step in range(4):
config = {"configurable": {"thread_id": tid, "checkpoint_ns": ""}}
if parent_cfg:
@@ -182,6 +207,9 @@ async def test_history_migration_plain_value_as_seed(
if step == 1:
cv["ch"] = [10, 20, 30]
cvs["ch"] = step + 1
md = generate_metadata(step=step)
if step >= 2:
md["counters_since_delta_snapshot"] = {"ch": (step - 1, step - 1)}
cp = Checkpoint(
v=1,
id=str(uuid6(clock_seq=-1)),
@@ -191,7 +219,7 @@ async def test_history_migration_plain_value_as_seed(
versions_seen={},
updated_channels=None,
)
parent_cfg = await saver.aput(config, cp, generate_metadata(step=step), cvs)
parent_cfg = await saver.aput(config, cp, md, cvs)
configs.append(parent_cfg)
if step != 1:
await saver.aput_writes(parent_cfg, [("ch", step)], str(uuid4()))
@@ -208,6 +236,67 @@ async def test_history_migration_plain_value_as_seed(
assert values == [2], f"Expected [2], got {values}"
async def test_history_migration_skips_seed_checkpoint_writes(
saver: BaseCheckpointSaver,
) -> None:
"""A migrated plain-value seed already incorporates its own checkpoint's
writes, so those writes must NOT be re-emitted in the history.
This is the discriminating case for non-additive reducers (e.g. an
even-only filter): re-applying the seed checkpoint's writes on top of
the seed would corrupt the reconstructed value. The saver contract is
to skip them — only writes strictly after the seed are returned.
"""
from langgraph.checkpoint.base import Checkpoint
from langgraph.checkpoint.base.id import uuid6
from langgraph.checkpoint.conformance.test_utils import generate_metadata
tid = str(uuid4())
configs: list = []
parent_cfg = None
for step in range(4):
config = {"configurable": {"thread_id": tid, "checkpoint_ns": ""}}
if parent_cfg:
config["configurable"]["checkpoint_id"] = parent_cfg["configurable"][
"checkpoint_id"
]
cv: dict = {}
cvs: dict = {}
# Step 1: pre-delta plain accumulated value AND its own writes.
if step == 1:
cv["ch"] = [2, 4]
cvs["ch"] = step + 1
md = generate_metadata(step=step)
if step >= 2:
md["counters_since_delta_snapshot"] = {"ch": (step - 1, step - 1)}
cp = Checkpoint(
v=1,
id=str(uuid6(clock_seq=-1)),
ts="",
channel_values=cv,
channel_versions=cvs,
versions_seen={},
updated_channels=None,
)
parent_cfg = await saver.aput(config, cp, md, cvs)
configs.append(parent_cfg)
# The seed checkpoint (step 1) carries writes that the plain value
# already subsumes; later steps carry post-migration delta writes.
write_value = 99 if step == 1 else step * 10
await saver.aput_writes(parent_cfg, [("ch", write_value)], str(uuid4()))
head = configs[-1]
result = await saver.aget_delta_channel_history(config=head, channels=["ch"])
assert result["ch"].get("seed") == [2, 4], (
f"Expected plain seed [2, 4], got {result['ch'].get('seed')}"
)
values = [w[2] for w in result["ch"]["writes"]]
# Seed checkpoint's own write (99) is skipped; step 2's write (20) kept.
assert values == [20], f"Expected only post-seed writes [20], got {values}"
ALL_DELTA_CHANNEL_HISTORY_TESTS = [
test_history_returns_writes_oldest_first,
test_history_seed_is_nearest_snapshot,
@@ -216,6 +305,7 @@ ALL_DELTA_CHANNEL_HISTORY_TESTS = [
test_history_empty_channels_returns_empty,
test_history_walk_to_root_no_seed,
test_history_migration_plain_value_as_seed,
test_history_migration_skips_seed_checkpoint_writes,
]
+72 -3
View File
@@ -370,7 +370,7 @@ test = [
[[package]]
name = "langsmith"
version = "0.8.2"
version = "0.8.18"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
@@ -380,12 +380,13 @@ dependencies = [
{ name = "requests" },
{ name = "requests-toolbelt" },
{ name = "uuid-utils" },
{ name = "websockets" },
{ name = "xxhash" },
{ name = "zstandard" },
]
sdist = { url = "https://files.pythonhosted.org/packages/98/8b/10b929694aeffc804f8ca9705abffeb64add0405043ff6d1aeb7eb345978/langsmith-0.8.2.tar.gz", hash = "sha256:588bc51566476eac987a849a08c71675930b21733545fe3031fbb1eeca78e8df", size = 4458004, upload-time = "2026-05-06T17:36:25.5Z" }
sdist = { url = "https://files.pythonhosted.org/packages/9a/d9/a6681aa9847bbbc5ec21abe20a5e233b94e5edcfe39624db607ac7e8ccb4/langsmith-0.8.18.tar.gz", hash = "sha256:32dde9c0e67e053e0fb738921fc8ced768af7b8fa83d7a0e3fd63597cf8776dd", size = 4526988, upload-time = "2026-06-19T13:12:17.123Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/56/3e/12ab2c357593ca1652df6dddbd763cff9ea2c7155a922910ccba6ac1530e/langsmith-0.8.2-py3-none-any.whl", hash = "sha256:4ff80d7dc1b273315401b681aef9b1fc92f4fa8a6d9d49eb65535520f8264fd4", size = 397520, upload-time = "2026-05-06T17:36:23.064Z" },
{ url = "https://files.pythonhosted.org/packages/03/70/0e0cc80a3b064c8d6c8d697c3125ed86e39d5a7393ec6dc8b07cb1cf13c4/langsmith-0.8.18-py3-none-any.whl", hash = "sha256:3940183349993faef48e6c7d08e4822ee9cefd906b362d0e3c2d650314d2f282", size = 508108, upload-time = "2026-06-19T13:12:15.348Z" },
]
[[package]]
@@ -978,6 +979,74 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ed/d0/5bf7cbf1ac138c92b9ac21066d18faf4d7e7f651047b700eb192ca4b9fdb/uuid_utils-0.14.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:258186964039a8e36db10810c1ece879d229b01331e09e9030bc5dcabe231bd2", size = 364700, upload-time = "2026-02-20T22:50:21.732Z" },
]
[[package]]
name = "websockets"
version = "16.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/20/74/221f58decd852f4b59cc3354cccaf87e8ef695fede361d03dc9a7396573b/websockets-16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:04cdd5d2d1dacbad0a7bf36ccbcd3ccd5a30ee188f2560b7a62a30d14107b31a", size = 177343, upload-time = "2026-01-10T09:22:21.28Z" },
{ url = "https://files.pythonhosted.org/packages/19/0f/22ef6107ee52ab7f0b710d55d36f5a5d3ef19e8a205541a6d7ffa7994e5a/websockets-16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8ff32bb86522a9e5e31439a58addbb0166f0204d64066fb955265c4e214160f0", size = 175021, upload-time = "2026-01-10T09:22:22.696Z" },
{ url = "https://files.pythonhosted.org/packages/10/40/904a4cb30d9b61c0e278899bf36342e9b0208eb3c470324a9ecbaac2a30f/websockets-16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:583b7c42688636f930688d712885cf1531326ee05effd982028212ccc13e5957", size = 175320, upload-time = "2026-01-10T09:22:23.94Z" },
{ url = "https://files.pythonhosted.org/packages/9d/2f/4b3ca7e106bc608744b1cdae041e005e446124bebb037b18799c2d356864/websockets-16.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7d837379b647c0c4c2355c2499723f82f1635fd2c26510e1f587d89bc2199e72", size = 183815, upload-time = "2026-01-10T09:22:25.469Z" },
{ url = "https://files.pythonhosted.org/packages/86/26/d40eaa2a46d4302becec8d15b0fc5e45bdde05191e7628405a19cf491ccd/websockets-16.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df57afc692e517a85e65b72e165356ed1df12386ecb879ad5693be08fac65dde", size = 185054, upload-time = "2026-01-10T09:22:27.101Z" },
{ url = "https://files.pythonhosted.org/packages/b0/ba/6500a0efc94f7373ee8fefa8c271acdfd4dca8bd49a90d4be7ccabfc397e/websockets-16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2b9f1e0d69bc60a4a87349d50c09a037a2607918746f07de04df9e43252c77a3", size = 184565, upload-time = "2026-01-10T09:22:28.293Z" },
{ url = "https://files.pythonhosted.org/packages/04/b4/96bf2cee7c8d8102389374a2616200574f5f01128d1082f44102140344cc/websockets-16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:335c23addf3d5e6a8633f9f8eda77efad001671e80b95c491dd0924587ece0b3", size = 183848, upload-time = "2026-01-10T09:22:30.394Z" },
{ url = "https://files.pythonhosted.org/packages/02/8e/81f40fb00fd125357814e8c3025738fc4ffc3da4b6b4a4472a82ba304b41/websockets-16.0-cp310-cp310-win32.whl", hash = "sha256:37b31c1623c6605e4c00d466c9d633f9b812ea430c11c8a278774a1fde1acfa9", size = 178249, upload-time = "2026-01-10T09:22:32.083Z" },
{ url = "https://files.pythonhosted.org/packages/b4/5f/7e40efe8df57db9b91c88a43690ac66f7b7aa73a11aa6a66b927e44f26fa/websockets-16.0-cp310-cp310-win_amd64.whl", hash = "sha256:8e1dab317b6e77424356e11e99a432b7cb2f3ec8c5ab4dabbcee6add48f72b35", size = 178685, upload-time = "2026-01-10T09:22:33.345Z" },
{ url = "https://files.pythonhosted.org/packages/f2/db/de907251b4ff46ae804ad0409809504153b3f30984daf82a1d84a9875830/websockets-16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:31a52addea25187bde0797a97d6fc3d2f92b6f72a9370792d65a6e84615ac8a8", size = 177340, upload-time = "2026-01-10T09:22:34.539Z" },
{ url = "https://files.pythonhosted.org/packages/f3/fa/abe89019d8d8815c8781e90d697dec52523fb8ebe308bf11664e8de1877e/websockets-16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:417b28978cdccab24f46400586d128366313e8a96312e4b9362a4af504f3bbad", size = 175022, upload-time = "2026-01-10T09:22:36.332Z" },
{ url = "https://files.pythonhosted.org/packages/58/5d/88ea17ed1ded2079358b40d31d48abe90a73c9e5819dbcde1606e991e2ad/websockets-16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:af80d74d4edfa3cb9ed973a0a5ba2b2a549371f8a741e0800cb07becdd20f23d", size = 175319, upload-time = "2026-01-10T09:22:37.602Z" },
{ url = "https://files.pythonhosted.org/packages/d2/ae/0ee92b33087a33632f37a635e11e1d99d429d3d323329675a6022312aac2/websockets-16.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:08d7af67b64d29823fed316505a89b86705f2b7981c07848fb5e3ea3020c1abe", size = 184631, upload-time = "2026-01-10T09:22:38.789Z" },
{ url = "https://files.pythonhosted.org/packages/c8/c5/27178df583b6c5b31b29f526ba2da5e2f864ecc79c99dae630a85d68c304/websockets-16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be95cfb0a4dae143eaed2bcba8ac23f4892d8971311f1b06f3c6b78952ee70b", size = 185870, upload-time = "2026-01-10T09:22:39.893Z" },
{ url = "https://files.pythonhosted.org/packages/87/05/536652aa84ddc1c018dbb7e2c4cbcd0db884580bf8e95aece7593fde526f/websockets-16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6297ce39ce5c2e6feb13c1a996a2ded3b6832155fcfc920265c76f24c7cceb5", size = 185361, upload-time = "2026-01-10T09:22:41.016Z" },
{ url = "https://files.pythonhosted.org/packages/6d/e2/d5332c90da12b1e01f06fb1b85c50cfc489783076547415bf9f0a659ec19/websockets-16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c1b30e4f497b0b354057f3467f56244c603a79c0d1dafce1d16c283c25f6e64", size = 184615, upload-time = "2026-01-10T09:22:42.442Z" },
{ url = "https://files.pythonhosted.org/packages/77/fb/d3f9576691cae9253b51555f841bc6600bf0a983a461c79500ace5a5b364/websockets-16.0-cp311-cp311-win32.whl", hash = "sha256:5f451484aeb5cafee1ccf789b1b66f535409d038c56966d6101740c1614b86c6", size = 178246, upload-time = "2026-01-10T09:22:43.654Z" },
{ url = "https://files.pythonhosted.org/packages/54/67/eaff76b3dbaf18dcddabc3b8c1dba50b483761cccff67793897945b37408/websockets-16.0-cp311-cp311-win_amd64.whl", hash = "sha256:8d7f0659570eefb578dacde98e24fb60af35350193e4f56e11190787bee77dac", size = 178684, upload-time = "2026-01-10T09:22:44.941Z" },
{ url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" },
{ url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" },
{ url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" },
{ url = "https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c", size = 184915, upload-time = "2026-01-10T09:22:51.071Z" },
{ url = "https://files.pythonhosted.org/packages/97/bb/21c36b7dbbafc85d2d480cd65df02a1dc93bf76d97147605a8e27ff9409d/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f", size = 186152, upload-time = "2026-01-10T09:22:52.224Z" },
{ url = "https://files.pythonhosted.org/packages/4a/34/9bf8df0c0cf88fa7bfe36678dc7b02970c9a7d5e065a3099292db87b1be2/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1", size = 185583, upload-time = "2026-01-10T09:22:53.443Z" },
{ url = "https://files.pythonhosted.org/packages/47/88/4dd516068e1a3d6ab3c7c183288404cd424a9a02d585efbac226cb61ff2d/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2", size = 184880, upload-time = "2026-01-10T09:22:55.033Z" },
{ url = "https://files.pythonhosted.org/packages/91/d6/7d4553ad4bf1c0421e1ebd4b18de5d9098383b5caa1d937b63df8d04b565/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89", size = 178261, upload-time = "2026-01-10T09:22:56.251Z" },
{ url = "https://files.pythonhosted.org/packages/c3/f0/f3a17365441ed1c27f850a80b2bc680a0fa9505d733fe152fdf5e98c1c0b/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea", size = 178693, upload-time = "2026-01-10T09:22:57.478Z" },
{ url = "https://files.pythonhosted.org/packages/cc/9c/baa8456050d1c1b08dd0ec7346026668cbc6f145ab4e314d707bb845bf0d/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9", size = 177364, upload-time = "2026-01-10T09:22:59.333Z" },
{ url = "https://files.pythonhosted.org/packages/7e/0c/8811fc53e9bcff68fe7de2bcbe75116a8d959ac699a3200f4847a8925210/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230", size = 175039, upload-time = "2026-01-10T09:23:01.171Z" },
{ url = "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c", size = 175323, upload-time = "2026-01-10T09:23:02.341Z" },
{ url = "https://files.pythonhosted.org/packages/bd/28/0a25ee5342eb5d5f297d992a77e56892ecb65e7854c7898fb7d35e9b33bd/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5", size = 184975, upload-time = "2026-01-10T09:23:03.756Z" },
{ url = "https://files.pythonhosted.org/packages/f9/66/27ea52741752f5107c2e41fda05e8395a682a1e11c4e592a809a90c6a506/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82", size = 186203, upload-time = "2026-01-10T09:23:05.01Z" },
{ url = "https://files.pythonhosted.org/packages/37/e5/8e32857371406a757816a2b471939d51c463509be73fa538216ea52b792a/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8", size = 185653, upload-time = "2026-01-10T09:23:06.301Z" },
{ url = "https://files.pythonhosted.org/packages/9b/67/f926bac29882894669368dc73f4da900fcdf47955d0a0185d60103df5737/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f", size = 184920, upload-time = "2026-01-10T09:23:07.492Z" },
{ url = "https://files.pythonhosted.org/packages/3c/a1/3d6ccdcd125b0a42a311bcd15a7f705d688f73b2a22d8cf1c0875d35d34a/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a", size = 178255, upload-time = "2026-01-10T09:23:09.245Z" },
{ url = "https://files.pythonhosted.org/packages/6b/ae/90366304d7c2ce80f9b826096a9e9048b4bb760e44d3b873bb272cba696b/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156", size = 178689, upload-time = "2026-01-10T09:23:10.483Z" },
{ url = "https://files.pythonhosted.org/packages/f3/1d/e88022630271f5bd349ed82417136281931e558d628dd52c4d8621b4a0b2/websockets-16.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8cc451a50f2aee53042ac52d2d053d08bf89bcb31ae799cb4487587661c038a0", size = 177406, upload-time = "2026-01-10T09:23:12.178Z" },
{ url = "https://files.pythonhosted.org/packages/f2/78/e63be1bf0724eeb4616efb1ae1c9044f7c3953b7957799abb5915bffd38e/websockets-16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:daa3b6ff70a9241cf6c7fc9e949d41232d9d7d26fd3522b1ad2b4d62487e9904", size = 175085, upload-time = "2026-01-10T09:23:13.511Z" },
{ url = "https://files.pythonhosted.org/packages/bb/f4/d3c9220d818ee955ae390cf319a7c7a467beceb24f05ee7aaaa2414345ba/websockets-16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd3cb4adb94a2a6e2b7c0d8d05cb94e6f1c81a0cf9dc2694fb65c7e8d94c42e4", size = 175328, upload-time = "2026-01-10T09:23:14.727Z" },
{ url = "https://files.pythonhosted.org/packages/63/bc/d3e208028de777087e6fb2b122051a6ff7bbcca0d6df9d9c2bf1dd869ae9/websockets-16.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:781caf5e8eee67f663126490c2f96f40906594cb86b408a703630f95550a8c3e", size = 185044, upload-time = "2026-01-10T09:23:15.939Z" },
{ url = "https://files.pythonhosted.org/packages/ad/6e/9a0927ac24bd33a0a9af834d89e0abc7cfd8e13bed17a86407a66773cc0e/websockets-16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caab51a72c51973ca21fa8a18bd8165e1a0183f1ac7066a182ff27107b71e1a4", size = 186279, upload-time = "2026-01-10T09:23:17.148Z" },
{ url = "https://files.pythonhosted.org/packages/b9/ca/bf1c68440d7a868180e11be653c85959502efd3a709323230314fda6e0b3/websockets-16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19c4dc84098e523fd63711e563077d39e90ec6702aff4b5d9e344a60cb3c0cb1", size = 185711, upload-time = "2026-01-10T09:23:18.372Z" },
{ url = "https://files.pythonhosted.org/packages/c4/f8/fdc34643a989561f217bb477cbc47a3a07212cbda91c0e4389c43c296ebf/websockets-16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a5e18a238a2b2249c9a9235466b90e96ae4795672598a58772dd806edc7ac6d3", size = 184982, upload-time = "2026-01-10T09:23:19.652Z" },
{ url = "https://files.pythonhosted.org/packages/dd/d1/574fa27e233764dbac9c52730d63fcf2823b16f0856b3329fc6268d6ae4f/websockets-16.0-cp314-cp314-win32.whl", hash = "sha256:a069d734c4a043182729edd3e9f247c3b2a4035415a9172fd0f1b71658a320a8", size = 177915, upload-time = "2026-01-10T09:23:21.458Z" },
{ url = "https://files.pythonhosted.org/packages/8a/f1/ae6b937bf3126b5134ce1f482365fde31a357c784ac51852978768b5eff4/websockets-16.0-cp314-cp314-win_amd64.whl", hash = "sha256:c0ee0e63f23914732c6d7e0cce24915c48f3f1512ec1d079ed01fc629dab269d", size = 178381, upload-time = "2026-01-10T09:23:22.715Z" },
{ url = "https://files.pythonhosted.org/packages/06/9b/f791d1db48403e1f0a27577a6beb37afae94254a8c6f08be4a23e4930bc0/websockets-16.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:a35539cacc3febb22b8f4d4a99cc79b104226a756aa7400adc722e83b0d03244", size = 177737, upload-time = "2026-01-10T09:23:24.523Z" },
{ url = "https://files.pythonhosted.org/packages/bd/40/53ad02341fa33b3ce489023f635367a4ac98b73570102ad2cdd770dacc9a/websockets-16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b784ca5de850f4ce93ec85d3269d24d4c82f22b7212023c974c401d4980ebc5e", size = 175268, upload-time = "2026-01-10T09:23:25.781Z" },
{ url = "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:569d01a4e7fba956c5ae4fc988f0d4e187900f5497ce46339c996dbf24f17641", size = 175486, upload-time = "2026-01-10T09:23:27.033Z" },
{ url = "https://files.pythonhosted.org/packages/e5/2d/7583b30208b639c8090206f95073646c2c9ffd66f44df967981a64f849ad/websockets-16.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50f23cdd8343b984957e4077839841146f67a3d31ab0d00e6b824e74c5b2f6e8", size = 185331, upload-time = "2026-01-10T09:23:28.259Z" },
{ url = "https://files.pythonhosted.org/packages/45/b0/cce3784eb519b7b5ad680d14b9673a31ab8dcb7aad8b64d81709d2430aa8/websockets-16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:152284a83a00c59b759697b7f9e9cddf4e3c7861dd0d964b472b70f78f89e80e", size = 186501, upload-time = "2026-01-10T09:23:29.449Z" },
{ url = "https://files.pythonhosted.org/packages/19/60/b8ebe4c7e89fb5f6cdf080623c9d92789a53636950f7abacfc33fe2b3135/websockets-16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc59589ab64b0022385f429b94697348a6a234e8ce22544e3681b2e9331b5944", size = 186062, upload-time = "2026-01-10T09:23:31.368Z" },
{ url = "https://files.pythonhosted.org/packages/88/a8/a080593f89b0138b6cba1b28f8df5673b5506f72879322288b031337c0b8/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206", size = 185356, upload-time = "2026-01-10T09:23:32.627Z" },
{ url = "https://files.pythonhosted.org/packages/c2/b6/b9afed2afadddaf5ebb2afa801abf4b0868f42f8539bfe4b071b5266c9fe/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6", size = 178085, upload-time = "2026-01-10T09:23:33.816Z" },
{ url = "https://files.pythonhosted.org/packages/9f/3e/28135a24e384493fa804216b79a6a6759a38cc4ff59118787b9fb693df93/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd", size = 178531, upload-time = "2026-01-10T09:23:35.016Z" },
{ url = "https://files.pythonhosted.org/packages/72/07/c98a68571dcf256e74f1f816b8cc5eae6eb2d3d5cfa44d37f801619d9166/websockets-16.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:349f83cd6c9a415428ee1005cadb5c2c56f4389bc06a9af16103c3bc3dcc8b7d", size = 174947, upload-time = "2026-01-10T09:23:36.166Z" },
{ url = "https://files.pythonhosted.org/packages/7e/52/93e166a81e0305b33fe416338be92ae863563fe7bce446b0f687b9df5aea/websockets-16.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:4a1aba3340a8dca8db6eb5a7986157f52eb9e436b74813764241981ca4888f03", size = 175260, upload-time = "2026-01-10T09:23:37.409Z" },
{ url = "https://files.pythonhosted.org/packages/56/0c/2dbf513bafd24889d33de2ff0368190a0e69f37bcfa19009ef819fe4d507/websockets-16.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f4a32d1bd841d4bcbffdcb3d2ce50c09c3909fbead375ab28d0181af89fd04da", size = 176071, upload-time = "2026-01-10T09:23:39.158Z" },
{ url = "https://files.pythonhosted.org/packages/a5/8f/aea9c71cc92bf9b6cc0f7f70df8f0b420636b6c96ef4feee1e16f80f75dd/websockets-16.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0298d07ee155e2e9fda5be8a9042200dd2e3bb0b8a38482156576f863a9d457c", size = 176968, upload-time = "2026-01-10T09:23:41.031Z" },
{ url = "https://files.pythonhosted.org/packages/9a/3f/f70e03f40ffc9a30d817eef7da1be72ee4956ba8d7255c399a01b135902a/websockets-16.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a653aea902e0324b52f1613332ddf50b00c06fdaf7e92624fbf8c77c78fa5767", size = 178735, upload-time = "2026-01-10T09:23:42.259Z" },
{ url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" },
]
[[package]]
name = "xxhash"
version = "3.7.0"
+33 -3
View File
@@ -1,10 +1,28 @@
# LangGraph Checkpoint Postgres
Implementation of LangGraph CheckpointSaver that uses Postgres.
[![PyPI - Version](https://img.shields.io/pypi/v/langgraph-checkpoint-postgres?label=%20)](https://pypi.org/project/langgraph-checkpoint-postgres/#history)
[![PyPI - License](https://img.shields.io/pypi/l/langgraph-checkpoint-postgres)](https://opensource.org/licenses/MIT)
[![PyPI - Downloads](https://img.shields.io/pepy/dt/langgraph-checkpoint-postgres)](https://pypistats.org/packages/langgraph-checkpoint-postgres)
[![Twitter](https://img.shields.io/twitter/url/https/twitter.com/langchain_oss.svg?style=social&label=Follow%20%40LangChain)](https://x.com/langchain_oss)
## Dependencies
To help you ship LangGraph apps to production faster, check out [LangSmith](https://www.langchain.com/langsmith).
[LangSmith](https://www.langchain.com/langsmith) is a unified developer platform for building, testing, and monitoring LLM applications.
By default `langgraph-checkpoint-postgres` installs `psycopg` (Psycopg 3) without any extras. However, you can choose a specific installation that best suits your needs [here](https://www.psycopg.org/psycopg3/docs/basic/install.html) (for example, `psycopg[binary]`).
## Quick Install
```bash
uv add langgraph-checkpoint-postgres
```
## 🤔 What is this?
This library provides a Postgres implementation of LangGraph's checkpoint saver. Use it when you want LangGraph state persistence backed by Postgres for durable, long-running workflows and agents.
By default, `langgraph-checkpoint-postgres` installs `psycopg` (Psycopg 3) without any extras. You can choose a specific installation that best suits your needs in the [Psycopg installation docs](https://www.psycopg.org/psycopg3/docs/basic/install.html), for example `psycopg[binary]`.
## 📖 Documentation
For full documentation, see the [API reference](https://reference.langchain.com/python/langgraph.checkpoint.postgres). For conceptual guides on persistence and memory, see the [LangGraph Docs](https://docs.langchain.com/oss/python/langgraph/overview).
## Security
@@ -20,10 +38,12 @@ By default `langgraph-checkpoint-postgres` installs `psycopg` (Psycopg 3) withou
> When manually creating Postgres connections and passing them to `PostgresSaver` or `AsyncPostgresSaver`, make sure to include `autocommit=True` and `row_factory=dict_row` (`from psycopg.rows import dict_row`). See a full example in this [how-to guide](https://langchain-ai.github.io/langgraph/how-tos/persistence_postgres/).
>
> **Why these parameters are required:**
>
> - `autocommit=True`: Required for the `.setup()` method to properly commit the checkpoint tables to the database. Without this, table creation may not be persisted.
> - `row_factory=dict_row`: Required because the PostgresSaver implementation accesses database rows using dictionary-style syntax (e.g., `row["column_name"]`). The default `tuple_row` factory returns tuples that only support index-based access (e.g., `row[0]`), which will cause `TypeError` exceptions when the checkpointer tries to access columns by name.
>
> **Example of incorrect usage:**
>
> ```python
> # ❌ This will fail with TypeError during checkpointer operations
> with psycopg.connect(DB_URI) as conn: # Missing autocommit=True and row_factory=dict_row
@@ -118,3 +138,13 @@ async with AsyncPostgresSaver.from_conn_string(DB_URI) as checkpointer:
# list checkpoints
[c async for c in checkpointer.alist(read_config)]
```
## 📕 Releases & Versioning
See our [Releases](https://docs.langchain.com/oss/python/release-policy) and [Versioning](https://docs.langchain.com/oss/python/versioning) policies.
## 💁 Contributing
As an open-source project in a rapidly developing field, we are extremely open to contributions, whether it be in the form of a new feature, improved infrastructure, or better documentation.
For detailed information on how to contribute, see the [Contributing Guide](https://docs.langchain.com/oss/python/contributing/overview).
@@ -14,6 +14,7 @@ from langgraph.checkpoint.base import (
CheckpointMetadata,
CheckpointTuple,
DeltaChannelHistory,
_parse_supersteps_since_last_snapshot_by_channel,
get_checkpoint_id,
get_serializable_checkpoint_metadata,
)
@@ -28,9 +29,11 @@ from langgraph.checkpoint.postgres import _internal
from langgraph.checkpoint.postgres.base import (
_DELTA_PAGE_SIZE,
BasePostgresSaver,
_build_delta_stage1_sql,
_build_delta_stage2_sql,
_advance_shared_chain,
_build_delta_fetch_sql,
_build_delta_walk_sql,
_DeltaStage2Row,
_ingest_walk_page,
)
from langgraph.checkpoint.postgres.shallow import ShallowPostgresSaver
@@ -446,107 +449,137 @@ class PostgresSaver(BasePostgresSaver):
) -> Mapping[str, DeltaChannelHistory]:
"""Fast-path override of `BaseCheckpointSaver.get_delta_channel_history`.
Two-stage query, both stages cover ALL requested channels:
Reconstructs each delta channel's state for the target checkpoint by
walking the parent chain `supersteps` hops (read from the target's
`counters_since_delta_snapshot` metadata) to its seed snapshot, then
collecting the writes between the seed and the target.
* Stage 1 (paged): dynamic SELECT over `checkpoints` with K parallel
JSONB key lookups (one column pair per channel) — no subquery, no
aggregation. Pages newest-first by `checkpoint_id` with a cursor;
page size is `_DELTA_PAGE_SIZE`. Stops paging when every channel
has found its seed or the chain is exhausted.
Two passes (see the `# Multi-channel two-pass` comment in `base.py`):
* Stage 2 (per-channel UNION ALL): one branch per channel reading
`checkpoint_writes` filtered to that channel's specific
`chain_cids`, plus one branch per channel that has a seed reading
`checkpoint_blobs` for that channel + version. Avoids the
over-fetch of a single `channel = ANY(channels)` filter when
channels have different chain depths.
* WALK (paged): dynamic SELECT over `checkpoints` with K parallel
JSONB lookups for `channel_versions[ch]` (the seed blob version),
following `parent_checkpoint_id` newest-first. Page size is
`_DELTA_PAGE_SIZE`; stops once the shared chain reaches the deepest
requested `supersteps`, the root is reached, or the chain is
exhausted.
* FETCH (per-channel UNION ALL): one branch per channel reading
`checkpoint_writes` for its `chain_cids`, plus one branch per
channel that located a seed reading `checkpoint_blobs` at the
seed's version.
"""
if not channels:
return {}
channels = list(channels)
thread_id = config["configurable"]["thread_id"]
if not thread_id:
raise ValueError("empty thread ID")
checkpoint_ns = config["configurable"].get("checkpoint_ns", "")
checkpoint_id = get_checkpoint_id(config)
if checkpoint_id is None:
target = self.get_tuple(config)
if target is None:
return {ch: {"writes": []} for ch in channels}
checkpoint_id = target.config["configurable"]["checkpoint_id"]
# Stage 1: paged K-JSONB-lookup scan, walking the parent chain in
# Python after each page. Stops as soon as every channel has its seed.
stage1_sql = _build_delta_stage1_sql(channels, paged=True)
# Resolve the target checkpoint id + its metadata (for supersteps).
checkpoint_id = get_checkpoint_id(config)
with self._cursor() as cur:
if checkpoint_id is None:
cur.execute(
"SELECT checkpoint_id, metadata FROM checkpoints "
"WHERE thread_id = %s AND checkpoint_ns = %s "
"ORDER BY checkpoint_id DESC LIMIT 1",
(thread_id, checkpoint_ns),
)
else:
cur.execute(
"SELECT checkpoint_id, metadata FROM checkpoints "
"WHERE thread_id = %s AND checkpoint_ns = %s "
"AND checkpoint_id = %s",
(thread_id, checkpoint_ns, checkpoint_id),
)
target_row = cur.fetchone()
if target_row is None:
return {ch: {"writes": []} for ch in channels}
target_id = cast(str, target_row["checkpoint_id"])
supersteps_by_ch = _parse_supersteps_since_last_snapshot_by_channel(
target_row["metadata"] or {}, channels
)
max_supersteps = max(supersteps_by_ch.values(), default=0)
# WALK: page the parent chain, bounded by the deepest supersteps.
walk_sql = _build_delta_walk_sql(channels)
parent_of: dict[str, str | None] = {}
ver_by_i_by_cid: list[dict[str, str | None]] = [{} for _ in channels]
hs_by_i_by_cid: list[dict[str, bool]] = [{} for _ in channels]
chain_by_ch: dict[str, list[str]] = {ch: [] for ch in channels}
seed_ver_by_ch: dict[str, str | None] = {ch: None for ch in channels}
walk_cursor_by_ch: dict[str, str | None] = {}
seeded: set[str] = set()
shared_cpid_chain: list[str] = []
has_reached_root = False
cursor: str | None = None
with self._cursor() as cur:
while True:
stage1_params: list[Any] = []
for ch in channels:
stage1_params.extend([ch, ch])
stage1_params.extend(
[thread_id, checkpoint_ns, cursor, cursor, _DELTA_PAGE_SIZE]
)
cur.execute(stage1_sql, stage1_params)
while max_supersteps > 0:
walk_params: list[Any] = [
*channels,
thread_id,
checkpoint_ns,
cursor,
cursor,
_DELTA_PAGE_SIZE,
]
with self._cursor() as cur:
cur.execute(walk_sql, walk_params)
page = cur.fetchall()
if not page:
break
oldest = self._ingest_stage1_page(
cast("list[Mapping[str, Any]]", page),
channels,
parent_of,
ver_by_i_by_cid,
hs_by_i_by_cid,
)
self._try_advance_walks(
checkpoint_id,
channels,
parent_of,
ver_by_i_by_cid,
hs_by_i_by_cid,
chain_by_ch,
seed_ver_by_ch,
walk_cursor_by_ch,
seeded,
)
# Stop if every channel is seeded, or the page was short
# (chain exhausted — no more rows to fetch).
if len(seeded) == len(channels) or len(page) < _DELTA_PAGE_SIZE:
break
cursor = oldest
if not page:
break
oldest = _ingest_walk_page(
cast("list[Mapping[str, Any]]", page),
channels,
parent_of,
ver_by_i_by_cid,
)
has_reached_root = _advance_shared_chain(
target_id, parent_of, shared_cpid_chain, max_supersteps
)
if (
has_reached_root
or len(shared_cpid_chain) >= max_supersteps
or len(page) < _DELTA_PAGE_SIZE
):
break
cursor = oldest
# Stage 2: per-channel UNION ALL — one writes branch per channel
# with non-empty chain, plus one blob branch per seeded channel.
channels_with_chain = [ch for ch in channels if chain_by_ch[ch]]
chained_cpid_by_ch, seed_cpid_by_ch, seed_ver_by_ch = (
self._resolve_delta_chains(
channels,
supersteps_by_ch,
shared_cpid_chain,
ver_by_i_by_cid,
has_reached_root,
thread_id,
)
)
# FETCH: per-channel UNION ALL — writes branch per chained channel,
# blob branch per seeded channel.
channels_with_chain = [ch for ch in channels if chained_cpid_by_ch[ch]]
channels_with_seed = [ch for ch in channels if seed_ver_by_ch[ch] is not None]
stage2_sql = _build_delta_stage2_sql(
fetch_sql = _build_delta_fetch_sql(
channels_with_chain=channels_with_chain,
channels_with_seed=channels_with_seed,
)
if stage2_sql:
stage2_params: list[Any] = []
if fetch_sql:
fetch_params: list[Any] = []
for ch in channels_with_chain:
stage2_params.extend([thread_id, checkpoint_ns, ch, chain_by_ch[ch]])
fetch_params.extend(
[thread_id, checkpoint_ns, ch, chained_cpid_by_ch[ch]]
)
for ch in channels_with_seed:
stage2_params.extend([thread_id, checkpoint_ns, ch, seed_ver_by_ch[ch]])
fetch_params.extend([thread_id, checkpoint_ns, ch, seed_ver_by_ch[ch]])
with self._cursor() as cur:
cur.execute(stage2_sql, stage2_params)
stage2_rows = cur.fetchall()
cur.execute(fetch_sql, fetch_params)
fetch_rows = cur.fetchall()
else:
stage2_rows = []
fetch_rows = []
return self._build_delta_channels_writes_history(
return self._assemble_delta_history(
channels=channels,
chain_by_ch=chain_by_ch,
chained_cpid_by_ch=chained_cpid_by_ch,
seed_cpid_by_ch=seed_cpid_by_ch,
seed_ver_by_ch=seed_ver_by_ch,
stage2_rows=cast("list[_DeltaStage2Row]", stage2_rows),
fetch_rows=cast("list[_DeltaStage2Row]", fetch_rows),
)
def _load_checkpoint_tuple(self, value: DictRow) -> CheckpointTuple:
@@ -14,6 +14,7 @@ from langgraph.checkpoint.base import (
CheckpointMetadata,
CheckpointTuple,
DeltaChannelHistory,
_parse_supersteps_since_last_snapshot_by_channel,
get_checkpoint_id,
get_serializable_checkpoint_metadata,
)
@@ -28,9 +29,11 @@ from langgraph.checkpoint.postgres import _ainternal
from langgraph.checkpoint.postgres.base import (
_DELTA_PAGE_SIZE,
BasePostgresSaver,
_build_delta_stage1_sql,
_build_delta_stage2_sql,
_advance_shared_chain,
_build_delta_fetch_sql,
_build_delta_walk_sql,
_DeltaStage2Row,
_ingest_walk_page,
)
from langgraph.checkpoint.postgres.shallow import AsyncShallowPostgresSaver
@@ -408,89 +411,122 @@ class AsyncPostgresSaver(BasePostgresSaver):
"""Fast-path override of `BaseCheckpointSaver.aget_delta_channel_history`.
See `PostgresSaver.get_delta_channel_history` for design notes; this is
the async equivalent with internal stage-1 paging and per-channel
UNION ALL stage-2.
the async equivalent: paged supersteps-bounded WALK + per-channel
UNION ALL FETCH.
"""
if not channels:
return {}
channels = list(channels)
thread_id = config["configurable"]["thread_id"]
if not thread_id:
raise ValueError("empty thread ID")
checkpoint_ns = config["configurable"].get("checkpoint_ns", "")
checkpoint_id = get_checkpoint_id(config)
if checkpoint_id is None:
target = await self.aget_tuple(config)
if target is None:
return {ch: {"writes": []} for ch in channels}
checkpoint_id = target.config["configurable"]["checkpoint_id"]
stage1_sql = _build_delta_stage1_sql(channels, paged=True)
# Resolve the target checkpoint id + its metadata (for supersteps).
checkpoint_id = get_checkpoint_id(config)
async with self._cursor() as cur:
if checkpoint_id is None:
await cur.execute(
"SELECT checkpoint_id, metadata FROM checkpoints "
"WHERE thread_id = %s AND checkpoint_ns = %s "
"ORDER BY checkpoint_id DESC LIMIT 1",
(thread_id, checkpoint_ns),
)
else:
await cur.execute(
"SELECT checkpoint_id, metadata FROM checkpoints "
"WHERE thread_id = %s AND checkpoint_ns = %s "
"AND checkpoint_id = %s",
(thread_id, checkpoint_ns, checkpoint_id),
)
target_row = await cur.fetchone()
if target_row is None:
return {ch: {"writes": []} for ch in channels}
target_id = cast(str, target_row["checkpoint_id"])
supersteps_by_ch = _parse_supersteps_since_last_snapshot_by_channel(
target_row["metadata"] or {}, channels
)
max_supersteps = max(supersteps_by_ch.values(), default=0)
# WALK: page the parent chain, bounded by the deepest supersteps.
walk_sql = _build_delta_walk_sql(channels)
parent_of: dict[str, str | None] = {}
ver_by_i_by_cid: list[dict[str, str | None]] = [{} for _ in channels]
hs_by_i_by_cid: list[dict[str, bool]] = [{} for _ in channels]
chain_by_ch: dict[str, list[str]] = {ch: [] for ch in channels}
seed_ver_by_ch: dict[str, str | None] = {ch: None for ch in channels}
walk_cursor_by_ch: dict[str, str | None] = {}
seeded: set[str] = set()
shared_cpid_chain: list[str] = []
has_reached_root = False
cursor: str | None = None
async with self._cursor() as cur:
while True:
stage1_params: list[Any] = []
for ch in channels:
stage1_params.extend([ch, ch])
stage1_params.extend(
[thread_id, checkpoint_ns, cursor, cursor, _DELTA_PAGE_SIZE]
)
await cur.execute(stage1_sql, stage1_params)
while max_supersteps > 0:
walk_params: list[Any] = [
*channels,
thread_id,
checkpoint_ns,
cursor,
cursor,
_DELTA_PAGE_SIZE,
]
async with self._cursor() as cur:
await cur.execute(walk_sql, walk_params)
page = await cur.fetchall()
if not page:
break
oldest = self._ingest_stage1_page(
cast("list[Mapping[str, Any]]", page),
channels,
parent_of,
ver_by_i_by_cid,
hs_by_i_by_cid,
)
self._try_advance_walks(
checkpoint_id,
channels,
parent_of,
ver_by_i_by_cid,
hs_by_i_by_cid,
chain_by_ch,
seed_ver_by_ch,
walk_cursor_by_ch,
seeded,
)
if len(seeded) == len(channels) or len(page) < _DELTA_PAGE_SIZE:
break
cursor = oldest
if not page:
break
oldest = _ingest_walk_page(
cast("list[Mapping[str, Any]]", page),
channels,
parent_of,
ver_by_i_by_cid,
)
has_reached_root = _advance_shared_chain(
target_id, parent_of, shared_cpid_chain, max_supersteps
)
if (
has_reached_root
or len(shared_cpid_chain) >= max_supersteps
or len(page) < _DELTA_PAGE_SIZE
):
break
cursor = oldest
channels_with_chain = [ch for ch in channels if chain_by_ch[ch]]
chained_cpid_by_ch, seed_cpid_by_ch, seed_ver_by_ch = (
self._resolve_delta_chains(
channels,
supersteps_by_ch,
shared_cpid_chain,
ver_by_i_by_cid,
has_reached_root,
thread_id,
)
)
# FETCH: per-channel UNION ALL — writes branch per chained channel,
# blob branch per seeded channel.
channels_with_chain = [ch for ch in channels if chained_cpid_by_ch[ch]]
channels_with_seed = [ch for ch in channels if seed_ver_by_ch[ch] is not None]
stage2_sql = _build_delta_stage2_sql(
fetch_sql = _build_delta_fetch_sql(
channels_with_chain=channels_with_chain,
channels_with_seed=channels_with_seed,
)
if stage2_sql:
stage2_params: list[Any] = []
if fetch_sql:
fetch_params: list[Any] = []
for ch in channels_with_chain:
stage2_params.extend([thread_id, checkpoint_ns, ch, chain_by_ch[ch]])
fetch_params.extend(
[thread_id, checkpoint_ns, ch, chained_cpid_by_ch[ch]]
)
for ch in channels_with_seed:
stage2_params.extend([thread_id, checkpoint_ns, ch, seed_ver_by_ch[ch]])
fetch_params.extend([thread_id, checkpoint_ns, ch, seed_ver_by_ch[ch]])
async with self._cursor() as cur:
await cur.execute(stage2_sql, stage2_params)
stage2_rows = await cur.fetchall()
await cur.execute(fetch_sql, fetch_params)
fetch_rows = await cur.fetchall()
else:
stage2_rows = []
fetch_rows = []
return self._build_delta_channels_writes_history(
return self._assemble_delta_history(
channels=channels,
chain_by_ch=chain_by_ch,
chained_cpid_by_ch=chained_cpid_by_ch,
seed_cpid_by_ch=seed_cpid_by_ch,
seed_ver_by_ch=seed_ver_by_ch,
stage2_rows=cast("list[_DeltaStage2Row]", stage2_rows),
fetch_rows=cast("list[_DeltaStage2Row]", fetch_rows),
)
async def _load_checkpoint_tuple(self, value: DictRow) -> CheckpointTuple:
@@ -1,5 +1,6 @@
from __future__ import annotations
import logging
import random
import warnings
from collections.abc import Mapping, Sequence
@@ -15,10 +16,12 @@ from langgraph.checkpoint.base import (
PendingWrite,
get_checkpoint_id,
)
from langgraph.checkpoint.serde.types import TASKS
from langgraph.checkpoint.serde.types import TASKS, _DeltaSnapshot
from psycopg.types.json import Jsonb
# Page size for stage-1 paged scan in `get_delta_channel_history`. Internal
logger = logging.getLogger(__name__)
# Page size for the paged WALK scan in `get_delta_channel_history`. Internal
# constant — exposing this as a kwarg is left as a follow-up.
_DELTA_PAGE_SIZE = 1024
@@ -160,7 +163,7 @@ INSERT_CHECKPOINT_WRITES_SQL = """
class _DeltaStage2Row(TypedDict, total=False):
"""One row from `_build_delta_stage2_sql` (a UNION ALL of writes and blobs)."""
"""One row from `_build_delta_fetch_sql` (a UNION ALL of writes and blobs)."""
_kind: str # "w" or "b"
checkpoint_id: str | None # "w" rows only
@@ -172,42 +175,58 @@ class _DeltaStage2Row(TypedDict, total=False):
version: str | None # "b" rows only
# Multi-channel two-stage DeltaChannel reconstruction.
# Multi-channel two-pass DeltaChannel reconstruction.
#
# Stage 1 scans checkpoint metadata (no blob bytes) and emits one row per
# checkpoint with K parallel JSONB key lookups (one column pair per
# requested delta channel: ver_i / hs_i). No subqueries, no aggregation.
# Python walks the parent chain once across all channels.
# A `DeltaChannel` does not store its full value at every checkpoint — it
# stores periodic full-value *snapshots* and accumulates intermediate
# *writes* between snapshots. To rebuild a channel's value at a target
# checkpoint we need:
#
# Stage 2 fetches all writes and the seed blobs for ALL channels in a
# single roundtrip via `channel = ANY(%s)` and chain/seed-version
# filtering.
# - the **seed** — the most recent snapshot at-or-before the target
# (a single blob row in `checkpoint_blobs`); and
# - the **chain writes** — every write for this channel committed
# between that snapshot and the target, in order
# (rows in `checkpoint_writes`).
#
# Empirical comparison vs an alternative "ship full channel_versions /
# channel_values JSONB and let Python pick" form (1000 checkpoints,
# 8 total channels in graph, 3 delta channels requested):
# Two passes, in order:
#
# Postgres execution: A=0.24ms vs B=0.38ms (both negligible)
# End-to-end latency: A=6.83ms vs B=2.28ms (B is 3.0x faster)
# Wire payload: A=836KB vs B=330KB (61% smaller)
# Buffer hits: identical (167 blocks)
# 1. WALK — scan checkpoint metadata only (no blob bytes). For each
# requested channel we read `channel_versions[ch]` (the seed's blob
# version pointer). Then follow `parent_checkpoint_id` from the
# target backwards in pages of `_DELTA_PAGE_SIZE` rows.
#
# B (this dynamic-columns design) wins because it avoids JSONB
# serialization on the wire and JSONB-to-dict deserialization in
# psycopg. Even at K=8 (8 delta channels = 16 dynamic columns), B
# still beats A end-to-end (4.2ms vs 6.8ms).
# Walk depth is driven by the *supersteps since last snapshot*
# counter — `metadata.counters_since_delta_snapshot[ch][1]` — read
# from the target checkpoint. A channel's seed snapshot sits exactly
# `supersteps` hops back along the parent chain; walking by the
# counter (rather than scanning `channel_values` for the snapshot
# marker) is the only reliable way to locate seeds that aren't a
# `_DeltaSnapshot` sentinel — e.g. legacy plain-value blobs left by a
# thread that migrated from a non-delta channel, which `put` stores
# out of the inline `channel_values` map.
#
# 2. FETCH — given each channel's chained checkpoint ids and seed
# version from WALK, pull only the rows we need: writes for those
# exact checkpoint_ids and the seed blob at that exact version. One
# roundtrip, per-channel UNION ALL — no over-fetch.
#
# Walking the *parent chain* (not `list(before=...)`) matters: forked
# threads have multiple branches, and only on-path ancestors contribute.
def _build_delta_stage1_sql(channels: Sequence[str], *, paged: bool) -> str:
"""Build stage 1 SQL with 2K parallel JSONB key lookups.
def _build_delta_walk_sql(channels: Sequence[str]) -> str:
"""Build the paged WALK SQL — scans checkpoint metadata only.
For channels=["messages", "files"] (with `paged=True`) the result is::
Emits one row per checkpoint with K parallel JSONB key lookups (one
`ver_i` column per requested channel — the channel's blob version, the
pointer we dereference in FETCH if this checkpoint is the seed). No
blob bytes; the result set fits a paged `LIMIT` cleanly.
For channels=["messages", "files"] the result is::
SELECT checkpoint_id, parent_checkpoint_id,
checkpoint -> 'channel_versions' ->> %s AS ver_0,
(checkpoint -> 'channel_values' -> %s) IS NOT NULL AS hs_0,
checkpoint -> 'channel_versions' ->> %s AS ver_1,
(checkpoint -> 'channel_values' -> %s) IS NOT NULL AS hs_1
checkpoint -> 'channel_versions' ->> %s AS ver_1
FROM checkpoints
WHERE thread_id = %s AND checkpoint_ns = %s
AND (%s::text IS NULL OR checkpoint_id < %s)
@@ -215,45 +234,38 @@ def _build_delta_stage1_sql(channels: Sequence[str], *, paged: bool) -> str:
LIMIT %s
Channel names are passed as `%s` parameters (safe from SQL injection).
Only the column aliases `ver_i` / `hs_i` are interpolated into the
SQL string (i is bounded by len(channels) and uses safe identifiers).
Only the column aliases `ver_i` are interpolated into the SQL string
(i is bounded by len(channels) and uses safe identifiers).
Caller must extend params with `[ch_0, ch_0, ch_1, ch_1, ...,
thread_id, ns, cursor, cursor, page_size]` when `paged=True`.
When `paged=False`, the WHERE has no cursor predicate and there's no
LIMIT/ORDER BY — kept as a non-public helper for tests/diagnostics.
Caller must extend params with `[ch_0, ch_1, ..., thread_id, ns,
cursor, cursor, page_size]`. The `cursor` is the smallest
`checkpoint_id` from the previous page (or `None` on the first page);
`(%s::text IS NULL OR ...)` makes the first-page `WHERE` a no-op.
"""
cols = []
for i in range(len(channels)):
cols.append(
f"checkpoint -> 'channel_versions' ->> %s AS ver_{i}, "
f"(checkpoint -> 'channel_values' -> %s) IS NOT NULL AS hs_{i}"
)
sql = (
cols = [
f"checkpoint -> 'channel_versions' ->> %s AS ver_{i}"
for i in range(len(channels))
]
return (
"SELECT checkpoint_id, parent_checkpoint_id, "
+ ", ".join(cols)
+ " FROM checkpoints WHERE thread_id = %s AND checkpoint_ns = %s"
" AND (%s::text IS NULL OR checkpoint_id < %s)"
" ORDER BY checkpoint_id DESC LIMIT %s"
)
if paged:
sql += (
" AND (%s::text IS NULL OR checkpoint_id < %s)"
" ORDER BY checkpoint_id DESC LIMIT %s"
)
return sql
def _build_delta_stage2_sql(
def _build_delta_fetch_sql(
*,
channels_with_chain: Sequence[str],
channels_with_seed: Sequence[str],
) -> str:
"""Build stage 2 SQL as a per-channel UNION ALL.
"""Build the FETCH SQL as a per-channel UNION ALL.
For each channel with a non-empty chain, emit one branch reading
`checkpoint_writes` for that specific channel + chain_cids. For each
channel with a seed_version, emit one branch reading `checkpoint_blobs`
for that channel + version. This avoids the over-fetch of the prior
for that channel + version. This avoids the over-fetch of a single
`channel = ANY(channels) AND checkpoint_id = ANY(union)` form when
channels have different chain depths.
@@ -269,6 +281,7 @@ def _build_delta_stage2_sql(
"""
branches: list[str] = []
for _ in channels_with_chain:
# NOTE: no ORDER BY on this branch — writes are sorted in assembly.
branches.append(
"SELECT 'w'::text AS _kind, "
"checkpoint_id, channel, "
@@ -288,10 +301,59 @@ def _build_delta_stage2_sql(
return " UNION ALL ".join(branches)
# Stage 1 rows are dynamic-shape dicts: {checkpoint_id, parent_checkpoint_id,
# ver_0, hs_0, ver_1, hs_1, ...}. Walking is parameterized by the channel
# list to map indices back to channel names — no static TypedDict here.
# `dict[str, Any]` is the practical signature.
def _ingest_walk_page(
page_rows: Sequence[Mapping[str, Any]],
channels: Sequence[str],
parent_of: dict[str, str | None],
ver_by_i_by_cid: list[dict[str, str | None]],
) -> str | None:
"""Fold one WALK page into `parent_of` + per-channel `ver_by_cid`.
Returns the oldest checkpoint_id seen on this page (smallest, since
pages come back DESC). Caller uses it as the cursor for the next page
(`AND checkpoint_id < cursor`).
"""
oldest: str | None = None
for r in page_rows:
cid = cast(str, r["checkpoint_id"])
parent_of[cid] = cast("str | None", r["parent_checkpoint_id"])
for i in range(len(channels)):
ver_by_i_by_cid[i][cid] = cast("str | None", r.get(f"ver_{i}"))
# Rows are DESC; the last one is the smallest cid in the page.
oldest = cid
return oldest
def _advance_shared_chain(
target_id: str,
parent_of: Mapping[str, str | None],
shared_cpid_chain: list[str],
max_supersteps: int,
) -> bool:
"""Extend the shared parent chain as far as ingested pages allow.
The chain holds ancestors of the target, newest first: `chain[0]` is
the target's parent, `chain[1]` its grandparent, and so on. A single
chain is shared across all channels and grown to the maximum requested
depth; each channel later slices `chain[:supersteps]`.
Stops when:
- the chain reaches `max_supersteps` hops, OR
- the root is reached (parent is None) — returns True, OR
- the next ancestor's cid isn't in `parent_of` yet (waits for the
next page).
Returns True iff the root was reached.
"""
while len(shared_cpid_chain) < max_supersteps:
top_of_chain = shared_cpid_chain[-1] if shared_cpid_chain else target_id
if top_of_chain not in parent_of:
return False # wait for the next page
parent = parent_of[top_of_chain]
if parent is None:
return True # hit the root
shared_cpid_chain.append(parent)
return False
class BasePostgresSaver(BaseCheckpointSaver[str]):
@@ -336,107 +398,92 @@ class BasePostgresSaver(BaseCheckpointSaver[str]):
if t.decode() != "empty"
}
@staticmethod
def _ingest_stage1_page(
stage1_rows: Sequence[Mapping[str, Any]],
def _resolve_delta_chains(
self,
channels: Sequence[str],
parent_of: dict[str, str | None],
ver_by_i_by_cid: list[dict[str, str | None]],
hs_by_i_by_cid: list[dict[str, bool]],
) -> str | None:
"""Fold one stage-1 page into the running walk-state mappings.
Returns the oldest checkpoint_id seen on this page (smallest, since
pages come back DESC). Caller uses it as the cursor for the next
page (`AND checkpoint_id < cursor`).
"""
oldest: str | None = None
for r in stage1_rows:
cid = cast(str, r["checkpoint_id"])
parent_of[cid] = cast("str | None", r["parent_checkpoint_id"])
for i in range(len(channels)):
ver_by_i_by_cid[i][cid] = cast("str | None", r.get(f"ver_{i}"))
hs_by_i_by_cid[i][cid] = bool(r.get(f"hs_{i}"))
# Rows are DESC; the last one is the smallest cid in the page.
oldest = cid
return oldest
@staticmethod
def _try_advance_walks(
target_id: str,
channels: Sequence[str],
parent_of: Mapping[str, str | None],
supersteps_by_ch: Mapping[str, int],
shared_cpid_chain: Sequence[str],
ver_by_i_by_cid: Sequence[Mapping[str, str | None]],
hs_by_i_by_cid: Sequence[Mapping[str, bool]],
chain_by_ch: dict[str, list[str]],
seed_ver_by_ch: dict[str, str | None],
walk_cursor_by_ch: dict[str, str | None],
seeded: set[str],
) -> None:
"""Advance each not-yet-seeded channel's walk as far as possible.
has_reached_root: bool,
thread_id: str,
) -> tuple[
dict[str, list[str]],
dict[str, str | None],
dict[str, str | None],
]:
"""Slice the shared parent chain into per-channel chain/seed mappings.
Uses the partial `parent_of` map accumulated so far. A walk stops
either because:
(a) it found a snapshot for its channel (channel becomes seeded),
(b) it reached a real root (parent_of[cid] is None — fully
materialized at this point), or
(c) the next ancestor cid isn't in `parent_of` yet (waiting for
a later page; the cursor stays put).
For each channel the seed snapshot sits `supersteps` hops back, so
the seed checkpoint is `shared_cpid_chain[supersteps - 1]` and the
chain is `shared_cpid_chain[:supersteps]` (newest first).
Mutates `chain_by_ch`, `seed_ver_by_ch`, `walk_cursor_by_ch`, and
`seeded` in place.
When the chain is shorter than `supersteps` but the walk reached the
root, the persisted chain is "compressed" relative to the logical
superstep count — either because intermediate supersteps were never
persisted (`durability="exit"`) or because the thread never produced
a snapshot at all. In both cases the seed candidate is the oldest
persisted checkpoint (`shared_cpid_chain[-1]`): FETCH loads its blob,
and assembly keeps it only if non-empty (a real snapshot or migrated
value) — otherwise it omits `seed` and replays the full chain on an
empty baseline.
"""
chained_cpid_by_ch: dict[str, list[str]] = {ch: [] for ch in channels}
seed_cpid_by_ch: dict[str, str | None] = {ch: None for ch in channels}
seed_ver_by_ch: dict[str, str | None] = {ch: None for ch in channels}
for i, ch in enumerate(channels):
if ch in seeded:
bound = supersteps_by_ch.get(ch, 0)
if bound <= 0:
continue
# First-time entry: cursor starts at the target's parent.
if ch not in walk_cursor_by_ch:
walk_cursor_by_ch[ch] = parent_of.get(target_id)
cur_cid = walk_cursor_by_ch[ch]
ch_chain = chain_by_ch[ch]
hs_i = hs_by_i_by_cid[i]
ver_i = ver_by_i_by_cid[i]
while cur_cid is not None:
if cur_cid not in parent_of:
# Need more pages to continue this walk.
break
ch_chain.append(cur_cid)
if hs_i.get(cur_cid, False):
seed_ver_by_ch[ch] = ver_i.get(cur_cid)
seeded.add(ch)
cur_cid = None
break
cur_cid = parent_of[cur_cid]
walk_cursor_by_ch[ch] = cur_cid
if len(shared_cpid_chain) >= bound:
seed_depth = bound
elif has_reached_root:
seed_depth = len(shared_cpid_chain)
else:
logger.warning(
"cannot find seed snapshot for delta channel "
"(thread_id=%s, channel=%s)",
thread_id,
ch,
)
continue
if seed_depth <= 0:
continue
chained_cpid_by_ch[ch] = list(shared_cpid_chain[:seed_depth])
seed_cpid_by_ch[ch] = shared_cpid_chain[seed_depth - 1]
seed_ver_by_ch[ch] = ver_by_i_by_cid[i].get(seed_cpid_by_ch[ch])
return chained_cpid_by_ch, seed_cpid_by_ch, seed_ver_by_ch
def _build_delta_channels_writes_history(
def _assemble_delta_history(
self,
*,
channels: Sequence[str],
chain_by_ch: Mapping[str, list[str]],
chained_cpid_by_ch: Mapping[str, Sequence[str]],
seed_cpid_by_ch: Mapping[str, str | None],
seed_ver_by_ch: Mapping[str, str | None],
stage2_rows: Sequence[_DeltaStage2Row],
fetch_rows: Sequence[_DeltaStage2Row],
) -> dict[str, DeltaChannelHistory]:
"""Demux stage 2 rows per channel; produce per-channel histories.
"""Demux FETCH rows per channel and produce per-channel histories.
stage2_rows carry `channel` on every row. We build per-channel
`writes_by_cid` and per-channel `seed_blob` dicts, then assemble
a `DeltaChannelHistory` per requested channel. The `seed` key is omitted
when the walk reached root with no snapshot found, or when the
seed blob is sentinel "empty" — in both cases the consumer treats
absence as "start empty".
`fetch_rows` carry `channel` on every row. Write rows (`_kind = 'w'`)
are bucketed per channel per checkpoint; seed-blob rows
(`_kind = 'b'`) give each channel its snapshot value.
The seed checkpoint's own writes are replayed on top of a
`_DeltaSnapshot` seed (the snapshot is the value *prior* to its own
writes), but skipped for a migrated plain-value seed (a legacy
non-delta blob already incorporates those writes). The `seed` key is
omitted when no seed was located or the blob is the "empty"
tombstone — the consumer treats absence as "start empty".
"""
# writes_by_ch_by_cid[channel][cid] = list of (type, blob, task_id, idx)
writes_by_ch_by_cid: dict[str, dict[str, list[tuple[str, bytes, str, int]]]] = {
ch: {} for ch in channels
}
# seed_blob_by_ver[(channel, version)] = (type, blob)
seed_blob_by_ver: dict[tuple[str, str], tuple[str, bytes]] = {}
seed_blob_by_ch: dict[str, tuple[str, bytes]] = {}
for r in stage2_rows:
for r in fetch_rows:
ch = cast(str, r["channel"])
kind = r["_kind"]
if kind == "w":
if r["_kind"] == "w":
cid = cast(str, r["checkpoint_id"])
writes_by_ch_by_cid.setdefault(ch, {}).setdefault(cid, []).append(
cast(
@@ -444,35 +491,39 @@ class BasePostgresSaver(BaseCheckpointSaver[str]):
(r["type"], r["blob"], r["task_id"], r["idx"]),
)
)
else: # kind == "b"
ver = cast(str, r["version"])
seed_blob_by_ver[(ch, ver)] = cast(
"tuple[str, bytes]", (r["type"], r["blob"])
)
else: # _kind == "b" — the seed blob for this channel.
seed_blob_by_ch[ch] = cast("tuple[str, bytes]", (r["type"], r["blob"]))
# Sort writes per (channel, cid) newest-first by (task_id, idx)
# Within a checkpoint, writes apply oldest→newest by (task_id, idx).
for cid_map in writes_by_ch_by_cid.values():
for ws in cid_map.values():
ws.sort(key=lambda w: (w[2], w[3]), reverse=True)
ws.sort(key=lambda w: (w[2], w[3]))
result: dict[str, DeltaChannelHistory] = {}
for ch in channels:
chain_cids = chain_by_ch.get(ch, [])
seed_version = seed_ver_by_ch.get(ch)
entry: DeltaChannelHistory = {"writes": []}
skip_seed_checkpoint_writes = False
seed_blob = seed_blob_by_ch.get(ch)
if seed_blob is not None and seed_blob[0] != "empty":
seed_value = self.serde.loads_typed(seed_blob)
entry["seed"] = seed_value
# A migrated (non-delta) seed already includes the writes on
# its own checkpoint; a `_DeltaSnapshot` does not.
skip_seed_checkpoint_writes = not isinstance(seed_value, _DeltaSnapshot)
collected: list[PendingWrite] = []
cid_writes = writes_by_ch_by_cid.get(ch, {})
for cid in chain_cids:
for type_tag, write_blob, task_id, _idx in cid_writes.get(cid, []):
val = self.serde.loads_typed((type_tag, write_blob))
collected.append((task_id, ch, val))
collected.reverse()
entry: DeltaChannelHistory = {"writes": collected}
if seed_version is not None:
blob = seed_blob_by_ver.get((ch, seed_version))
if blob is not None and blob[0] != "empty":
entry["seed"] = self.serde.loads_typed(blob)
if cid_writes:
collected: list[PendingWrite] = []
seed_cpid = seed_cpid_by_ch.get(ch)
# Chain is newest→oldest; replay oldest→newest.
for cid in reversed(chained_cpid_by_ch.get(ch, [])):
if skip_seed_checkpoint_writes and cid == seed_cpid:
continue
for type_tag, write_blob, task_id, _idx in cid_writes.get(cid, []):
val = self.serde.loads_typed((type_tag, write_blob))
collected.append((task_id, ch, val))
entry["writes"] = collected
result[ch] = entry
return result
+72 -3
View File
@@ -399,7 +399,7 @@ test = [
[[package]]
name = "langsmith"
version = "0.8.0"
version = "0.8.18"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
@@ -409,12 +409,13 @@ dependencies = [
{ name = "requests" },
{ name = "requests-toolbelt" },
{ name = "uuid-utils" },
{ name = "websockets" },
{ name = "xxhash" },
{ name = "zstandard" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a8/64/95f1f013531395f4e8ed73caeee780f65c7c58fe028cb543f8937b45611b/langsmith-0.8.0.tar.gz", hash = "sha256:59fe5b2a56bbbe14a08aa76691f84b49e8675dd21e11b57d80c6db8c08bac2e3", size = 4432996, upload-time = "2026-04-30T22:13:07.341Z" }
sdist = { url = "https://files.pythonhosted.org/packages/9a/d9/a6681aa9847bbbc5ec21abe20a5e233b94e5edcfe39624db607ac7e8ccb4/langsmith-0.8.18.tar.gz", hash = "sha256:32dde9c0e67e053e0fb738921fc8ced768af7b8fa83d7a0e3fd63597cf8776dd", size = 4526988, upload-time = "2026-06-19T13:12:17.123Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f3/e1/a4be2e696c9473bb53298df398237da5674704d781d4b748ed35aeef592a/langsmith-0.8.0-py3-none-any.whl", hash = "sha256:12cc4bc5622b835a6d841964d6034df3617bdb912dae0c1381fd0a68a9b3a3ef", size = 393268, upload-time = "2026-04-30T22:13:05.56Z" },
{ url = "https://files.pythonhosted.org/packages/03/70/0e0cc80a3b064c8d6c8d697c3125ed86e39d5a7393ec6dc8b07cb1cf13c4/langsmith-0.8.18-py3-none-any.whl", hash = "sha256:3940183349993faef48e6c7d08e4822ee9cefd906b362d0e3c2d650314d2f282", size = 508108, upload-time = "2026-06-19T13:12:15.348Z" },
]
[[package]]
@@ -1167,6 +1168,74 @@ wheels = [
{ 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 = "websockets"
version = "16.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/20/74/221f58decd852f4b59cc3354cccaf87e8ef695fede361d03dc9a7396573b/websockets-16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:04cdd5d2d1dacbad0a7bf36ccbcd3ccd5a30ee188f2560b7a62a30d14107b31a", size = 177343, upload-time = "2026-01-10T09:22:21.28Z" },
{ url = "https://files.pythonhosted.org/packages/19/0f/22ef6107ee52ab7f0b710d55d36f5a5d3ef19e8a205541a6d7ffa7994e5a/websockets-16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8ff32bb86522a9e5e31439a58addbb0166f0204d64066fb955265c4e214160f0", size = 175021, upload-time = "2026-01-10T09:22:22.696Z" },
{ url = "https://files.pythonhosted.org/packages/10/40/904a4cb30d9b61c0e278899bf36342e9b0208eb3c470324a9ecbaac2a30f/websockets-16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:583b7c42688636f930688d712885cf1531326ee05effd982028212ccc13e5957", size = 175320, upload-time = "2026-01-10T09:22:23.94Z" },
{ url = "https://files.pythonhosted.org/packages/9d/2f/4b3ca7e106bc608744b1cdae041e005e446124bebb037b18799c2d356864/websockets-16.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7d837379b647c0c4c2355c2499723f82f1635fd2c26510e1f587d89bc2199e72", size = 183815, upload-time = "2026-01-10T09:22:25.469Z" },
{ url = "https://files.pythonhosted.org/packages/86/26/d40eaa2a46d4302becec8d15b0fc5e45bdde05191e7628405a19cf491ccd/websockets-16.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df57afc692e517a85e65b72e165356ed1df12386ecb879ad5693be08fac65dde", size = 185054, upload-time = "2026-01-10T09:22:27.101Z" },
{ url = "https://files.pythonhosted.org/packages/b0/ba/6500a0efc94f7373ee8fefa8c271acdfd4dca8bd49a90d4be7ccabfc397e/websockets-16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2b9f1e0d69bc60a4a87349d50c09a037a2607918746f07de04df9e43252c77a3", size = 184565, upload-time = "2026-01-10T09:22:28.293Z" },
{ url = "https://files.pythonhosted.org/packages/04/b4/96bf2cee7c8d8102389374a2616200574f5f01128d1082f44102140344cc/websockets-16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:335c23addf3d5e6a8633f9f8eda77efad001671e80b95c491dd0924587ece0b3", size = 183848, upload-time = "2026-01-10T09:22:30.394Z" },
{ url = "https://files.pythonhosted.org/packages/02/8e/81f40fb00fd125357814e8c3025738fc4ffc3da4b6b4a4472a82ba304b41/websockets-16.0-cp310-cp310-win32.whl", hash = "sha256:37b31c1623c6605e4c00d466c9d633f9b812ea430c11c8a278774a1fde1acfa9", size = 178249, upload-time = "2026-01-10T09:22:32.083Z" },
{ url = "https://files.pythonhosted.org/packages/b4/5f/7e40efe8df57db9b91c88a43690ac66f7b7aa73a11aa6a66b927e44f26fa/websockets-16.0-cp310-cp310-win_amd64.whl", hash = "sha256:8e1dab317b6e77424356e11e99a432b7cb2f3ec8c5ab4dabbcee6add48f72b35", size = 178685, upload-time = "2026-01-10T09:22:33.345Z" },
{ url = "https://files.pythonhosted.org/packages/f2/db/de907251b4ff46ae804ad0409809504153b3f30984daf82a1d84a9875830/websockets-16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:31a52addea25187bde0797a97d6fc3d2f92b6f72a9370792d65a6e84615ac8a8", size = 177340, upload-time = "2026-01-10T09:22:34.539Z" },
{ url = "https://files.pythonhosted.org/packages/f3/fa/abe89019d8d8815c8781e90d697dec52523fb8ebe308bf11664e8de1877e/websockets-16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:417b28978cdccab24f46400586d128366313e8a96312e4b9362a4af504f3bbad", size = 175022, upload-time = "2026-01-10T09:22:36.332Z" },
{ url = "https://files.pythonhosted.org/packages/58/5d/88ea17ed1ded2079358b40d31d48abe90a73c9e5819dbcde1606e991e2ad/websockets-16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:af80d74d4edfa3cb9ed973a0a5ba2b2a549371f8a741e0800cb07becdd20f23d", size = 175319, upload-time = "2026-01-10T09:22:37.602Z" },
{ url = "https://files.pythonhosted.org/packages/d2/ae/0ee92b33087a33632f37a635e11e1d99d429d3d323329675a6022312aac2/websockets-16.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:08d7af67b64d29823fed316505a89b86705f2b7981c07848fb5e3ea3020c1abe", size = 184631, upload-time = "2026-01-10T09:22:38.789Z" },
{ url = "https://files.pythonhosted.org/packages/c8/c5/27178df583b6c5b31b29f526ba2da5e2f864ecc79c99dae630a85d68c304/websockets-16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be95cfb0a4dae143eaed2bcba8ac23f4892d8971311f1b06f3c6b78952ee70b", size = 185870, upload-time = "2026-01-10T09:22:39.893Z" },
{ url = "https://files.pythonhosted.org/packages/87/05/536652aa84ddc1c018dbb7e2c4cbcd0db884580bf8e95aece7593fde526f/websockets-16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6297ce39ce5c2e6feb13c1a996a2ded3b6832155fcfc920265c76f24c7cceb5", size = 185361, upload-time = "2026-01-10T09:22:41.016Z" },
{ url = "https://files.pythonhosted.org/packages/6d/e2/d5332c90da12b1e01f06fb1b85c50cfc489783076547415bf9f0a659ec19/websockets-16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c1b30e4f497b0b354057f3467f56244c603a79c0d1dafce1d16c283c25f6e64", size = 184615, upload-time = "2026-01-10T09:22:42.442Z" },
{ url = "https://files.pythonhosted.org/packages/77/fb/d3f9576691cae9253b51555f841bc6600bf0a983a461c79500ace5a5b364/websockets-16.0-cp311-cp311-win32.whl", hash = "sha256:5f451484aeb5cafee1ccf789b1b66f535409d038c56966d6101740c1614b86c6", size = 178246, upload-time = "2026-01-10T09:22:43.654Z" },
{ url = "https://files.pythonhosted.org/packages/54/67/eaff76b3dbaf18dcddabc3b8c1dba50b483761cccff67793897945b37408/websockets-16.0-cp311-cp311-win_amd64.whl", hash = "sha256:8d7f0659570eefb578dacde98e24fb60af35350193e4f56e11190787bee77dac", size = 178684, upload-time = "2026-01-10T09:22:44.941Z" },
{ url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" },
{ url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" },
{ url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" },
{ url = "https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c", size = 184915, upload-time = "2026-01-10T09:22:51.071Z" },
{ url = "https://files.pythonhosted.org/packages/97/bb/21c36b7dbbafc85d2d480cd65df02a1dc93bf76d97147605a8e27ff9409d/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f", size = 186152, upload-time = "2026-01-10T09:22:52.224Z" },
{ url = "https://files.pythonhosted.org/packages/4a/34/9bf8df0c0cf88fa7bfe36678dc7b02970c9a7d5e065a3099292db87b1be2/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1", size = 185583, upload-time = "2026-01-10T09:22:53.443Z" },
{ url = "https://files.pythonhosted.org/packages/47/88/4dd516068e1a3d6ab3c7c183288404cd424a9a02d585efbac226cb61ff2d/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2", size = 184880, upload-time = "2026-01-10T09:22:55.033Z" },
{ url = "https://files.pythonhosted.org/packages/91/d6/7d4553ad4bf1c0421e1ebd4b18de5d9098383b5caa1d937b63df8d04b565/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89", size = 178261, upload-time = "2026-01-10T09:22:56.251Z" },
{ url = "https://files.pythonhosted.org/packages/c3/f0/f3a17365441ed1c27f850a80b2bc680a0fa9505d733fe152fdf5e98c1c0b/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea", size = 178693, upload-time = "2026-01-10T09:22:57.478Z" },
{ url = "https://files.pythonhosted.org/packages/cc/9c/baa8456050d1c1b08dd0ec7346026668cbc6f145ab4e314d707bb845bf0d/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9", size = 177364, upload-time = "2026-01-10T09:22:59.333Z" },
{ url = "https://files.pythonhosted.org/packages/7e/0c/8811fc53e9bcff68fe7de2bcbe75116a8d959ac699a3200f4847a8925210/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230", size = 175039, upload-time = "2026-01-10T09:23:01.171Z" },
{ url = "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c", size = 175323, upload-time = "2026-01-10T09:23:02.341Z" },
{ url = "https://files.pythonhosted.org/packages/bd/28/0a25ee5342eb5d5f297d992a77e56892ecb65e7854c7898fb7d35e9b33bd/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5", size = 184975, upload-time = "2026-01-10T09:23:03.756Z" },
{ url = "https://files.pythonhosted.org/packages/f9/66/27ea52741752f5107c2e41fda05e8395a682a1e11c4e592a809a90c6a506/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82", size = 186203, upload-time = "2026-01-10T09:23:05.01Z" },
{ url = "https://files.pythonhosted.org/packages/37/e5/8e32857371406a757816a2b471939d51c463509be73fa538216ea52b792a/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8", size = 185653, upload-time = "2026-01-10T09:23:06.301Z" },
{ url = "https://files.pythonhosted.org/packages/9b/67/f926bac29882894669368dc73f4da900fcdf47955d0a0185d60103df5737/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f", size = 184920, upload-time = "2026-01-10T09:23:07.492Z" },
{ url = "https://files.pythonhosted.org/packages/3c/a1/3d6ccdcd125b0a42a311bcd15a7f705d688f73b2a22d8cf1c0875d35d34a/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a", size = 178255, upload-time = "2026-01-10T09:23:09.245Z" },
{ url = "https://files.pythonhosted.org/packages/6b/ae/90366304d7c2ce80f9b826096a9e9048b4bb760e44d3b873bb272cba696b/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156", size = 178689, upload-time = "2026-01-10T09:23:10.483Z" },
{ url = "https://files.pythonhosted.org/packages/f3/1d/e88022630271f5bd349ed82417136281931e558d628dd52c4d8621b4a0b2/websockets-16.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8cc451a50f2aee53042ac52d2d053d08bf89bcb31ae799cb4487587661c038a0", size = 177406, upload-time = "2026-01-10T09:23:12.178Z" },
{ url = "https://files.pythonhosted.org/packages/f2/78/e63be1bf0724eeb4616efb1ae1c9044f7c3953b7957799abb5915bffd38e/websockets-16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:daa3b6ff70a9241cf6c7fc9e949d41232d9d7d26fd3522b1ad2b4d62487e9904", size = 175085, upload-time = "2026-01-10T09:23:13.511Z" },
{ url = "https://files.pythonhosted.org/packages/bb/f4/d3c9220d818ee955ae390cf319a7c7a467beceb24f05ee7aaaa2414345ba/websockets-16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd3cb4adb94a2a6e2b7c0d8d05cb94e6f1c81a0cf9dc2694fb65c7e8d94c42e4", size = 175328, upload-time = "2026-01-10T09:23:14.727Z" },
{ url = "https://files.pythonhosted.org/packages/63/bc/d3e208028de777087e6fb2b122051a6ff7bbcca0d6df9d9c2bf1dd869ae9/websockets-16.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:781caf5e8eee67f663126490c2f96f40906594cb86b408a703630f95550a8c3e", size = 185044, upload-time = "2026-01-10T09:23:15.939Z" },
{ url = "https://files.pythonhosted.org/packages/ad/6e/9a0927ac24bd33a0a9af834d89e0abc7cfd8e13bed17a86407a66773cc0e/websockets-16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caab51a72c51973ca21fa8a18bd8165e1a0183f1ac7066a182ff27107b71e1a4", size = 186279, upload-time = "2026-01-10T09:23:17.148Z" },
{ url = "https://files.pythonhosted.org/packages/b9/ca/bf1c68440d7a868180e11be653c85959502efd3a709323230314fda6e0b3/websockets-16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19c4dc84098e523fd63711e563077d39e90ec6702aff4b5d9e344a60cb3c0cb1", size = 185711, upload-time = "2026-01-10T09:23:18.372Z" },
{ url = "https://files.pythonhosted.org/packages/c4/f8/fdc34643a989561f217bb477cbc47a3a07212cbda91c0e4389c43c296ebf/websockets-16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a5e18a238a2b2249c9a9235466b90e96ae4795672598a58772dd806edc7ac6d3", size = 184982, upload-time = "2026-01-10T09:23:19.652Z" },
{ url = "https://files.pythonhosted.org/packages/dd/d1/574fa27e233764dbac9c52730d63fcf2823b16f0856b3329fc6268d6ae4f/websockets-16.0-cp314-cp314-win32.whl", hash = "sha256:a069d734c4a043182729edd3e9f247c3b2a4035415a9172fd0f1b71658a320a8", size = 177915, upload-time = "2026-01-10T09:23:21.458Z" },
{ url = "https://files.pythonhosted.org/packages/8a/f1/ae6b937bf3126b5134ce1f482365fde31a357c784ac51852978768b5eff4/websockets-16.0-cp314-cp314-win_amd64.whl", hash = "sha256:c0ee0e63f23914732c6d7e0cce24915c48f3f1512ec1d079ed01fc629dab269d", size = 178381, upload-time = "2026-01-10T09:23:22.715Z" },
{ url = "https://files.pythonhosted.org/packages/06/9b/f791d1db48403e1f0a27577a6beb37afae94254a8c6f08be4a23e4930bc0/websockets-16.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:a35539cacc3febb22b8f4d4a99cc79b104226a756aa7400adc722e83b0d03244", size = 177737, upload-time = "2026-01-10T09:23:24.523Z" },
{ url = "https://files.pythonhosted.org/packages/bd/40/53ad02341fa33b3ce489023f635367a4ac98b73570102ad2cdd770dacc9a/websockets-16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b784ca5de850f4ce93ec85d3269d24d4c82f22b7212023c974c401d4980ebc5e", size = 175268, upload-time = "2026-01-10T09:23:25.781Z" },
{ url = "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:569d01a4e7fba956c5ae4fc988f0d4e187900f5497ce46339c996dbf24f17641", size = 175486, upload-time = "2026-01-10T09:23:27.033Z" },
{ url = "https://files.pythonhosted.org/packages/e5/2d/7583b30208b639c8090206f95073646c2c9ffd66f44df967981a64f849ad/websockets-16.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50f23cdd8343b984957e4077839841146f67a3d31ab0d00e6b824e74c5b2f6e8", size = 185331, upload-time = "2026-01-10T09:23:28.259Z" },
{ url = "https://files.pythonhosted.org/packages/45/b0/cce3784eb519b7b5ad680d14b9673a31ab8dcb7aad8b64d81709d2430aa8/websockets-16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:152284a83a00c59b759697b7f9e9cddf4e3c7861dd0d964b472b70f78f89e80e", size = 186501, upload-time = "2026-01-10T09:23:29.449Z" },
{ url = "https://files.pythonhosted.org/packages/19/60/b8ebe4c7e89fb5f6cdf080623c9d92789a53636950f7abacfc33fe2b3135/websockets-16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc59589ab64b0022385f429b94697348a6a234e8ce22544e3681b2e9331b5944", size = 186062, upload-time = "2026-01-10T09:23:31.368Z" },
{ url = "https://files.pythonhosted.org/packages/88/a8/a080593f89b0138b6cba1b28f8df5673b5506f72879322288b031337c0b8/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206", size = 185356, upload-time = "2026-01-10T09:23:32.627Z" },
{ url = "https://files.pythonhosted.org/packages/c2/b6/b9afed2afadddaf5ebb2afa801abf4b0868f42f8539bfe4b071b5266c9fe/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6", size = 178085, upload-time = "2026-01-10T09:23:33.816Z" },
{ url = "https://files.pythonhosted.org/packages/9f/3e/28135a24e384493fa804216b79a6a6759a38cc4ff59118787b9fb693df93/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd", size = 178531, upload-time = "2026-01-10T09:23:35.016Z" },
{ url = "https://files.pythonhosted.org/packages/72/07/c98a68571dcf256e74f1f816b8cc5eae6eb2d3d5cfa44d37f801619d9166/websockets-16.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:349f83cd6c9a415428ee1005cadb5c2c56f4389bc06a9af16103c3bc3dcc8b7d", size = 174947, upload-time = "2026-01-10T09:23:36.166Z" },
{ url = "https://files.pythonhosted.org/packages/7e/52/93e166a81e0305b33fe416338be92ae863563fe7bce446b0f687b9df5aea/websockets-16.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:4a1aba3340a8dca8db6eb5a7986157f52eb9e436b74813764241981ca4888f03", size = 175260, upload-time = "2026-01-10T09:23:37.409Z" },
{ url = "https://files.pythonhosted.org/packages/56/0c/2dbf513bafd24889d33de2ff0368190a0e69f37bcfa19009ef819fe4d507/websockets-16.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f4a32d1bd841d4bcbffdcb3d2ce50c09c3909fbead375ab28d0181af89fd04da", size = 176071, upload-time = "2026-01-10T09:23:39.158Z" },
{ url = "https://files.pythonhosted.org/packages/a5/8f/aea9c71cc92bf9b6cc0f7f70df8f0b420636b6c96ef4feee1e16f80f75dd/websockets-16.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0298d07ee155e2e9fda5be8a9042200dd2e3bb0b8a38482156576f863a9d457c", size = 176968, upload-time = "2026-01-10T09:23:41.031Z" },
{ url = "https://files.pythonhosted.org/packages/9a/3f/f70e03f40ffc9a30d817eef7da1be72ee4956ba8d7255c399a01b135902a/websockets-16.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a653aea902e0324b52f1613332ddf50b00c06fdaf7e92624fbf8c77c78fa5767", size = 178735, upload-time = "2026-01-10T09:23:42.259Z" },
{ url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" },
]
[[package]]
name = "xxhash"
version = "3.6.0"
+31 -1
View File
@@ -1,6 +1,26 @@
# LangGraph SQLite Checkpoint
Implementation of LangGraph CheckpointSaver that uses SQLite DB (both sync and async, via `aiosqlite`)
[![PyPI - Version](https://img.shields.io/pypi/v/langgraph-checkpoint-sqlite?label=%20)](https://pypi.org/project/langgraph-checkpoint-sqlite/#history)
[![PyPI - License](https://img.shields.io/pypi/l/langgraph-checkpoint-sqlite)](https://opensource.org/licenses/MIT)
[![PyPI - Downloads](https://img.shields.io/pepy/dt/langgraph-checkpoint-sqlite)](https://pypistats.org/packages/langgraph-checkpoint-sqlite)
[![Twitter](https://img.shields.io/twitter/url/https/twitter.com/langchain_oss.svg?style=social&label=Follow%20%40LangChain)](https://x.com/langchain_oss)
To help you ship LangGraph apps to production faster, check out [LangSmith](https://www.langchain.com/langsmith).
[LangSmith](https://www.langchain.com/langsmith) is a unified developer platform for building, testing, and monitoring LLM applications.
## Quick Install
```bash
uv add langgraph-checkpoint-sqlite
```
## 🤔 What is this?
This library provides a SQLite implementation of LangGraph's checkpoint saver, with both sync and async support via `aiosqlite`. Use it when you want LangGraph state persistence backed by SQLite for local development, testing, or lightweight deployments.
## 📖 Documentation
For full documentation, see the [API reference](https://reference.langchain.com/python/langgraph.checkpoint.sqlite). For conceptual guides on persistence and memory, see the [LangGraph Docs](https://docs.langchain.com/oss/python/langgraph/overview).
## Security
@@ -91,3 +111,13 @@ async with AsyncSqliteSaver.from_conn_string(":memory:") as checkpointer:
# list checkpoints
[c async for c in checkpointer.alist(read_config)]
```
## 📕 Releases & Versioning
See our [Releases](https://docs.langchain.com/oss/python/release-policy) and [Versioning](https://docs.langchain.com/oss/python/versioning) policies.
## 💁 Contributing
As an open-source project in a rapidly developing field, we are extremely open to contributions, whether it be in the form of a new feature, improved infrastructure, or better documentation.
For detailed information on how to contribute, see the [Contributing Guide](https://docs.langchain.com/oss/python/contributing/overview).
@@ -24,10 +24,12 @@ from langgraph.checkpoint.base import (
from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer
from langgraph.checkpoint.sqlite._delta import (
DELTA_STAGE1_SQL,
DELTA_WALK_SQL,
build_delta_channels_writes_history,
build_delta_stage2_sql,
step_walk_with_row,
build_delta_writes_fetch_sql,
parse_supersteps_since_last_snapshot_by_channel,
resolve_delta_chains,
step_walk_supersteps,
)
from langgraph.checkpoint.sqlite.utils import search_where
@@ -505,68 +507,106 @@ class SqliteSaver(BaseCheckpointSaver[str]):
) -> Mapping[str, DeltaChannelHistory]:
"""Fast-path override of `BaseCheckpointSaver.get_delta_channel_history`.
Two-stage query:
Walks the parent chain `supersteps` hops (read from the target's
`counters_since_delta_snapshot` metadata) to each channel's seed
snapshot, then collects the writes between the seed and the target.
* Stage 1 (paged): newest-first slice of `checkpoints` returning
* WALK: stream a newest-first slice of `checkpoints` returning
`(checkpoint_id, parent_checkpoint_id, type, checkpoint)` per
ancestor. Sqlite has no JSONB, so we ship the full serialized
checkpoint blob and inspect `channel_values` in Python. Pages
newest-first by `checkpoint_id` with a `< cursor` predicate;
page size is `DELTA_PAGE_SIZE`. Stops paging when every channel
has found its seed or the chain is exhausted.
ancestor. Sqlite has no JSONB, so we deserialize only the seed
checkpoints to read their inline `channel_values`. Stops once the
shared chain reaches the deepest requested `supersteps` or the
root is reached.
* Stage 2 (per-channel UNION ALL): one branch per channel reading
`writes` filtered to that channel's specific `chain_cids`. No
separate seed-blob fetch — sqlite stores `channel_values` inline
in the checkpoint blob, so seeds come back from stage 1.
* FETCH (per-channel UNION ALL): one branch per channel reading
`writes` filtered to that channel's `chain_cids`. No separate
seed-blob fetch — sqlite stores `channel_values` inline.
"""
if not channels:
return {}
channels = list(channels)
thread_id = str(config["configurable"]["thread_id"])
if not thread_id:
raise ValueError("empty thread ID")
checkpoint_ns = config["configurable"].get("checkpoint_ns", "")
checkpoint_id = get_checkpoint_id(config)
if checkpoint_id is None:
target = self.get_tuple(config)
if target is None:
return {ch: {"writes": []} for ch in channels}
checkpoint_id = target.config["configurable"]["checkpoint_id"]
chain_by_ch: dict[str, list[str]] = {ch: [] for ch in channels}
seed_val_by_ch: dict[str, Any] = {}
# Resolve the target checkpoint id + its metadata (for supersteps).
checkpoint_id = get_checkpoint_id(config)
with self.cursor(transaction=False) as cur:
if checkpoint_id is None:
cur.execute(
"SELECT checkpoint_id, metadata FROM checkpoints "
"WHERE thread_id = ? AND checkpoint_ns = ? "
"ORDER BY checkpoint_id DESC LIMIT 1",
(thread_id, checkpoint_ns),
)
else:
cur.execute(
"SELECT checkpoint_id, metadata FROM checkpoints "
"WHERE thread_id = ? AND checkpoint_ns = ? "
"AND checkpoint_id = ?",
(thread_id, checkpoint_ns, checkpoint_id),
)
target_row = cur.fetchone()
if target_row is None:
return {ch: {"writes": []} for ch in channels}
target_id = str(target_row[0])
metadata = json.loads(target_row[1]) if target_row[1] is not None else {}
supersteps_by_ch = parse_supersteps_since_last_snapshot_by_channel(
metadata, channels
)
max_supersteps = max(supersteps_by_ch.values(), default=0)
needed_depths = set(supersteps_by_ch.values())
shared_cpid_chain: list[str] = []
walk_state: dict[str, Any] = {}
seeded: set[str] = set()
seed_values_by_depth: dict[int, dict[str, Any]] = {}
with self.cursor(transaction=False) as cur:
cur.execute(DELTA_STAGE1_SQL, (thread_id, checkpoint_ns, checkpoint_id))
for row in cur:
cid, parent_cid, type_tag, blob = row
if step_walk_with_row(
cid=cid,
parent_cid=parent_cid,
type_tag=type_tag,
blob=blob,
target_id=checkpoint_id,
serde=self.serde,
chain_by_ch=chain_by_ch,
seed_val_by_ch=seed_val_by_ch,
walk_state=walk_state,
seeded=seeded,
channels=channels,
):
break
if max_supersteps > 0:
cur.execute(DELTA_WALK_SQL, (thread_id, checkpoint_ns, target_id))
for row in cur:
cid, parent_cid, type_tag, blob = row
if step_walk_supersteps(
cid=cid,
parent_cid=parent_cid,
type_tag=type_tag,
blob=blob,
target_id=target_id,
serde=self.serde,
shared_cpid_chain=shared_cpid_chain,
walk_state=walk_state,
max_supersteps=max_supersteps,
needed_depths=needed_depths,
seed_values_by_depth=seed_values_by_depth,
channels=channels,
):
break
channels_with_chain = [ch for ch in channels if chain_by_ch[ch]]
stage2_sql = build_delta_stage2_sql(
chain_lens=[len(chain_by_ch[ch]) for ch in channels_with_chain],
(
chained_cpid_by_ch,
seed_cpid_by_ch,
seed_value_by_ch,
) = resolve_delta_chains(
channels=channels,
supersteps_by_ch=supersteps_by_ch,
shared_cpid_chain=shared_cpid_chain,
seed_values_by_depth=seed_values_by_depth,
has_reached_root=bool(walk_state.get("reached_root")),
thread_id=thread_id,
)
if stage2_sql:
stage2_params: list[Any] = []
channels_with_chain = [ch for ch in channels if chained_cpid_by_ch[ch]]
fetch_sql = build_delta_writes_fetch_sql(
chain_lens=[len(chained_cpid_by_ch[ch]) for ch in channels_with_chain],
)
if fetch_sql:
fetch_params: list[Any] = []
for ch in channels_with_chain:
stage2_params.extend(
[thread_id, checkpoint_ns, ch, *chain_by_ch[ch]]
fetch_params.extend(
[thread_id, checkpoint_ns, ch, *chained_cpid_by_ch[ch]]
)
cur.execute(stage2_sql, stage2_params)
cur.execute(fetch_sql, fetch_params)
stage2_rows = cast(
"list[tuple[str, str, str, int, str, bytes]]", cur.fetchall()
)
@@ -575,9 +615,9 @@ class SqliteSaver(BaseCheckpointSaver[str]):
return build_delta_channels_writes_history(
channels=channels,
chain_by_ch=chain_by_ch,
seed_val_by_ch=seed_val_by_ch,
seeded=seeded,
chained_cpid_by_ch=chained_cpid_by_ch,
seed_cpid_by_ch=seed_cpid_by_ch,
seed_value_by_ch=seed_value_by_ch,
stage2_rows=stage2_rows,
serde=self.serde,
)
@@ -1,37 +1,50 @@
"""Shared helpers for `get_delta_channel_history` on sqlite savers.
Mirrors the two-stage shape of `BasePostgresSaver` (ancestor walk +
per-channel UNION ALL writes fetch), but adapted for sqlite's
constraints. The structural differences:
Mirrors the supersteps-based two-pass shape of `BasePostgresSaver`
(ancestor walk bounded by `counters_since_delta_snapshot` + per-channel
UNION ALL writes fetch), adapted for sqlite's constraints:
* No JSONB — to inspect `channel_values` for a checkpoint we must
deserialize the full blob. Stage 1 streams the cursor row-by-row and
deserializes only the rows the merged walk visits, freeing each blob
before advancing.
deserialize the full blob. The WALK streams the cursor row-by-row and
deserializes only the seed checkpoints (the ones at a channel's
`supersteps` depth), freeing each blob before advancing.
* No separate blob table — `channel_values` lives inline in the
checkpoint, so seeds come back from stage 1 with no second fetch.
* Single merged walk (not K independent walks): each visited cid is
deserialized exactly once, regardless of how many channels are still
seeking their seed.
checkpoint, so seeds come back from the WALK with no second fetch.
* Single shared parent-chain walk: each requested channel slices the
same chain to its own `supersteps` depth.
The streaming design keeps peak in-flight memory at roughly one
deserialized checkpoint at a time, instead of holding the entire
ancestor chain's worth of raw blobs as a `fetchall()`-materialized list.
Walk depth is driven by the *supersteps since last snapshot* counter,
not by scanning `channel_values` for the snapshot marker — the only
reliable way to locate seeds that aren't a `_DeltaSnapshot` sentinel
(e.g. legacy plain-value blobs from a thread migrated off a non-delta
channel).
"""
from __future__ import annotations
import logging
from collections.abc import Mapping, Sequence
from typing import Any
from langgraph.checkpoint.base import DeltaChannelHistory, PendingWrite
from langgraph.checkpoint.base import (
DeltaChannelHistory,
PendingWrite,
_parse_supersteps_since_last_snapshot_by_channel,
)
from langgraph.checkpoint.serde.types import _DeltaSnapshot
# Stage 1 streams ancestors of `target_cid` newest-first. The `<=`
logger = logging.getLogger(__name__)
# Re-exported under the package-local name used by the sqlite savers.
parse_supersteps_since_last_snapshot_by_channel = (
_parse_supersteps_since_last_snapshot_by_channel
)
# The WALK streams ancestors of `target_id` newest-first. The `<=`
# predicate keeps target itself in the stream so we can read its
# `parent_checkpoint_id` from the first row without a separate lookup;
# the caller skips target's own writes/seed (matches the
# `BaseCheckpointSaver` contract).
DELTA_STAGE1_SQL = (
# `parent_checkpoint_id` from the first matching row without a separate
# lookup; target's own writes/seed are not part of the contract.
DELTA_WALK_SQL = (
"SELECT checkpoint_id, parent_checkpoint_id, type, checkpoint "
"FROM checkpoints "
"WHERE thread_id = ? AND checkpoint_ns = ? AND checkpoint_id <= ? "
@@ -39,12 +52,12 @@ DELTA_STAGE1_SQL = (
)
def build_delta_stage2_sql(*, chain_lens: Sequence[int]) -> str:
"""Stage-2 per-channel UNION ALL fetching writes from `writes`.
def build_delta_writes_fetch_sql(*, chain_lens: Sequence[int]) -> str:
"""Per-channel UNION ALL fetching writes from `writes`.
One branch per channel with a non-empty chain. Each branch inlines its
own `IN (?, ?, ...)` placeholder list because sqlite has no array-bind
equivalent of postgres's `= ANY(%s)`. Caller passes parameters in
equivalent of postgres's `= ANY(?)`. Caller passes parameters in
matching order: `[thread_id, checkpoint_ns, channel, *chain_cids]` per
branch.
@@ -65,7 +78,7 @@ def build_delta_stage2_sql(*, chain_lens: Sequence[int]) -> str:
return " UNION ALL ".join(branches)
def step_walk_with_row(
def step_walk_supersteps(
*,
cid: str,
parent_cid: str | None,
@@ -73,75 +86,142 @@ def step_walk_with_row(
blob: bytes,
target_id: str,
serde: Any,
chain_by_ch: dict[str, list[str]],
seed_val_by_ch: dict[str, Any],
shared_cpid_chain: list[str],
walk_state: dict[str, Any],
seeded: set[str],
max_supersteps: int,
needed_depths: set[int],
seed_values_by_depth: dict[int, dict[str, Any]],
channels: Sequence[str],
) -> bool:
"""Process one streamed stage-1 row in the merged ancestor walk.
"""Process one streamed WALK row, extending the shared parent chain.
The cursor returns (cid, parent_cid, type, blob) rows in
`checkpoint_id` DESC order starting at target. The first row is
target itself; we read its parent_cid to seed the walk and otherwise
skip it (target's own writes/seed are not part of the contract).
The cursor returns `(cid, parent_cid, type, checkpoint)` rows in
`checkpoint_id` DESC order starting at target. The first row is target
itself; we read its `parent_cid` to seed the walk and skip it (target's
own writes/seed are not part of the contract). Off-path rows (a sibling
branch on the same thread) advance the cursor without doing work.
For each subsequent row, if `cid` matches the walk's current
position, we deserialize the blob, append the cid to every
not-yet-seeded channel's chain, and check `channel_values` for
seeds. The deserialized checkpoint is dropped before advancing — no
cross-row cache, so peak in-flight is one deserialized checkpoint.
For each on-path ancestor we append its cid to `shared_cpid_chain`
(newest first). When the ancestor sits at a depth some channel needs as
its seed (`len(chain)` ∈ `needed_depths`), we deserialize it once and
record its `channel_values` for the requested channels. The
deserialized checkpoint is dropped immediately — peak in-flight is one
deserialized checkpoint.
Off-path rows (different branch on the same thread) advance the
cursor without doing any work.
Returns True when every requested channel is seeded — the caller
can stop iterating and close the cursor.
Sets `walk_state["reached_root"]` when an ancestor has no parent.
Returns True when the walk can stop: chain reached `max_supersteps`, or
the root was reached.
"""
if "started" not in walk_state:
if cid == target_id:
walk_state["started"] = True
walk_state["cur_cid"] = parent_cid
walk_state["active"] = {ch for ch in channels if ch not in seeded}
if parent_cid is None:
walk_state["reached_root"] = True
return True
# Not target yet (or target not present): keep streaming.
return False
active: set[str] = walk_state["active"]
if not active:
if len(shared_cpid_chain) >= max_supersteps:
return True
if cid != walk_state["cur_cid"]:
# Off-path row from a sibling branch — skip without deserializing.
return False
for ch in active:
chain_by_ch[ch].append(cid)
ckpt = serde.loads_typed((type_tag, blob))
channel_values: Mapping[str, Any] = ckpt.get("channel_values") or {}
for ch in [ch for ch in active if ch in channel_values]:
seed_val_by_ch[ch] = channel_values[ch]
seeded.add(ch)
active.discard(ch)
del ckpt, channel_values
shared_cpid_chain.append(cid)
depth = len(shared_cpid_chain) # 1-indexed position along the chain
# Capture channel_values at any depth a channel may use as its seed: the
# exact `supersteps` depths, plus the root-most checkpoint (the seed
# candidate when the chain is shorter than `supersteps`).
if depth in needed_depths or parent_cid is None:
ckpt = serde.loads_typed((type_tag, blob))
channel_values: Mapping[str, Any] = ckpt.get("channel_values") or {}
seed_values_by_depth[depth] = {
ch: channel_values[ch] for ch in channels if ch in channel_values
}
del ckpt, channel_values
if parent_cid is None:
walk_state["reached_root"] = True
return True
walk_state["cur_cid"] = parent_cid
return not active
return len(shared_cpid_chain) >= max_supersteps
def resolve_delta_chains(
*,
channels: Sequence[str],
supersteps_by_ch: Mapping[str, int],
shared_cpid_chain: Sequence[str],
seed_values_by_depth: Mapping[int, Mapping[str, Any]],
has_reached_root: bool,
thread_id: str,
) -> tuple[
dict[str, list[str]],
dict[str, str | None],
dict[str, Any],
]:
"""Slice the shared parent chain into per-channel chain/seed mappings.
For each channel the seed snapshot sits `supersteps` hops back: the seed
checkpoint is `shared_cpid_chain[supersteps - 1]` and the chain is
`shared_cpid_chain[:supersteps]` (newest first), with the seed's inline
`channel_values[ch]` captured during the walk.
When the chain is shorter than `supersteps` but the walk reached the
root, the persisted chain is "compressed" relative to the logical
superstep count (`durability="exit"`, or a thread that never
snapshotted). The seed candidate is then the oldest persisted checkpoint
(`shared_cpid_chain[-1]`); if its `channel_values[ch]` is absent the
channel has no seed and replays the full chain on an empty baseline.
"""
chained_cpid_by_ch: dict[str, list[str]] = {ch: [] for ch in channels}
seed_cpid_by_ch: dict[str, str | None] = {ch: None for ch in channels}
seed_value_by_ch: dict[str, Any] = {}
for ch in channels:
bound = supersteps_by_ch.get(ch, 0)
if bound <= 0:
continue
if len(shared_cpid_chain) >= bound:
seed_depth = bound
elif has_reached_root:
seed_depth = len(shared_cpid_chain)
else:
logger.warning(
"cannot find seed snapshot for delta channel "
"(thread_id=%s, channel=%s)",
thread_id,
ch,
)
continue
if seed_depth <= 0:
continue
chained_cpid_by_ch[ch] = list(shared_cpid_chain[:seed_depth])
seed_cpid_by_ch[ch] = shared_cpid_chain[seed_depth - 1]
seed_vals = seed_values_by_depth.get(seed_depth, {})
if ch in seed_vals:
seed_value_by_ch[ch] = seed_vals[ch]
return chained_cpid_by_ch, seed_cpid_by_ch, seed_value_by_ch
def build_delta_channels_writes_history(
*,
channels: Sequence[str],
chain_by_ch: Mapping[str, list[str]],
seed_val_by_ch: Mapping[str, Any],
seeded: set[str],
chained_cpid_by_ch: Mapping[str, Sequence[str]],
seed_cpid_by_ch: Mapping[str, str | None],
seed_value_by_ch: Mapping[str, Any],
stage2_rows: Sequence[tuple[str, str, str, int, str, bytes]],
serde: Any,
) -> dict[str, DeltaChannelHistory]:
"""Demux stage-2 rows per channel; produce per-channel histories.
"""Demux writes rows per channel; produce per-channel histories.
Stage-2 rows are `(checkpoint_id, channel, task_id, idx, type, value)`.
`stage2_rows` are `(checkpoint_id, channel, task_id, idx, type, value)`.
Final write order is oldest→newest globally and `(task_id, idx)` within
a checkpoint, matching the contract on `DeltaChannelHistory.writes`.
`seed` is omitted when the walk reached a true root with no snapshot
found (channel never entered `seeded`); consumers treat absence as
"start empty".
The seed checkpoint's own writes are replayed on top of a
`_DeltaSnapshot` seed (the snapshot is the value *prior* to its own
writes), but skipped for a migrated plain-value seed (a legacy
non-delta blob already incorporates those writes). `seed` is omitted
when no seed was located (implicit empty baseline); consumers treat
absence as "start empty".
"""
writes_by_ch_by_cid: dict[str, dict[str, list[tuple[str, bytes, str, int]]]] = {
ch: {} for ch in channels
@@ -156,17 +236,26 @@ def build_delta_channels_writes_history(
result: dict[str, DeltaChannelHistory] = {}
for ch in channels:
chain_cids = chain_by_ch.get(ch, [])
entry: DeltaChannelHistory = {"writes": []}
skip_seed_checkpoint_writes = False
if ch in seed_value_by_ch:
seed_value = seed_value_by_ch[ch]
entry["seed"] = seed_value
skip_seed_checkpoint_writes = not isinstance(seed_value, _DeltaSnapshot)
cid_writes = writes_by_ch_by_cid.get(ch, {})
collected: list[PendingWrite] = []
# Chain is newest-first; iterate oldest-first for the public order.
for cid in reversed(chain_cids):
for type_tag, value_blob, task_id, _idx in cid_writes.get(cid, []):
collected.append(
(task_id, ch, serde.loads_typed((type_tag, value_blob)))
)
entry: DeltaChannelHistory = {"writes": collected}
if ch in seeded:
entry["seed"] = seed_val_by_ch[ch]
if cid_writes:
collected: list[PendingWrite] = []
seed_cpid = seed_cpid_by_ch.get(ch)
# Chain is newest→oldest; replay oldest→newest.
for cid in reversed(list(chained_cpid_by_ch.get(ch, []))):
if skip_seed_checkpoint_writes and cid == seed_cpid:
continue
for type_tag, value_blob, task_id, _idx in cid_writes.get(cid, []):
collected.append(
(task_id, ch, serde.loads_typed((type_tag, value_blob)))
)
entry["writes"] = collected
result[ch] = entry
return result
@@ -25,10 +25,12 @@ from langgraph.checkpoint.base import (
from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer
from langgraph.checkpoint.sqlite._delta import (
DELTA_STAGE1_SQL,
DELTA_WALK_SQL,
build_delta_channels_writes_history,
build_delta_stage2_sql,
step_walk_with_row,
build_delta_writes_fetch_sql,
parse_supersteps_since_last_snapshot_by_channel,
resolve_delta_chains,
step_walk_supersteps,
)
from langgraph.checkpoint.sqlite.utils import search_where
@@ -625,61 +627,98 @@ class AsyncSqliteSaver(BaseCheckpointSaver[str]):
"""Fast-path override of `BaseCheckpointSaver.aget_delta_channel_history`.
See `SqliteSaver.get_delta_channel_history` for design notes; this
is the async equivalent using `aiosqlite` cursors. Stage 1 pages
the parent chain newest-first and Python-deserializes each
checkpoint blob to find per-channel snapshots; stage 2 fetches
only the relevant writes via per-channel UNION ALL.
is the async equivalent using `aiosqlite` cursors. The WALK streams
the parent chain newest-first, bounded by the target's
`counters_since_delta_snapshot` supersteps, and deserializes only
seed checkpoints; FETCH pulls the relevant writes via per-channel
UNION ALL.
"""
if not channels:
return {}
channels = list(channels)
await self.setup()
thread_id = str(config["configurable"]["thread_id"])
if not thread_id:
raise ValueError("empty thread ID")
checkpoint_ns = config["configurable"].get("checkpoint_ns", "")
checkpoint_id = get_checkpoint_id(config)
if checkpoint_id is None:
target = await self.aget_tuple(config)
if target is None:
return {ch: {"writes": []} for ch in channels}
checkpoint_id = target.config["configurable"]["checkpoint_id"]
chain_by_ch: dict[str, list[str]] = {ch: [] for ch in channels}
seed_val_by_ch: dict[str, Any] = {}
# Resolve the target checkpoint id + its metadata (for supersteps).
checkpoint_id = get_checkpoint_id(config)
async with self.lock, self.conn.cursor() as cur:
if checkpoint_id is None:
await cur.execute(
"SELECT checkpoint_id, metadata FROM checkpoints "
"WHERE thread_id = ? AND checkpoint_ns = ? "
"ORDER BY checkpoint_id DESC LIMIT 1",
(thread_id, checkpoint_ns),
)
else:
await cur.execute(
"SELECT checkpoint_id, metadata FROM checkpoints "
"WHERE thread_id = ? AND checkpoint_ns = ? "
"AND checkpoint_id = ?",
(thread_id, checkpoint_ns, checkpoint_id),
)
target_row = await cur.fetchone()
if target_row is None:
return {ch: {"writes": []} for ch in channels}
target_id = str(target_row[0])
metadata = json.loads(target_row[1]) if target_row[1] is not None else {}
supersteps_by_ch = parse_supersteps_since_last_snapshot_by_channel(
metadata, channels
)
max_supersteps = max(supersteps_by_ch.values(), default=0)
needed_depths = set(supersteps_by_ch.values())
shared_cpid_chain: list[str] = []
walk_state: dict[str, Any] = {}
seeded: set[str] = set()
seed_values_by_depth: dict[int, dict[str, Any]] = {}
async with self.lock, self.conn.cursor() as cur:
await cur.execute(
DELTA_STAGE1_SQL, (thread_id, checkpoint_ns, checkpoint_id)
)
async for row in cur:
cid, parent_cid, type_tag, blob = row
if step_walk_with_row(
cid=cid,
parent_cid=parent_cid,
type_tag=type_tag,
blob=blob,
target_id=checkpoint_id,
serde=self.serde,
chain_by_ch=chain_by_ch,
seed_val_by_ch=seed_val_by_ch,
walk_state=walk_state,
seeded=seeded,
channels=channels,
):
break
if max_supersteps > 0:
await cur.execute(DELTA_WALK_SQL, (thread_id, checkpoint_ns, target_id))
async for row in cur:
cid, parent_cid, type_tag, blob = row
if step_walk_supersteps(
cid=cid,
parent_cid=parent_cid,
type_tag=type_tag,
blob=blob,
target_id=target_id,
serde=self.serde,
shared_cpid_chain=shared_cpid_chain,
walk_state=walk_state,
max_supersteps=max_supersteps,
needed_depths=needed_depths,
seed_values_by_depth=seed_values_by_depth,
channels=channels,
):
break
channels_with_chain = [ch for ch in channels if chain_by_ch[ch]]
stage2_sql = build_delta_stage2_sql(
chain_lens=[len(chain_by_ch[ch]) for ch in channels_with_chain],
(
chained_cpid_by_ch,
seed_cpid_by_ch,
seed_value_by_ch,
) = resolve_delta_chains(
channels=channels,
supersteps_by_ch=supersteps_by_ch,
shared_cpid_chain=shared_cpid_chain,
seed_values_by_depth=seed_values_by_depth,
has_reached_root=bool(walk_state.get("reached_root")),
thread_id=thread_id,
)
if stage2_sql:
stage2_params: list[Any] = []
channels_with_chain = [ch for ch in channels if chained_cpid_by_ch[ch]]
fetch_sql = build_delta_writes_fetch_sql(
chain_lens=[len(chained_cpid_by_ch[ch]) for ch in channels_with_chain],
)
if fetch_sql:
fetch_params: list[Any] = []
for ch in channels_with_chain:
stage2_params.extend(
[thread_id, checkpoint_ns, ch, *chain_by_ch[ch]]
fetch_params.extend(
[thread_id, checkpoint_ns, ch, *chained_cpid_by_ch[ch]]
)
await cur.execute(stage2_sql, stage2_params)
await cur.execute(fetch_sql, fetch_params)
stage2_rows = cast(
"list[tuple[str, str, str, int, str, bytes]]",
await cur.fetchall(),
@@ -689,9 +728,9 @@ class AsyncSqliteSaver(BaseCheckpointSaver[str]):
return build_delta_channels_writes_history(
channels=channels,
chain_by_ch=chain_by_ch,
seed_val_by_ch=seed_val_by_ch,
seeded=seeded,
chained_cpid_by_ch=chained_cpid_by_ch,
seed_cpid_by_ch=seed_cpid_by_ch,
seed_value_by_ch=seed_value_by_ch,
stage2_rows=stage2_rows,
serde=self.serde,
)
+72 -3
View File
@@ -402,7 +402,7 @@ test = [
[[package]]
name = "langsmith"
version = "0.8.0"
version = "0.8.18"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
@@ -412,12 +412,13 @@ dependencies = [
{ name = "requests" },
{ name = "requests-toolbelt" },
{ name = "uuid-utils" },
{ name = "websockets" },
{ name = "xxhash" },
{ name = "zstandard" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a8/64/95f1f013531395f4e8ed73caeee780f65c7c58fe028cb543f8937b45611b/langsmith-0.8.0.tar.gz", hash = "sha256:59fe5b2a56bbbe14a08aa76691f84b49e8675dd21e11b57d80c6db8c08bac2e3", size = 4432996, upload-time = "2026-04-30T22:13:07.341Z" }
sdist = { url = "https://files.pythonhosted.org/packages/9a/d9/a6681aa9847bbbc5ec21abe20a5e233b94e5edcfe39624db607ac7e8ccb4/langsmith-0.8.18.tar.gz", hash = "sha256:32dde9c0e67e053e0fb738921fc8ced768af7b8fa83d7a0e3fd63597cf8776dd", size = 4526988, upload-time = "2026-06-19T13:12:17.123Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f3/e1/a4be2e696c9473bb53298df398237da5674704d781d4b748ed35aeef592a/langsmith-0.8.0-py3-none-any.whl", hash = "sha256:12cc4bc5622b835a6d841964d6034df3617bdb912dae0c1381fd0a68a9b3a3ef", size = 393268, upload-time = "2026-04-30T22:13:05.56Z" },
{ url = "https://files.pythonhosted.org/packages/03/70/0e0cc80a3b064c8d6c8d697c3125ed86e39d5a7393ec6dc8b07cb1cf13c4/langsmith-0.8.18-py3-none-any.whl", hash = "sha256:3940183349993faef48e6c7d08e4822ee9cefd906b362d0e3c2d650314d2f282", size = 508108, upload-time = "2026-06-19T13:12:15.348Z" },
]
[[package]]
@@ -1093,6 +1094,74 @@ wheels = [
{ 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 = "websockets"
version = "16.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/20/74/221f58decd852f4b59cc3354cccaf87e8ef695fede361d03dc9a7396573b/websockets-16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:04cdd5d2d1dacbad0a7bf36ccbcd3ccd5a30ee188f2560b7a62a30d14107b31a", size = 177343, upload-time = "2026-01-10T09:22:21.28Z" },
{ url = "https://files.pythonhosted.org/packages/19/0f/22ef6107ee52ab7f0b710d55d36f5a5d3ef19e8a205541a6d7ffa7994e5a/websockets-16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8ff32bb86522a9e5e31439a58addbb0166f0204d64066fb955265c4e214160f0", size = 175021, upload-time = "2026-01-10T09:22:22.696Z" },
{ url = "https://files.pythonhosted.org/packages/10/40/904a4cb30d9b61c0e278899bf36342e9b0208eb3c470324a9ecbaac2a30f/websockets-16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:583b7c42688636f930688d712885cf1531326ee05effd982028212ccc13e5957", size = 175320, upload-time = "2026-01-10T09:22:23.94Z" },
{ url = "https://files.pythonhosted.org/packages/9d/2f/4b3ca7e106bc608744b1cdae041e005e446124bebb037b18799c2d356864/websockets-16.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7d837379b647c0c4c2355c2499723f82f1635fd2c26510e1f587d89bc2199e72", size = 183815, upload-time = "2026-01-10T09:22:25.469Z" },
{ url = "https://files.pythonhosted.org/packages/86/26/d40eaa2a46d4302becec8d15b0fc5e45bdde05191e7628405a19cf491ccd/websockets-16.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df57afc692e517a85e65b72e165356ed1df12386ecb879ad5693be08fac65dde", size = 185054, upload-time = "2026-01-10T09:22:27.101Z" },
{ url = "https://files.pythonhosted.org/packages/b0/ba/6500a0efc94f7373ee8fefa8c271acdfd4dca8bd49a90d4be7ccabfc397e/websockets-16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2b9f1e0d69bc60a4a87349d50c09a037a2607918746f07de04df9e43252c77a3", size = 184565, upload-time = "2026-01-10T09:22:28.293Z" },
{ url = "https://files.pythonhosted.org/packages/04/b4/96bf2cee7c8d8102389374a2616200574f5f01128d1082f44102140344cc/websockets-16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:335c23addf3d5e6a8633f9f8eda77efad001671e80b95c491dd0924587ece0b3", size = 183848, upload-time = "2026-01-10T09:22:30.394Z" },
{ url = "https://files.pythonhosted.org/packages/02/8e/81f40fb00fd125357814e8c3025738fc4ffc3da4b6b4a4472a82ba304b41/websockets-16.0-cp310-cp310-win32.whl", hash = "sha256:37b31c1623c6605e4c00d466c9d633f9b812ea430c11c8a278774a1fde1acfa9", size = 178249, upload-time = "2026-01-10T09:22:32.083Z" },
{ url = "https://files.pythonhosted.org/packages/b4/5f/7e40efe8df57db9b91c88a43690ac66f7b7aa73a11aa6a66b927e44f26fa/websockets-16.0-cp310-cp310-win_amd64.whl", hash = "sha256:8e1dab317b6e77424356e11e99a432b7cb2f3ec8c5ab4dabbcee6add48f72b35", size = 178685, upload-time = "2026-01-10T09:22:33.345Z" },
{ url = "https://files.pythonhosted.org/packages/f2/db/de907251b4ff46ae804ad0409809504153b3f30984daf82a1d84a9875830/websockets-16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:31a52addea25187bde0797a97d6fc3d2f92b6f72a9370792d65a6e84615ac8a8", size = 177340, upload-time = "2026-01-10T09:22:34.539Z" },
{ url = "https://files.pythonhosted.org/packages/f3/fa/abe89019d8d8815c8781e90d697dec52523fb8ebe308bf11664e8de1877e/websockets-16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:417b28978cdccab24f46400586d128366313e8a96312e4b9362a4af504f3bbad", size = 175022, upload-time = "2026-01-10T09:22:36.332Z" },
{ url = "https://files.pythonhosted.org/packages/58/5d/88ea17ed1ded2079358b40d31d48abe90a73c9e5819dbcde1606e991e2ad/websockets-16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:af80d74d4edfa3cb9ed973a0a5ba2b2a549371f8a741e0800cb07becdd20f23d", size = 175319, upload-time = "2026-01-10T09:22:37.602Z" },
{ url = "https://files.pythonhosted.org/packages/d2/ae/0ee92b33087a33632f37a635e11e1d99d429d3d323329675a6022312aac2/websockets-16.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:08d7af67b64d29823fed316505a89b86705f2b7981c07848fb5e3ea3020c1abe", size = 184631, upload-time = "2026-01-10T09:22:38.789Z" },
{ url = "https://files.pythonhosted.org/packages/c8/c5/27178df583b6c5b31b29f526ba2da5e2f864ecc79c99dae630a85d68c304/websockets-16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be95cfb0a4dae143eaed2bcba8ac23f4892d8971311f1b06f3c6b78952ee70b", size = 185870, upload-time = "2026-01-10T09:22:39.893Z" },
{ url = "https://files.pythonhosted.org/packages/87/05/536652aa84ddc1c018dbb7e2c4cbcd0db884580bf8e95aece7593fde526f/websockets-16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6297ce39ce5c2e6feb13c1a996a2ded3b6832155fcfc920265c76f24c7cceb5", size = 185361, upload-time = "2026-01-10T09:22:41.016Z" },
{ url = "https://files.pythonhosted.org/packages/6d/e2/d5332c90da12b1e01f06fb1b85c50cfc489783076547415bf9f0a659ec19/websockets-16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c1b30e4f497b0b354057f3467f56244c603a79c0d1dafce1d16c283c25f6e64", size = 184615, upload-time = "2026-01-10T09:22:42.442Z" },
{ url = "https://files.pythonhosted.org/packages/77/fb/d3f9576691cae9253b51555f841bc6600bf0a983a461c79500ace5a5b364/websockets-16.0-cp311-cp311-win32.whl", hash = "sha256:5f451484aeb5cafee1ccf789b1b66f535409d038c56966d6101740c1614b86c6", size = 178246, upload-time = "2026-01-10T09:22:43.654Z" },
{ url = "https://files.pythonhosted.org/packages/54/67/eaff76b3dbaf18dcddabc3b8c1dba50b483761cccff67793897945b37408/websockets-16.0-cp311-cp311-win_amd64.whl", hash = "sha256:8d7f0659570eefb578dacde98e24fb60af35350193e4f56e11190787bee77dac", size = 178684, upload-time = "2026-01-10T09:22:44.941Z" },
{ url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" },
{ url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" },
{ url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" },
{ url = "https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c", size = 184915, upload-time = "2026-01-10T09:22:51.071Z" },
{ url = "https://files.pythonhosted.org/packages/97/bb/21c36b7dbbafc85d2d480cd65df02a1dc93bf76d97147605a8e27ff9409d/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f", size = 186152, upload-time = "2026-01-10T09:22:52.224Z" },
{ url = "https://files.pythonhosted.org/packages/4a/34/9bf8df0c0cf88fa7bfe36678dc7b02970c9a7d5e065a3099292db87b1be2/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1", size = 185583, upload-time = "2026-01-10T09:22:53.443Z" },
{ url = "https://files.pythonhosted.org/packages/47/88/4dd516068e1a3d6ab3c7c183288404cd424a9a02d585efbac226cb61ff2d/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2", size = 184880, upload-time = "2026-01-10T09:22:55.033Z" },
{ url = "https://files.pythonhosted.org/packages/91/d6/7d4553ad4bf1c0421e1ebd4b18de5d9098383b5caa1d937b63df8d04b565/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89", size = 178261, upload-time = "2026-01-10T09:22:56.251Z" },
{ url = "https://files.pythonhosted.org/packages/c3/f0/f3a17365441ed1c27f850a80b2bc680a0fa9505d733fe152fdf5e98c1c0b/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea", size = 178693, upload-time = "2026-01-10T09:22:57.478Z" },
{ url = "https://files.pythonhosted.org/packages/cc/9c/baa8456050d1c1b08dd0ec7346026668cbc6f145ab4e314d707bb845bf0d/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9", size = 177364, upload-time = "2026-01-10T09:22:59.333Z" },
{ url = "https://files.pythonhosted.org/packages/7e/0c/8811fc53e9bcff68fe7de2bcbe75116a8d959ac699a3200f4847a8925210/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230", size = 175039, upload-time = "2026-01-10T09:23:01.171Z" },
{ url = "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c", size = 175323, upload-time = "2026-01-10T09:23:02.341Z" },
{ url = "https://files.pythonhosted.org/packages/bd/28/0a25ee5342eb5d5f297d992a77e56892ecb65e7854c7898fb7d35e9b33bd/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5", size = 184975, upload-time = "2026-01-10T09:23:03.756Z" },
{ url = "https://files.pythonhosted.org/packages/f9/66/27ea52741752f5107c2e41fda05e8395a682a1e11c4e592a809a90c6a506/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82", size = 186203, upload-time = "2026-01-10T09:23:05.01Z" },
{ url = "https://files.pythonhosted.org/packages/37/e5/8e32857371406a757816a2b471939d51c463509be73fa538216ea52b792a/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8", size = 185653, upload-time = "2026-01-10T09:23:06.301Z" },
{ url = "https://files.pythonhosted.org/packages/9b/67/f926bac29882894669368dc73f4da900fcdf47955d0a0185d60103df5737/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f", size = 184920, upload-time = "2026-01-10T09:23:07.492Z" },
{ url = "https://files.pythonhosted.org/packages/3c/a1/3d6ccdcd125b0a42a311bcd15a7f705d688f73b2a22d8cf1c0875d35d34a/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a", size = 178255, upload-time = "2026-01-10T09:23:09.245Z" },
{ url = "https://files.pythonhosted.org/packages/6b/ae/90366304d7c2ce80f9b826096a9e9048b4bb760e44d3b873bb272cba696b/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156", size = 178689, upload-time = "2026-01-10T09:23:10.483Z" },
{ url = "https://files.pythonhosted.org/packages/f3/1d/e88022630271f5bd349ed82417136281931e558d628dd52c4d8621b4a0b2/websockets-16.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8cc451a50f2aee53042ac52d2d053d08bf89bcb31ae799cb4487587661c038a0", size = 177406, upload-time = "2026-01-10T09:23:12.178Z" },
{ url = "https://files.pythonhosted.org/packages/f2/78/e63be1bf0724eeb4616efb1ae1c9044f7c3953b7957799abb5915bffd38e/websockets-16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:daa3b6ff70a9241cf6c7fc9e949d41232d9d7d26fd3522b1ad2b4d62487e9904", size = 175085, upload-time = "2026-01-10T09:23:13.511Z" },
{ url = "https://files.pythonhosted.org/packages/bb/f4/d3c9220d818ee955ae390cf319a7c7a467beceb24f05ee7aaaa2414345ba/websockets-16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd3cb4adb94a2a6e2b7c0d8d05cb94e6f1c81a0cf9dc2694fb65c7e8d94c42e4", size = 175328, upload-time = "2026-01-10T09:23:14.727Z" },
{ url = "https://files.pythonhosted.org/packages/63/bc/d3e208028de777087e6fb2b122051a6ff7bbcca0d6df9d9c2bf1dd869ae9/websockets-16.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:781caf5e8eee67f663126490c2f96f40906594cb86b408a703630f95550a8c3e", size = 185044, upload-time = "2026-01-10T09:23:15.939Z" },
{ url = "https://files.pythonhosted.org/packages/ad/6e/9a0927ac24bd33a0a9af834d89e0abc7cfd8e13bed17a86407a66773cc0e/websockets-16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caab51a72c51973ca21fa8a18bd8165e1a0183f1ac7066a182ff27107b71e1a4", size = 186279, upload-time = "2026-01-10T09:23:17.148Z" },
{ url = "https://files.pythonhosted.org/packages/b9/ca/bf1c68440d7a868180e11be653c85959502efd3a709323230314fda6e0b3/websockets-16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19c4dc84098e523fd63711e563077d39e90ec6702aff4b5d9e344a60cb3c0cb1", size = 185711, upload-time = "2026-01-10T09:23:18.372Z" },
{ url = "https://files.pythonhosted.org/packages/c4/f8/fdc34643a989561f217bb477cbc47a3a07212cbda91c0e4389c43c296ebf/websockets-16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a5e18a238a2b2249c9a9235466b90e96ae4795672598a58772dd806edc7ac6d3", size = 184982, upload-time = "2026-01-10T09:23:19.652Z" },
{ url = "https://files.pythonhosted.org/packages/dd/d1/574fa27e233764dbac9c52730d63fcf2823b16f0856b3329fc6268d6ae4f/websockets-16.0-cp314-cp314-win32.whl", hash = "sha256:a069d734c4a043182729edd3e9f247c3b2a4035415a9172fd0f1b71658a320a8", size = 177915, upload-time = "2026-01-10T09:23:21.458Z" },
{ url = "https://files.pythonhosted.org/packages/8a/f1/ae6b937bf3126b5134ce1f482365fde31a357c784ac51852978768b5eff4/websockets-16.0-cp314-cp314-win_amd64.whl", hash = "sha256:c0ee0e63f23914732c6d7e0cce24915c48f3f1512ec1d079ed01fc629dab269d", size = 178381, upload-time = "2026-01-10T09:23:22.715Z" },
{ url = "https://files.pythonhosted.org/packages/06/9b/f791d1db48403e1f0a27577a6beb37afae94254a8c6f08be4a23e4930bc0/websockets-16.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:a35539cacc3febb22b8f4d4a99cc79b104226a756aa7400adc722e83b0d03244", size = 177737, upload-time = "2026-01-10T09:23:24.523Z" },
{ url = "https://files.pythonhosted.org/packages/bd/40/53ad02341fa33b3ce489023f635367a4ac98b73570102ad2cdd770dacc9a/websockets-16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b784ca5de850f4ce93ec85d3269d24d4c82f22b7212023c974c401d4980ebc5e", size = 175268, upload-time = "2026-01-10T09:23:25.781Z" },
{ url = "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:569d01a4e7fba956c5ae4fc988f0d4e187900f5497ce46339c996dbf24f17641", size = 175486, upload-time = "2026-01-10T09:23:27.033Z" },
{ url = "https://files.pythonhosted.org/packages/e5/2d/7583b30208b639c8090206f95073646c2c9ffd66f44df967981a64f849ad/websockets-16.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50f23cdd8343b984957e4077839841146f67a3d31ab0d00e6b824e74c5b2f6e8", size = 185331, upload-time = "2026-01-10T09:23:28.259Z" },
{ url = "https://files.pythonhosted.org/packages/45/b0/cce3784eb519b7b5ad680d14b9673a31ab8dcb7aad8b64d81709d2430aa8/websockets-16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:152284a83a00c59b759697b7f9e9cddf4e3c7861dd0d964b472b70f78f89e80e", size = 186501, upload-time = "2026-01-10T09:23:29.449Z" },
{ url = "https://files.pythonhosted.org/packages/19/60/b8ebe4c7e89fb5f6cdf080623c9d92789a53636950f7abacfc33fe2b3135/websockets-16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc59589ab64b0022385f429b94697348a6a234e8ce22544e3681b2e9331b5944", size = 186062, upload-time = "2026-01-10T09:23:31.368Z" },
{ url = "https://files.pythonhosted.org/packages/88/a8/a080593f89b0138b6cba1b28f8df5673b5506f72879322288b031337c0b8/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206", size = 185356, upload-time = "2026-01-10T09:23:32.627Z" },
{ url = "https://files.pythonhosted.org/packages/c2/b6/b9afed2afadddaf5ebb2afa801abf4b0868f42f8539bfe4b071b5266c9fe/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6", size = 178085, upload-time = "2026-01-10T09:23:33.816Z" },
{ url = "https://files.pythonhosted.org/packages/9f/3e/28135a24e384493fa804216b79a6a6759a38cc4ff59118787b9fb693df93/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd", size = 178531, upload-time = "2026-01-10T09:23:35.016Z" },
{ url = "https://files.pythonhosted.org/packages/72/07/c98a68571dcf256e74f1f816b8cc5eae6eb2d3d5cfa44d37f801619d9166/websockets-16.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:349f83cd6c9a415428ee1005cadb5c2c56f4389bc06a9af16103c3bc3dcc8b7d", size = 174947, upload-time = "2026-01-10T09:23:36.166Z" },
{ url = "https://files.pythonhosted.org/packages/7e/52/93e166a81e0305b33fe416338be92ae863563fe7bce446b0f687b9df5aea/websockets-16.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:4a1aba3340a8dca8db6eb5a7986157f52eb9e436b74813764241981ca4888f03", size = 175260, upload-time = "2026-01-10T09:23:37.409Z" },
{ url = "https://files.pythonhosted.org/packages/56/0c/2dbf513bafd24889d33de2ff0368190a0e69f37bcfa19009ef819fe4d507/websockets-16.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f4a32d1bd841d4bcbffdcb3d2ce50c09c3909fbead375ab28d0181af89fd04da", size = 176071, upload-time = "2026-01-10T09:23:39.158Z" },
{ url = "https://files.pythonhosted.org/packages/a5/8f/aea9c71cc92bf9b6cc0f7f70df8f0b420636b6c96ef4feee1e16f80f75dd/websockets-16.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0298d07ee155e2e9fda5be8a9042200dd2e3bb0b8a38482156576f863a9d457c", size = 176968, upload-time = "2026-01-10T09:23:41.031Z" },
{ url = "https://files.pythonhosted.org/packages/9a/3f/f70e03f40ffc9a30d817eef7da1be72ee4956ba8d7255c399a01b135902a/websockets-16.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a653aea902e0324b52f1613332ddf50b00c06fdaf7e92624fbf8c77c78fa5767", size = 178735, upload-time = "2026-01-10T09:23:42.259Z" },
{ url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" },
]
[[package]]
name = "xxhash"
version = "3.6.0"
+32 -2
View File
@@ -1,6 +1,26 @@
# LangGraph Checkpoint
This library defines the base interface for LangGraph checkpointers. Checkpointers provide a persistence layer for LangGraph. They allow you to interact with and manage the graph's state. When you use a graph with a checkpointer, the checkpointer saves a _checkpoint_ of the graph state at every superstep, enabling several powerful capabilities like human-in-the-loop, "memory" between interactions and more.
[![PyPI - Version](https://img.shields.io/pypi/v/langgraph-checkpoint?label=%20)](https://pypi.org/project/langgraph-checkpoint/#history)
[![PyPI - License](https://img.shields.io/pypi/l/langgraph-checkpoint)](https://opensource.org/licenses/MIT)
[![PyPI - Downloads](https://img.shields.io/pepy/dt/langgraph-checkpoint)](https://pypistats.org/packages/langgraph-checkpoint)
[![Twitter](https://img.shields.io/twitter/url/https/twitter.com/langchain_oss.svg?style=social&label=Follow%20%40LangChain)](https://x.com/langchain_oss)
To help you ship LangGraph apps to production faster, check out [LangSmith](https://www.langchain.com/langsmith).
[LangSmith](https://www.langchain.com/langsmith) is a unified developer platform for building, testing, and monitoring LLM applications.
## Quick Install
```bash
uv add langgraph-checkpoint
```
## 🤔 What is this?
This library defines the base interface for LangGraph checkpointers. Checkpointers provide a persistence layer for LangGraph: they save graph state at every superstep, enabling human-in-the-loop, memory between interactions, durable execution, and more.
## 📖 Documentation
For full documentation, see the [API reference](https://reference.langchain.com/python/langgraph.checkpoint). For conceptual guides on persistence and memory, see the [LangGraph Docs](https://docs.langchain.com/oss/python/langgraph/overview).
## Key concepts
@@ -24,7 +44,7 @@ You must pass these when invoking the graph as part of the configurable part of
### Serde
`langgraph_checkpoint` also defines protocol for serialization/deserialization (serde) and provides an default implementation (`langgraph.checkpoint.serde.jsonplus.JsonPlusSerializer`) that handles a wide variety of types, including LangChain and LangGraph primitives, datetimes, enums and more.
`langgraph-checkpoint` also defines protocol for serialization/deserialization (serde) and provides a default implementation (`langgraph.checkpoint.serde.jsonplus.JsonPlusSerializer`) that handles a wide variety of types, including LangChain and LangGraph primitives, datetimes, enums and more.
> [!IMPORTANT]
> **Checkpoint deserialization security:** By default the serializer allows any Python type found in checkpoint data. New applications should set the environment variable `LANGGRAPH_STRICT_MSGPACK=true` or pass an explicit `allowed_msgpack_modules` list to `JsonPlusSerializer` to restrict deserialization to known-safe types.
@@ -89,3 +109,13 @@ checkpointer.get(read_config)
# list checkpoints
list(checkpointer.list(read_config))
```
## 📕 Releases & Versioning
See our [Releases](https://docs.langchain.com/oss/python/release-policy) and [Versioning](https://docs.langchain.com/oss/python/versioning) policies.
## 💁 Contributing
As an open-source project in a rapidly developing field, we are extremely open to contributions, whether it be in the form of a new feature, improved infrastructure, or better documentation.
For detailed information on how to contribute, see the [Contributing Guide](https://docs.langchain.com/oss/python/contributing/overview).
@@ -34,6 +34,37 @@ PendingWrite = tuple[str, str, Any]
logger = logging.getLogger(__name__)
def _parse_supersteps_since_last_snapshot_by_channel(
metadata: Mapping[str, Any],
channels: Sequence[str],
) -> dict[str, int]:
"""Per-channel supersteps-since-last-snapshot, parsed from metadata.
Reads `metadata.counters_since_delta_snapshot[ch]`, a `(updates,
supersteps)` pair, and returns `{ch: supersteps}` for channels whose
supersteps count is positive. Channels with no counter entry (just
snapshotted, or never written) are omitted — their seed, if any, is the
target checkpoint itself and needs no ancestor walk.
Used to drive the ancestor-walk depth in `get_delta_channel_history`:
a channel's seed snapshot sits exactly `supersteps` hops back along the
parent chain.
"""
counters = metadata.get("counters_since_delta_snapshot") or {}
result: dict[str, int] = {}
for ch in channels:
entry = counters.get(ch)
if not isinstance(entry, (list, tuple)) or len(entry) < 2:
continue
try:
supersteps = int(entry[1])
except (TypeError, ValueError):
continue
if supersteps > 0:
result[ch] = supersteps
return result
# Marked as total=False to allow for future expansion.
class CheckpointMetadata(TypedDict, total=False):
"""Metadata associated with a checkpoint."""
@@ -619,34 +650,30 @@ class BaseCheckpointSaver(Generic[V]):
"""
if not channels:
return {}
collected_by_ch: dict[str, list[PendingWrite]] = {c: [] for c in channels}
seed_by_ch: dict[str, Any] = {}
remaining: set[str] = set(channels)
channels = list(channels)
target_tuple = self.get_tuple(config)
cursor_config: RunnableConfig | None = (
target_tuple.parent_config if target_tuple else None
if target_tuple is None:
return {ch: {"writes": []} for ch in channels}
supersteps_by_ch = _parse_supersteps_since_last_snapshot_by_channel(
target_tuple.metadata or {}, channels
)
while cursor_config is not None and remaining:
max_supersteps = max(supersteps_by_ch.values(), default=0)
chain: list[CheckpointTuple] = []
has_reached_root = False
cursor_config: RunnableConfig | None = target_tuple.parent_config
while cursor_config is not None and len(chain) < max_supersteps:
tup = self.get_tuple(cursor_config)
if tup is None:
break
if tup.pending_writes:
for write in reversed(tup.pending_writes):
ch = write[1]
if ch in remaining:
collected_by_ch[ch].append(write)
for ch in list(remaining):
if ch in tup.checkpoint["channel_values"]:
seed_by_ch[ch] = tup.checkpoint["channel_values"][ch]
remaining.discard(ch)
chain.append(tup)
if tup.parent_config is None:
has_reached_root = True
break
cursor_config = tup.parent_config
result: dict[str, DeltaChannelHistory] = {}
for ch in channels:
entry: DeltaChannelHistory = {"writes": list(reversed(collected_by_ch[ch]))}
if ch in seed_by_ch:
entry["seed"] = seed_by_ch[ch]
result[ch] = entry
return result
return self._assemble_default_delta_history(
channels, supersteps_by_ch, chain, has_reached_root, config
)
async def aget_delta_channel_history(
self, *, config: RunnableConfig, channels: Sequence[str]
@@ -660,32 +687,106 @@ class BaseCheckpointSaver(Generic[V]):
"""
if not channels:
return {}
collected_by_ch: dict[str, list[PendingWrite]] = {c: [] for c in channels}
seed_by_ch: dict[str, Any] = {}
remaining: set[str] = set(channels)
channels = list(channels)
target_tuple = await self.aget_tuple(config)
cursor_config: RunnableConfig | None = (
target_tuple.parent_config if target_tuple else None
if target_tuple is None:
return {ch: {"writes": []} for ch in channels}
supersteps_by_ch = _parse_supersteps_since_last_snapshot_by_channel(
target_tuple.metadata or {}, channels
)
while cursor_config is not None and remaining:
max_supersteps = max(supersteps_by_ch.values(), default=0)
chain: list[CheckpointTuple] = []
has_reached_root = False
cursor_config: RunnableConfig | None = target_tuple.parent_config
while cursor_config is not None and len(chain) < max_supersteps:
tup = await self.aget_tuple(cursor_config)
if tup is None:
break
if tup.pending_writes:
for write in reversed(tup.pending_writes):
ch = write[1]
if ch in remaining:
collected_by_ch[ch].append(write)
for ch in list(remaining):
if ch in tup.checkpoint["channel_values"]:
seed_by_ch[ch] = tup.checkpoint["channel_values"][ch]
remaining.discard(ch)
chain.append(tup)
if tup.parent_config is None:
has_reached_root = True
break
cursor_config = tup.parent_config
return self._assemble_default_delta_history(
channels, supersteps_by_ch, chain, has_reached_root, config
)
def _assemble_default_delta_history(
self,
channels: Sequence[str],
supersteps_by_ch: Mapping[str, int],
chain: Sequence[CheckpointTuple],
has_reached_root: bool,
config: RunnableConfig,
) -> dict[str, DeltaChannelHistory]:
"""Slice the walked parent chain into per-channel histories.
For each channel the seed snapshot sits `supersteps` hops back along
`chain` (newest first): the seed checkpoint is `chain[supersteps - 1]`
and its `channel_values[ch]` is the seed value. The seed checkpoint's
own writes are replayed on top of a `_DeltaSnapshot` seed but skipped
for a migrated plain-value seed (the legacy non-delta blob already
incorporates them).
When the chain is shorter than `supersteps` but the root was reached,
the persisted chain is "compressed" relative to the logical superstep
count (`durability="exit"`, or a thread that never snapshotted). The
seed candidate is then the oldest checkpoint (`chain[-1]`); if its
`channel_values[ch]` is absent the channel has no seed and replays
the full chain on an empty baseline.
"""
# Imported lazily to avoid a hard checkpoint→serde-types coupling at
# module import; only the delta surface needs the runtime check.
from langgraph.checkpoint.serde.types import _DeltaSnapshot
thread_id = config["configurable"].get("thread_id")
result: dict[str, DeltaChannelHistory] = {}
for ch in channels:
entry: DeltaChannelHistory = {"writes": list(reversed(collected_by_ch[ch]))}
if ch in seed_by_ch:
entry["seed"] = seed_by_ch[ch]
entry: DeltaChannelHistory = {"writes": []}
bound = supersteps_by_ch.get(ch, 0)
if bound <= 0:
result[ch] = entry
continue
if len(chain) >= bound:
seed_depth = bound
elif has_reached_root:
seed_depth = len(chain)
else:
logger.warning(
"cannot find seed snapshot for delta channel "
"(thread_id=%s, channel=%s)",
thread_id,
ch,
)
result[ch] = entry
continue
if seed_depth <= 0:
result[ch] = entry
continue
chain_slice: Sequence[CheckpointTuple] = chain[:seed_depth]
seed_tuple: CheckpointTuple | None = chain[seed_depth - 1]
skip_seed_checkpoint_writes = False
channel_values = seed_tuple.checkpoint["channel_values"]
if ch in channel_values:
seed_value = channel_values[ch]
entry["seed"] = seed_value
skip_seed_checkpoint_writes = not isinstance(seed_value, _DeltaSnapshot)
else:
# No stored value at the oldest checkpoint → empty baseline,
# so the chain's own writes are all replayed from empty.
seed_tuple = None
collected: list[PendingWrite] = []
# Chain is newest→oldest; replay oldest→newest.
for tup in reversed(list(chain_slice)):
if skip_seed_checkpoint_writes and tup is seed_tuple:
continue
for write in tup.pending_writes or []:
if write[1] == ch:
collected.append(write)
entry["writes"] = collected
result[ch] = entry
return result
@@ -23,6 +23,7 @@ from langgraph.checkpoint.base import (
DeltaChannelHistory,
PendingWrite,
SerializerProtocol,
_parse_supersteps_since_last_snapshot_by_channel,
get_checkpoint_id,
get_checkpoint_metadata,
)
@@ -144,14 +145,20 @@ class InMemorySaver(
) -> Mapping[str, DeltaChannelHistory]:
"""Override: walk the parent chain ONCE for all requested channels.
Each channel terminates independently at the nearest ancestor
whose stored blob is non-empty. Other channels keep walking until
they find their own terminator or hit the root.
Walk depth is driven by the target checkpoint's
`counters_since_delta_snapshot[ch]` supersteps counter: each
channel's seed snapshot sits exactly `supersteps` hops back along
the parent chain. This locates seeds reliably even when they aren't
a `_DeltaSnapshot` sentinel — e.g. a legacy plain-value blob from a
thread migrated off a non-delta channel.
Pre-delta plain-value blobs subsume their ancestor's pending
writes (the value already includes them); `_DeltaSnapshot` blobs
do not (snapshot is the value AT that ancestor, prior to its own
pending writes that produce the child).
Pre-delta plain-value seeds subsume their own checkpoint's pending
writes (the value already includes them), so those are skipped;
`_DeltaSnapshot` seeds do not (the snapshot is the value AT that
ancestor, prior to its own pending writes), so they are replayed.
When the chain reaches the root short of `supersteps`, the snapshot
was never persisted (implicit empty baseline) — replay the full
chain with no seed.
"""
if not channels:
return {}
@@ -159,72 +166,98 @@ class InMemorySaver(
# module import; only this override needs the runtime check.
from langgraph.checkpoint.serde.types import _DeltaSnapshot
channels = list(channels)
thread_id = config["configurable"]["thread_id"]
checkpoint_ns = config["configurable"].get("checkpoint_ns", "")
checkpoint_id = config["configurable"].get("checkpoint_id", "")
ns_storage = self.storage.get(thread_id, {}).get(checkpoint_ns, {})
# Resolve the target checkpoint id + its metadata (for supersteps).
checkpoint_id = get_checkpoint_id(config)
if checkpoint_id is None:
checkpoint_id = next(reversed(ns_storage), None)
target_entry = ns_storage.get(checkpoint_id) if checkpoint_id else None
if target_entry is None:
return {ch: {"writes": []} for ch in channels}
metadata = self.serde.loads_typed(target_entry[1])
supersteps_by_ch = _parse_supersteps_since_last_snapshot_by_channel(
metadata or {}, channels
)
max_supersteps = max(supersteps_by_ch.values(), default=0)
# Walk the parent chain (newest first) up to the deepest supersteps.
chain: list[str] = []
target_entry = ns_storage.get(checkpoint_id)
current: str | None = target_entry[2] if target_entry is not None else None
while current is not None:
has_reached_root = False
current: str | None = target_entry[2]
while current is not None and len(chain) < max_supersteps:
entry = ns_storage.get(current)
if entry is None:
break
chain.append(current)
_, _, parent = entry
current = parent
collected_by_ch: dict[str, list[PendingWrite]] = {c: [] for c in channels}
seed_by_ch: dict[str, Any] = {}
remaining: set[str] = set(channels)
for cp_id in chain:
if not remaining:
parent = entry[2]
if parent is None:
has_reached_root = True
break
entry = ns_storage.get(cp_id)
ckpt = self.serde.loads_typed(entry[0]) if entry is not None else None
terminated_here: set[str] = set()
blob_value_by_ch: dict[str, Any] = {}
if ckpt is not None:
versions = ckpt.get("channel_versions", {})
for ch in remaining:
ver = versions.get(ch)
if ver is None:
continue
blob_entry = self.blobs.get((thread_id, checkpoint_ns, ch, ver))
if blob_entry is None or blob_entry[0] == "empty":
continue
blob_value_by_ch[ch] = self.serde.loads_typed(blob_entry)
terminated_here.add(ch)
step_writes = self.writes.get((thread_id, checkpoint_ns, cp_id), {})
for (_task_id, _idx), (tid, ch, serialized, _) in sorted(
step_writes.items(), reverse=True
):
if ch not in remaining:
continue
blob_value = blob_value_by_ch.get(ch)
if blob_value is not None and not isinstance(
blob_value, _DeltaSnapshot
):
continue
collected_by_ch[ch].append(
(tid, ch, self.serde.loads_typed(serialized))
)
for ch in terminated_here:
seed_by_ch[ch] = blob_value_by_ch[ch]
remaining.discard(ch)
current = parent
result: dict[str, DeltaChannelHistory] = {}
for ch in channels:
entry_h: DeltaChannelHistory = {
"writes": list(reversed(collected_by_ch[ch]))
}
if ch in seed_by_ch:
entry_h["seed"] = seed_by_ch[ch]
entry_h: DeltaChannelHistory = {"writes": []}
bound = supersteps_by_ch.get(ch, 0)
if bound <= 0:
result[ch] = entry_h
continue
if len(chain) >= bound:
seed_depth = bound
elif has_reached_root:
seed_depth = len(chain)
else:
logger.warning(
"cannot find seed snapshot for delta channel "
"(thread_id=%s, channel=%s)",
thread_id,
ch,
)
result[ch] = entry_h
continue
if seed_depth <= 0:
result[ch] = entry_h
continue
chain_slice: list[str] = chain[:seed_depth]
seed_cpid: str | None = chain[seed_depth - 1]
skip_seed_checkpoint_writes = False
seed_entry = ns_storage.get(seed_cpid)
if seed_entry is not None:
ckpt = self.serde.loads_typed(seed_entry[0])
ver = (ckpt.get("channel_versions") or {}).get(ch)
blob_entry = (
self.blobs.get((thread_id, checkpoint_ns, ch, ver))
if ver is not None
else None
)
if blob_entry is not None and blob_entry[0] != "empty":
seed_value = self.serde.loads_typed(blob_entry)
entry_h["seed"] = seed_value
skip_seed_checkpoint_writes = not isinstance(
seed_value, _DeltaSnapshot
)
else:
# No stored value at the oldest checkpoint → empty
# baseline; the chain's own writes replay from empty.
seed_cpid = None
collected: list[PendingWrite] = []
# Chain is newest→oldest; replay oldest→newest.
for cp_id in reversed(chain_slice):
if skip_seed_checkpoint_writes and cp_id == seed_cpid:
continue
step_writes = self.writes.get((thread_id, checkpoint_ns, cp_id), {})
for (_task_id, _idx), (tid, w_ch, serialized, _) in sorted(
step_writes.items()
):
if w_ch == ch:
collected.append((tid, ch, self.serde.loads_typed(serialized)))
entry_h["writes"] = collected
result[ch] = entry_h
return result
+15 -3
View File
@@ -351,9 +351,12 @@ class TestInMemorySaverDeltaChannel:
cp1["id"] = "cp1"
cp2 = empty_checkpoint()
cp2["id"] = "cp2"
# Target (cp2) carries the supersteps counter; no snapshot was ever
# taken, so the walk runs back to the root → no seed, empty baseline.
cp2_md = {"counters_since_delta_snapshot": {channel: [1, 2]}}
saver.storage[thread_id][ns] = {
"cp1": (serde.dumps_typed(cp1), serde.dumps_typed({}), None),
"cp2": (serde.dumps_typed(cp2), serde.dumps_typed({}), "cp1"),
"cp2": (serde.dumps_typed(cp2), serde.dumps_typed(cp2_md), "cp1"),
}
# Writes stored at cp1 produced the cp1 snapshot; part of history.
saver.writes[(thread_id, ns, "cp1")][("task1", 0)] = (
@@ -456,10 +459,15 @@ class TestBaseFallbackGetChannelWrites:
cp1["id"] = "00000000000000000000000000000002.0000000000000000"
cp2 = empty_checkpoint()
cp2["id"] = "00000000000000000000000000000003.0000000000000000"
# The target (cp2) carries `counters_since_delta_snapshot` — the
# supersteps-since-last-snapshot driving the ancestor-walk depth. No
# snapshot was ever taken, so the count runs back past the oldest
# persisted checkpoint (root) → implicit empty baseline, no seed.
cp2_md = {"counters_since_delta_snapshot": {channel: [2, 3]}}
saver.storage[thread_id][ns] = {
cp0["id"]: (serde.dumps_typed(cp0), serde.dumps_typed({}), None),
cp1["id"]: (serde.dumps_typed(cp1), serde.dumps_typed({}), cp0["id"]),
cp2["id"]: (serde.dumps_typed(cp2), serde.dumps_typed({}), cp1["id"]),
cp2["id"]: (serde.dumps_typed(cp2), serde.dumps_typed(cp2_md), cp1["id"]),
}
# Writes under cp0 produced cp1's state; writes under cp1 produced cp2's.
saver.writes[(thread_id, ns, cp0["id"])][("task1", 0)] = (
@@ -607,10 +615,14 @@ class TestPreDeltaBlobTerminator:
cp3["id"] = "cp3"
cp3["channel_versions"][channel] = v3
# cp1 is the pre-delta (migration) seed; the channel became a
# DeltaChannel at cp2, so its supersteps counter starts there: cp2 -> 1,
# cp3 -> 2. The target (cp3) walks 2 hops back to the cp1 seed blob.
cp3_md = {"counters_since_delta_snapshot": {channel: [2, 2]}}
saver.storage[thread_id][ns] = {
"cp1": (serde.dumps_typed(cp1), serde.dumps_typed({}), None),
"cp2": (serde.dumps_typed(cp2), serde.dumps_typed({}), "cp1"),
"cp3": (serde.dumps_typed(cp3), serde.dumps_typed({}), "cp2"),
"cp3": (serde.dumps_typed(cp3), serde.dumps_typed(cp3_md), "cp2"),
}
# Write under cp1 would be from the pre-delta era and MUST be ignored
# (the blob already captures it). We add one and assert it is not
+72 -3
View File
@@ -383,7 +383,7 @@ test = [
[[package]]
name = "langsmith"
version = "0.8.0"
version = "0.8.18"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
@@ -393,12 +393,13 @@ dependencies = [
{ name = "requests" },
{ name = "requests-toolbelt" },
{ name = "uuid-utils" },
{ name = "websockets" },
{ name = "xxhash" },
{ name = "zstandard" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a8/64/95f1f013531395f4e8ed73caeee780f65c7c58fe028cb543f8937b45611b/langsmith-0.8.0.tar.gz", hash = "sha256:59fe5b2a56bbbe14a08aa76691f84b49e8675dd21e11b57d80c6db8c08bac2e3", size = 4432996, upload-time = "2026-04-30T22:13:07.341Z" }
sdist = { url = "https://files.pythonhosted.org/packages/9a/d9/a6681aa9847bbbc5ec21abe20a5e233b94e5edcfe39624db607ac7e8ccb4/langsmith-0.8.18.tar.gz", hash = "sha256:32dde9c0e67e053e0fb738921fc8ced768af7b8fa83d7a0e3fd63597cf8776dd", size = 4526988, upload-time = "2026-06-19T13:12:17.123Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f3/e1/a4be2e696c9473bb53298df398237da5674704d781d4b748ed35aeef592a/langsmith-0.8.0-py3-none-any.whl", hash = "sha256:12cc4bc5622b835a6d841964d6034df3617bdb912dae0c1381fd0a68a9b3a3ef", size = 393268, upload-time = "2026-04-30T22:13:05.56Z" },
{ url = "https://files.pythonhosted.org/packages/03/70/0e0cc80a3b064c8d6c8d697c3125ed86e39d5a7393ec6dc8b07cb1cf13c4/langsmith-0.8.18-py3-none-any.whl", hash = "sha256:3940183349993faef48e6c7d08e4822ee9cefd906b362d0e3c2d650314d2f282", size = 508108, upload-time = "2026-06-19T13:12:15.348Z" },
]
[[package]]
@@ -1404,6 +1405,74 @@ wheels = [
{ 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 = "websockets"
version = "16.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/20/74/221f58decd852f4b59cc3354cccaf87e8ef695fede361d03dc9a7396573b/websockets-16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:04cdd5d2d1dacbad0a7bf36ccbcd3ccd5a30ee188f2560b7a62a30d14107b31a", size = 177343, upload-time = "2026-01-10T09:22:21.28Z" },
{ url = "https://files.pythonhosted.org/packages/19/0f/22ef6107ee52ab7f0b710d55d36f5a5d3ef19e8a205541a6d7ffa7994e5a/websockets-16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8ff32bb86522a9e5e31439a58addbb0166f0204d64066fb955265c4e214160f0", size = 175021, upload-time = "2026-01-10T09:22:22.696Z" },
{ url = "https://files.pythonhosted.org/packages/10/40/904a4cb30d9b61c0e278899bf36342e9b0208eb3c470324a9ecbaac2a30f/websockets-16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:583b7c42688636f930688d712885cf1531326ee05effd982028212ccc13e5957", size = 175320, upload-time = "2026-01-10T09:22:23.94Z" },
{ url = "https://files.pythonhosted.org/packages/9d/2f/4b3ca7e106bc608744b1cdae041e005e446124bebb037b18799c2d356864/websockets-16.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7d837379b647c0c4c2355c2499723f82f1635fd2c26510e1f587d89bc2199e72", size = 183815, upload-time = "2026-01-10T09:22:25.469Z" },
{ url = "https://files.pythonhosted.org/packages/86/26/d40eaa2a46d4302becec8d15b0fc5e45bdde05191e7628405a19cf491ccd/websockets-16.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df57afc692e517a85e65b72e165356ed1df12386ecb879ad5693be08fac65dde", size = 185054, upload-time = "2026-01-10T09:22:27.101Z" },
{ url = "https://files.pythonhosted.org/packages/b0/ba/6500a0efc94f7373ee8fefa8c271acdfd4dca8bd49a90d4be7ccabfc397e/websockets-16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2b9f1e0d69bc60a4a87349d50c09a037a2607918746f07de04df9e43252c77a3", size = 184565, upload-time = "2026-01-10T09:22:28.293Z" },
{ url = "https://files.pythonhosted.org/packages/04/b4/96bf2cee7c8d8102389374a2616200574f5f01128d1082f44102140344cc/websockets-16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:335c23addf3d5e6a8633f9f8eda77efad001671e80b95c491dd0924587ece0b3", size = 183848, upload-time = "2026-01-10T09:22:30.394Z" },
{ url = "https://files.pythonhosted.org/packages/02/8e/81f40fb00fd125357814e8c3025738fc4ffc3da4b6b4a4472a82ba304b41/websockets-16.0-cp310-cp310-win32.whl", hash = "sha256:37b31c1623c6605e4c00d466c9d633f9b812ea430c11c8a278774a1fde1acfa9", size = 178249, upload-time = "2026-01-10T09:22:32.083Z" },
{ url = "https://files.pythonhosted.org/packages/b4/5f/7e40efe8df57db9b91c88a43690ac66f7b7aa73a11aa6a66b927e44f26fa/websockets-16.0-cp310-cp310-win_amd64.whl", hash = "sha256:8e1dab317b6e77424356e11e99a432b7cb2f3ec8c5ab4dabbcee6add48f72b35", size = 178685, upload-time = "2026-01-10T09:22:33.345Z" },
{ url = "https://files.pythonhosted.org/packages/f2/db/de907251b4ff46ae804ad0409809504153b3f30984daf82a1d84a9875830/websockets-16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:31a52addea25187bde0797a97d6fc3d2f92b6f72a9370792d65a6e84615ac8a8", size = 177340, upload-time = "2026-01-10T09:22:34.539Z" },
{ url = "https://files.pythonhosted.org/packages/f3/fa/abe89019d8d8815c8781e90d697dec52523fb8ebe308bf11664e8de1877e/websockets-16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:417b28978cdccab24f46400586d128366313e8a96312e4b9362a4af504f3bbad", size = 175022, upload-time = "2026-01-10T09:22:36.332Z" },
{ url = "https://files.pythonhosted.org/packages/58/5d/88ea17ed1ded2079358b40d31d48abe90a73c9e5819dbcde1606e991e2ad/websockets-16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:af80d74d4edfa3cb9ed973a0a5ba2b2a549371f8a741e0800cb07becdd20f23d", size = 175319, upload-time = "2026-01-10T09:22:37.602Z" },
{ url = "https://files.pythonhosted.org/packages/d2/ae/0ee92b33087a33632f37a635e11e1d99d429d3d323329675a6022312aac2/websockets-16.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:08d7af67b64d29823fed316505a89b86705f2b7981c07848fb5e3ea3020c1abe", size = 184631, upload-time = "2026-01-10T09:22:38.789Z" },
{ url = "https://files.pythonhosted.org/packages/c8/c5/27178df583b6c5b31b29f526ba2da5e2f864ecc79c99dae630a85d68c304/websockets-16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7be95cfb0a4dae143eaed2bcba8ac23f4892d8971311f1b06f3c6b78952ee70b", size = 185870, upload-time = "2026-01-10T09:22:39.893Z" },
{ url = "https://files.pythonhosted.org/packages/87/05/536652aa84ddc1c018dbb7e2c4cbcd0db884580bf8e95aece7593fde526f/websockets-16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6297ce39ce5c2e6feb13c1a996a2ded3b6832155fcfc920265c76f24c7cceb5", size = 185361, upload-time = "2026-01-10T09:22:41.016Z" },
{ url = "https://files.pythonhosted.org/packages/6d/e2/d5332c90da12b1e01f06fb1b85c50cfc489783076547415bf9f0a659ec19/websockets-16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c1b30e4f497b0b354057f3467f56244c603a79c0d1dafce1d16c283c25f6e64", size = 184615, upload-time = "2026-01-10T09:22:42.442Z" },
{ url = "https://files.pythonhosted.org/packages/77/fb/d3f9576691cae9253b51555f841bc6600bf0a983a461c79500ace5a5b364/websockets-16.0-cp311-cp311-win32.whl", hash = "sha256:5f451484aeb5cafee1ccf789b1b66f535409d038c56966d6101740c1614b86c6", size = 178246, upload-time = "2026-01-10T09:22:43.654Z" },
{ url = "https://files.pythonhosted.org/packages/54/67/eaff76b3dbaf18dcddabc3b8c1dba50b483761cccff67793897945b37408/websockets-16.0-cp311-cp311-win_amd64.whl", hash = "sha256:8d7f0659570eefb578dacde98e24fb60af35350193e4f56e11190787bee77dac", size = 178684, upload-time = "2026-01-10T09:22:44.941Z" },
{ url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" },
{ url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" },
{ url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" },
{ url = "https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c", size = 184915, upload-time = "2026-01-10T09:22:51.071Z" },
{ url = "https://files.pythonhosted.org/packages/97/bb/21c36b7dbbafc85d2d480cd65df02a1dc93bf76d97147605a8e27ff9409d/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f", size = 186152, upload-time = "2026-01-10T09:22:52.224Z" },
{ url = "https://files.pythonhosted.org/packages/4a/34/9bf8df0c0cf88fa7bfe36678dc7b02970c9a7d5e065a3099292db87b1be2/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1", size = 185583, upload-time = "2026-01-10T09:22:53.443Z" },
{ url = "https://files.pythonhosted.org/packages/47/88/4dd516068e1a3d6ab3c7c183288404cd424a9a02d585efbac226cb61ff2d/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2", size = 184880, upload-time = "2026-01-10T09:22:55.033Z" },
{ url = "https://files.pythonhosted.org/packages/91/d6/7d4553ad4bf1c0421e1ebd4b18de5d9098383b5caa1d937b63df8d04b565/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89", size = 178261, upload-time = "2026-01-10T09:22:56.251Z" },
{ url = "https://files.pythonhosted.org/packages/c3/f0/f3a17365441ed1c27f850a80b2bc680a0fa9505d733fe152fdf5e98c1c0b/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea", size = 178693, upload-time = "2026-01-10T09:22:57.478Z" },
{ url = "https://files.pythonhosted.org/packages/cc/9c/baa8456050d1c1b08dd0ec7346026668cbc6f145ab4e314d707bb845bf0d/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9", size = 177364, upload-time = "2026-01-10T09:22:59.333Z" },
{ url = "https://files.pythonhosted.org/packages/7e/0c/8811fc53e9bcff68fe7de2bcbe75116a8d959ac699a3200f4847a8925210/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230", size = 175039, upload-time = "2026-01-10T09:23:01.171Z" },
{ url = "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c", size = 175323, upload-time = "2026-01-10T09:23:02.341Z" },
{ url = "https://files.pythonhosted.org/packages/bd/28/0a25ee5342eb5d5f297d992a77e56892ecb65e7854c7898fb7d35e9b33bd/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5", size = 184975, upload-time = "2026-01-10T09:23:03.756Z" },
{ url = "https://files.pythonhosted.org/packages/f9/66/27ea52741752f5107c2e41fda05e8395a682a1e11c4e592a809a90c6a506/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82", size = 186203, upload-time = "2026-01-10T09:23:05.01Z" },
{ url = "https://files.pythonhosted.org/packages/37/e5/8e32857371406a757816a2b471939d51c463509be73fa538216ea52b792a/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8", size = 185653, upload-time = "2026-01-10T09:23:06.301Z" },
{ url = "https://files.pythonhosted.org/packages/9b/67/f926bac29882894669368dc73f4da900fcdf47955d0a0185d60103df5737/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f", size = 184920, upload-time = "2026-01-10T09:23:07.492Z" },
{ url = "https://files.pythonhosted.org/packages/3c/a1/3d6ccdcd125b0a42a311bcd15a7f705d688f73b2a22d8cf1c0875d35d34a/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a", size = 178255, upload-time = "2026-01-10T09:23:09.245Z" },
{ url = "https://files.pythonhosted.org/packages/6b/ae/90366304d7c2ce80f9b826096a9e9048b4bb760e44d3b873bb272cba696b/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156", size = 178689, upload-time = "2026-01-10T09:23:10.483Z" },
{ url = "https://files.pythonhosted.org/packages/f3/1d/e88022630271f5bd349ed82417136281931e558d628dd52c4d8621b4a0b2/websockets-16.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8cc451a50f2aee53042ac52d2d053d08bf89bcb31ae799cb4487587661c038a0", size = 177406, upload-time = "2026-01-10T09:23:12.178Z" },
{ url = "https://files.pythonhosted.org/packages/f2/78/e63be1bf0724eeb4616efb1ae1c9044f7c3953b7957799abb5915bffd38e/websockets-16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:daa3b6ff70a9241cf6c7fc9e949d41232d9d7d26fd3522b1ad2b4d62487e9904", size = 175085, upload-time = "2026-01-10T09:23:13.511Z" },
{ url = "https://files.pythonhosted.org/packages/bb/f4/d3c9220d818ee955ae390cf319a7c7a467beceb24f05ee7aaaa2414345ba/websockets-16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd3cb4adb94a2a6e2b7c0d8d05cb94e6f1c81a0cf9dc2694fb65c7e8d94c42e4", size = 175328, upload-time = "2026-01-10T09:23:14.727Z" },
{ url = "https://files.pythonhosted.org/packages/63/bc/d3e208028de777087e6fb2b122051a6ff7bbcca0d6df9d9c2bf1dd869ae9/websockets-16.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:781caf5e8eee67f663126490c2f96f40906594cb86b408a703630f95550a8c3e", size = 185044, upload-time = "2026-01-10T09:23:15.939Z" },
{ url = "https://files.pythonhosted.org/packages/ad/6e/9a0927ac24bd33a0a9af834d89e0abc7cfd8e13bed17a86407a66773cc0e/websockets-16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caab51a72c51973ca21fa8a18bd8165e1a0183f1ac7066a182ff27107b71e1a4", size = 186279, upload-time = "2026-01-10T09:23:17.148Z" },
{ url = "https://files.pythonhosted.org/packages/b9/ca/bf1c68440d7a868180e11be653c85959502efd3a709323230314fda6e0b3/websockets-16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19c4dc84098e523fd63711e563077d39e90ec6702aff4b5d9e344a60cb3c0cb1", size = 185711, upload-time = "2026-01-10T09:23:18.372Z" },
{ url = "https://files.pythonhosted.org/packages/c4/f8/fdc34643a989561f217bb477cbc47a3a07212cbda91c0e4389c43c296ebf/websockets-16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a5e18a238a2b2249c9a9235466b90e96ae4795672598a58772dd806edc7ac6d3", size = 184982, upload-time = "2026-01-10T09:23:19.652Z" },
{ url = "https://files.pythonhosted.org/packages/dd/d1/574fa27e233764dbac9c52730d63fcf2823b16f0856b3329fc6268d6ae4f/websockets-16.0-cp314-cp314-win32.whl", hash = "sha256:a069d734c4a043182729edd3e9f247c3b2a4035415a9172fd0f1b71658a320a8", size = 177915, upload-time = "2026-01-10T09:23:21.458Z" },
{ url = "https://files.pythonhosted.org/packages/8a/f1/ae6b937bf3126b5134ce1f482365fde31a357c784ac51852978768b5eff4/websockets-16.0-cp314-cp314-win_amd64.whl", hash = "sha256:c0ee0e63f23914732c6d7e0cce24915c48f3f1512ec1d079ed01fc629dab269d", size = 178381, upload-time = "2026-01-10T09:23:22.715Z" },
{ url = "https://files.pythonhosted.org/packages/06/9b/f791d1db48403e1f0a27577a6beb37afae94254a8c6f08be4a23e4930bc0/websockets-16.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:a35539cacc3febb22b8f4d4a99cc79b104226a756aa7400adc722e83b0d03244", size = 177737, upload-time = "2026-01-10T09:23:24.523Z" },
{ url = "https://files.pythonhosted.org/packages/bd/40/53ad02341fa33b3ce489023f635367a4ac98b73570102ad2cdd770dacc9a/websockets-16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b784ca5de850f4ce93ec85d3269d24d4c82f22b7212023c974c401d4980ebc5e", size = 175268, upload-time = "2026-01-10T09:23:25.781Z" },
{ url = "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:569d01a4e7fba956c5ae4fc988f0d4e187900f5497ce46339c996dbf24f17641", size = 175486, upload-time = "2026-01-10T09:23:27.033Z" },
{ url = "https://files.pythonhosted.org/packages/e5/2d/7583b30208b639c8090206f95073646c2c9ffd66f44df967981a64f849ad/websockets-16.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50f23cdd8343b984957e4077839841146f67a3d31ab0d00e6b824e74c5b2f6e8", size = 185331, upload-time = "2026-01-10T09:23:28.259Z" },
{ url = "https://files.pythonhosted.org/packages/45/b0/cce3784eb519b7b5ad680d14b9673a31ab8dcb7aad8b64d81709d2430aa8/websockets-16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:152284a83a00c59b759697b7f9e9cddf4e3c7861dd0d964b472b70f78f89e80e", size = 186501, upload-time = "2026-01-10T09:23:29.449Z" },
{ url = "https://files.pythonhosted.org/packages/19/60/b8ebe4c7e89fb5f6cdf080623c9d92789a53636950f7abacfc33fe2b3135/websockets-16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc59589ab64b0022385f429b94697348a6a234e8ce22544e3681b2e9331b5944", size = 186062, upload-time = "2026-01-10T09:23:31.368Z" },
{ url = "https://files.pythonhosted.org/packages/88/a8/a080593f89b0138b6cba1b28f8df5673b5506f72879322288b031337c0b8/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206", size = 185356, upload-time = "2026-01-10T09:23:32.627Z" },
{ url = "https://files.pythonhosted.org/packages/c2/b6/b9afed2afadddaf5ebb2afa801abf4b0868f42f8539bfe4b071b5266c9fe/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6", size = 178085, upload-time = "2026-01-10T09:23:33.816Z" },
{ url = "https://files.pythonhosted.org/packages/9f/3e/28135a24e384493fa804216b79a6a6759a38cc4ff59118787b9fb693df93/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd", size = 178531, upload-time = "2026-01-10T09:23:35.016Z" },
{ url = "https://files.pythonhosted.org/packages/72/07/c98a68571dcf256e74f1f816b8cc5eae6eb2d3d5cfa44d37f801619d9166/websockets-16.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:349f83cd6c9a415428ee1005cadb5c2c56f4389bc06a9af16103c3bc3dcc8b7d", size = 174947, upload-time = "2026-01-10T09:23:36.166Z" },
{ url = "https://files.pythonhosted.org/packages/7e/52/93e166a81e0305b33fe416338be92ae863563fe7bce446b0f687b9df5aea/websockets-16.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:4a1aba3340a8dca8db6eb5a7986157f52eb9e436b74813764241981ca4888f03", size = 175260, upload-time = "2026-01-10T09:23:37.409Z" },
{ url = "https://files.pythonhosted.org/packages/56/0c/2dbf513bafd24889d33de2ff0368190a0e69f37bcfa19009ef819fe4d507/websockets-16.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f4a32d1bd841d4bcbffdcb3d2ce50c09c3909fbead375ab28d0181af89fd04da", size = 176071, upload-time = "2026-01-10T09:23:39.158Z" },
{ url = "https://files.pythonhosted.org/packages/a5/8f/aea9c71cc92bf9b6cc0f7f70df8f0b420636b6c96ef4feee1e16f80f75dd/websockets-16.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0298d07ee155e2e9fda5be8a9042200dd2e3bb0b8a38482156576f863a9d457c", size = 176968, upload-time = "2026-01-10T09:23:41.031Z" },
{ url = "https://files.pythonhosted.org/packages/9a/3f/f70e03f40ffc9a30d817eef7da1be72ee4956ba8d7255c399a01b135902a/websockets-16.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a653aea902e0324b52f1613332ddf50b00c06fdaf7e92624fbf8c77c78fa5767", size = 178735, upload-time = "2026-01-10T09:23:42.259Z" },
{ url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" },
]
[[package]]
name = "xxhash"
version = "3.6.0"
+60 -29
View File
@@ -1,29 +1,47 @@
# LangGraph CLI
The official command-line interface for LangGraph, providing tools to create, develop, and deploy LangGraph applications.
[![PyPI - Version](https://img.shields.io/pypi/v/langgraph-cli?label=%20)](https://pypi.org/project/langgraph-cli/#history)
[![PyPI - License](https://img.shields.io/pypi/l/langgraph-cli)](https://opensource.org/licenses/MIT)
[![PyPI - Downloads](https://img.shields.io/pepy/dt/langgraph-cli)](https://pypistats.org/packages/langgraph-cli)
[![Twitter](https://img.shields.io/twitter/url/https/twitter.com/langchain_oss.svg?style=social&label=Follow%20%40LangChain)](https://x.com/langchain_oss)
## Installation
To help you ship LangGraph apps to production faster, check out [LangSmith](https://www.langchain.com/langsmith).
[LangSmith](https://www.langchain.com/langsmith) is a unified developer platform for building, testing, and monitoring LLM applications.
## Quick Install
Install via pip:
```bash
pip install langgraph-cli
uv add langgraph-cli
```
## 🤔 What is this?
The LangGraph CLI is the official command-line interface for LangGraph. It provides tools to create, develop, build, and run LangGraph applications locally or in Docker.
## 📖 Documentation
For full documentation, see the [LangGraph CLI reference](https://reference.langchain.com/python/langgraph-cli). For conceptual guides and tutorials, see the [LangGraph Docs](https://docs.langchain.com/oss/python/langgraph/overview).
For development mode with hot reloading:
```bash
pip install "langgraph-cli[inmem]"
uv add "langgraph-cli[inmem]"
```
## Commands
### `langgraph new` 🌱
Create a new LangGraph project from a template
Create a new LangGraph project from a template.
```bash
langgraph new [PATH] --template TEMPLATE_NAME
```
### `langgraph dev` 🏃‍♀️
Run LangGraph API server in development mode with hot reloading
Run LangGraph API server in development mode with hot reloading.
```bash
langgraph dev [OPTIONS]
--host TEXT Host to bind to (default: 127.0.0.1)
@@ -35,7 +53,9 @@ langgraph dev [OPTIONS]
```
### `langgraph up` 🚀
Launch LangGraph API server in Docker
Launch LangGraph API server in Docker.
```bash
langgraph up [OPTIONS]
-p, --port INTEGER Port to expose (default: 8123)
@@ -47,7 +67,9 @@ langgraph up [OPTIONS]
```
### `langgraph build`
Build a Docker image for your LangGraph application
Build a Docker image for your LangGraph application.
```bash
langgraph build -t IMAGE_TAG [OPTIONS]
--platform TEXT Target platforms (e.g., linux/amd64,linux/arm64)
@@ -56,7 +78,9 @@ langgraph build -t IMAGE_TAG [OPTIONS]
```
### `langgraph dockerfile`
Generate a Dockerfile for custom deployments
Generate a Dockerfile for custom deployments.
```bash
langgraph dockerfile SAVE_PATH [OPTIONS]
-c, --config FILE Config file path
@@ -68,18 +92,18 @@ The CLI uses a `langgraph.json` configuration file with these key settings:
```json
{
"dependencies": ["langchain_openai", "./your_package"], // Required: Package dependencies
"dependencies": ["langchain_openai", "./your_package"],
"graphs": {
"my_graph": "./your_package/file.py:graph" // Required: Graph definitions
"my_graph": "./your_package/file.py:graph"
},
"env": "./.env", // Optional: Environment variables
"python_version": "3.11", // Optional: Python version (3.11/3.12)
"pip_config_file": "./pip.conf", // Optional: pip configuration
"dockerfile_lines": [] // Optional: Additional Dockerfile commands
"env": "./.env",
"python_version": "3.11",
"pip_config_file": "./pip.conf",
"dockerfile_lines": []
}
```
See the [full documentation](https://langchain-ai.github.io/langgraph/cloud/reference/cli/) for detailed configuration options.
See the [full documentation](https://reference.langchain.com/python/langgraph-cli) for detailed configuration options.
## Development
@@ -87,19 +111,26 @@ To develop the CLI itself:
1. Clone the repository
2. Navigate to the CLI directory: `cd libs/cli`
3. Install development dependencies: `uv pip install`
3. Install development dependencies: `uv sync`
4. Make your changes to the CLI code
5. Test your changes:
```bash
# Run CLI commands directly
uv run langgraph --help
# Or use the examples
cd examples
uv pip install
uv run langgraph dev # or other commands
```
## License
```bash
# Run CLI commands directly
uv run langgraph --help
This project is licensed under the terms specified in the repository's LICENSE file.
# Or use the examples
cd examples
uv sync
uv run langgraph dev # or other commands
```
## 📕 Releases & Versioning
See our [Releases](https://docs.langchain.com/oss/python/release-policy) and [Versioning](https://docs.langchain.com/oss/python/versioning) policies.
## 💁 Contributing
As an open-source project in a rapidly developing field, we are extremely open to contributions, whether it be in the form of a new feature, improved infrastructure, or better documentation.
For detailed information on how to contribute, see the [Contributing Guide](https://docs.langchain.com/oss/python/contributing/overview).
@@ -6,7 +6,7 @@ readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"langchain-openai==1.1.14",
"langchain-anthropic==1.0.0a5",
"langchain-anthropic==1.4.6",
"langgraph==1.1.5"
]
+5 -1
View File
@@ -10,7 +10,7 @@ This template demonstrates a simple chatbot implemented using [LangGraph.js](htt
The core logic, defined in `src/agent/graph.ts`, showcases a straightforward chatbot that responds to user queries while maintaining context from previous messages.
## What it does
## 🤔 What is this?
The simple chatbot:
@@ -20,6 +20,10 @@ The simple chatbot:
This template provides a foundation that can be easily customized and extended to create more complex conversational agents.
## 📖 Documentation
For JavaScript and TypeScript documentation, see the [LangGraph.js docs](https://docs.langchain.com/oss/javascript/langgraph/overview). LangGraph Studio also integrates with [LangSmith](https://smith.langchain.com/) for tracing and collaboration with teammates.
## Getting Started
Assuming you have already [installed LangGraph Studio](https://github.com/langchain-ai/langgraph-studio?tab=readme-ov-file#download), to set up:
+117 -231
View File
@@ -2,15 +2,7 @@
# yarn lockfile v1
"@ampproject/remapping@^2.2.0":
version "2.3.0"
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4"
integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==
dependencies:
"@jridgewell/gen-mapping" "^0.3.5"
"@jridgewell/trace-mapping" "^0.3.24"
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.24.7":
"@babel/code-frame@^7.0.0":
version "7.24.7"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465"
integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==
@@ -18,7 +10,7 @@
"@babel/highlight" "^7.24.7"
picocolors "^1.0.0"
"@babel/code-frame@^7.27.1", "@babel/code-frame@^7.28.6", "@babel/code-frame@^7.29.0":
"@babel/code-frame@^7.27.1":
version "7.29.0"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.0.tgz#7cd7a59f15b3cc0dcd803038f7792712a7d0b15c"
integrity sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==
@@ -27,51 +19,34 @@
js-tokens "^4.0.0"
picocolors "^1.1.1"
"@babel/compat-data@^7.25.2":
version "7.25.2"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.2.tgz#e41928bd33475305c586f6acbbb7e3ade7a6f7f5"
integrity sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==
"@babel/compat-data@^7.28.6":
version "7.29.0"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.0.tgz#00d03e8c0ac24dd9be942c5370990cbe1f17d88d"
integrity sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==
"@babel/core@^7.23.9":
version "7.25.2"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77"
integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==
"@babel/code-frame@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.7.tgz#f2fbbfea87c44a21590ec515b778b2c26d8866e7"
integrity sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==
dependencies:
"@ampproject/remapping" "^2.2.0"
"@babel/code-frame" "^7.24.7"
"@babel/generator" "^7.25.0"
"@babel/helper-compilation-targets" "^7.25.2"
"@babel/helper-module-transforms" "^7.25.2"
"@babel/helpers" "^7.25.0"
"@babel/parser" "^7.25.0"
"@babel/template" "^7.25.0"
"@babel/traverse" "^7.25.2"
"@babel/types" "^7.25.2"
convert-source-map "^2.0.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
json5 "^2.2.3"
semver "^6.3.1"
"@babel/helper-validator-identifier" "^7.29.7"
js-tokens "^4.0.0"
picocolors "^1.1.1"
"@babel/core@^7.27.4":
version "7.29.0"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.0.tgz#5286ad785df7f79d656e88ce86e650d16ca5f322"
integrity sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==
"@babel/compat-data@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.7.tgz#6f0237f0f36d2e51c0570a636faed9d2d0efe629"
integrity sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==
"@babel/core@^7.23.9", "@babel/core@^7.27.4":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.7.tgz#80c10b17248082968b57a857b91640971f2070f7"
integrity sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==
dependencies:
"@babel/code-frame" "^7.29.0"
"@babel/generator" "^7.29.0"
"@babel/helper-compilation-targets" "^7.28.6"
"@babel/helper-module-transforms" "^7.28.6"
"@babel/helpers" "^7.28.6"
"@babel/parser" "^7.29.0"
"@babel/template" "^7.28.6"
"@babel/traverse" "^7.29.0"
"@babel/types" "^7.29.0"
"@babel/code-frame" "^7.29.7"
"@babel/generator" "^7.29.7"
"@babel/helper-compilation-targets" "^7.29.7"
"@babel/helper-module-transforms" "^7.29.7"
"@babel/helpers" "^7.29.7"
"@babel/parser" "^7.29.7"
"@babel/template" "^7.29.7"
"@babel/traverse" "^7.29.7"
"@babel/types" "^7.29.7"
"@jridgewell/remapping" "^2.3.5"
convert-source-map "^2.0.0"
debug "^4.1.0"
@@ -79,17 +54,7 @@
json5 "^2.2.3"
semver "^6.3.1"
"@babel/generator@^7.25.0":
version "7.25.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.0.tgz#f858ddfa984350bc3d3b7f125073c9af6988f18e"
integrity sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==
dependencies:
"@babel/types" "^7.25.0"
"@jridgewell/gen-mapping" "^0.3.5"
"@jridgewell/trace-mapping" "^0.3.25"
jsesc "^2.5.1"
"@babel/generator@^7.27.5", "@babel/generator@^7.29.0":
"@babel/generator@^7.27.5":
version "7.29.1"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.1.tgz#d09876290111abbb00ef962a7b83a5307fba0d50"
integrity sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==
@@ -100,67 +65,49 @@
"@jridgewell/trace-mapping" "^0.3.28"
jsesc "^3.0.2"
"@babel/helper-compilation-targets@^7.25.2":
version "7.25.2"
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz#e1d9410a90974a3a5a66e84ff55ef62e3c02d06c"
integrity sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==
"@babel/generator@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.7.tgz#cca0b8827e6bcf3ba176788e7f3b180ad6db2fa3"
integrity sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==
dependencies:
"@babel/compat-data" "^7.25.2"
"@babel/helper-validator-option" "^7.24.8"
browserslist "^4.23.1"
lru-cache "^5.1.1"
semver "^6.3.1"
"@babel/parser" "^7.29.7"
"@babel/types" "^7.29.7"
"@jridgewell/gen-mapping" "^0.3.12"
"@jridgewell/trace-mapping" "^0.3.28"
jsesc "^3.0.2"
"@babel/helper-compilation-targets@^7.28.6":
version "7.28.6"
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25"
integrity sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==
"@babel/helper-compilation-targets@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz#7a1def704302401c47f64fa85589e974ae217042"
integrity sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==
dependencies:
"@babel/compat-data" "^7.28.6"
"@babel/helper-validator-option" "^7.27.1"
"@babel/compat-data" "^7.29.7"
"@babel/helper-validator-option" "^7.29.7"
browserslist "^4.24.0"
lru-cache "^5.1.1"
semver "^6.3.1"
"@babel/helper-globals@^7.28.0":
version "7.28.0"
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674"
integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==
"@babel/helper-globals@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.29.7.tgz#f04a96fbd8473241b1079243f5b3f03a3010ab7b"
integrity sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==
"@babel/helper-module-imports@^7.24.7":
version "7.24.7"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b"
integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==
"@babel/helper-module-imports@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz#ef25048a518e828d7393fac5882ddd73921d7396"
integrity sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==
dependencies:
"@babel/traverse" "^7.24.7"
"@babel/types" "^7.24.7"
"@babel/traverse" "^7.29.7"
"@babel/types" "^7.29.7"
"@babel/helper-module-imports@^7.28.6":
version "7.28.6"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c"
integrity sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==
"@babel/helper-module-transforms@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz#b062747a5997ba138637201328bbff77960574ae"
integrity sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==
dependencies:
"@babel/traverse" "^7.28.6"
"@babel/types" "^7.28.6"
"@babel/helper-module-transforms@^7.25.2":
version "7.25.2"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz#ee713c29768100f2776edf04d4eb23b8d27a66e6"
integrity sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==
dependencies:
"@babel/helper-module-imports" "^7.24.7"
"@babel/helper-simple-access" "^7.24.7"
"@babel/helper-validator-identifier" "^7.24.7"
"@babel/traverse" "^7.25.2"
"@babel/helper-module-transforms@^7.28.6":
version "7.28.6"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e"
integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==
dependencies:
"@babel/helper-module-imports" "^7.28.6"
"@babel/helper-validator-identifier" "^7.28.5"
"@babel/traverse" "^7.28.6"
"@babel/helper-module-imports" "^7.29.7"
"@babel/helper-validator-identifier" "^7.29.7"
"@babel/traverse" "^7.29.7"
"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.8.0":
version "7.24.8"
@@ -172,14 +119,6 @@
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz#6f13ea251b68c8532e985fd532f28741a8af9ac8"
integrity sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==
"@babel/helper-simple-access@^7.24.7":
version "7.24.7"
resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3"
integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==
dependencies:
"@babel/traverse" "^7.24.7"
"@babel/types" "^7.24.7"
"@babel/helper-string-parser@^7.24.8":
version "7.24.8"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d"
@@ -190,6 +129,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687"
integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==
"@babel/helper-string-parser@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz#7f0871d99824d23137d60f86fcf6130fd5a1b51f"
integrity sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==
"@babel/helper-validator-identifier@^7.24.7":
version "7.24.7"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db"
@@ -200,31 +144,23 @@
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4"
integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==
"@babel/helper-validator-option@^7.24.8":
version "7.24.8"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d"
integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==
"@babel/helper-validator-identifier@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz#bd87084ced0c796ec46bda492de6e83d29e89fc2"
integrity sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==
"@babel/helper-validator-option@^7.27.1":
version "7.27.1"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f"
integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==
"@babel/helper-validator-option@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz#cf315be940213b354eb4abcc0bd01ebe3f73bc2a"
integrity sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==
"@babel/helpers@^7.25.0":
version "7.25.0"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.0.tgz#e69beb7841cb93a6505531ede34f34e6a073650a"
integrity sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==
"@babel/helpers@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.29.7.tgz#45abfde7548997e34376c3e69feb475cffb4a607"
integrity sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==
dependencies:
"@babel/template" "^7.25.0"
"@babel/types" "^7.25.0"
"@babel/helpers@^7.28.6":
version "7.28.6"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.6.tgz#fca903a313ae675617936e8998b814c415cbf5d7"
integrity sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==
dependencies:
"@babel/template" "^7.28.6"
"@babel/types" "^7.28.6"
"@babel/template" "^7.29.7"
"@babel/types" "^7.29.7"
"@babel/highlight@^7.24.7":
version "7.24.7"
@@ -236,20 +172,27 @@
js-tokens "^4.0.0"
picocolors "^1.0.0"
"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.0", "@babel/parser@^7.25.3":
"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9":
version "7.25.3"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.3.tgz#91fb126768d944966263f0657ab222a642b82065"
integrity sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==
dependencies:
"@babel/types" "^7.25.2"
"@babel/parser@^7.28.6", "@babel/parser@^7.29.0":
"@babel/parser@^7.29.0":
version "7.29.0"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.0.tgz#669ef345add7d057e92b7ed15f0bac07611831b6"
integrity sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==
dependencies:
"@babel/types" "^7.29.0"
"@babel/parser@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.7.tgz#837b87387cbf5ec5530cb634b3c622f68edb9334"
integrity sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==
dependencies:
"@babel/types" "^7.29.7"
"@babel/plugin-syntax-async-generators@^7.8.4":
version "7.8.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
@@ -369,51 +312,29 @@
dependencies:
"@babel/helper-plugin-utils" "^7.28.6"
"@babel/template@^7.25.0":
version "7.25.0"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a"
integrity sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==
"@babel/template@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.29.7.tgz#4d9d4004f645cdd304de958c725162784ecac700"
integrity sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==
dependencies:
"@babel/code-frame" "^7.24.7"
"@babel/parser" "^7.25.0"
"@babel/types" "^7.25.0"
"@babel/code-frame" "^7.29.7"
"@babel/parser" "^7.29.7"
"@babel/types" "^7.29.7"
"@babel/template@^7.28.6":
version "7.28.6"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.28.6.tgz#0e7e56ecedb78aeef66ce7972b082fce76a23e57"
integrity sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==
"@babel/traverse@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.7.tgz#c47b07a41b95da0907d026b5dd894d98de7d2f2d"
integrity sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==
dependencies:
"@babel/code-frame" "^7.28.6"
"@babel/parser" "^7.28.6"
"@babel/types" "^7.28.6"
"@babel/traverse@^7.24.7", "@babel/traverse@^7.25.2":
version "7.25.3"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.3.tgz#f1b901951c83eda2f3e29450ce92743783373490"
integrity sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==
dependencies:
"@babel/code-frame" "^7.24.7"
"@babel/generator" "^7.25.0"
"@babel/parser" "^7.25.3"
"@babel/template" "^7.25.0"
"@babel/types" "^7.25.2"
debug "^4.3.1"
globals "^11.1.0"
"@babel/traverse@^7.28.6", "@babel/traverse@^7.29.0":
version "7.29.0"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.0.tgz#f323d05001440253eead3c9c858adbe00b90310a"
integrity sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==
dependencies:
"@babel/code-frame" "^7.29.0"
"@babel/generator" "^7.29.0"
"@babel/helper-globals" "^7.28.0"
"@babel/parser" "^7.29.0"
"@babel/template" "^7.28.6"
"@babel/types" "^7.29.0"
"@babel/code-frame" "^7.29.7"
"@babel/generator" "^7.29.7"
"@babel/helper-globals" "^7.29.7"
"@babel/parser" "^7.29.7"
"@babel/template" "^7.29.7"
"@babel/types" "^7.29.7"
debug "^4.3.1"
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2":
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.2":
version "7.25.2"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.2.tgz#55fb231f7dc958cd69ea141a4c2997e819646125"
integrity sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==
@@ -422,7 +343,7 @@
"@babel/helper-validator-identifier" "^7.24.7"
to-fast-properties "^2.0.0"
"@babel/types@^7.27.3", "@babel/types@^7.28.6", "@babel/types@^7.29.0":
"@babel/types@^7.27.3", "@babel/types@^7.29.0":
version "7.29.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.0.tgz#9f5b1e838c446e72cf3cd4b918152b8c605e37c7"
integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==
@@ -430,6 +351,14 @@
"@babel/helper-string-parser" "^7.27.1"
"@babel/helper-validator-identifier" "^7.28.5"
"@babel/types@^7.29.7":
version "7.29.7"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.7.tgz#8005e31d82712ee7adaef6e23c63b71a62770a92"
integrity sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==
dependencies:
"@babel/helper-string-parser" "^7.29.7"
"@babel/helper-validator-identifier" "^7.29.7"
"@bcoe/v8-coverage@^0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
@@ -1614,16 +1543,6 @@ braces@^3.0.3:
dependencies:
fill-range "^7.1.1"
browserslist@^4.23.1:
version "4.23.3"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800"
integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==
dependencies:
caniuse-lite "^1.0.30001646"
electron-to-chromium "^1.5.4"
node-releases "^2.0.18"
update-browserslist-db "^1.1.0"
browserslist@^4.24.0:
version "4.28.1"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.1.tgz#7f534594628c53c63101079e27e40de490456a95"
@@ -1706,11 +1625,6 @@ camelcase@^6.3.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
caniuse-lite@^1.0.30001646:
version "1.0.30001651"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz#52de59529e8b02b1aedcaaf5c05d9e23c0c28138"
integrity sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==
caniuse-lite@^1.0.30001759:
version "1.0.30001769"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz#1ad91594fad7dc233777c2781879ab5409f7d9c2"
@@ -1947,11 +1861,6 @@ electron-to-chromium@^1.5.263:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz#142be1ab5e1cd5044954db0e5898f60a4960384e"
integrity sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==
electron-to-chromium@^1.5.4:
version "1.5.12"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.12.tgz#ee31756eaa2e06f2aa606f170b7ad06dd402b4e4"
integrity sha512-tIhPkdlEoCL1Y+PToq3zRNehUaKp3wBX/sr7aclAWdIWjvqAe/Im/H0SiCM4c1Q8BLPHCdoJTol+ZblflydehA==
emittery@^0.13.1:
version "0.13.1"
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad"
@@ -2168,7 +2077,7 @@ es-to-primitive@^1.3.0:
is-date-object "^1.0.5"
is-symbol "^1.0.4"
escalade@^3.1.1, escalade@^3.1.2:
escalade@^3.1.1:
version "3.1.2"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
@@ -2662,11 +2571,6 @@ glob@^7.1.4:
once "^1.3.0"
path-is-absolute "^1.0.0"
globals@^11.1.0:
version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
globals@^14.0.0:
version "14.0.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e"
@@ -3646,11 +3550,6 @@ js-yaml@^4.1.1:
dependencies:
argparse "^2.0.1"
jsesc@^2.5.1:
version "2.5.2"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
jsesc@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d"
@@ -3854,11 +3753,6 @@ node-int64@^0.4.0:
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==
node-releases@^2.0.18:
version "2.0.18"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f"
integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==
node-releases@^2.0.27:
version "2.0.27"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.27.tgz#eedca519205cf20f650f61d56b070db111231e4e"
@@ -4100,7 +3994,7 @@ path-scurry@^1.11.1:
lru-cache "^10.2.0"
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
picocolors@^1.0.0, picocolors@^1.0.1:
picocolors@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1"
integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==
@@ -4856,14 +4750,6 @@ unrs-resolver@^1.7.11:
"@unrs/resolver-binding-win32-ia32-msvc" "1.11.1"
"@unrs/resolver-binding-win32-x64-msvc" "1.11.1"
update-browserslist-db@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e"
integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==
dependencies:
escalade "^3.1.2"
picocolors "^1.0.1"
update-browserslist-db@^1.2.0:
version "1.2.3"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz#64d76db58713136acbeb4c49114366cc6cc2e80d"
+3 -3
View File
@@ -1280,9 +1280,9 @@ js-tiktoken@^1.0.12:
base64-js "^1.5.1"
js-yaml@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b"
integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==
version "4.2.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.2.0.tgz#2bd9e85682dd91bd469afb809d816043b3d49524"
integrity sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==
dependencies:
argparse "^2.0.1"
+1 -1
View File
@@ -1 +1 @@
__version__ = "0.4.29"
__version__ = "0.4.30"
+8 -1
View File
@@ -159,7 +159,14 @@ OPT_POSTGRES_URI = click.option(
OPT_API_VERSION = click.option(
"--api-version",
type=str,
help="API server version to use for the base image. If unspecified, the latest version will be used.",
help=(
"API server version to use for the base image. If unspecified, the "
"latest stable version will be used. Compatible ranges like "
"~=0.11.0.dev5 stay on 0.11.0.dev5 while only newer dev builds exist, "
"then resolve to the newest matching rc or stable release, for example "
"0.11.0rc1 or 0.11.0. Stable-floating ranges like >~=0.11.0.dev5 "
"can also pick up future stable releases, for example 0.12.0."
),
)
OPT_ENGINE_RUNTIME_MODE = click.option(
+162 -1
View File
@@ -9,6 +9,7 @@ from collections import Counter
from typing import Literal, NamedTuple
import click
import httpx
from langgraph_cli.schemas import Config, Distros
from langgraph_cli.uv_lock import python_config_to_docker_uv_lock
@@ -41,6 +42,31 @@ _API_VERSION_PATTERN = re.compile(
r"(?:\.(?P<patch>\d+))?"
r"(?:(?:\.|)(?:[A-Za-z][0-9A-Za-z]*))?$"
)
_API_VERSION_RANGE_PATTERN = re.compile(r"^(?P<operator>~=|>~=)\s*(?P<version>.+)$")
_API_VERSION_PART_PATTERN = re.compile(
r"^(?P<major>\d+)"
r"(?:\.(?P<minor>\d+))?"
r"(?:\.(?P<patch>\d+))?"
r"(?:(?:\.|)(?P<pre>dev|rc)(?P<pre_n>\d+))?$"
)
class _ParsedApiVersion(NamedTuple):
release: tuple[int, ...]
prerelease: str | None
prerelease_number: int
class _ApiVersionRange(NamedTuple):
floor: _ParsedApiVersion
allow_future_stable: bool
_PRERELEASE_ORDER = {
"dev": 0,
"rc": 1,
None: 2,
}
def has_disallowed_build_command_content(command: str) -> bool:
@@ -141,6 +167,133 @@ def _parse_api_version_parts(version_str: str) -> tuple[int, ...]:
return tuple(int(part) for part in match.groups() if part is not None)
def _parse_api_version(version_str: str) -> _ParsedApiVersion:
match = _API_VERSION_PART_PATTERN.fullmatch(version_str)
if not match:
raise ValueError("Version must be major or major.minor or major.minor.patch.")
release = tuple(
int(part)
for part in (
match.group("major"),
match.group("minor"),
match.group("patch"),
)
if part is not None
)
prerelease = match.group("pre")
prerelease_number = int(match.group("pre_n") or 0)
return _ParsedApiVersion(release, prerelease, prerelease_number)
def _api_version_sort_key(
version: _ParsedApiVersion,
) -> tuple[tuple[int, ...], int, int]:
return (
version.release,
_PRERELEASE_ORDER[version.prerelease],
version.prerelease_number,
)
def _api_version_upper_bound(version: _ParsedApiVersion) -> tuple[int, ...]:
release = version.release
if len(release) <= 2:
return (release[0] + 1,)
return (release[0], release[1] + 1)
def _is_compatible_api_version_candidate(
candidate: _ParsedApiVersion,
version_range: _ApiVersionRange,
upper_bound: tuple[int, ...],
) -> bool:
floor = version_range.floor
if _api_version_sort_key(candidate) < _api_version_sort_key(floor):
return False
outside_compatible_range = candidate.release[: len(upper_bound)] >= upper_bound
if outside_compatible_range and not version_range.allow_future_stable:
return False
if outside_compatible_range and candidate.prerelease is not None:
return False
if floor.prerelease == "dev" and candidate.prerelease == "dev":
return candidate == floor
return True
def _ensure_compatible_api_version_base_image(base_image: str) -> None:
if ":" in base_image:
raise click.UsageError(
"Compatible api_version ranges cannot be used with a tagged base_image."
)
def _get_pypi_versions(package_name: str) -> list[str]:
try:
response = httpx.get(
f"https://pypi.org/pypi/{package_name}/json",
timeout=10,
)
response.raise_for_status()
except httpx.HTTPError as exc:
raise click.UsageError(
f"Failed to fetch PyPI versions for {package_name}: {exc}"
) from None
payload = response.json()
releases = payload.get("releases", {})
if not isinstance(releases, dict):
raise click.UsageError(
f"Failed to fetch PyPI versions for {package_name}: invalid response."
)
return [version for version in releases if isinstance(version, str)]
def _resolve_compatible_api_version(
api_version: str,
base_image: str,
version_distro_tag: str,
) -> str:
match = _API_VERSION_RANGE_PATTERN.fullmatch(api_version)
if not match:
return api_version
floor_str = match.group("version").strip()
try:
floor = _parse_api_version(floor_str)
except ValueError:
raise click.UsageError(
f"Invalid compatible api_version range: {api_version}.\n\n"
"Use a compatible version range, e.g.:\n"
' "api_version": "~=0.11.0.dev5"\n'
"or a stable-floating range, e.g.:\n"
' "api_version": ">~=0.11.0.dev5"'
) from None
version_range = _ApiVersionRange(
floor=floor,
allow_future_stable=match.group("operator") == ">~=",
)
_ensure_compatible_api_version_base_image(base_image)
pypi_versions = _get_pypi_versions("langgraph-api")
candidates: list[tuple[_ParsedApiVersion, str]] = []
upper_bound = _api_version_upper_bound(floor)
for candidate_str in pypi_versions:
try:
candidate = _parse_api_version(candidate_str)
except ValueError:
continue
if _is_compatible_api_version_candidate(candidate, version_range, upper_bound):
candidates.append((candidate, candidate_str))
if not candidates:
raise click.UsageError(
f"No PyPI releases match compatible api_version range {api_version!r} "
f"for {base_image} with {version_distro_tag!r}."
)
return max(candidates, key=lambda item: _api_version_sort_key(item[0]))[1]
def _is_node_graph(spec: str | dict) -> bool:
"""Check if a graph is a Node.js graph based on the file extension."""
if isinstance(spec, dict):
@@ -194,7 +347,12 @@ def validate_config(config: Config) -> Config:
)
if api_version:
try:
parts = _parse_api_version_parts(api_version)
compatible_match = _API_VERSION_RANGE_PATTERN.fullmatch(api_version)
parts = _parse_api_version_parts(
compatible_match.group("version").strip()
if compatible_match
else api_version
)
if len(parts) > 3:
raise ValueError(
"Version must be major or major.minor or major.minor.patch."
@@ -1430,6 +1588,9 @@ def docker_tag(
# Prepend API version if provided
if api_version:
api_version = _resolve_compatible_api_version(
api_version, base_image, f"{language}{version_distro_tag}"
)
full_tag = f"{api_version}-{language}{version_distro_tag}"
elif "/langgraph-server" in base_image and version_distro_tag not in base_image:
return f"{base_image}-{language}{version_distro_tag}"
+108 -45
View File
@@ -366,6 +366,42 @@ def normalize_image_tag(value: str) -> str:
return value
def _validate_prebuilt_image(runner, image: str, *, verbose: bool) -> None:
"""Ensure a prebuilt image exists locally for linux/amd64."""
try:
stdout, _ = runner.run(
subp_exec(
"docker",
"image",
"inspect",
"--format",
"{{.Os}}/{{.Architecture}}",
image,
verbose=verbose,
collect=True,
)
)
except FileNotFoundError:
raise click.ClickException(
"Docker is required but not installed.\n"
"Install Docker Desktop: https://docs.docker.com/get-docker/"
) from None
except click.exceptions.Exit:
raise click.ClickException(
f"Docker image '{image}' was not found locally. Build or pull the image "
"before deploying with --image."
) from None
image_platform = (stdout or "").strip()
if image_platform != "linux/amd64":
detected = image_platform or "unknown"
raise click.ClickException(
f"Docker image '{image}' targets {detected}, but LangSmith Deployment "
"requires linux/amd64. Rebuild or pull the image for linux/amd64 before "
"deploying with --image."
)
def _extract_deployment_url(deployment: dict[str, object]) -> str:
source_config = deployment.get("source_config")
if isinstance(source_config, dict):
@@ -525,12 +561,18 @@ def _secrets_from_env(
def _resolve_build_mode(
remote_build_flag: bool | None,
*,
force_local: bool = False,
) -> tuple[bool, str | None]:
"""Determine whether to use a remote build.
Returns (use_remote_build, local_build_error). Raises UsageError when
--no-remote is set but the machine cannot build locally.
--no-remote is set but the machine cannot build locally. When
`force_local` is set, the function short-circuits and always selects a
local build.
"""
if force_local:
return False, None
local_build_supported, local_build_error = can_build_locally()
if remote_build_flag is True:
@@ -897,6 +939,7 @@ def _run_local_build(
api_version: str | None,
base_image: str | None,
image_name: str | None,
prebuilt_image: str | None,
name: str | None,
tag: str,
install_command: str | None,
@@ -910,51 +953,57 @@ def _run_local_build(
# (e.g. Apple Silicon). On amd64 hosts, plain docker build is sufficient.
needs_buildx = platform.machine() != "x86_64"
local_tag = f"langgraph-deploy-tmp:{int(time.time())}"
image_to_push = prebuilt_image or local_tag
with Runner() as runner:
# -- Step: Build image --
_log_deploy_step(step, "Building image")
if needs_buildx:
build_flags: list[str] = [
"--platform",
"linux/amd64",
"--load",
]
if not verbose:
build_flags.append("--progress=quiet")
with Progress(message="Building...", elapsed=not verbose):
build_docker_image(
runner,
lambda _msg: None,
config,
config_json,
base_image,
api_version,
pull,
local_tag,
docker_build_args,
install_command,
build_command,
docker_command=("docker", "buildx", "build"),
extra_flags=build_flags,
verbose=verbose,
)
if prebuilt_image:
_log_deploy_step(step, f"Validating image {prebuilt_image}")
_validate_prebuilt_image(runner, prebuilt_image, verbose=verbose)
click.secho(" Image is available for linux/amd64", fg="green")
else:
with Progress(message="Building...", elapsed=not verbose):
build_docker_image(
runner,
lambda _msg: None,
config,
config_json,
base_image,
api_version,
pull,
local_tag,
docker_build_args,
install_command,
build_command,
verbose=verbose,
)
# -- Step: Build image --
_log_deploy_step(step, "Building image")
if needs_buildx:
build_flags: list[str] = [
"--platform",
"linux/amd64",
"--load",
]
if not verbose:
build_flags.append("--progress=quiet")
with Progress(message="Building...", elapsed=not verbose):
build_docker_image(
runner,
lambda _msg: None,
config,
config_json,
base_image,
api_version,
pull,
local_tag,
docker_build_args,
install_command,
build_command,
docker_command=("docker", "buildx", "build"),
extra_flags=build_flags,
verbose=verbose,
)
else:
with Progress(message="Building...", elapsed=not verbose):
build_docker_image(
runner,
lambda _msg: None,
config,
config_json,
base_image,
api_version,
pull,
local_tag,
docker_build_args,
install_command,
build_command,
verbose=verbose,
)
step += 1
# -- Step: Get push token and authenticate --
@@ -1023,7 +1072,7 @@ def _run_local_build(
subp_exec(
"docker",
"tag",
local_tag,
image_to_push,
remote_image,
verbose=verbose,
)
@@ -1423,6 +1472,13 @@ def _deploy_base_options(
show_default=True,
help="Tag to use for the pushed deployment image.",
),
click.option(
"--image",
help=(
"Use an existing local image reference (e.g. repo:tag) and "
"skip building. The image must target linux/amd64."
),
),
click.option(
"--config",
"-c",
@@ -1523,6 +1579,7 @@ def _deploy_cmd(
deployment_type: str,
name: str | None,
image_name: str | None,
image: str | None,
tag: str,
base_image: str | None,
install_command: str | None,
@@ -1569,7 +1626,12 @@ def _deploy_cmd(
secrets = _secrets_from_env(_env_without_deployment_name(env_vars))
use_remote_build, local_build_error = _resolve_build_mode(remote_build_flag)
if image and remote_build_flag is True:
raise click.UsageError("--image cannot be combined with --remote builds.")
use_remote_build, local_build_error = _resolve_build_mode(
remote_build_flag, force_local=image is not None
)
if use_remote_build and remote_build_flag is None and local_build_error:
em.note(f"{local_build_error}\nUsing remote build instead.")
if not json_output:
@@ -1639,6 +1701,7 @@ def _deploy_cmd(
api_version=api_version,
base_image=base_image,
image_name=image_name,
prebuilt_image=image,
name=name,
tag=tag,
install_command=install_command,
+1 -1
View File
@@ -23,7 +23,7 @@ dependencies = [
path = "langgraph_cli/__init__.py"
[project.optional-dependencies]
inmem = [
"langgraph-api>=0.5.35,<0.12.0a0 ; python_version >= '3.11'",
"langgraph-api>=0.5.35,<0.12.0 ; python_version >= '3.11'",
"langgraph-runtime-inmem>=0.7 ; python_version >= '3.11'",
]
+157
View File
@@ -2961,6 +2961,163 @@ def test_docker_tag_with_prerelease_api_version(version: str, in_config: bool):
assert tag == f"langchain/langgraph-api:{version}-py3.11"
def test_docker_tag_with_compatible_api_version_promotes_to_latest_patch():
config = validate_config(
{
"python_version": "3.12",
"dependencies": ["."],
"graphs": {"agent": "./agent.py:graph"},
"image_distro": "wolfi",
"api_version": "~=0.11.0.dev5",
}
)
with patch(
"langgraph_cli.config._get_pypi_versions",
return_value=[
"0.11.0.dev5",
"0.11.0.dev6",
"0.11.0rc1",
"0.11.0",
"0.11.1rc1",
"0.11.1",
"0.12.0rc1",
],
) as get_versions:
tag = docker_tag(config)
get_versions.assert_called_once_with("langgraph-api")
assert tag == "langchain/langgraph-api:0.11.1-py3.12-wolfi"
def test_docker_tag_with_compatible_api_version_freezes_dev_until_rc():
config = validate_config(
{
"python_version": "3.12",
"dependencies": ["."],
"graphs": {"agent": "./agent.py:graph"},
"api_version": "~=0.11.0.dev5",
}
)
with patch(
"langgraph_cli.config._get_pypi_versions",
return_value=[
"0.11.0.dev5",
"0.11.0.dev6",
"0.11.0.dev7",
],
):
tag = docker_tag(config)
assert tag == "langchain/langgraph-api:0.11.0.dev5-py3.12"
def test_docker_tag_with_stable_floating_api_version_promotes_to_future_stable():
config = validate_config(
{
"python_version": "3.12",
"dependencies": ["."],
"graphs": {"agent": "./agent.py:graph"},
"image_distro": "wolfi",
"api_version": ">~=0.11.0.dev5",
}
)
with patch(
"langgraph_cli.config._get_pypi_versions",
return_value=[
"0.11.0.dev5",
"0.11.0.dev6",
"0.11.0rc1",
"0.11.0",
"0.11.1",
"0.12.0rc1",
"0.12.0",
"0.13.0.dev1",
"0.13.0",
],
) as get_versions:
tag = docker_tag(config)
get_versions.assert_called_once_with("langgraph-api")
assert tag == "langchain/langgraph-api:0.13.0-py3.12-wolfi"
def test_docker_tag_with_stable_floating_api_version_ignores_future_prereleases():
config = validate_config(
{
"python_version": "3.12",
"dependencies": ["."],
"graphs": {"agent": "./agent.py:graph"},
"api_version": ">~=0.11.0.dev5",
}
)
with patch(
"langgraph_cli.config._get_pypi_versions",
return_value=[
"0.11.0.dev5",
"0.11.0",
"0.12.0rc1",
"0.12.0.dev1",
],
):
tag = docker_tag(config)
assert tag == "langchain/langgraph-api:0.11.0-py3.12"
def test_validate_config_rejects_unrecognized_api_version_range_operator():
with pytest.raises(click.UsageError, match="Invalid version format"):
validate_config(
{
"python_version": "3.12",
"dependencies": ["."],
"graphs": {"agent": "./agent.py:graph"},
"api_version": "~>=0.11.0.dev5",
}
)
def test_docker_tag_with_compatible_api_version_supports_node_images():
config = validate_config(
{
"node_version": "20",
"graphs": {"agent": "./agent.js:graph"},
"image_distro": "wolfi",
"api_version": "~=1.2.4",
}
)
with patch(
"langgraph_cli.config._get_pypi_versions",
return_value=[
"1.2.4",
"1.2.5",
"1.3.0",
],
) as get_versions:
tag = docker_tag(config)
get_versions.assert_called_once_with("langgraph-api")
assert tag == "langchain/langgraphjs-api:1.2.5-node20-wolfi"
def test_docker_tag_with_compatible_api_version_rejects_tagged_base_image():
config = validate_config(
{
"python_version": "3.11",
"dependencies": ["."],
"graphs": {"agent": "./agent.py:graph"},
"api_version": "~=0.11.0.dev5",
}
)
with pytest.raises(click.UsageError, match="tagged base_image"):
docker_tag(config, base_image="langchain/langgraph-api:0.11.0")
def test_config_to_docker_with_api_version():
"""Test config_to_docker function with api_version parameter."""
@@ -1,3 +1,4 @@
import asyncio
import base64
import io
import json
@@ -6,9 +7,11 @@ import sys
from unittest.mock import MagicMock
import click
import click.exceptions
import httpx
import pytest
import langgraph_cli.deploy as deploy_mod
from langgraph_cli.deploy import (
_call_host_backend_with_optional_tenant,
_create_host_backend_client,
@@ -19,6 +22,7 @@ from langgraph_cli.deploy import (
_resolve_env_path,
_resolve_pushed_image_digest,
_smith_dashboard_base_url,
_validate_prebuilt_image,
normalize_image_tag,
normalize_name,
)
@@ -95,6 +99,65 @@ class TestNormalizeImageTag:
normalize_image_tag("has space")
class _FakeRunner:
def run(self, coro):
return asyncio.run(coro)
class TestValidatePrebuiltImage:
def test_accepts_linux_amd64(self, monkeypatch):
calls = []
async def fake_subp_exec(*args, **kwargs):
calls.append((args, kwargs))
return "linux/amd64\n", None
monkeypatch.setattr(deploy_mod, "subp_exec", fake_subp_exec)
_validate_prebuilt_image(_FakeRunner(), "repo/app:tag", verbose=False)
assert calls == [
(
(
"docker",
"image",
"inspect",
"--format",
"{{.Os}}/{{.Architecture}}",
"repo/app:tag",
),
{"verbose": False, "collect": True},
)
]
def test_missing_docker_binary_raises_actionable_error(self, monkeypatch):
async def fake_subp_exec(*args, **kwargs):
raise FileNotFoundError("docker")
monkeypatch.setattr(deploy_mod, "subp_exec", fake_subp_exec)
with pytest.raises(click.ClickException, match="Docker is required"):
_validate_prebuilt_image(_FakeRunner(), "repo/app:tag", verbose=False)
def test_missing_image_raises_actionable_error(self, monkeypatch):
async def fake_subp_exec(*args, **kwargs):
raise click.exceptions.Exit(1)
monkeypatch.setattr(deploy_mod, "subp_exec", fake_subp_exec)
with pytest.raises(click.ClickException, match="not found locally"):
_validate_prebuilt_image(_FakeRunner(), "missing:tag", verbose=False)
def test_rejects_non_amd64_platform(self, monkeypatch):
async def fake_subp_exec(*args, **kwargs):
return "linux/arm64\n", None
monkeypatch.setattr(deploy_mod, "subp_exec", fake_subp_exec)
with pytest.raises(click.ClickException, match="requires linux/amd64"):
_validate_prebuilt_image(_FakeRunner(), "repo/app:arm", verbose=False)
class TestParseEnvFromConfig:
def test_env_dict(self, tmp_path):
config_path = tmp_path / "langgraph.json"
+3 -3
View File
@@ -237,14 +237,14 @@ wheels = [
[[package]]
name = "langchain-protocol"
version = "0.0.15"
version = "0.0.17"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/4f/24/9777489d6fbbee64af0c8f96d4f840239c408cf694f3394672807dafc490/langchain_protocol-0.0.15.tar.gz", hash = "sha256:9ab2d11ee73944754f10e037e717098d3a6796f0e58afa9cadda6154e7655ade", size = 5862, upload-time = "2026-05-01T22:30:04.748Z" }
sdist = { url = "https://files.pythonhosted.org/packages/44/b3/4e2429876c7a35585618caa2b9f9089f7162a6b50562b614ad82ac11c17e/langchain_protocol-0.0.17.tar.gz", hash = "sha256:e7cbe58c205df4b4fd87dc6d5bb23f10e13b236d0e2e1b0b9d05bc2b648f3eea", size = 6026, upload-time = "2026-06-12T18:39:51.923Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1d/7a/9c97a7b9cbe4c5dc6a44cdb1545450c28f0c8ce89b9c1f0ee7fbad896263/langchain_protocol-0.0.15-py3-none-any.whl", hash = "sha256:461eb794358f83d5e42635a5797799ffec7b4702314e34edf73ac21e75d3ef79", size = 6982, upload-time = "2026-05-01T22:30:03.877Z" },
{ url = "https://files.pythonhosted.org/packages/13/0a/a1bfe72c6ec856e99773bbd96c8086421e554b3693d0142b9ea009c6ac92/langchain_protocol-0.0.17-py3-none-any.whl", hash = "sha256:982a08fe152586ed10d4ff3d538c2e0b5766e5f307cdea325e10be3f2c17cae6", size = 7096, upload-time = "2026-06-12T18:39:50.973Z" },
]
[[package]]
+3 -3
View File
@@ -211,14 +211,14 @@ wheels = [
[[package]]
name = "langchain-protocol"
version = "0.0.15"
version = "0.0.17"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/4f/24/9777489d6fbbee64af0c8f96d4f840239c408cf694f3394672807dafc490/langchain_protocol-0.0.15.tar.gz", hash = "sha256:9ab2d11ee73944754f10e037e717098d3a6796f0e58afa9cadda6154e7655ade", size = 5862, upload-time = "2026-05-01T22:30:04.748Z" }
sdist = { url = "https://files.pythonhosted.org/packages/44/b3/4e2429876c7a35585618caa2b9f9089f7162a6b50562b614ad82ac11c17e/langchain_protocol-0.0.17.tar.gz", hash = "sha256:e7cbe58c205df4b4fd87dc6d5bb23f10e13b236d0e2e1b0b9d05bc2b648f3eea", size = 6026, upload-time = "2026-06-12T18:39:51.923Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1d/7a/9c97a7b9cbe4c5dc6a44cdb1545450c28f0c8ce89b9c1f0ee7fbad896263/langchain_protocol-0.0.15-py3-none-any.whl", hash = "sha256:461eb794358f83d5e42635a5797799ffec7b4702314e34edf73ac21e75d3ef79", size = 6982, upload-time = "2026-05-01T22:30:03.877Z" },
{ url = "https://files.pythonhosted.org/packages/13/0a/a1bfe72c6ec856e99773bbd96c8086421e554b3693d0142b9ea009c6ac92/langchain_protocol-0.0.17-py3-none-any.whl", hash = "sha256:982a08fe152586ed10d4ff3d538c2e0b5766e5f307cdea325e10be3f2c17cae6", size = 7096, upload-time = "2026-06-12T18:39:50.973Z" },
]
[[package]]
+179 -176
View File
@@ -414,62 +414,62 @@ wheels = [
[[package]]
name = "cryptography"
version = "46.0.7"
version = "48.0.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/47/93/ac8f3d5ff04d54bc814e961a43ae5b0b146154c89c61b47bb07557679b18/cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5", size = 750652, upload-time = "2026-04-08T01:57:54.692Z" }
sdist = { url = "https://files.pythonhosted.org/packages/12/45/870e7f4bef50e5f53b9f51d4428aee5290eedf58ba443f16b1ebb7ab8e66/cryptography-48.0.1.tar.gz", hash = "sha256:266f4ee051abb2f725b74ef8072b521ce1feacf685a3364fa6a6b45548db791a", size = 832989, upload-time = "2026-06-09T22:32:31.8Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0b/5d/4a8f770695d73be252331e60e526291e3df0c9b27556a90a6b47bccca4c2/cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4", size = 7179869, upload-time = "2026-04-08T01:56:17.157Z" },
{ url = "https://files.pythonhosted.org/packages/5f/45/6d80dc379b0bbc1f9d1e429f42e4cb9e1d319c7a8201beffd967c516ea01/cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325", size = 4275492, upload-time = "2026-04-08T01:56:19.36Z" },
{ url = "https://files.pythonhosted.org/packages/4a/9a/1765afe9f572e239c3469f2cb429f3ba7b31878c893b246b4b2994ffe2fe/cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308", size = 4426670, upload-time = "2026-04-08T01:56:21.415Z" },
{ url = "https://files.pythonhosted.org/packages/8f/3e/af9246aaf23cd4ee060699adab1e47ced3f5f7e7a8ffdd339f817b446462/cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77", size = 4280275, upload-time = "2026-04-08T01:56:23.539Z" },
{ url = "https://files.pythonhosted.org/packages/0f/54/6bbbfc5efe86f9d71041827b793c24811a017c6ac0fd12883e4caa86b8ed/cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1", size = 4928402, upload-time = "2026-04-08T01:56:25.624Z" },
{ url = "https://files.pythonhosted.org/packages/2d/cf/054b9d8220f81509939599c8bdbc0c408dbd2bdd41688616a20731371fe0/cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef", size = 4459985, upload-time = "2026-04-08T01:56:27.309Z" },
{ url = "https://files.pythonhosted.org/packages/f9/46/4e4e9c6040fb01c7467d47217d2f882daddeb8828f7df800cb806d8a2288/cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de", size = 3990652, upload-time = "2026-04-08T01:56:29.095Z" },
{ url = "https://files.pythonhosted.org/packages/36/5f/313586c3be5a2fbe87e4c9a254207b860155a8e1f3cca99f9910008e7d08/cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83", size = 4279805, upload-time = "2026-04-08T01:56:30.928Z" },
{ url = "https://files.pythonhosted.org/packages/69/33/60dfc4595f334a2082749673386a4d05e4f0cf4df8248e63b2c3437585f2/cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb", size = 4892883, upload-time = "2026-04-08T01:56:32.614Z" },
{ url = "https://files.pythonhosted.org/packages/c7/0b/333ddab4270c4f5b972f980adef4faa66951a4aaf646ca067af597f15563/cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b", size = 4459756, upload-time = "2026-04-08T01:56:34.306Z" },
{ url = "https://files.pythonhosted.org/packages/d2/14/633913398b43b75f1234834170947957c6b623d1701ffc7a9600da907e89/cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85", size = 4410244, upload-time = "2026-04-08T01:56:35.977Z" },
{ url = "https://files.pythonhosted.org/packages/10/f2/19ceb3b3dc14009373432af0c13f46aa08e3ce334ec6eff13492e1812ccd/cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e", size = 4674868, upload-time = "2026-04-08T01:56:38.034Z" },
{ url = "https://files.pythonhosted.org/packages/1a/bb/a5c213c19ee94b15dfccc48f363738633a493812687f5567addbcbba9f6f/cryptography-46.0.7-cp311-abi3-win32.whl", hash = "sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457", size = 3026504, upload-time = "2026-04-08T01:56:39.666Z" },
{ url = "https://files.pythonhosted.org/packages/2b/02/7788f9fefa1d060ca68717c3901ae7fffa21ee087a90b7f23c7a603c32ae/cryptography-46.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b", size = 3488363, upload-time = "2026-04-08T01:56:41.893Z" },
{ url = "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:d151173275e1728cf7839aaa80c34fe550c04ddb27b34f48c232193df8db5842", size = 7119671, upload-time = "2026-04-08T01:56:44Z" },
{ url = "https://files.pythonhosted.org/packages/74/66/e3ce040721b0b5599e175ba91ab08884c75928fbeb74597dd10ef13505d2/cryptography-46.0.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:db0f493b9181c7820c8134437eb8b0b4792085d37dbb24da050476ccb664e59c", size = 4268551, upload-time = "2026-04-08T01:56:46.071Z" },
{ url = "https://files.pythonhosted.org/packages/03/11/5e395f961d6868269835dee1bafec6a1ac176505a167f68b7d8818431068/cryptography-46.0.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ebd6daf519b9f189f85c479427bbd6e9c9037862cf8fe89ee35503bd209ed902", size = 4408887, upload-time = "2026-04-08T01:56:47.718Z" },
{ url = "https://files.pythonhosted.org/packages/40/53/8ed1cf4c3b9c8e611e7122fb56f1c32d09e1fff0f1d77e78d9ff7c82653e/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:b7b412817be92117ec5ed95f880defe9cf18a832e8cafacf0a22337dc1981b4d", size = 4271354, upload-time = "2026-04-08T01:56:49.312Z" },
{ url = "https://files.pythonhosted.org/packages/50/46/cf71e26025c2e767c5609162c866a78e8a2915bbcfa408b7ca495c6140c4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:fbfd0e5f273877695cb93baf14b185f4878128b250cc9f8e617ea0c025dfb022", size = 4905845, upload-time = "2026-04-08T01:56:50.916Z" },
{ url = "https://files.pythonhosted.org/packages/c0/ea/01276740375bac6249d0a971ebdf6b4dc9ead0ee0a34ef3b5a88c1a9b0d4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:ffca7aa1d00cf7d6469b988c581598f2259e46215e0140af408966a24cf086ce", size = 4444641, upload-time = "2026-04-08T01:56:52.882Z" },
{ url = "https://files.pythonhosted.org/packages/3d/4c/7d258f169ae71230f25d9f3d06caabcff8c3baf0978e2b7d65e0acac3827/cryptography-46.0.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:60627cf07e0d9274338521205899337c5d18249db56865f943cbe753aa96f40f", size = 3967749, upload-time = "2026-04-08T01:56:54.597Z" },
{ url = "https://files.pythonhosted.org/packages/b5/2a/2ea0767cad19e71b3530e4cad9605d0b5e338b6a1e72c37c9c1ceb86c333/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:80406c3065e2c55d7f49a9550fe0c49b3f12e5bfff5dedb727e319e1afb9bf99", size = 4270942, upload-time = "2026-04-08T01:56:56.416Z" },
{ url = "https://files.pythonhosted.org/packages/41/3d/fe14df95a83319af25717677e956567a105bb6ab25641acaa093db79975d/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:c5b1ccd1239f48b7151a65bc6dd54bcfcc15e028c8ac126d3fada09db0e07ef1", size = 4871079, upload-time = "2026-04-08T01:56:58.31Z" },
{ url = "https://files.pythonhosted.org/packages/9c/59/4a479e0f36f8f378d397f4eab4c850b4ffb79a2f0d58704b8fa0703ddc11/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:d5f7520159cd9c2154eb61eb67548ca05c5774d39e9c2c4339fd793fe7d097b2", size = 4443999, upload-time = "2026-04-08T01:57:00.508Z" },
{ url = "https://files.pythonhosted.org/packages/28/17/b59a741645822ec6d04732b43c5d35e4ef58be7bfa84a81e5ae6f05a1d33/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fcd8eac50d9138c1d7fc53a653ba60a2bee81a505f9f8850b6b2888555a45d0e", size = 4399191, upload-time = "2026-04-08T01:57:02.654Z" },
{ url = "https://files.pythonhosted.org/packages/59/6a/bb2e166d6d0e0955f1e9ff70f10ec4b2824c9cfcdb4da772c7dd69cc7d80/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:65814c60f8cc400c63131584e3e1fad01235edba2614b61fbfbfa954082db0ee", size = 4655782, upload-time = "2026-04-08T01:57:04.592Z" },
{ url = "https://files.pythonhosted.org/packages/95/b6/3da51d48415bcb63b00dc17c2eff3a651b7c4fed484308d0f19b30e8cb2c/cryptography-46.0.7-cp314-cp314t-win32.whl", hash = "sha256:fdd1736fed309b4300346f88f74cd120c27c56852c3838cab416e7a166f67298", size = 3002227, upload-time = "2026-04-08T01:57:06.91Z" },
{ url = "https://files.pythonhosted.org/packages/32/a8/9f0e4ed57ec9cebe506e58db11ae472972ecb0c659e4d52bbaee80ca340a/cryptography-46.0.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e06acf3c99be55aa3b516397fe42f5855597f430add9c17fa46bf2e0fb34c9bb", size = 3475332, upload-time = "2026-04-08T01:57:08.807Z" },
{ url = "https://files.pythonhosted.org/packages/a7/7f/cd42fc3614386bc0c12f0cb3c4ae1fc2bbca5c9662dfed031514911d513d/cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4", size = 7165618, upload-time = "2026-04-08T01:57:10.645Z" },
{ url = "https://files.pythonhosted.org/packages/a5/d0/36a49f0262d2319139d2829f773f1b97ef8aef7f97e6e5bd21455e5a8fb5/cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7", size = 4270628, upload-time = "2026-04-08T01:57:12.885Z" },
{ url = "https://files.pythonhosted.org/packages/8a/6c/1a42450f464dda6ffbe578a911f773e54dd48c10f9895a23a7e88b3e7db5/cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832", size = 4415405, upload-time = "2026-04-08T01:57:14.923Z" },
{ url = "https://files.pythonhosted.org/packages/9a/92/4ed714dbe93a066dc1f4b4581a464d2d7dbec9046f7c8b7016f5286329e2/cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163", size = 4272715, upload-time = "2026-04-08T01:57:16.638Z" },
{ url = "https://files.pythonhosted.org/packages/b7/e6/a26b84096eddd51494bba19111f8fffe976f6a09f132706f8f1bf03f51f7/cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2", size = 4918400, upload-time = "2026-04-08T01:57:19.021Z" },
{ url = "https://files.pythonhosted.org/packages/c7/08/ffd537b605568a148543ac3c2b239708ae0bd635064bab41359252ef88ed/cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067", size = 4450634, upload-time = "2026-04-08T01:57:21.185Z" },
{ url = "https://files.pythonhosted.org/packages/16/01/0cd51dd86ab5b9befe0d031e276510491976c3a80e9f6e31810cce46c4ad/cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0", size = 3985233, upload-time = "2026-04-08T01:57:22.862Z" },
{ url = "https://files.pythonhosted.org/packages/92/49/819d6ed3a7d9349c2939f81b500a738cb733ab62fbecdbc1e38e83d45e12/cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba", size = 4271955, upload-time = "2026-04-08T01:57:24.814Z" },
{ url = "https://files.pythonhosted.org/packages/80/07/ad9b3c56ebb95ed2473d46df0847357e01583f4c52a85754d1a55e29e4d0/cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006", size = 4879888, upload-time = "2026-04-08T01:57:26.88Z" },
{ url = "https://files.pythonhosted.org/packages/b8/c7/201d3d58f30c4c2bdbe9b03844c291feb77c20511cc3586daf7edc12a47b/cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0", size = 4449961, upload-time = "2026-04-08T01:57:29.068Z" },
{ url = "https://files.pythonhosted.org/packages/a5/ef/649750cbf96f3033c3c976e112265c33906f8e462291a33d77f90356548c/cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85", size = 4401696, upload-time = "2026-04-08T01:57:31.029Z" },
{ url = "https://files.pythonhosted.org/packages/41/52/a8908dcb1a389a459a29008c29966c1d552588d4ae6d43f3a1a4512e0ebe/cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e", size = 4664256, upload-time = "2026-04-08T01:57:33.144Z" },
{ url = "https://files.pythonhosted.org/packages/4b/fa/f0ab06238e899cc3fb332623f337a7364f36f4bb3f2534c2bb95a35b132c/cryptography-46.0.7-cp38-abi3-win32.whl", hash = "sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246", size = 3013001, upload-time = "2026-04-08T01:57:34.933Z" },
{ url = "https://files.pythonhosted.org/packages/d2/f1/00ce3bde3ca542d1acd8f8cfa38e446840945aa6363f9b74746394b14127/cryptography-46.0.7-cp38-abi3-win_amd64.whl", hash = "sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3", size = 3472985, upload-time = "2026-04-08T01:57:36.714Z" },
{ url = "https://files.pythonhosted.org/packages/63/0c/dca8abb64e7ca4f6b2978769f6fea5ad06686a190cec381f0a796fdcaaba/cryptography-46.0.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:fc9ab8856ae6cf7c9358430e49b368f3108f050031442eaeb6b9d87e4dcf4e4f", size = 3476879, upload-time = "2026-04-08T01:57:38.664Z" },
{ url = "https://files.pythonhosted.org/packages/3a/ea/075aac6a84b7c271578d81a2f9968acb6e273002408729f2ddff517fed4a/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d3b99c535a9de0adced13d159c5a9cf65c325601aa30f4be08afd680643e9c15", size = 4219700, upload-time = "2026-04-08T01:57:40.625Z" },
{ url = "https://files.pythonhosted.org/packages/6c/7b/1c55db7242b5e5612b29fc7a630e91ee7a6e3c8e7bf5406d22e206875fbd/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d02c738dacda7dc2a74d1b2b3177042009d5cab7c7079db74afc19e56ca1b455", size = 4385982, upload-time = "2026-04-08T01:57:42.725Z" },
{ url = "https://files.pythonhosted.org/packages/cb/da/9870eec4b69c63ef5925bf7d8342b7e13bc2ee3d47791461c4e49ca212f4/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:04959522f938493042d595a736e7dbdff6eb6cc2339c11465b3ff89343b65f65", size = 4219115, upload-time = "2026-04-08T01:57:44.939Z" },
{ url = "https://files.pythonhosted.org/packages/f4/72/05aa5832b82dd341969e9a734d1812a6aadb088d9eb6f0430fc337cc5a8f/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:3986ac1dee6def53797289999eabe84798ad7817f3e97779b5061a95b0ee4968", size = 4385479, upload-time = "2026-04-08T01:57:46.86Z" },
{ url = "https://files.pythonhosted.org/packages/20/2a/1b016902351a523aa2bd446b50a5bc1175d7a7d1cf90fe2ef904f9b84ebc/cryptography-46.0.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:258514877e15963bd43b558917bc9f54cf7cf866c38aa576ebf47a77ddbc43a4", size = 3412829, upload-time = "2026-04-08T01:57:48.874Z" },
{ url = "https://files.pythonhosted.org/packages/1b/bc/ee4137cbbe105652c0ee4252792b78fc8e7afa4b8e61d9d5dc05a7f45731/cryptography-48.0.1-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:3e4a1a3232eef2e6c732827d5722db29a0cc8b27af2a4d865b094cf954be9ca1", size = 8008324, upload-time = "2026-06-09T22:31:00.702Z" },
{ url = "https://files.pythonhosted.org/packages/d5/85/6379d42181bfc713094f081360fc5784d6c816b599d45e7f082502d173ce/cryptography-48.0.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:32143b24adb918f078134e1e230f1eb8cc04886b92c28b5f0041aaf3e5699225", size = 4696243, upload-time = "2026-06-09T22:32:33.446Z" },
{ url = "https://files.pythonhosted.org/packages/9c/87/c85d147b53323c7eb4d850920c8901377323c2a0ff8d79c262d4fee89aa2/cryptography-48.0.1-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0d27a5696721ef7a672b8c810f6aded391058e0b9486e63e6d93baf765da691", size = 4713235, upload-time = "2026-06-09T22:31:40.141Z" },
{ url = "https://files.pythonhosted.org/packages/79/58/67cbf8cf1ee7c54b439ca07bbecf8362c07afc11a3724fea70f745784add/cryptography-48.0.1-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:eb86ce1af36fe65041b6db9a8bb064ee621a7e5fded0f80d475ec243477cd242", size = 4702323, upload-time = "2026-06-09T22:31:42.191Z" },
{ url = "https://files.pythonhosted.org/packages/89/c6/24266ac10c47f6cd2a865f4446062b466da1d1f10b27189eac00e61bf0c9/cryptography-48.0.1-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:b024e784ad6c077ee0147b35ea9cbfc1e34e1fd4c1dcca214c2794d73a12df08", size = 5300085, upload-time = "2026-06-09T22:31:58.703Z" },
{ url = "https://files.pythonhosted.org/packages/d2/bb/cc4b78784f97efc8c5874c2a9743708d172be6663024b34a0467885ae0c8/cryptography-48.0.1-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3752f2dbc8f07a30aad2932c986cea495b03bb554887828225da104f732852b6", size = 4746137, upload-time = "2026-06-09T22:31:31.01Z" },
{ url = "https://files.pythonhosted.org/packages/1f/52/0c44de3f5267f8fbe8e835138017522a333436166e406f0db9b9e6e3033f/cryptography-48.0.1-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:bd81490cd5801d755cf97bb68ac191f14b708470b1c7cf4580f669b9c9264cd8", size = 4333867, upload-time = "2026-06-09T22:32:28.096Z" },
{ url = "https://files.pythonhosted.org/packages/9a/2e/772d7adbfa931537bc401640b7cac9976bff689bda187833e5d63b428e49/cryptography-48.0.1-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:66fd0771e7b9c6dcd44cf1120690d2338d16d72795cf40cae2786a39eba65429", size = 4701805, upload-time = "2026-06-09T22:31:38.284Z" },
{ url = "https://files.pythonhosted.org/packages/f8/a3/b06844f303873493c963caf581c04df31c7035e0c1b0f02c4814d319ec80/cryptography-48.0.1-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:3fd2ca57062b241c856670b073487d2e86c4637937ca5601e48f97bf8e11fc8f", size = 5258461, upload-time = "2026-06-09T22:31:04.187Z" },
{ url = "https://files.pythonhosted.org/packages/9f/13/8b765e2e12b07c74941caadb9d1c8fdc006c4dfbf2b8f2d610519758954d/cryptography-48.0.1-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:0ee6ea481db1ab889cba043ec1eda17bb9c1ea79db6722f779c3667f9f70322f", size = 4745488, upload-time = "2026-06-09T22:32:30.07Z" },
{ url = "https://files.pythonhosted.org/packages/2e/aa/48972bce55049b32a94f4907eda4d75fa385aad8a39506cc2fc72196ecf0/cryptography-48.0.1-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f2ceef93cb096aa3c4cc4b5c94ca6131f9196d28c64d6111533402a9b2054d41", size = 4830256, upload-time = "2026-06-09T22:31:43.868Z" },
{ url = "https://files.pythonhosted.org/packages/47/a2/e5079a032fb85cf6005046ca92bbd78b0c82dad2b5751ab8c311659da06f/cryptography-48.0.1-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9bd3f92d76217892b15df84ca256c2c113d386fdda7a7d8691aeeced976507c6", size = 4979117, upload-time = "2026-06-09T22:31:05.845Z" },
{ url = "https://files.pythonhosted.org/packages/b7/a0/8f50cae9c74e718ed769d63ed5c74bd0ea830c9550a74629cebd1b9c7bc7/cryptography-48.0.1-cp311-abi3-win32.whl", hash = "sha256:b9a32b876490d66c8bcc9963ef220199569748434ab01a9d6aaeabf88e7f5158", size = 3304154, upload-time = "2026-06-09T22:32:16.845Z" },
{ url = "https://files.pythonhosted.org/packages/c5/69/0572c77dbace6fef72f33755bd52ea399c71367250d366237f8691826b9e/cryptography-48.0.1-cp311-abi3-win_amd64.whl", hash = "sha256:39489bfca54c7a1f6b297efcd8bc608ab92d16c4ca631b0cad4da46724588b24", size = 3817138, upload-time = "2026-06-09T22:32:00.388Z" },
{ url = "https://files.pythonhosted.org/packages/42/06/3e768b4c3bc78201583fa35a0e18f640dd782ff41afba88f8545481a8874/cryptography-48.0.1-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:f817adc181390bd54f2f700107a7419040fb7c1bdf2fc26f36551a06a68c3345", size = 7989830, upload-time = "2026-06-09T22:31:07.8Z" },
{ url = "https://files.pythonhosted.org/packages/8a/13/6476736484b94041110c8340a3eb63962fea4975baea8cb4a512adb44d4d/cryptography-48.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d5d30989c6917b478b5817902e85fddaea2261efa8648383d965381ccb9e1ac4", size = 4689201, upload-time = "2026-06-09T22:31:09.745Z" },
{ url = "https://files.pythonhosted.org/packages/79/62/65a87f34d2a431546e2509b85d55e8c90df86d668f6731da64d538512ac2/cryptography-48.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:df637c05205ea7c1d7fbcbe54bbfea648a52951155f997af13d895d0ecc96991", size = 4702822, upload-time = "2026-06-09T22:32:24.409Z" },
{ url = "https://files.pythonhosted.org/packages/7f/59/810b5204b0a9b10f4b6bc06bd551a8b609803cd931806bc3b71884b225e5/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:869c3b8a53bfe27147832df48b32adadf558249d50e76cb3769d40e986b13265", size = 4694875, upload-time = "2026-06-09T22:32:08.737Z" },
{ url = "https://files.pythonhosted.org/packages/24/dc/d8ca05ffea724eec6d232ea6f18e74c269eb6bdfdcc9bfba689790d1325f/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:e361afba8918070d376df76f408a4f67fec0ee9cff81a99e48fe9a233ef59e17", size = 5290385, upload-time = "2026-06-09T22:31:15.212Z" },
{ url = "https://files.pythonhosted.org/packages/03/8c/3be6cb4da181f5bb6c19cf560c2359d60644a6b5fc5b57854e528f47b296/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:d069066deead00ac7f090be101be875a06855908f7ec004c27b8fefb4acfb411", size = 4737082, upload-time = "2026-06-09T22:32:22.66Z" },
{ url = "https://files.pythonhosted.org/packages/aa/f6/d5f60a5a1434dbfd949e227fd0065d194c7e6b6ac526b17f5c06152b8231/cryptography-48.0.1-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:09f73a725d582cef64b91281a322cd798d14a33b2b6f2b7ad9531dc336d84c02", size = 4325328, upload-time = "2026-06-09T22:32:10.777Z" },
{ url = "https://files.pythonhosted.org/packages/17/b7/ba75dd947a14b6ad907b01ae8f6b5b348cdd1b48142f0063dee9e20c1d9d/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:15254441469dd6bf027039453288e2072124f8b6603563f5d759e1c9b69273fa", size = 4694530, upload-time = "2026-06-09T22:31:53.105Z" },
{ url = "https://files.pythonhosted.org/packages/62/29/50d6b9e8aff12d8b67afaeb3569335e32dc83a5723e3bbded24fdac9f809/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:8ace4507d1e6533c125f4fac754f8bb8b6a74c08e92179dabd7e16571a3efbf3", size = 5245046, upload-time = "2026-06-09T22:31:25.774Z" },
{ url = "https://files.pythonhosted.org/packages/9f/04/618f4115cfc0add0838c82507aa18a346089428da8653ad38b3ff36f5cb3/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:b4e391975f038e66432328639620a4aff2d307513b004f1ca06d6225bced815c", size = 4736660, upload-time = "2026-06-09T22:32:12.676Z" },
{ url = "https://files.pythonhosted.org/packages/24/9c/06e062462a0de28a3b3911322eded4c16deb9f441b1b7575d3dc59488ab5/cryptography-48.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42fcd8e26fe555d9b3577a135f5091fefa0aa4e99129c23fb56787a1bd4ada72", size = 4822229, upload-time = "2026-06-09T22:31:17.062Z" },
{ url = "https://files.pythonhosted.org/packages/f4/be/0561971eaaee4b8a0e7d5113c536921063ab91aaf23278ac374eaf881e11/cryptography-48.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c1400da5e32a43253392277eac7490a60e497d810a63dd5608d71bbd7af507c9", size = 4966364, upload-time = "2026-06-09T22:31:32.842Z" },
{ url = "https://files.pythonhosted.org/packages/a4/27/728c77876f12b000820b69ae490f3c4083775e79e07827e9e60be07ad209/cryptography-48.0.1-cp314-cp314t-win32.whl", hash = "sha256:0df56b056bc17c1b7d6821dfa65216e62bd232d8ab05eb3db44e71d235651471", size = 3278498, upload-time = "2026-06-09T22:31:29.154Z" },
{ url = "https://files.pythonhosted.org/packages/06/e3/79a612c6d7b1e6ee0edd43633d53035bec2cfb78c82b76f7864f39e36f34/cryptography-48.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:9de21387aa95e2a895823d0745b430bed4f33503ba9ab5e0b5311f33e37d66d2", size = 3798790, upload-time = "2026-06-09T22:31:56.697Z" },
{ url = "https://files.pythonhosted.org/packages/ca/6c/00fa2a95997164c8b2072ce327c23d4ab20809ccc323ea5fab91e53a4bba/cryptography-48.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:4fdc69f8e4316bcf0c8c8ec1f26f285d12e8142d88d96c876a59a03be3f6ae67", size = 7987408, upload-time = "2026-06-09T22:32:20.777Z" },
{ url = "https://files.pythonhosted.org/packages/b0/d9/45f309a7e4e5f3f8f121d6d3be9e94024a7726ec598d6e08ae04edb2f04d/cryptography-48.0.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48fe40804d4caa2288f24e70ca8c64c42dd826da0ad7e4f1b41b2128d679e6c8", size = 4690196, upload-time = "2026-06-09T22:31:54.74Z" },
{ url = "https://files.pythonhosted.org/packages/5f/9f/a1bc8bcc798811b8527eb374bbccf30a3f3e806829d967118222bf1125eb/cryptography-48.0.1-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:86be3b1b0b6bf09482fb50a979c508d2950ed95f5621ec77f4e385962006b83a", size = 4696782, upload-time = "2026-06-09T22:31:45.615Z" },
{ url = "https://files.pythonhosted.org/packages/66/c2/81a4fb4e4373c500bb526bc337ac5719dd31dd15b970b84a238168c6aa08/cryptography-48.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:4ab0a343c807bbcd90c971cd1ecf072937cd01847a9e002bef88fb47ac6be577", size = 4696618, upload-time = "2026-06-09T22:31:11.564Z" },
{ url = "https://files.pythonhosted.org/packages/e5/0b/aa68b221dde92d09cb29a024ede17550ee21e77a404e59fc093c82bb51e1/cryptography-48.0.1-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9621de99d2da096006b629979efd8ae7eb2d8b822488d0c89ee4000c306c59b1", size = 5289970, upload-time = "2026-06-09T22:31:20.368Z" },
{ url = "https://files.pythonhosted.org/packages/78/13/fba657f958d2af66ea959a4ba01212632089249d34af1ae48054136344d7/cryptography-48.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:88c852a0ae366e262e5a1744b685e6a433dc8788dd2a277e418bf4904203609d", size = 4731873, upload-time = "2026-06-09T22:31:22.253Z" },
{ url = "https://files.pythonhosted.org/packages/4c/4c/9a964756d24a26b3e34dfcb16f961b89838786e6700b635b0d1e3adff4b6/cryptography-48.0.1-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:43c5835e2cb98c8733d86f57d6fc879b613f5c3478607281c3e36daffc6dd8a6", size = 4330804, upload-time = "2026-06-09T22:31:36.56Z" },
{ url = "https://files.pythonhosted.org/packages/4b/0f/a10f3a6eb12950a10e3a874070283aa2dd5875b2bfd15fad8a3e17b3f13e/cryptography-48.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:fe0180af5bf9236518a087e35bf2d9a347d5f5f51e63c579d683ddff424e3d46", size = 4696217, upload-time = "2026-06-09T22:31:13.351Z" },
{ url = "https://files.pythonhosted.org/packages/f3/6f/5cd12f951165ea73ef85266775d97e4c763b2474ccfd816dd69d3a18d6f8/cryptography-48.0.1-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:b7a2d1a937a738a881737cec135a38bb61470589b17515b9f73f571d0ae10401", size = 5245252, upload-time = "2026-06-09T22:32:02.193Z" },
{ url = "https://files.pythonhosted.org/packages/68/ab/8aaa12e4516ec4464033ab79b6f3b592bd5a92102467c4ace8a0d970203f/cryptography-48.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b74ca3b8e5ecdd833bf6a002ca41b4793bb27fb8f1c06ffaf2643c9e9140e31b", size = 4731388, upload-time = "2026-06-09T22:32:04.019Z" },
{ url = "https://files.pythonhosted.org/packages/1b/24/50027ea4dca85ec1f40688f3c24fb32ccacd520583c9592c3cc95628e6fb/cryptography-48.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2c37f2461406063b417837f5f3daab668652acd82423efcd7f0a9f04be972de1", size = 4824186, upload-time = "2026-06-09T22:32:18.707Z" },
{ url = "https://files.pythonhosted.org/packages/52/41/04cb5eb17085ade6f50cc611fb657df6a0f5885350de8764ece89c050197/cryptography-48.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:86fe77abb1bd87afb251d4d02ada7ecf53a32cee9b67d976abb2e45a13297475", size = 4964539, upload-time = "2026-06-09T22:31:18.793Z" },
{ url = "https://files.pythonhosted.org/packages/36/bf/ed70785c496e89d7e73b7cda2d21f2447fd6d4e821714b8d04ff217fed92/cryptography-48.0.1-cp39-abi3-win32.whl", hash = "sha256:6b2c0c3e6ccf3ade7750f836ef3ee36eea250cc467d45c256895573ac08cc6f1", size = 3282307, upload-time = "2026-06-09T22:30:53.162Z" },
{ url = "https://files.pythonhosted.org/packages/b3/ff/371ea7d252656ee1eb6d83eeeef3d1d0c6baf1d6497687d081ea03814670/cryptography-48.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:9a49ca6c81417f6a5edb50375a60cccdd70fa0a91a5211829dbea74eba94d2ac", size = 3793408, upload-time = "2026-06-09T22:32:15.191Z" },
{ url = "https://files.pythonhosted.org/packages/a9/d3/eb4e394e587341fdad09a09101fa76478ead3a78b0ad63e55c22f0d75c02/cryptography-48.0.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:08a597acce1ff37f347400087776599e2348a3a8bc53b44120e463cd274efe4a", size = 3951747, upload-time = "2026-06-09T22:31:23.871Z" },
{ url = "https://files.pythonhosted.org/packages/e0/4a/3f43451b4f858bfceaaaffc649e6e787e8d4fb332a1d443af39ab02cc8f1/cryptography-48.0.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:735824ec41b7f74a7c45fb1591349333e4c696cb6c044e5f46356e560143e4cd", size = 4641226, upload-time = "2026-06-09T22:31:02.532Z" },
{ url = "https://files.pythonhosted.org/packages/73/4e/855584c2c23b09e4ce2d3b9c30e983e679cd60b068c513c6bbdb91e11782/cryptography-48.0.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:92a46e1d638daa264ba2971c0b0489c9409787943efae4d60ffda3d091ef832c", size = 4668958, upload-time = "2026-06-09T22:32:06.213Z" },
{ url = "https://files.pythonhosted.org/packages/42/3b/d35750e41d803d1e516fd6d6011f065424924da7af1748cef4cc9cb3ede1/cryptography-48.0.1-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:7e234ac052af99f2700826a5c29ea99d9c1b1f80341cde62d11c8154dc8e0bd9", size = 4640793, upload-time = "2026-06-09T22:32:26.331Z" },
{ url = "https://files.pythonhosted.org/packages/ca/aa/cdb7181fe865285e87e96825aaab239400f1de0c3bfba9bd9769b79f1a92/cryptography-48.0.1-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:33842cf0888951cef5bc7ac724ab844a42044c1727b967b7f8997289a0464f92", size = 4668505, upload-time = "2026-06-09T22:31:27.534Z" },
{ url = "https://files.pythonhosted.org/packages/5d/8c/ce3823c06c2804f194f9e64f0d67fa3f4094a39f2bb1a990cd03603af8fc/cryptography-48.0.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6184ca7b174f28d7c703f1290d4b297217c45355f77a98f67e9b7f14549ac54a", size = 3742204, upload-time = "2026-06-09T22:31:34.773Z" },
]
[[package]]
@@ -528,139 +528,139 @@ wheels = [
[[package]]
name = "grpcio"
version = "1.78.0"
version = "1.80.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions", marker = "python_full_version >= '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/06/8a/3d098f35c143a89520e568e6539cc098fcd294495910e359889ce8741c84/grpcio-1.78.0.tar.gz", hash = "sha256:7382b95189546f375c174f53a5fa873cef91c4b8005faa05cc5b3beea9c4f1c5", size = 12852416, upload-time = "2026-02-06T09:57:18.093Z" }
sdist = { url = "https://files.pythonhosted.org/packages/b7/48/af6173dbca4454f4637a4678b67f52ca7e0c1ed7d5894d89d434fecede05/grpcio-1.80.0.tar.gz", hash = "sha256:29aca15edd0688c22ba01d7cc01cb000d72b2033f4a3c72a81a19b56fd143257", size = 12978905, upload-time = "2026-03-30T08:49:10.502Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5a/a8/690a085b4d1fe066130de97a87de32c45062cf2ecd218df9675add895550/grpcio-1.78.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:7cc47943d524ee0096f973e1081cb8f4f17a4615f2116882a5f1416e4cfe92b5", size = 5946986, upload-time = "2026-02-06T09:54:34.043Z" },
{ url = "https://files.pythonhosted.org/packages/c7/1b/e5213c5c0ced9d2d92778d30529ad5bb2dcfb6c48c4e2d01b1f302d33d64/grpcio-1.78.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:c3f293fdc675ccba4db5a561048cca627b5e7bd1c8a6973ffedabe7d116e22e2", size = 11816533, upload-time = "2026-02-06T09:54:37.04Z" },
{ url = "https://files.pythonhosted.org/packages/18/37/1ba32dccf0a324cc5ace744c44331e300b000a924bf14840f948c559ede7/grpcio-1.78.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:10a9a644b5dd5aec3b82b5b0b90d41c0fa94c85ef42cb42cf78a23291ddb5e7d", size = 6519964, upload-time = "2026-02-06T09:54:40.268Z" },
{ url = "https://files.pythonhosted.org/packages/ed/f5/c0e178721b818072f2e8b6fde13faaba942406c634009caf065121ce246b/grpcio-1.78.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4c5533d03a6cbd7f56acfc9cfb44ea64f63d29091e40e44010d34178d392d7eb", size = 7198058, upload-time = "2026-02-06T09:54:42.389Z" },
{ url = "https://files.pythonhosted.org/packages/5b/b2/40d43c91ae9cd667edc960135f9f08e58faa1576dc95af29f66ec912985f/grpcio-1.78.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ff870aebe9a93a85283837801d35cd5f8814fe2ad01e606861a7fb47c762a2b7", size = 6727212, upload-time = "2026-02-06T09:54:44.91Z" },
{ url = "https://files.pythonhosted.org/packages/ed/88/9da42eed498f0efcfcd9156e48ae63c0cde3bea398a16c99fb5198c885b6/grpcio-1.78.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:391e93548644e6b2726f1bb84ed60048d4bcc424ce5e4af0843d28ca0b754fec", size = 7300845, upload-time = "2026-02-06T09:54:47.562Z" },
{ url = "https://files.pythonhosted.org/packages/23/3f/1c66b7b1b19a8828890e37868411a6e6925df5a9030bfa87ab318f34095d/grpcio-1.78.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:df2c8f3141f7cbd112a6ebbd760290b5849cda01884554f7c67acc14e7b1758a", size = 8284605, upload-time = "2026-02-06T09:54:50.475Z" },
{ url = "https://files.pythonhosted.org/packages/94/c4/ca1bd87394f7b033e88525384b4d1e269e8424ab441ea2fba1a0c5b50986/grpcio-1.78.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bd8cb8026e5f5b50498a3c4f196f57f9db344dad829ffae16b82e4fdbaea2813", size = 7726672, upload-time = "2026-02-06T09:54:53.11Z" },
{ url = "https://files.pythonhosted.org/packages/41/09/f16e487d4cc65ccaf670f6ebdd1a17566b965c74fc3d93999d3b2821e052/grpcio-1.78.0-cp310-cp310-win32.whl", hash = "sha256:f8dff3d9777e5d2703a962ee5c286c239bf0ba173877cc68dc02c17d042e29de", size = 4076715, upload-time = "2026-02-06T09:54:55.549Z" },
{ url = "https://files.pythonhosted.org/packages/2a/32/4ce60d94e242725fd3bcc5673c04502c82a8e87b21ea411a63992dc39f8f/grpcio-1.78.0-cp310-cp310-win_amd64.whl", hash = "sha256:94f95cf5d532d0e717eed4fc1810e8e6eded04621342ec54c89a7c2f14b581bf", size = 4799157, upload-time = "2026-02-06T09:54:59.838Z" },
{ url = "https://files.pythonhosted.org/packages/86/c7/d0b780a29b0837bf4ca9580904dfb275c1fc321ded7897d620af7047ec57/grpcio-1.78.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:2777b783f6c13b92bd7b716667452c329eefd646bfb3f2e9dabea2e05dbd34f6", size = 5951525, upload-time = "2026-02-06T09:55:01.989Z" },
{ url = "https://files.pythonhosted.org/packages/c5/b1/96920bf2ee61df85a9503cb6f733fe711c0ff321a5a697d791b075673281/grpcio-1.78.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:9dca934f24c732750389ce49d638069c3892ad065df86cb465b3fa3012b70c9e", size = 11830418, upload-time = "2026-02-06T09:55:04.462Z" },
{ url = "https://files.pythonhosted.org/packages/83/0c/7c1528f098aeb75a97de2bae18c530f56959fb7ad6c882db45d9884d6edc/grpcio-1.78.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:459ab414b35f4496138d0ecd735fed26f1318af5e52cb1efbc82a09f0d5aa911", size = 6524477, upload-time = "2026-02-06T09:55:07.111Z" },
{ url = "https://files.pythonhosted.org/packages/8d/52/e7c1f3688f949058e19a011c4e0dec973da3d0ae5e033909677f967ae1f4/grpcio-1.78.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:082653eecbdf290e6e3e2c276ab2c54b9e7c299e07f4221872380312d8cf395e", size = 7198266, upload-time = "2026-02-06T09:55:10.016Z" },
{ url = "https://files.pythonhosted.org/packages/e5/61/8ac32517c1e856677282c34f2e7812d6c328fa02b8f4067ab80e77fdc9c9/grpcio-1.78.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:85f93781028ec63f383f6bc90db785a016319c561cc11151fbb7b34e0d012303", size = 6730552, upload-time = "2026-02-06T09:55:12.207Z" },
{ url = "https://files.pythonhosted.org/packages/bd/98/b8ee0158199250220734f620b12e4a345955ac7329cfd908d0bf0fda77f0/grpcio-1.78.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f12857d24d98441af6a1d5c87442d624411db486f7ba12550b07788f74b67b04", size = 7304296, upload-time = "2026-02-06T09:55:15.044Z" },
{ url = "https://files.pythonhosted.org/packages/bd/0f/7b72762e0d8840b58032a56fdbd02b78fc645b9fa993d71abf04edbc54f4/grpcio-1.78.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5397fff416b79e4b284959642a4e95ac4b0f1ece82c9993658e0e477d40551ec", size = 8288298, upload-time = "2026-02-06T09:55:17.276Z" },
{ url = "https://files.pythonhosted.org/packages/24/ae/ae4ce56bc5bb5caa3a486d60f5f6083ac3469228faa734362487176c15c5/grpcio-1.78.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fbe6e89c7ffb48518384068321621b2a69cab509f58e40e4399fdd378fa6d074", size = 7730953, upload-time = "2026-02-06T09:55:19.545Z" },
{ url = "https://files.pythonhosted.org/packages/b5/6e/8052e3a28eb6a820c372b2eb4b5e32d195c661e137d3eca94d534a4cfd8a/grpcio-1.78.0-cp311-cp311-win32.whl", hash = "sha256:6092beabe1966a3229f599d7088b38dfc8ffa1608b5b5cdda31e591e6500f856", size = 4076503, upload-time = "2026-02-06T09:55:21.521Z" },
{ url = "https://files.pythonhosted.org/packages/08/62/f22c98c5265dfad327251fa2f840b591b1df5f5e15d88b19c18c86965b27/grpcio-1.78.0-cp311-cp311-win_amd64.whl", hash = "sha256:1afa62af6e23f88629f2b29ec9e52ec7c65a7176c1e0a83292b93c76ca882558", size = 4799767, upload-time = "2026-02-06T09:55:24.107Z" },
{ url = "https://files.pythonhosted.org/packages/4e/f4/7384ed0178203d6074446b3c4f46c90a22ddf7ae0b3aee521627f54cfc2a/grpcio-1.78.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:f9ab915a267fc47c7e88c387a3a28325b58c898e23d4995f765728f4e3dedb97", size = 5913985, upload-time = "2026-02-06T09:55:26.832Z" },
{ url = "https://files.pythonhosted.org/packages/81/ed/be1caa25f06594463f685b3790b320f18aea49b33166f4141bfdc2bfb236/grpcio-1.78.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3f8904a8165ab21e07e58bf3e30a73f4dffc7a1e0dbc32d51c61b5360d26f43e", size = 11811853, upload-time = "2026-02-06T09:55:29.224Z" },
{ url = "https://files.pythonhosted.org/packages/24/a7/f06d151afc4e64b7e3cc3e872d331d011c279aaab02831e40a81c691fb65/grpcio-1.78.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:859b13906ce098c0b493af92142ad051bf64c7870fa58a123911c88606714996", size = 6475766, upload-time = "2026-02-06T09:55:31.825Z" },
{ url = "https://files.pythonhosted.org/packages/8a/a8/4482922da832ec0082d0f2cc3a10976d84a7424707f25780b82814aafc0a/grpcio-1.78.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b2342d87af32790f934a79c3112641e7b27d63c261b8b4395350dad43eff1dc7", size = 7170027, upload-time = "2026-02-06T09:55:34.7Z" },
{ url = "https://files.pythonhosted.org/packages/54/bf/f4a3b9693e35d25b24b0b39fa46d7d8a3c439e0a3036c3451764678fec20/grpcio-1.78.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:12a771591ae40bc65ba67048fa52ef4f0e6db8279e595fd349f9dfddeef571f9", size = 6690766, upload-time = "2026-02-06T09:55:36.902Z" },
{ url = "https://files.pythonhosted.org/packages/c7/b9/521875265cc99fe5ad4c5a17010018085cae2810a928bf15ebe7d8bcd9cc/grpcio-1.78.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:185dea0d5260cbb2d224c507bf2a5444d5abbb1fa3594c1ed7e4c709d5eb8383", size = 7266161, upload-time = "2026-02-06T09:55:39.824Z" },
{ url = "https://files.pythonhosted.org/packages/05/86/296a82844fd40a4ad4a95f100b55044b4f817dece732bf686aea1a284147/grpcio-1.78.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:51b13f9aed9d59ee389ad666b8c2214cc87b5de258fa712f9ab05f922e3896c6", size = 8253303, upload-time = "2026-02-06T09:55:42.353Z" },
{ url = "https://files.pythonhosted.org/packages/f3/e4/ea3c0caf5468537f27ad5aab92b681ed7cc0ef5f8c9196d3fd42c8c2286b/grpcio-1.78.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fd5f135b1bd58ab088930b3c613455796dfa0393626a6972663ccdda5b4ac6ce", size = 7698222, upload-time = "2026-02-06T09:55:44.629Z" },
{ url = "https://files.pythonhosted.org/packages/d7/47/7f05f81e4bb6b831e93271fb12fd52ba7b319b5402cbc101d588f435df00/grpcio-1.78.0-cp312-cp312-win32.whl", hash = "sha256:94309f498bcc07e5a7d16089ab984d42ad96af1d94b5a4eb966a266d9fcabf68", size = 4066123, upload-time = "2026-02-06T09:55:47.644Z" },
{ url = "https://files.pythonhosted.org/packages/ad/e7/d6914822c88aa2974dbbd10903d801a28a19ce9cd8bad7e694cbbcf61528/grpcio-1.78.0-cp312-cp312-win_amd64.whl", hash = "sha256:9566fe4ababbb2610c39190791e5b829869351d14369603702e890ef3ad2d06e", size = 4797657, upload-time = "2026-02-06T09:55:49.86Z" },
{ url = "https://files.pythonhosted.org/packages/05/a9/8f75894993895f361ed8636cd9237f4ab39ef87fd30db17467235ed1c045/grpcio-1.78.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:ce3a90455492bf8bfa38e56fbbe1dbd4f872a3d8eeaf7337dc3b1c8aa28c271b", size = 5920143, upload-time = "2026-02-06T09:55:52.035Z" },
{ url = "https://files.pythonhosted.org/packages/55/06/0b78408e938ac424100100fd081189451b472236e8a3a1f6500390dc4954/grpcio-1.78.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:2bf5e2e163b356978b23652c4818ce4759d40f4712ee9ec5a83c4be6f8c23a3a", size = 11803926, upload-time = "2026-02-06T09:55:55.494Z" },
{ url = "https://files.pythonhosted.org/packages/88/93/b59fe7832ff6ae3c78b813ea43dac60e295fa03606d14d89d2e0ec29f4f3/grpcio-1.78.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8f2ac84905d12918e4e55a16da17939eb63e433dc11b677267c35568aa63fc84", size = 6478628, upload-time = "2026-02-06T09:55:58.533Z" },
{ url = "https://files.pythonhosted.org/packages/ed/df/e67e3734527f9926b7d9c0dde6cd998d1d26850c3ed8eeec81297967ac67/grpcio-1.78.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b58f37edab4a3881bc6c9bca52670610e0c9ca14e2ea3cf9debf185b870457fb", size = 7173574, upload-time = "2026-02-06T09:56:01.786Z" },
{ url = "https://files.pythonhosted.org/packages/a6/62/cc03fffb07bfba982a9ec097b164e8835546980aec25ecfa5f9c1a47e022/grpcio-1.78.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:735e38e176a88ce41840c21bb49098ab66177c64c82426e24e0082500cc68af5", size = 6692639, upload-time = "2026-02-06T09:56:04.529Z" },
{ url = "https://files.pythonhosted.org/packages/bf/9a/289c32e301b85bdb67d7ec68b752155e674ee3ba2173a1858f118e399ef3/grpcio-1.78.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2045397e63a7a0ee7957c25f7dbb36ddc110e0cfb418403d110c0a7a68a844e9", size = 7268838, upload-time = "2026-02-06T09:56:08.397Z" },
{ url = "https://files.pythonhosted.org/packages/0e/79/1be93f32add280461fa4773880196572563e9c8510861ac2da0ea0f892b6/grpcio-1.78.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9f136fbafe7ccf4ac7e8e0c28b31066e810be52d6e344ef954a3a70234e1702", size = 8251878, upload-time = "2026-02-06T09:56:10.914Z" },
{ url = "https://files.pythonhosted.org/packages/65/65/793f8e95296ab92e4164593674ae6291b204bb5f67f9d4a711489cd30ffa/grpcio-1.78.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:748b6138585379c737adc08aeffd21222abbda1a86a0dca2a39682feb9196c20", size = 7695412, upload-time = "2026-02-06T09:56:13.593Z" },
{ url = "https://files.pythonhosted.org/packages/1c/9f/1e233fe697ecc82845942c2822ed06bb522e70d6771c28d5528e4c50f6a4/grpcio-1.78.0-cp313-cp313-win32.whl", hash = "sha256:271c73e6e5676afe4fc52907686670c7cea22ab2310b76a59b678403ed40d670", size = 4064899, upload-time = "2026-02-06T09:56:15.601Z" },
{ url = "https://files.pythonhosted.org/packages/4d/27/d86b89e36de8a951501fb06a0f38df19853210f341d0b28f83f4aa0ffa08/grpcio-1.78.0-cp313-cp313-win_amd64.whl", hash = "sha256:f2d4e43ee362adfc05994ed479334d5a451ab7bc3f3fee1b796b8ca66895acb4", size = 4797393, upload-time = "2026-02-06T09:56:17.882Z" },
{ url = "https://files.pythonhosted.org/packages/29/f2/b56e43e3c968bfe822fa6ce5bca10d5c723aa40875b48791ce1029bb78c7/grpcio-1.78.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:e87cbc002b6f440482b3519e36e1313eb5443e9e9e73d6a52d43bd2004fcfd8e", size = 5920591, upload-time = "2026-02-06T09:56:20.758Z" },
{ url = "https://files.pythonhosted.org/packages/5d/81/1f3b65bd30c334167bfa8b0d23300a44e2725ce39bba5b76a2460d85f745/grpcio-1.78.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:c41bc64626db62e72afec66b0c8a0da76491510015417c127bfc53b2fe6d7f7f", size = 11813685, upload-time = "2026-02-06T09:56:24.315Z" },
{ url = "https://files.pythonhosted.org/packages/0e/1c/bbe2f8216a5bd3036119c544d63c2e592bdf4a8ec6e4a1867592f4586b26/grpcio-1.78.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8dfffba826efcf366b1e3ccc37e67afe676f290e13a3b48d31a46739f80a8724", size = 6487803, upload-time = "2026-02-06T09:56:27.367Z" },
{ url = "https://files.pythonhosted.org/packages/16/5c/a6b2419723ea7ddce6308259a55e8e7593d88464ce8db9f4aa857aba96fa/grpcio-1.78.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:74be1268d1439eaaf552c698cdb11cd594f0c49295ae6bb72c34ee31abbe611b", size = 7173206, upload-time = "2026-02-06T09:56:29.876Z" },
{ url = "https://files.pythonhosted.org/packages/df/1e/b8801345629a415ea7e26c83d75eb5dbe91b07ffe5210cc517348a8d4218/grpcio-1.78.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be63c88b32e6c0f1429f1398ca5c09bc64b0d80950c8bb7807d7d7fb36fb84c7", size = 6693826, upload-time = "2026-02-06T09:56:32.305Z" },
{ url = "https://files.pythonhosted.org/packages/34/84/0de28eac0377742679a510784f049738a80424b17287739fc47d63c2439e/grpcio-1.78.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3c586ac70e855c721bda8f548d38c3ca66ac791dc49b66a8281a1f99db85e452", size = 7277897, upload-time = "2026-02-06T09:56:34.915Z" },
{ url = "https://files.pythonhosted.org/packages/ca/9c/ad8685cfe20559a9edb66f735afdcb2b7d3de69b13666fdfc542e1916ebd/grpcio-1.78.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:35eb275bf1751d2ffbd8f57cdbc46058e857cf3971041521b78b7db94bdaf127", size = 8252404, upload-time = "2026-02-06T09:56:37.553Z" },
{ url = "https://files.pythonhosted.org/packages/3c/05/33a7a4985586f27e1de4803887c417ec7ced145ebd069bc38a9607059e2b/grpcio-1.78.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:207db540302c884b8848036b80db352a832b99dfdf41db1eb554c2c2c7800f65", size = 7696837, upload-time = "2026-02-06T09:56:40.173Z" },
{ url = "https://files.pythonhosted.org/packages/73/77/7382241caf88729b106e49e7d18e3116216c778e6a7e833826eb96de22f7/grpcio-1.78.0-cp314-cp314-win32.whl", hash = "sha256:57bab6deef2f4f1ca76cc04565df38dc5713ae6c17de690721bdf30cb1e0545c", size = 4142439, upload-time = "2026-02-06T09:56:43.258Z" },
{ url = "https://files.pythonhosted.org/packages/48/b2/b096ccce418882fbfda4f7496f9357aaa9a5af1896a9a7f60d9f2b275a06/grpcio-1.78.0-cp314-cp314-win_amd64.whl", hash = "sha256:dce09d6116df20a96acfdbf85e4866258c3758180e8c49845d6ba8248b6d0bbb", size = 4929852, upload-time = "2026-02-06T09:56:45.885Z" },
{ url = "https://files.pythonhosted.org/packages/9d/cd/bb7b7e54084a344c03d68144450da7ddd5564e51a298ae1662de65f48e2d/grpcio-1.80.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:886457a7768e408cdce226ad1ca67d2958917d306523a0e21e1a2fdaa75c9c9c", size = 6050363, upload-time = "2026-03-30T08:46:20.894Z" },
{ url = "https://files.pythonhosted.org/packages/16/02/1417f5c3460dea65f7a2e3c14e8b31e77f7ffb730e9bfadd89eda7a9f477/grpcio-1.80.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:7b641fc3f1dc647bfd80bd713addc68f6d145956f64677e56d9ebafc0bd72388", size = 12026037, upload-time = "2026-03-30T08:46:25.144Z" },
{ url = "https://files.pythonhosted.org/packages/43/98/c910254eedf2cae368d78336a2de0678e66a7317d27c02522392f949b5c6/grpcio-1.80.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:33eb763f18f006dc7fee1e69831d38d23f5eccd15b2e0f92a13ee1d9242e5e02", size = 6602306, upload-time = "2026-03-30T08:46:27.593Z" },
{ url = "https://files.pythonhosted.org/packages/7c/f8/88ca4e78c077b2b2113d95da1e1ab43efd43d723c9a0397d26529c2c1a56/grpcio-1.80.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:52d143637e3872633fc7dd7c3c6a1c84e396b359f3a72e215f8bf69fd82084fc", size = 7301535, upload-time = "2026-03-30T08:46:29.556Z" },
{ url = "https://files.pythonhosted.org/packages/f9/96/f28660fe2fe0f153288bf4a04e4910b7309d442395135c88ed4f5b3b8b40/grpcio-1.80.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c51bf8ac4575af2e0678bccfb07e47321fc7acb5049b4482832c5c195e04e13a", size = 6808669, upload-time = "2026-03-30T08:46:31.984Z" },
{ url = "https://files.pythonhosted.org/packages/47/eb/3f68a5e955779c00aeef23850e019c1c1d0e032d90633ba49c01ad5a96e0/grpcio-1.80.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:50a9871536d71c4fba24ee856abc03a87764570f0c457dd8db0b4018f379fed9", size = 7409489, upload-time = "2026-03-30T08:46:34.684Z" },
{ url = "https://files.pythonhosted.org/packages/5b/a7/d2f681a4bfb881be40659a309771f3bdfbfdb1190619442816c3f0ffc079/grpcio-1.80.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a72d84ad0514db063e21887fbacd1fd7acb4d494a564cae22227cd45c7fbf199", size = 8423167, upload-time = "2026-03-30T08:46:36.833Z" },
{ url = "https://files.pythonhosted.org/packages/97/8a/29b4589c204959aa35ce5708400a05bba72181807c45c47b3ec000c39333/grpcio-1.80.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f7691a6788ad9196872f95716df5bc643ebba13c97140b7a5ee5c8e75d1dea81", size = 7846761, upload-time = "2026-03-30T08:46:40.091Z" },
{ url = "https://files.pythonhosted.org/packages/6b/d2/ed143e097230ee121ac5848f6ff14372dba91289b10b536d54fb1b7cbae7/grpcio-1.80.0-cp310-cp310-win32.whl", hash = "sha256:46c2390b59d67f84e882694d489f5b45707c657832d7934859ceb8c33f467069", size = 4156534, upload-time = "2026-03-30T08:46:42.026Z" },
{ url = "https://files.pythonhosted.org/packages/d5/c9/df8279bb49b29409995e95efa85b72973d62f8aeff89abee58c91f393710/grpcio-1.80.0-cp310-cp310-win_amd64.whl", hash = "sha256:dc053420fc75749c961e2a4c906398d7c15725d36ccc04ae6d16093167223b58", size = 4889869, upload-time = "2026-03-30T08:46:44.219Z" },
{ url = "https://files.pythonhosted.org/packages/5d/db/1d56e5f5823257b291962d6c0ce106146c6447f405b60b234c4f222a7cde/grpcio-1.80.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:dfab85db094068ff42e2a3563f60ab3dddcc9d6488a35abf0132daec13209c8a", size = 6055009, upload-time = "2026-03-30T08:46:46.265Z" },
{ url = "https://files.pythonhosted.org/packages/6e/18/c83f3cad64c5ca63bca7e91e5e46b0d026afc5af9d0a9972472ceba294b3/grpcio-1.80.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:5c07e82e822e1161354e32da2662f741a4944ea955f9f580ec8fb409dd6f6060", size = 12035295, upload-time = "2026-03-30T08:46:49.099Z" },
{ url = "https://files.pythonhosted.org/packages/0f/8e/e14966b435be2dda99fbe89db9525ea436edc79780431a1c2875a3582644/grpcio-1.80.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba0915d51fd4ced2db5ff719f84e270afe0e2d4c45a7bdb1e8d036e4502928c2", size = 6610297, upload-time = "2026-03-30T08:46:52.123Z" },
{ url = "https://files.pythonhosted.org/packages/cc/26/d5eb38f42ce0e3fdc8174ea4d52036ef8d58cc4426cb800f2610f625dd75/grpcio-1.80.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3cb8130ba457d2aa09fa6b7c3ed6b6e4e6a2685fce63cb803d479576c4d80e21", size = 7300208, upload-time = "2026-03-30T08:46:54.859Z" },
{ url = "https://files.pythonhosted.org/packages/25/51/bd267c989f85a17a5b3eea65a6feb4ff672af41ca614e5a0279cc0ea381c/grpcio-1.80.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:09e5e478b3d14afd23f12e49e8b44c8684ac3c5f08561c43a5b9691c54d136ab", size = 6813442, upload-time = "2026-03-30T08:46:57.056Z" },
{ url = "https://files.pythonhosted.org/packages/9e/d9/d80eef735b19e9169e30164bbf889b46f9df9127598a83d174eb13a48b26/grpcio-1.80.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:00168469238b022500e486c1c33916acf2f2a9b2c022202cf8a1885d2e3073c1", size = 7414743, upload-time = "2026-03-30T08:46:59.682Z" },
{ url = "https://files.pythonhosted.org/packages/de/f2/567f5bd5054398ed6b0509b9a30900376dcf2786bd936812098808b49d8d/grpcio-1.80.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8502122a3cc1714038e39a0b071acb1207ca7844208d5ea0d091317555ee7106", size = 8426046, upload-time = "2026-03-30T08:47:02.474Z" },
{ url = "https://files.pythonhosted.org/packages/62/29/73ef0141b4732ff5eacd68430ff2512a65c004696997f70476a83e548e7e/grpcio-1.80.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ce1794f4ea6cc3ca29463f42d665c32ba1b964b48958a66497917fe9069f26e6", size = 7851641, upload-time = "2026-03-30T08:47:05.462Z" },
{ url = "https://files.pythonhosted.org/packages/46/69/abbfa360eb229a8623bab5f5a4f8105e445bd38ce81a89514ba55d281ad0/grpcio-1.80.0-cp311-cp311-win32.whl", hash = "sha256:51b4a7189b0bef2aa30adce3c78f09c83526cf3dddb24c6a96555e3b97340440", size = 4154368, upload-time = "2026-03-30T08:47:08.027Z" },
{ url = "https://files.pythonhosted.org/packages/6f/d4/ae92206d01183b08613e846076115f5ac5991bae358d2a749fa864da5699/grpcio-1.80.0-cp311-cp311-win_amd64.whl", hash = "sha256:02e64bb0bb2da14d947a49e6f120a75e947250aebe65f9629b62bb1f5c14e6e9", size = 4894235, upload-time = "2026-03-30T08:47:10.839Z" },
{ url = "https://files.pythonhosted.org/packages/5c/e8/a2b749265eb3415abc94f2e619bbd9e9707bebdda787e61c593004ec927a/grpcio-1.80.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:c624cc9f1008361014378c9d776de7182b11fe8b2e5a81bc69f23a295f2a1ad0", size = 6015616, upload-time = "2026-03-30T08:47:13.428Z" },
{ url = "https://files.pythonhosted.org/packages/3e/97/b1282161a15d699d1e90c360df18d19165a045ce1c343c7f313f5e8a0b77/grpcio-1.80.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:f49eddcac43c3bf350c0385366a58f36bed8cc2c0ec35ef7b74b49e56552c0c2", size = 12014204, upload-time = "2026-03-30T08:47:15.873Z" },
{ url = "https://files.pythonhosted.org/packages/6e/5e/d319c6e997b50c155ac5a8cb12f5173d5b42677510e886d250d50264949d/grpcio-1.80.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d334591df610ab94714048e0d5b4f3dd5ad1bee74dfec11eee344220077a79de", size = 6563866, upload-time = "2026-03-30T08:47:18.588Z" },
{ url = "https://files.pythonhosted.org/packages/ae/f6/fdd975a2cb4d78eb67769a7b3b3830970bfa2e919f1decf724ae4445f42c/grpcio-1.80.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0cb517eb1d0d0aaf1d87af7cc5b801d686557c1d88b2619f5e31fab3c2315921", size = 7273060, upload-time = "2026-03-30T08:47:21.113Z" },
{ url = "https://files.pythonhosted.org/packages/db/f0/a3deb5feba60d9538a962913e37bd2e69a195f1c3376a3dd44fe0427e996/grpcio-1.80.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4e78c4ac0d97dc2e569b2f4bcbbb447491167cb358d1a389fc4af71ab6f70411", size = 6782121, upload-time = "2026-03-30T08:47:23.827Z" },
{ url = "https://files.pythonhosted.org/packages/ca/84/36c6dcfddc093e108141f757c407902a05085e0c328007cb090d56646cdf/grpcio-1.80.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2ed770b4c06984f3b47eb0517b1c69ad0b84ef3f40128f51448433be904634cd", size = 7383811, upload-time = "2026-03-30T08:47:26.517Z" },
{ url = "https://files.pythonhosted.org/packages/7c/ef/f3a77e3dc5b471a0ec86c564c98d6adfa3510d38f8ee99010410858d591e/grpcio-1.80.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:256507e2f524092f1473071a05e65a5b10d84b82e3ff24c5b571513cfaa61e2f", size = 8393860, upload-time = "2026-03-30T08:47:29.439Z" },
{ url = "https://files.pythonhosted.org/packages/9b/8d/9d4d27ed7f33d109c50d6b5ce578a9914aa68edab75d65869a17e630a8d1/grpcio-1.80.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a6284a5d907c37db53350645567c522be314bac859a64a7a5ca63b77bb7958f", size = 7830132, upload-time = "2026-03-30T08:47:33.254Z" },
{ url = "https://files.pythonhosted.org/packages/14/e4/9990b41c6d7a44e1e9dee8ac11d7a9802ba1378b40d77468a7761d1ad288/grpcio-1.80.0-cp312-cp312-win32.whl", hash = "sha256:c71309cfce2f22be26aa4a847357c502db6c621f1a49825ae98aa0907595b193", size = 4140904, upload-time = "2026-03-30T08:47:35.319Z" },
{ url = "https://files.pythonhosted.org/packages/2f/2c/296f6138caca1f4b92a31ace4ae1b87dab692fc16a7a3417af3bb3c805bf/grpcio-1.80.0-cp312-cp312-win_amd64.whl", hash = "sha256:9fe648599c0e37594c4809d81a9e77bd138cc82eb8baa71b6a86af65426723ff", size = 4880944, upload-time = "2026-03-30T08:47:37.831Z" },
{ url = "https://files.pythonhosted.org/packages/2f/3a/7c3c25789e3f069e581dc342e03613c5b1cb012c4e8c7d9d5cf960a75856/grpcio-1.80.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:e9e408fc016dffd20661f0126c53d8a31c2821b5c13c5d67a0f5ed5de93319ad", size = 6017243, upload-time = "2026-03-30T08:47:40.075Z" },
{ url = "https://files.pythonhosted.org/packages/04/19/21a9806eb8240e174fd1ab0cd5b9aa948bb0e05c2f2f55f9d5d7405e6d08/grpcio-1.80.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:92d787312e613754d4d8b9ca6d3297e69994a7912a32fa38c4c4e01c272974b0", size = 12010840, upload-time = "2026-03-30T08:47:43.11Z" },
{ url = "https://files.pythonhosted.org/packages/18/3a/23347d35f76f639e807fb7a36fad3068aed100996849a33809591f26eca6/grpcio-1.80.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac393b58aa16991a2f1144ec578084d544038c12242da3a215966b512904d0f", size = 6567644, upload-time = "2026-03-30T08:47:46.806Z" },
{ url = "https://files.pythonhosted.org/packages/ff/40/96e07ecb604a6a67ae6ab151e3e35b132875d98bc68ec65f3e5ab3e781d7/grpcio-1.80.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:68e5851ac4b9afe07e7f84483803ad167852570d65326b34d54ca560bfa53fb6", size = 7277830, upload-time = "2026-03-30T08:47:49.643Z" },
{ url = "https://files.pythonhosted.org/packages/9b/e2/da1506ecea1f34a5e365964644b35edef53803052b763ca214ba3870c856/grpcio-1.80.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:873ff5d17d68992ef6605330127425d2fc4e77e612fa3c3e0ed4e668685e3140", size = 6783216, upload-time = "2026-03-30T08:47:52.817Z" },
{ url = "https://files.pythonhosted.org/packages/44/83/3b20ff58d0c3b7f6caaa3af9a4174d4023701df40a3f39f7f1c8e7c48f9d/grpcio-1.80.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2bea16af2750fd0a899bf1abd9022244418b55d1f37da2202249ba4ba673838d", size = 7385866, upload-time = "2026-03-30T08:47:55.687Z" },
{ url = "https://files.pythonhosted.org/packages/47/45/55c507599c5520416de5eefecc927d6a0d7af55e91cfffb2e410607e5744/grpcio-1.80.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba0db34f7e1d803a878284cd70e4c63cb6ae2510ba51937bf8f45ba997cefcf7", size = 8391602, upload-time = "2026-03-30T08:47:58.303Z" },
{ url = "https://files.pythonhosted.org/packages/10/bb/dd06f4c24c01db9cf11341b547d0a016b2c90ed7dbbb086a5710df7dd1d7/grpcio-1.80.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8eb613f02d34721f1acf3626dfdb3545bd3c8505b0e52bf8b5710a28d02e8aa7", size = 7826752, upload-time = "2026-03-30T08:48:01.311Z" },
{ url = "https://files.pythonhosted.org/packages/f9/1e/9d67992ba23371fd63d4527096eb8c6b76d74d52b500df992a3343fd7251/grpcio-1.80.0-cp313-cp313-win32.whl", hash = "sha256:93b6f823810720912fd131f561f91f5fed0fda372b6b7028a2681b8194d5d294", size = 4142310, upload-time = "2026-03-30T08:48:04.594Z" },
{ url = "https://files.pythonhosted.org/packages/cf/e6/283326a27da9e2c3038bc93eeea36fb118ce0b2d03922a9cda6688f53c5b/grpcio-1.80.0-cp313-cp313-win_amd64.whl", hash = "sha256:e172cf795a3ba5246d3529e4d34c53db70e888fa582a8ffebd2e6e48bc0cba50", size = 4882833, upload-time = "2026-03-30T08:48:07.363Z" },
{ url = "https://files.pythonhosted.org/packages/c5/6d/e65307ce20f5a09244ba9e9d8476e99fb039de7154f37fb85f26978b59c3/grpcio-1.80.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:3d4147a97c8344d065d01bbf8b6acec2cf86fb0400d40696c8bdad34a64ffc0e", size = 6017376, upload-time = "2026-03-30T08:48:10.005Z" },
{ url = "https://files.pythonhosted.org/packages/69/10/9cef5d9650c72625a699c549940f0abb3c4bfdb5ed45a5ce431f92f31806/grpcio-1.80.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:d8e11f167935b3eb089ac9038e1a063e6d7dbe995c0bb4a661e614583352e76f", size = 12018133, upload-time = "2026-03-30T08:48:12.927Z" },
{ url = "https://files.pythonhosted.org/packages/04/82/983aabaad82ba26113caceeb9091706a0696b25da004fe3defb5b346e15b/grpcio-1.80.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f14b618fc30de822681ee986cfdcc2d9327229dc4c98aed16896761cacd468b9", size = 6574748, upload-time = "2026-03-30T08:48:16.386Z" },
{ url = "https://files.pythonhosted.org/packages/07/d7/031666ef155aa0bf399ed7e19439656c38bbd143779ae0861b038ce82abd/grpcio-1.80.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4ed39fbdcf9b87370f6e8df4e39ca7b38b3e5e9d1b0013c7b6be9639d6578d14", size = 7277711, upload-time = "2026-03-30T08:48:19.627Z" },
{ url = "https://files.pythonhosted.org/packages/e8/43/f437a78f7f4f1d311804189e8f11fb311a01049b2e08557c1068d470cb2e/grpcio-1.80.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2dcc70e9f0ba987526e8e8603a610fb4f460e42899e74e7a518bf3c68fe1bf05", size = 6785372, upload-time = "2026-03-30T08:48:22.373Z" },
{ url = "https://files.pythonhosted.org/packages/93/3d/f6558e9c6296cb4227faa5c43c54a34c68d32654b829f53288313d16a86e/grpcio-1.80.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:448c884b668b868562b1bda833c5fce6272d26e1926ec46747cda05741d302c1", size = 7395268, upload-time = "2026-03-30T08:48:25.638Z" },
{ url = "https://files.pythonhosted.org/packages/06/21/0fdd77e84720b08843c371a2efa6f2e19dbebf56adc72df73d891f5506f0/grpcio-1.80.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a1dc80fe55685b4a543555e6eef975303b36c8db1023b1599b094b92aa77965f", size = 8392000, upload-time = "2026-03-30T08:48:28.974Z" },
{ url = "https://files.pythonhosted.org/packages/f5/68/67f4947ed55d2e69f2cc199ab9fd85e0a0034d813bbeef84df6d2ba4d4b7/grpcio-1.80.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:31b9ac4ad1aa28ffee5503821fafd09e4da0a261ce1c1281c6c8da0423c83b6e", size = 7828477, upload-time = "2026-03-30T08:48:32.054Z" },
{ url = "https://files.pythonhosted.org/packages/44/b6/8d4096691b2e385e8271911a0de4f35f0a6c7d05aff7098e296c3de86939/grpcio-1.80.0-cp314-cp314-win32.whl", hash = "sha256:367ce30ba67d05e0592470428f0ec1c31714cab9ef19b8f2e37be1f4c7d32fae", size = 4218563, upload-time = "2026-03-30T08:48:34.538Z" },
{ url = "https://files.pythonhosted.org/packages/e5/8c/bbe6baf2557262834f2070cf668515fa308b2d38a4bbf771f8f7872a7036/grpcio-1.80.0-cp314-cp314-win_amd64.whl", hash = "sha256:3b01e1f5464c583d2f567b2e46ff0d516ef979978f72091fd81f5ab7fa6e2e7f", size = 5019457, upload-time = "2026-03-30T08:48:37.308Z" },
]
[[package]]
name = "grpcio-health-checking"
version = "1.78.0"
version = "1.80.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "grpcio", marker = "python_full_version >= '3.11'" },
{ name = "protobuf", marker = "python_full_version >= '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/8e/ac/8eb871f4e47b11abfe45497e6187a582ec680ccd7232706d228474a8c7a5/grpcio_health_checking-1.78.0.tar.gz", hash = "sha256:78526d5c60b9b99fd18954b89f86d70033c702e96ad6ccc9749baf16136979b3", size = 17008, upload-time = "2026-02-06T10:01:47.269Z" }
sdist = { url = "https://files.pythonhosted.org/packages/d1/a2/aa3cc47f19c03f8e5287b987317059753141a3af8f66b96d5a64b3be10b8/grpcio_health_checking-1.80.0.tar.gz", hash = "sha256:2cc5f08bc8b816b8655ab6f59c71450063ba20766d31e21a493e912e3560c8b1", size = 17117, upload-time = "2026-03-30T08:54:41.899Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8e/30/dbaf47e2210697e2923b49eb62a6a2c07d5ee55bb40cff1e6cc0c5bb22e1/grpcio_health_checking-1.78.0-py3-none-any.whl", hash = "sha256:309798c098c5de72a9bff7172d788fdf309d246d231db9955b32e7c1c773fbeb", size = 19010, upload-time = "2026-02-06T10:01:37.949Z" },
{ url = "https://files.pythonhosted.org/packages/5e/d1/d97eb30386feff6ac2a662620e2ed68be352e9a182d62e06213db694906a/grpcio_health_checking-1.80.0-py3-none-any.whl", hash = "sha256:d804d4549cbb71e90ca2c7bf0c501060135dfd220aca8e2c54f96d3e79e210e5", size = 19125, upload-time = "2026-03-30T08:53:44.835Z" },
]
[[package]]
name = "grpcio-tools"
version = "1.78.0"
version = "1.80.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "grpcio", marker = "python_full_version >= '3.11'" },
{ name = "protobuf", marker = "python_full_version >= '3.11'" },
{ name = "setuptools", marker = "python_full_version >= '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/8b/d1/cbefe328653f746fd319c4377836a25ba64226e41c6a1d7d5cdbc87a459f/grpcio_tools-1.78.0.tar.gz", hash = "sha256:4b0dd86560274316e155d925158276f8564508193088bc43e20d3f5dff956b2b", size = 5393026, upload-time = "2026-02-06T09:59:59.53Z" }
sdist = { url = "https://files.pythonhosted.org/packages/94/c8/1223f29c84a143ae9a56c084fc96894de0ba84b6e8d60a26241abd81d278/grpcio_tools-1.80.0.tar.gz", hash = "sha256:26052b19c6ce0dcf52d1024496aea3e2bdfa864159f06dc7b97b22d041a94b26", size = 6133212, upload-time = "2026-03-30T08:52:39.077Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5e/70/2118a814a62ab205c905d221064bc09021db83fceeb84764d35c00f0f633/grpcio_tools-1.78.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:ea64e38d1caa2b8468b08cb193f5a091d169b6dbfe1c7dac37d746651ab9d84e", size = 2545568, upload-time = "2026-02-06T09:57:30.308Z" },
{ url = "https://files.pythonhosted.org/packages/2b/a9/68134839dd1a00f964185ead103646d6dd6a396b92ed264eaf521431b793/grpcio_tools-1.78.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:4003fcd5cbb5d578b06176fd45883a72a8f9203152149b7c680ce28653ad9e3a", size = 5708704, upload-time = "2026-02-06T09:57:33.512Z" },
{ url = "https://files.pythonhosted.org/packages/36/1b/b6135aa9534e22051c53e5b9c0853d18024a41c50aaff464b7b47c1ed379/grpcio_tools-1.78.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe6b0081775394c61ec633c9ff5dbc18337100eabb2e946b5c83967fe43b2748", size = 2591905, upload-time = "2026-02-06T09:57:35.338Z" },
{ url = "https://files.pythonhosted.org/packages/41/2b/6380df1390d62b1d18ae18d4d790115abf4997fa29498aa50ba644ecb9d8/grpcio_tools-1.78.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:7e989ad2cd93db52d7f1a643ecaa156ac55bf0484f1007b485979ce8aef62022", size = 2905271, upload-time = "2026-02-06T09:57:37.932Z" },
{ url = "https://files.pythonhosted.org/packages/3a/07/9b369f37c8f4956b68778c044d57390a8f0f3b1cca590018809e75a4fce2/grpcio_tools-1.78.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b874991797e96c41a37e563236c3317ed41b915eff25b292b202d6277d30da85", size = 2656234, upload-time = "2026-02-06T09:57:41.157Z" },
{ url = "https://files.pythonhosted.org/packages/51/61/40eee40e7a54f775a0d4117536532713606b6b177fff5e327f33ad18746e/grpcio_tools-1.78.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:daa8c288b728228377aaf758925692fc6068939d9fa32f92ca13dedcbeb41f33", size = 3105770, upload-time = "2026-02-06T09:57:43.373Z" },
{ url = "https://files.pythonhosted.org/packages/b6/ac/81ee4b728e70e8ba66a589f86469925ead02ed6f8973434e4a52e3576148/grpcio_tools-1.78.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:87e648759b06133199f4bc0c0053e3819f4ec3b900dc399e1097b6065db998b5", size = 3654896, upload-time = "2026-02-06T09:57:45.402Z" },
{ url = "https://files.pythonhosted.org/packages/be/b9/facb3430ee427c800bb1e39588c85685677ea649491d6e0874bd9f3a1c0e/grpcio_tools-1.78.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f3d3ced52bfe39eba3d24f5a8fab4e12d071959384861b41f0c52ca5399d6920", size = 3322529, upload-time = "2026-02-06T09:57:47.292Z" },
{ url = "https://files.pythonhosted.org/packages/c7/de/d7a011df9abfed8c30f0d2077b0562a6e3edc57cb3e5514718e2a81f370a/grpcio_tools-1.78.0-cp310-cp310-win32.whl", hash = "sha256:4bb6ed690d417b821808796221bde079377dff98fdc850ac157ad2f26cda7a36", size = 993518, upload-time = "2026-02-06T09:57:48.836Z" },
{ url = "https://files.pythonhosted.org/packages/c8/5e/f7f60c3ae2281c6b438c3a8455f4a5d5d2e677cf20207864cbee3763da22/grpcio_tools-1.78.0-cp310-cp310-win_amd64.whl", hash = "sha256:0c676d8342fd53bd85a5d5f0d070cd785f93bc040510014708ede6fcb32fada1", size = 1158505, upload-time = "2026-02-06T09:57:50.633Z" },
{ url = "https://files.pythonhosted.org/packages/75/78/280184d19242ed6762bf453c47a70b869b3c5c72a24dc5bf2bf43909faa3/grpcio_tools-1.78.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:6a8b8b7b49f319d29dbcf507f62984fa382d1d10437d75c3f26db5f09c4ac0af", size = 2545904, upload-time = "2026-02-06T09:57:52.769Z" },
{ url = "https://files.pythonhosted.org/packages/5b/51/3c46dea5113f68fe879961cae62d34bb7a3c308a774301b45d614952ee98/grpcio_tools-1.78.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:d62cf3b68372b0c6d722a6165db41b976869811abeabc19c8522182978d8db10", size = 5709078, upload-time = "2026-02-06T09:57:56.389Z" },
{ url = "https://files.pythonhosted.org/packages/e0/2c/dc1ae9ec53182c96d56dfcbf3bcd3e55a8952ad508b188c75bf5fc8993d4/grpcio_tools-1.78.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fa9056742efeaf89d5fe14198af71e5cbc4fbf155d547b89507e19d6025906c6", size = 2591744, upload-time = "2026-02-06T09:57:58.341Z" },
{ url = "https://files.pythonhosted.org/packages/04/63/9b53fc9a9151dd24386785171a4191ee7cb5afb4d983b6a6a87408f41b28/grpcio_tools-1.78.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:e3191af125dcb705aa6bc3856ba81ba99b94121c1b6ebee152e66ea084672831", size = 2905113, upload-time = "2026-02-06T09:58:00.38Z" },
{ url = "https://files.pythonhosted.org/packages/96/b2/0ad8d789f3a2a00893131c140865605fa91671a6e6fcf9da659e1fabba10/grpcio_tools-1.78.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:283239ddbb67ae83fac111c61b25d8527a1dbd355b377cbc8383b79f1329944d", size = 2656436, upload-time = "2026-02-06T09:58:03.038Z" },
{ url = "https://files.pythonhosted.org/packages/09/4d/580f47ce2fc61b093ade747b378595f51b4f59972dd39949f7444b464a03/grpcio_tools-1.78.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ac977508c0db15301ef36d6c79769ec1a6cc4e3bc75735afca7fe7e360cead3a", size = 3106128, upload-time = "2026-02-06T09:58:05.064Z" },
{ url = "https://files.pythonhosted.org/packages/c9/29/d83b2d89f8d10e438bad36b1eb29356510fb97e81e6a608b22ae1890e8e6/grpcio_tools-1.78.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4ff605e25652a0bd13aa8a73a09bc48669c68170902f5d2bf1468a57d5e78771", size = 3654953, upload-time = "2026-02-06T09:58:07.15Z" },
{ url = "https://files.pythonhosted.org/packages/08/71/917ce85633311e54fefd7e6eb1224fb780ef317a4d092766f5630c3fc419/grpcio_tools-1.78.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0197d7b561c79be78ab93d0fe2836c8def470683df594bae3ac89dd8e5c821b2", size = 3322630, upload-time = "2026-02-06T09:58:10.305Z" },
{ url = "https://files.pythonhosted.org/packages/b2/55/3fbf6b26ab46fc79e1e6f7f4e0993cf540263dad639290299fad374a0829/grpcio_tools-1.78.0-cp311-cp311-win32.whl", hash = "sha256:28f71f591f7f39555863ced84fcc209cbf4454e85ef957232f43271ee99af577", size = 993804, upload-time = "2026-02-06T09:58:13.698Z" },
{ url = "https://files.pythonhosted.org/packages/73/86/4affe006d9e1e9e1c6653d6aafe2f8b9188acb2b563cd8ed3a2c7c0e8aec/grpcio_tools-1.78.0-cp311-cp311-win_amd64.whl", hash = "sha256:5a6de495dabf86a3b40b9a7492994e1232b077af9d63080811838b781abbe4e8", size = 1158566, upload-time = "2026-02-06T09:58:15.721Z" },
{ url = "https://files.pythonhosted.org/packages/0c/ae/5b1fa5dd8d560a6925aa52de0de8731d319f121c276e35b9b2af7cc220a2/grpcio_tools-1.78.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:9eb122da57d4cad7d339fc75483116f0113af99e8d2c67f3ef9cae7501d806e4", size = 2546823, upload-time = "2026-02-06T09:58:17.944Z" },
{ url = "https://files.pythonhosted.org/packages/a7/ed/d33ccf7fa701512efea7e7e23333b748848a123e9d3bbafde4e126784546/grpcio_tools-1.78.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:d0c501b8249940b886420e6935045c44cb818fa6f265f4c2b97d5cff9cb5e796", size = 5706776, upload-time = "2026-02-06T09:58:20.944Z" },
{ url = "https://files.pythonhosted.org/packages/c6/69/4285583f40b37af28277fc6b867d636e3b10e1b6a7ebd29391a856e1279b/grpcio_tools-1.78.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:77e5aa2d2a7268d55b1b113f958264681ef1994c970f69d48db7d4683d040f57", size = 2593972, upload-time = "2026-02-06T09:58:23.29Z" },
{ url = "https://files.pythonhosted.org/packages/d7/eb/ecc1885bd6b3147f0a1b7dff5565cab72f01c8f8aa458f682a1c77a9fb08/grpcio_tools-1.78.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:8e3c0b0e6ba5275322ba29a97bf890565a55f129f99a21b121145e9e93a22525", size = 2905531, upload-time = "2026-02-06T09:58:25.406Z" },
{ url = "https://files.pythonhosted.org/packages/ae/a9/511d0040ced66960ca10ba0f082d6b2d2ee6dd61837b1709636fdd8e23b4/grpcio_tools-1.78.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:975d4cb48694e20ebd78e1643e5f1cd94cdb6a3d38e677a8e84ae43665aa4790", size = 2656909, upload-time = "2026-02-06T09:58:28.022Z" },
{ url = "https://files.pythonhosted.org/packages/06/a3/3d2c707e7dee8df842c96fbb24feb2747e506e39f4a81b661def7fed107c/grpcio_tools-1.78.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:553ff18c5d52807dedecf25045ae70bad7a3dbba0b27a9a3cdd9bcf0a1b7baec", size = 3109778, upload-time = "2026-02-06T09:58:30.091Z" },
{ url = "https://files.pythonhosted.org/packages/1f/4b/646811ba241bf05da1f0dc6f25764f1c837f78f75b4485a4210c84b79eae/grpcio_tools-1.78.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8c7f5e4af5a84d2e96c862b1a65e958a538237e268d5f8203a3a784340975b51", size = 3658763, upload-time = "2026-02-06T09:58:32.875Z" },
{ url = "https://files.pythonhosted.org/packages/45/de/0a5ef3b3e79d1011375f5580dfee3a9c1ccb96c5f5d1c74c8cee777a2483/grpcio_tools-1.78.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:96183e2b44afc3f9a761e9d0f985c3b44e03e8bb98e626241a6cbfb3b6f7e88f", size = 3325116, upload-time = "2026-02-06T09:58:34.894Z" },
{ url = "https://files.pythonhosted.org/packages/95/d2/6391b241ad571bc3e71d63f957c0b1860f0c47932d03c7f300028880f9b8/grpcio_tools-1.78.0-cp312-cp312-win32.whl", hash = "sha256:2250e8424c565a88573f7dc10659a0b92802e68c2a1d57e41872c9b88ccea7a6", size = 993493, upload-time = "2026-02-06T09:58:37.242Z" },
{ url = "https://files.pythonhosted.org/packages/7c/8f/7d0d3a39ecad76ccc136be28274daa660569b244fa7d7d0bbb24d68e5ece/grpcio_tools-1.78.0-cp312-cp312-win_amd64.whl", hash = "sha256:217d1fa29de14d9c567d616ead7cb0fef33cde36010edff5a9390b00d52e5094", size = 1158423, upload-time = "2026-02-06T09:58:40.072Z" },
{ url = "https://files.pythonhosted.org/packages/53/ce/17311fb77530420e2f441e916b347515133e83d21cd6cc77be04ce093d5b/grpcio_tools-1.78.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:2d6de1cc23bdc1baafc23e201b1e48c617b8c1418b4d8e34cebf72141676e5fb", size = 2546284, upload-time = "2026-02-06T09:58:43.073Z" },
{ url = "https://files.pythonhosted.org/packages/1d/d3/79e101483115f0e78223397daef71751b75eba7e92a32060c10aae11ca64/grpcio_tools-1.78.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:2afeaad88040894c76656202ff832cb151bceb05c0e6907e539d129188b1e456", size = 5705653, upload-time = "2026-02-06T09:58:45.533Z" },
{ url = "https://files.pythonhosted.org/packages/8b/a7/52fa3ccb39ceeee6adc010056eadfbca8198651c113e418dafebbdf2b306/grpcio_tools-1.78.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:33cc593735c93c03d63efe7a8ba25f3c66f16c52f0651910712490244facad72", size = 2592788, upload-time = "2026-02-06T09:58:48.918Z" },
{ url = "https://files.pythonhosted.org/packages/68/08/682ff6bb548225513d73dc9403742d8975439d7469c673bc534b9bbc83a7/grpcio_tools-1.78.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:2921d7989c4d83b71f03130ab415fa4d66e6693b8b8a1fcbb7a1c67cff19b812", size = 2905157, upload-time = "2026-02-06T09:58:51.478Z" },
{ url = "https://files.pythonhosted.org/packages/b2/66/264f3836a96423b7018e5ada79d62576a6401f6da4e1f4975b18b2be1265/grpcio_tools-1.78.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e6a0df438e82c804c7b95e3f311c97c2f876dcc36376488d5b736b7bcf5a9b45", size = 2656166, upload-time = "2026-02-06T09:58:54.117Z" },
{ url = "https://files.pythonhosted.org/packages/f3/6b/f108276611522e03e98386b668cc7e575eff6952f2db9caa15b2a3b3e883/grpcio_tools-1.78.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e9c6070a9500798225191ef25d0055a15d2c01c9c8f2ee7b681fffa99c98c822", size = 3109110, upload-time = "2026-02-06T09:58:56.891Z" },
{ url = "https://files.pythonhosted.org/packages/6f/c7/cf048dbcd64b3396b3c860a2ffbcc67a8f8c87e736aaa74c2e505a7eee4c/grpcio_tools-1.78.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:394e8b57d85370a62e5b0a4d64c96fcf7568345c345d8590c821814d227ecf1d", size = 3657863, upload-time = "2026-02-06T09:58:59.176Z" },
{ url = "https://files.pythonhosted.org/packages/b6/37/e2736912c8fda57e2e57a66ea5e0bc8eb9a5fb7ded00e866ad22d50afb08/grpcio_tools-1.78.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a3ef700293ab375e111a2909d87434ed0a0b086adf0ce67a8d9cf12ea7765e63", size = 3324748, upload-time = "2026-02-06T09:59:01.242Z" },
{ url = "https://files.pythonhosted.org/packages/1c/5d/726abc75bb5bfc2841e88ea05896e42f51ca7c30cb56da5c5b63058b3867/grpcio_tools-1.78.0-cp313-cp313-win32.whl", hash = "sha256:6993b960fec43a8d840ee5dc20247ef206c1a19587ea49fe5e6cc3d2a09c1585", size = 993074, upload-time = "2026-02-06T09:59:03.085Z" },
{ url = "https://files.pythonhosted.org/packages/c5/68/91b400bb360faf9b177ffb5540ec1c4d06ca923691ddf0f79e2c9683f4da/grpcio_tools-1.78.0-cp313-cp313-win_amd64.whl", hash = "sha256:275ce3c2978842a8cf9dd88dce954e836e590cf7029649ad5d1145b779039ed5", size = 1158185, upload-time = "2026-02-06T09:59:05.036Z" },
{ url = "https://files.pythonhosted.org/packages/cf/5e/278f3831c8d56bae02e3acc570465648eccf0a6bbedcb1733789ac966803/grpcio_tools-1.78.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:8b080d0d072e6032708a3a91731b808074d7ab02ca8fb9847b6a011fdce64cd9", size = 2546270, upload-time = "2026-02-06T09:59:07.426Z" },
{ url = "https://files.pythonhosted.org/packages/a3/d9/68582f2952b914b60dddc18a2e3f9c6f09af9372b6f6120d6cf3ec7f8b4e/grpcio_tools-1.78.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:8c0ad8f8f133145cd7008b49cb611a5c6a9d89ab276c28afa17050516e801f79", size = 5705731, upload-time = "2026-02-06T09:59:09.856Z" },
{ url = "https://files.pythonhosted.org/packages/70/68/feb0f9a48818ee1df1e8b644069379a1e6ef5447b9b347c24e96fd258e5d/grpcio_tools-1.78.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2f8ea092a7de74c6359335d36f0674d939a3c7e1a550f4c2c9e80e0226de8fe4", size = 2593896, upload-time = "2026-02-06T09:59:12.23Z" },
{ url = "https://files.pythonhosted.org/packages/1f/08/a430d8d06e1b8d33f3e48d3f0cc28236723af2f35e37bd5c8db05df6c3aa/grpcio_tools-1.78.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:da422985e0cac822b41822f43429c19ecb27c81ffe3126d0b74e77edec452608", size = 2905298, upload-time = "2026-02-06T09:59:14.458Z" },
{ url = "https://files.pythonhosted.org/packages/71/0a/348c36a3eae101ca0c090c9c3bc96f2179adf59ee0c9262d11cdc7bfe7db/grpcio_tools-1.78.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4fab1faa3fbcb246263e68da7a8177d73772283f9db063fb8008517480888d26", size = 2656186, upload-time = "2026-02-06T09:59:16.949Z" },
{ url = "https://files.pythonhosted.org/packages/1d/3f/18219f331536fad4af6207ade04142292faa77b5cb4f4463787988963df8/grpcio_tools-1.78.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dd9c094f73f734becae3f20f27d4944d3cd8fb68db7338ee6c58e62fc5c3d99f", size = 3109859, upload-time = "2026-02-06T09:59:19.202Z" },
{ url = "https://files.pythonhosted.org/packages/5b/d9/341ea20a44c8e5a3a18acc820b65014c2e3ea5b4f32a53d14864bcd236bc/grpcio_tools-1.78.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:2ed51ce6b833068f6c580b73193fc2ec16468e6bc18354bc2f83a58721195a58", size = 3657915, upload-time = "2026-02-06T09:59:21.839Z" },
{ url = "https://files.pythonhosted.org/packages/fb/f4/5978b0f91611a64371424c109dd0027b247e5b39260abad2eaee66b6aa37/grpcio_tools-1.78.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:05803a5cdafe77c8bdf36aa660ad7a6a1d9e49bc59ce45c1bade2a4698826599", size = 3324724, upload-time = "2026-02-06T09:59:24.402Z" },
{ url = "https://files.pythonhosted.org/packages/b2/80/96a324dba99cfbd20e291baf0b0ae719dbb62b76178c5ce6c788e7331cb1/grpcio_tools-1.78.0-cp314-cp314-win32.whl", hash = "sha256:f7c722e9ce6f11149ac5bddd5056e70aaccfd8168e74e9d34d8b8b588c3f5c7c", size = 1015505, upload-time = "2026-02-06T09:59:26.3Z" },
{ url = "https://files.pythonhosted.org/packages/3b/d1/909e6a05bfd44d46327dc4b8a78beb2bae4fb245ffab2772e350081aaf7e/grpcio_tools-1.78.0-cp314-cp314-win_amd64.whl", hash = "sha256:7d58ade518b546120ec8f0a8e006fc8076ae5df151250ebd7e82e9b5e152c229", size = 1190196, upload-time = "2026-02-06T09:59:28.359Z" },
{ url = "https://files.pythonhosted.org/packages/7a/54/1de67f5080da305a258758a8deb33f85666fa759f56785042a80b114a53f/grpcio_tools-1.80.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:727477b9afa4b53f5ec70cafb41c3965d893835e0d4ea9b542fe3d0d005602bf", size = 2549601, upload-time = "2026-03-30T08:50:09.498Z" },
{ url = "https://files.pythonhosted.org/packages/9a/b4/6d57ea199c5b880d182a2234aafa9a686f9c54c708ea7be75bd19d5aa825/grpcio_tools-1.80.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:85fe8d15f146c62cb76f38d963e256392d287442b9232717d30ae9e3bbda9bc3", size = 5712717, upload-time = "2026-03-30T08:50:15.028Z" },
{ url = "https://files.pythonhosted.org/packages/6a/1a/5505ee2277d368b409c796c78f22ea34a2a517b7d16755247efd663dc7af/grpcio_tools-1.80.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:95f0fffb5ca00519f3b602f938169b4dfa04b165e03258323965a9dfe8cc4d80", size = 2595941, upload-time = "2026-03-30T08:50:17.299Z" },
{ url = "https://files.pythonhosted.org/packages/4e/39/7fc1d16d8b767805079d76365d73e82c88dfaf179034473dbc9fbccedb77/grpcio_tools-1.80.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:7a0106af212748823a6ebd8ffbd9043414216f47cae3835f3187de0a62c415d3", size = 2909304, upload-time = "2026-03-30T08:50:19.485Z" },
{ url = "https://files.pythonhosted.org/packages/97/d8/276ee759755d8f34f2ca5e9d2debd1a59f29f66059fb790bc369f2236c26/grpcio_tools-1.80.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:31fd01a4038b5dfc4ec79504a17061344f670f851833411717fef66920f13cd7", size = 2660269, upload-time = "2026-03-30T08:50:21.266Z" },
{ url = "https://files.pythonhosted.org/packages/51/04/a6bb47942ad52901d777a649324d3203cf19d487f1d446263637f7a5bf12/grpcio_tools-1.80.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:57da9e19607fac4a01c48ead333c0dd15d91ed38794dce1194eda308f73e2038", size = 3109798, upload-time = "2026-03-30T08:50:23.267Z" },
{ url = "https://files.pythonhosted.org/packages/be/50/7ee69b2919916739787d725f205b878e8d1619dd30422b8278e324664669/grpcio_tools-1.80.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:90968f751851abb8b145593609800fa70c837e1c93ba0792c480b1c8d8bc29ef", size = 3658930, upload-time = "2026-03-30T08:50:25.458Z" },
{ url = "https://files.pythonhosted.org/packages/92/61/6d50783092b0e8bbcb04152d5388bf50ecf3ea2f783d95288ff6c3bb00fa/grpcio_tools-1.80.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b69dc5d6376ab43406304d1e2fc61ccf960b287d4325d77c3d45448c37a9d2da", size = 3326562, upload-time = "2026-03-30T08:50:27.809Z" },
{ url = "https://files.pythonhosted.org/packages/ea/58/d272ba549f6b1f0d8504f5fc4cd0a296f2c495a64d6e987fe871c4151557/grpcio_tools-1.80.0-cp310-cp310-win32.whl", hash = "sha256:3e8dcfebe34cb54df095de3d5871a4562a85a29f26d0f8bb41ee2c3dcfb11c3c", size = 997620, upload-time = "2026-03-30T08:50:29.959Z" },
{ url = "https://files.pythonhosted.org/packages/70/5f/9f45a9946a0298711c72ca48b2c1f46a7d0c207a44cd3e4bb59d04556ba3/grpcio_tools-1.80.0-cp310-cp310-win_amd64.whl", hash = "sha256:fc622ed4ca400695f41c9eae3266276c6ba007e4c28164ce53b44e7ccc5e492b", size = 1162466, upload-time = "2026-03-30T08:50:32.242Z" },
{ url = "https://files.pythonhosted.org/packages/8a/d7/225dc91e6cb4f8d4830f16a478a468e9c6f342dcdf8cacc3772cc1d1f607/grpcio_tools-1.80.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:1c43e5c768578fe0c6de3dbfaabe64af642951e1aa05c487cacedda63fa6c6c4", size = 2549937, upload-time = "2026-03-30T08:50:34.651Z" },
{ url = "https://files.pythonhosted.org/packages/97/3d/a3684cb7677f3bea8db434eae02a9ce30135d7a268cd473b1bc8041c4722/grpcio_tools-1.80.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:a225348456575f3ac7851d8e23163195e76d2a905ee340cf73f33da62fba08aa", size = 5713099, upload-time = "2026-03-30T08:50:37.158Z" },
{ url = "https://files.pythonhosted.org/packages/b1/81/5665c697173ec346076358bfbfed0f7386825852494593ca14386478dfee/grpcio_tools-1.80.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a9396f02820d3f51c368c2c9dee15c55c77636c91be48a4d5c702e98d6fe0fdc", size = 2595776, upload-time = "2026-03-30T08:50:39.087Z" },
{ url = "https://files.pythonhosted.org/packages/03/4f/fb81384f08a8226fa079972ba88272ac6277581fc72e8ab234d74c7e065b/grpcio_tools-1.80.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:797c08460cae16b402326eac329aec720dccf45c9f9279b95a352792eb53cf0f", size = 2909144, upload-time = "2026-03-30T08:50:40.922Z" },
{ url = "https://files.pythonhosted.org/packages/4d/9c/c957618f1c2a3195ecf5e83b03edcb364c2c1391f74183cb76e5763fa536/grpcio_tools-1.80.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1872a867eb6217de19edb70a4ce4a374ced9d94293533dfd42fa649713f55bf4", size = 2660477, upload-time = "2026-03-30T08:50:42.766Z" },
{ url = "https://files.pythonhosted.org/packages/42/c7/23913da184febfd4eaf04de256a26bc5ff0411a5feb753e2adcff10fa86a/grpcio_tools-1.80.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:db122ba5ee357e3bb14e8944d69bbebcbdae91d5eace29ed4df3edc53cbc6528", size = 3110164, upload-time = "2026-03-30T08:50:44.761Z" },
{ url = "https://files.pythonhosted.org/packages/af/fa/b25ed85ebdb0396910eaa250b1346d75527d22fca586265416bd4330dcd5/grpcio_tools-1.80.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ddefd48c227e6f4d640fe576fac5fb2c4a8898196f513604c8ec7671b3b3d421", size = 3658988, upload-time = "2026-03-30T08:50:47.546Z" },
{ url = "https://files.pythonhosted.org/packages/60/85/2a55147cc9645e2ed777d1afcd2dc68cb34ba6f6c726bd4378ddb001a5ea/grpcio_tools-1.80.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:970ec058fa469dd6dae6ebc687501c5da670d95dead75f62f5b0933dce2c9794", size = 3326662, upload-time = "2026-03-30T08:50:49.59Z" },
{ url = "https://files.pythonhosted.org/packages/68/ed/b05bee2a992e6f9bda81909692ea920d0896cfa05c5c9dd77ba03f2d22fb/grpcio_tools-1.80.0-cp311-cp311-win32.whl", hash = "sha256:526b4402d47a0e9b31cd6087e42b7674784617916cc73c764e0bc35ed41b4ee5", size = 997969, upload-time = "2026-03-30T08:50:51.539Z" },
{ url = "https://files.pythonhosted.org/packages/b6/9a/cb50c8270e2f6285ff2761130ae257ac4e51789ded4b9d9710ce0381814d/grpcio_tools-1.80.0-cp311-cp311-win_amd64.whl", hash = "sha256:ee101ecda7231770f6a5da1024a9a6ed587a7785f8fe23ab8283f4a1acb3ffe6", size = 1162742, upload-time = "2026-03-30T08:50:54.232Z" },
{ url = "https://files.pythonhosted.org/packages/0c/b9/65929df8c9614792db900a8e45d4997fadbd1734c827da3f0eb1f2fe4866/grpcio_tools-1.80.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:d19d5a8244311947b96f749c417b32d144641c6953f1164824579e1f0a51d040", size = 2550856, upload-time = "2026-03-30T08:50:57.3Z" },
{ url = "https://files.pythonhosted.org/packages/28/17/af1557544d68d1aeca9d9ea53ed16524022d521fec6ba334ab3530e9c1a6/grpcio_tools-1.80.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:fb599a3dc89ed1bb24489a2724b2f6dd4cddbbf0f7bdd69c073477bab0dc7554", size = 5710883, upload-time = "2026-03-30T08:51:00.077Z" },
{ url = "https://files.pythonhosted.org/packages/cc/48/aa9b4f7519ca972bc40d315d5c28f05ca28fa08de13d4e8b69f551b798ab/grpcio_tools-1.80.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:623ee31fc2ff7df9a987b4f3d139c30af17ce46a861ae0e25fb8c112daa32dd8", size = 2598004, upload-time = "2026-03-30T08:51:02.102Z" },
{ url = "https://files.pythonhosted.org/packages/b4/b8/b01371c119924b3beca1fe3f047b1bc2cdc66b3d37f0f3acc9d10c567a43/grpcio_tools-1.80.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b46570a68378539ee2b75a5a43202561f8d753c832798b1047099e3c551cf5d6", size = 2909568, upload-time = "2026-03-30T08:51:04.159Z" },
{ url = "https://files.pythonhosted.org/packages/4f/7c/1108f7bdb58475a7e701ec89b55eb494538b6e76acd211ba0d4cc5fd28e8/grpcio_tools-1.80.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:51caf99c28999e7e0f97e9cea190c1405b7681a57bb2e0631205accd92b43fa4", size = 2660938, upload-time = "2026-03-30T08:51:06.126Z" },
{ url = "https://files.pythonhosted.org/packages/67/59/d1c0063d4cd3b85363c7044ff3e5159d6d5df96e2692a9a5312d9c8cb290/grpcio_tools-1.80.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cdaa1c9aa8d3a87891a96700cadd29beec214711d6522818d207277f6452567c", size = 3113814, upload-time = "2026-03-30T08:51:08.834Z" },
{ url = "https://files.pythonhosted.org/packages/76/21/18d34a4efe524c903cf66b0cfa5260d81f277b6ae668b647edf795df9ce5/grpcio_tools-1.80.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3399b5fd7b59bcffd59c6b9975a969d9f37a3c87f3e3d63c3a09c147907acb0d", size = 3662793, upload-time = "2026-03-30T08:51:11.094Z" },
{ url = "https://files.pythonhosted.org/packages/f3/40/cf2d9295a6bd593244ea703858f8fc2efd315046ca3ef7c6f9ebc5b810fa/grpcio_tools-1.80.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9c6abc08d3485b2aac99bb58afcd31dc6cd4316ce36cf263ff09cb6df15f287f", size = 3329149, upload-time = "2026-03-30T08:51:13.066Z" },
{ url = "https://files.pythonhosted.org/packages/0d/1d/fc34b32167966df20d69429b71dfca83c48434b047a5ac4fd6cd91ca4eed/grpcio_tools-1.80.0-cp312-cp312-win32.whl", hash = "sha256:18c51e07652ac7386fcdbd11866f8d55a795de073337c12447b5805575339f74", size = 997519, upload-time = "2026-03-30T08:51:14.87Z" },
{ url = "https://files.pythonhosted.org/packages/91/98/6d6563cdf51085b75f8ec24605c6f2ce84197571878ca8ab4af949c6be2d/grpcio_tools-1.80.0-cp312-cp312-win_amd64.whl", hash = "sha256:ac6fdd42d5bb18f0d903a067e2825be172deff70cf197164b6f65676cb506c9b", size = 1162407, upload-time = "2026-03-30T08:51:16.793Z" },
{ url = "https://files.pythonhosted.org/packages/44/d9/f7887a4805939e9a85d03744b66fc02575dc1df3c3e8b4d9ec000ee7a33d/grpcio_tools-1.80.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:e7046837859bbfd10b01786056145480155c16b222c9e209215b68d3be13060e", size = 2550319, upload-time = "2026-03-30T08:51:19.117Z" },
{ url = "https://files.pythonhosted.org/packages/57/5a/c8a05b32bd7203f1b9f4c0151090a2d6179d6c97692d32f2066dc29c67a6/grpcio_tools-1.80.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:a447f28958a8fe84ff0d9d3d9473868feb27ee4a9c9c805e66f5b670121cec59", size = 5709681, upload-time = "2026-03-30T08:51:21.991Z" },
{ url = "https://files.pythonhosted.org/packages/82/6b/794350ed645c12c310008f97068f6a6fd927150b0d0d08aad1d909e880b1/grpcio_tools-1.80.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:75f00450e08fe648ad8a1eeb25bc52219679d54cdd02f04dfdddc747309d83f6", size = 2596820, upload-time = "2026-03-30T08:51:24.323Z" },
{ url = "https://files.pythonhosted.org/packages/f9/b2/b39e7b79f7c878135e0784a53cd7260ee77260c8c7f2c9e46bca8e05d017/grpcio_tools-1.80.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3db830eaff1f2c2797328f2fa86c9dcdbd7d81af573a68db81e27afa2182a611", size = 2909193, upload-time = "2026-03-30T08:51:27.025Z" },
{ url = "https://files.pythonhosted.org/packages/10/f3/abe089b058f87f9910c9a458409505cbeb0b3e1c2d993a79721d02ee6a32/grpcio_tools-1.80.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7982b5fe42f012686b667dda12916884de95c4b1c65ff64371fb7232a1474b23", size = 2660197, upload-time = "2026-03-30T08:51:29.392Z" },
{ url = "https://files.pythonhosted.org/packages/09/c3/3f7806ad8b731d8a89fe3c6ed496473abd1ef4c9c42c9e9a8836ce96e377/grpcio_tools-1.80.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6451b3f4eb52d12c7f32d04bf8e0185f80521f3f088ad04b8d222b3a4819c71e", size = 3113144, upload-time = "2026-03-30T08:51:31.671Z" },
{ url = "https://files.pythonhosted.org/packages/fe/f5/415ef205e0b7e75d2a2005df6120145c4f02fda28d7b3715b55d924fe1a4/grpcio_tools-1.80.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:258bc30654a9a2236be4ca8e2ad443e2ac6db7c8cc20454d34cce60265922726", size = 3661897, upload-time = "2026-03-30T08:51:34.849Z" },
{ url = "https://files.pythonhosted.org/packages/e3/d3/2ad54764c2a9547080dd8518f4a4dc7899c7e6e747a1b1de542ce6a12066/grpcio_tools-1.80.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:865a2b8e6334c838976ab02a322cbd55c863d2eaf3c1e1a0255883c63996772a", size = 3328786, upload-time = "2026-03-30T08:51:37.265Z" },
{ url = "https://files.pythonhosted.org/packages/eb/63/23ab7db01f9630ab4f3742a2fc9fbff38b0cfc30c976114f913950664a75/grpcio_tools-1.80.0-cp313-cp313-win32.whl", hash = "sha256:f760ac1722f33e774814c37b6aa0444143f612e85088ead7447a0e9cd306a1f1", size = 997087, upload-time = "2026-03-30T08:51:39.137Z" },
{ url = "https://files.pythonhosted.org/packages/9b/af/b1c1c4423fb49cb7c8e9d2c02196b038c44160b7028b425466743c6c81fa/grpcio_tools-1.80.0-cp313-cp313-win_amd64.whl", hash = "sha256:7843b9ac6ff8ca508424d0dd968bd9a1a4559967e4a290f26be5bd6f04af2234", size = 1162167, upload-time = "2026-03-30T08:51:41.498Z" },
{ url = "https://files.pythonhosted.org/packages/0e/44/7beeee2348f9f412804f5bf80b7d13b81d522bf926a338ae3da46b2213b7/grpcio_tools-1.80.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:12f950470449dbeec78317dbc090add7a00eb6ca812af7b0538ab7441e0a42c3", size = 2550303, upload-time = "2026-03-30T08:51:44.373Z" },
{ url = "https://files.pythonhosted.org/packages/2d/aa/f77dd85409a1855f8c6319ffc69d81e8c3ffe122ee3a7136653e1991d8b6/grpcio_tools-1.80.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:d3f9a376a29c9adf62bb56f7ff5bc81eb4abeaf53d1e7dde5015564832901a51", size = 5709778, upload-time = "2026-03-30T08:51:47.112Z" },
{ url = "https://files.pythonhosted.org/packages/9c/7c/ab7af4883ebdfdc228b853de89fed409703955e8d47285b321a5794856bd/grpcio_tools-1.80.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ba1ffbf2cff71533615e2c5a138ed5569611eec9ae7f9c67b8898e127b54ac0", size = 2597928, upload-time = "2026-03-30T08:51:49.494Z" },
{ url = "https://files.pythonhosted.org/packages/22/e8/4381a963d472e3ab6690ba067ed2b1f1abf8518b10f402678bd2dcb79a54/grpcio_tools-1.80.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:13f60f8d9397c514c6745a967d22b5c8c698347e88deebca1ff2e1b94555e450", size = 2909333, upload-time = "2026-03-30T08:51:52.124Z" },
{ url = "https://files.pythonhosted.org/packages/94/cb/356b5fdf79dd99455b425fb16302fe60995554ceb721afbf3cf770a19208/grpcio_tools-1.80.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:88d77bad5dd3cd5e6f952c4ecdd0ee33e0c02ecfc2e4b0cbee3391ac19e0a431", size = 2660217, upload-time = "2026-03-30T08:51:55.066Z" },
{ url = "https://files.pythonhosted.org/packages/2b/d7/1752018cc2c36b2c5612051379e2e5f59f2dbe612de23e817d2f066a9487/grpcio_tools-1.80.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:017945c3e98a4ed1c4e21399781b4137fc08dfc1f802c8ace2e64ef52d32b142", size = 3113896, upload-time = "2026-03-30T08:51:57.3Z" },
{ url = "https://files.pythonhosted.org/packages/cc/17/695bbe454f70df35c03e22b48c5314683b913d3e6ed35ec90d065418c1ab/grpcio_tools-1.80.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a33e265d4db803495007a6c623eafb0f6b9bb123ff4a0af89e44567dad809b88", size = 3661950, upload-time = "2026-03-30T08:51:59.867Z" },
{ url = "https://files.pythonhosted.org/packages/9c/d0/533d87629ec823c02c9169ee20228f734c264b209dcdf55268b5a14cde0a/grpcio_tools-1.80.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6c129da370c5f85f569be2e545317dda786a60dd51d7deea29b03b0c05f6aac3", size = 3328755, upload-time = "2026-03-30T08:52:02.942Z" },
{ url = "https://files.pythonhosted.org/packages/08/a1/504d7838770c73a9761e8a8ff4869dba1146b44f297ff0ac6641481942d3/grpcio_tools-1.80.0-cp314-cp314-win32.whl", hash = "sha256:25742de5958ae4325249a37e724e7c0e5120f8e302a24a977ebd1737b48a5e97", size = 1019620, upload-time = "2026-03-30T08:52:05.342Z" },
{ url = "https://files.pythonhosted.org/packages/f3/75/8b7cd281c5cdfb4ca2c308f7e9b2799bab2be6e7a9e9212ea5a82e2aecd4/grpcio_tools-1.80.0-cp314-cp314-win_amd64.whl", hash = "sha256:bbf8eeef78fda1966f732f79c1c802fadd5cfd203d845d2af4d314d18569069c", size = 1194210, upload-time = "2026-03-30T08:52:08.105Z" },
]
[[package]]
@@ -966,14 +966,14 @@ wheels = [
[[package]]
name = "langchain-protocol"
version = "0.0.15"
version = "0.0.17"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions", marker = "python_full_version >= '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/4f/24/9777489d6fbbee64af0c8f96d4f840239c408cf694f3394672807dafc490/langchain_protocol-0.0.15.tar.gz", hash = "sha256:9ab2d11ee73944754f10e037e717098d3a6796f0e58afa9cadda6154e7655ade", size = 5862, upload-time = "2026-05-01T22:30:04.748Z" }
sdist = { url = "https://files.pythonhosted.org/packages/44/b3/4e2429876c7a35585618caa2b9f9089f7162a6b50562b614ad82ac11c17e/langchain_protocol-0.0.17.tar.gz", hash = "sha256:e7cbe58c205df4b4fd87dc6d5bb23f10e13b236d0e2e1b0b9d05bc2b648f3eea", size = 6026, upload-time = "2026-06-12T18:39:51.923Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1d/7a/9c97a7b9cbe4c5dc6a44cdb1545450c28f0c8ce89b9c1f0ee7fbad896263/langchain_protocol-0.0.15-py3-none-any.whl", hash = "sha256:461eb794358f83d5e42635a5797799ffec7b4702314e34edf73ac21e75d3ef79", size = 6982, upload-time = "2026-05-01T22:30:03.877Z" },
{ url = "https://files.pythonhosted.org/packages/13/0a/a1bfe72c6ec856e99773bbd96c8086421e554b3693d0142b9ea009c6ac92/langchain_protocol-0.0.17-py3-none-any.whl", hash = "sha256:982a08fe152586ed10d4ff3d538c2e0b5766e5f307cdea325e10be3f2c17cae6", size = 7096, upload-time = "2026-06-12T18:39:50.973Z" },
]
[[package]]
@@ -995,7 +995,7 @@ wheels = [
[[package]]
name = "langgraph-api"
version = "0.8.0"
version = "0.10.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cloudpickle", marker = "python_full_version >= '3.11'" },
@@ -1007,6 +1007,7 @@ dependencies = [
{ name = "httpx", marker = "python_full_version >= '3.11'" },
{ name = "jsonschema-rs", marker = "python_full_version >= '3.11'" },
{ name = "langchain-core", marker = "python_full_version >= '3.11'" },
{ name = "langchain-protocol", marker = "python_full_version >= '3.11'" },
{ name = "langgraph", marker = "python_full_version >= '3.11'" },
{ name = "langgraph-checkpoint", marker = "python_full_version >= '3.11'" },
{ name = "langgraph-runtime-inmem", marker = "python_full_version >= '3.11'" },
@@ -1027,11 +1028,12 @@ dependencies = [
{ name = "uvicorn", marker = "python_full_version >= '3.11'" },
{ name = "uvloop", marker = "python_full_version >= '3.11' and sys_platform != 'win32'" },
{ name = "watchfiles", marker = "python_full_version >= '3.11'" },
{ name = "websockets", marker = "python_full_version >= '3.11'" },
{ name = "zstandard", marker = "python_full_version >= '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e2/43/bbe861a620b3cd3a0e622ade25a90618ec9f960994b88e0e7fb71732ac8c/langgraph_api-0.8.0.tar.gz", hash = "sha256:38f5102fc1c33103697dcf0f01fc3314eb20ca7fc1f02c7b06886c92a822cc3e", size = 671157, upload-time = "2026-04-16T20:32:35.273Z" }
sdist = { url = "https://files.pythonhosted.org/packages/7d/17/a23ecdad3de7e48209bc8d534312ba83e332126ec60da9e6487461b02597/langgraph_api-0.10.0.tar.gz", hash = "sha256:f594a160857e2cd7fb2352bba585111177a4a394625ad0cf5898814754fb7bc1", size = 713903, upload-time = "2026-06-11T14:36:50.469Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d0/77/b5f0784cbb18938f19786ed6e87e0f0a5f143acd8e9aea300817a50c91ed/langgraph_api-0.8.0-py3-none-any.whl", hash = "sha256:09575711d50300a6d6816e76907ff55d4a611167717e20639bfcdd2f76c2fb36", size = 558327, upload-time = "2026-04-16T20:32:33.544Z" },
{ url = "https://files.pythonhosted.org/packages/0e/38/6b0cdcaaed9b3105102b452a5a70fb08894a9511458cf00c061c4725347c/langgraph_api-0.10.0-py3-none-any.whl", hash = "sha256:f4b545bf1936c4e90bed1cc07a6852b1be37e1667007ab4736d800cc18e9f9b3", size = 577475, upload-time = "2026-06-11T14:36:48.838Z" },
]
[[package]]
@@ -1094,7 +1096,7 @@ test = [
requires-dist = [
{ name = "click", specifier = ">=8.1.7" },
{ name = "httpx", specifier = ">=0.24.0" },
{ name = "langgraph-api", marker = "python_full_version >= '3.11' and extra == 'inmem'", specifier = ">=0.5.35,<0.12.0a0" },
{ name = "langgraph-api", marker = "python_full_version >= '3.11' and extra == 'inmem'", specifier = ">=0.5.35,<0.12.0" },
{ name = "langgraph-runtime-inmem", marker = "python_full_version >= '3.11' and extra == 'inmem'", specifier = ">=0.7" },
{ name = "langgraph-sdk", marker = "python_full_version >= '3.11'", specifier = ">=0.1.0" },
{ name = "pathspec", specifier = ">=0.11.0" },
@@ -1143,7 +1145,7 @@ wheels = [
[[package]]
name = "langgraph-runtime-inmem"
version = "0.27.4"
version = "0.30.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "blockbuster", marker = "python_full_version >= '3.11'" },
@@ -1154,9 +1156,9 @@ dependencies = [
{ name = "starlette", marker = "python_full_version >= '3.11'" },
{ name = "structlog", marker = "python_full_version >= '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/15/f7/99ebb2ac0e13cd10b62794de19be5563c1c91dd1e44e11dc1184fda7aae2/langgraph_runtime_inmem-0.27.4.tar.gz", hash = "sha256:ff41a31bf22999ebb11aedde722838aff4a218510d0d8a6c8d14e8f9cc58d00d", size = 115323, upload-time = "2026-04-16T02:00:52.951Z" }
sdist = { url = "https://files.pythonhosted.org/packages/98/19/5d330e22e3ee2569742d3577b4ddfbb6b8e383f2edd9724b4a4b73735717/langgraph_runtime_inmem-0.30.0.tar.gz", hash = "sha256:31954e1de6cd43c284b425243d4faeae818f68b3daca4dbe4313e651b6f5e11d", size = 129940, upload-time = "2026-06-11T14:22:46.985Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/09/3f/1f07b8b1b077d1c7899f80a4d08ab01967f3aae48c40d5db2f8f62a07e97/langgraph_runtime_inmem-0.27.4-py3-none-any.whl", hash = "sha256:0a60a22e5e2b58983e845c709655d82730e5427e5fb2b94eec52b33424fc4ff8", size = 47543, upload-time = "2026-04-16T02:00:51.495Z" },
{ url = "https://files.pythonhosted.org/packages/fe/df/cfb15c70fa4dcab9ea48f8fda9f4ed87d1767eea6e4d2901dc704da297ba/langgraph_runtime_inmem-0.30.0-py3-none-any.whl", hash = "sha256:08a36b83b5e32fe6e30cb25062a1e671a42e2a0206e4043cc95f41198dcbbb12", size = 51762, upload-time = "2026-06-11T14:22:46.012Z" },
]
[[package]]
@@ -1177,7 +1179,7 @@ wheels = [
[[package]]
name = "langsmith"
version = "0.8.0"
version = "0.8.18"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx", marker = "python_full_version >= '3.11'" },
@@ -1187,12 +1189,13 @@ dependencies = [
{ name = "requests", marker = "python_full_version >= '3.11'" },
{ name = "requests-toolbelt", marker = "python_full_version >= '3.11'" },
{ name = "uuid-utils", marker = "python_full_version >= '3.11'" },
{ name = "websockets", marker = "python_full_version >= '3.11'" },
{ name = "xxhash", marker = "python_full_version >= '3.11'" },
{ name = "zstandard", marker = "python_full_version >= '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a8/64/95f1f013531395f4e8ed73caeee780f65c7c58fe028cb543f8937b45611b/langsmith-0.8.0.tar.gz", hash = "sha256:59fe5b2a56bbbe14a08aa76691f84b49e8675dd21e11b57d80c6db8c08bac2e3", size = 4432996, upload-time = "2026-04-30T22:13:07.341Z" }
sdist = { url = "https://files.pythonhosted.org/packages/9a/d9/a6681aa9847bbbc5ec21abe20a5e233b94e5edcfe39624db607ac7e8ccb4/langsmith-0.8.18.tar.gz", hash = "sha256:32dde9c0e67e053e0fb738921fc8ced768af7b8fa83d7a0e3fd63597cf8776dd", size = 4526988, upload-time = "2026-06-19T13:12:17.123Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f3/e1/a4be2e696c9473bb53298df398237da5674704d781d4b748ed35aeef592a/langsmith-0.8.0-py3-none-any.whl", hash = "sha256:12cc4bc5622b835a6d841964d6034df3617bdb912dae0c1381fd0a68a9b3a3ef", size = 393268, upload-time = "2026-04-30T22:13:05.56Z" },
{ url = "https://files.pythonhosted.org/packages/03/70/0e0cc80a3b064c8d6c8d697c3125ed86e39d5a7393ec6dc8b07cb1cf13c4/langsmith-0.8.18-py3-none-any.whl", hash = "sha256:3940183349993faef48e6c7d08e4822ee9cefd906b362d0e3c2d650314d2f282", size = 508108, upload-time = "2026-06-19T13:12:15.348Z" },
]
[package.optional-dependencies]
@@ -1730,11 +1733,11 @@ wheels = [
[[package]]
name = "pyjwt"
version = "2.12.1"
version = "2.13.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/c2/27/a3b6e5bf6ff856d2509292e95c8f57f0df7017cf5394921fc4e4ef40308a/pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b", size = 102564, upload-time = "2026-03-13T19:27:37.25Z" }
sdist = { url = "https://files.pythonhosted.org/packages/3b/81/58d0ac84e1ef3a3843791d6954d94c0b33d526c75eeb1efbce9d0a4c4077/pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423", size = 107515, upload-time = "2026-05-21T19:54:36.618Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c", size = 29726, upload-time = "2026-03-13T19:27:35.677Z" },
{ url = "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728", size = 31274, upload-time = "2026-05-21T19:54:35.362Z" },
]
[[package]]
@@ -2029,15 +2032,15 @@ wheels = [
[[package]]
name = "starlette"
version = "1.0.1"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio", marker = "python_full_version >= '3.11'" },
{ name = "typing-extensions", marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/08/a3/84e821cc54b4ab50ae6dbc6ac3800a651b65ec35f045cc73785380654057/starlette-1.0.1.tar.gz", hash = "sha256:512399c5f1de7fac99c88572212ded9ddeddef2fb32afa82d724000e88b38f4f", size = 2659596, upload-time = "2026-05-21T21:58:58.433Z" }
sdist = { url = "https://files.pythonhosted.org/packages/eb/e3/7c1dc7381d9f8ab7d854328ebfa884e62cb3f3d8549ddfd37c7814f42afa/starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0", size = 2703240, upload-time = "2026-06-12T09:23:11.602Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/e1/b2df4bc09a1e51ff664c1e17018a4274b42e5e9352e4a478ea540512dc88/starlette-1.0.1-py3-none-any.whl", hash = "sha256:7c0e69b2ee1c848bd54669d908500117a3ee13de603a21427e5c6fc1adf98dcd", size = 72802, upload-time = "2026-05-21T21:58:56.551Z" },
{ url = "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl", hash = "sha256:c7372aae11c3c3f26a42df7bd626cec2f47d03483d261d369516a615a53714c6", size = 73632, upload-time = "2026-06-12T09:23:10.017Z" },
]
[[package]]
+24 -79
View File
@@ -1,100 +1,45 @@
<div align="center">
<a href="https://www.langchain.com/langgraph">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="../../.github/images/logo-dark.svg">
<source media="(prefers-color-scheme: light)" srcset="../../.github/images/logo-light.svg">
<img alt="LangGraph Logo" src=".github/images/logo-dark.svg" width="50%">
</picture>
</a>
</div>
# 🦜🕸️ LangGraph
<div align="center">
<h3>Low-level orchestration framework for building stateful agents.</h3>
</div>
[![PyPI - Version](https://img.shields.io/pypi/v/langgraph?label=%20)](https://pypi.org/project/langgraph/#history)
[![PyPI - License](https://img.shields.io/pypi/l/langgraph)](https://opensource.org/licenses/MIT)
[![PyPI - Downloads](https://img.shields.io/pepy/dt/langgraph)](https://pypistats.org/packages/langgraph)
[![Open Issues](https://img.shields.io/github/issues-raw/langchain-ai/langgraph)](https://github.com/langchain-ai/langgraph/issues)
[![Twitter](https://img.shields.io/twitter/url/https/twitter.com/langchain_oss.svg?style=social&label=Follow%20%40LangChain)](https://x.com/langchain_oss)
<div align="center">
<a href="https://opensource.org/licenses/MIT" target="_blank"><img src="https://img.shields.io/pypi/l/langgraph" alt="PyPI - License"></a>
<a href="https://pypistats.org/packages/langgraph" target="_blank"><img src="https://img.shields.io/pepy/dt/langgraph" alt="PyPI - Downloads"></a>
<a href="https://pypi.org/project/langgraph/" target="_blank"><img src="https://img.shields.io/pypi/v/langgraph.svg?label=%20" alt="Version"></a>
<a href="https://github.com/langchain-ai/langgraph/issues" target="_blank"><img src="https://img.shields.io/github/issues-raw/langchain-ai/langgraph" alt="Open Issues"></a>
<a href="https://docs.langchain.com/oss/python/langgraph/overview" target="_blank"><img src="https://img.shields.io/badge/docs-latest-blue" alt="Docs"></a>
<a href="https://x.com/langchain_oss" target="_blank"><img src="https://img.shields.io/twitter/url/https/twitter.com/langchain_oss.svg?style=social&label=Follow%20%40LangChain" alt="Twitter / X"></a>
</div>
Looking for the JS/TS version? Check out [LangGraph.js](https://github.com/langchain-ai/langgraphjs).
<br>
To help you ship LangGraph apps to production faster, check out [LangSmith](https://www.langchain.com/langsmith).
[LangSmith](https://www.langchain.com/langsmith) is a unified developer platform for building, testing, and monitoring LLM applications.
Trusted by companies shaping the future of agents including Klarna, Replit, Elastic, and more LangGraph is a low-level orchestration framework for building, managing, and deploying long-running, stateful agents.
## Quick Install
## Get started
Install LangGraph:
```
pip install -U langgraph
```bash
uv add langgraph
```
Create a simple workflow:
## 🤔 What is this?
```python
from langgraph.graph import START, StateGraph
from typing_extensions import TypedDict
LangGraph is a low-level orchestration framework for building, managing, and deploying long-running, stateful agents. LangGraph provides the infrastructure for durable execution, streaming, human-in-the-loop, persistence, memory, and more.
We recommend you use LangGraph when you have advanced needs that require a combination of deterministic and agentic workflows, heavy customization, and carefully controlled latency. Use [LangChain](https://docs.langchain.com/oss/python/langchain/overview) when you want to quickly build agents and applications powered by LLMs using pre-built agent architectures and model integrations.
class State(TypedDict):
text: str
LangChain [agents](https://docs.langchain.com/oss/python/langchain/agents) are built on top of LangGraph in order to provide durable execution, streaming, human-in-the-loop, persistence, and more. (You do not need to know LangGraph for basic LangChain agent usage.)
Trusted by companies shaping the future of agents including Klarna, Replit, Elastic, and more LangGraph is used to ship AI applications at scale.
def node_a(state: State) -> dict:
return {"text": state["text"] + "a"}
## 📖 Documentation
For full documentation, see the [API reference](https://reference.langchain.com/python/langgraph/). For conceptual guides, tutorials, and examples on using LangGraph, see the [LangGraph Docs](https://docs.langchain.com/oss/python/langgraph/overview). Get started with the [LangGraph Quickstart](https://docs.langchain.com/oss/python/langgraph/quickstart).
def node_b(state: State) -> dict:
return {"text": state["text"] + "b"}
## 📕 Releases & Versioning
See our [Releases](https://docs.langchain.com/oss/python/release-policy) and [Versioning](https://docs.langchain.com/oss/python/versioning) policies.
graph = StateGraph(State)
graph.add_node("node_a", node_a)
graph.add_node("node_b", node_b)
graph.add_edge(START, "node_a")
graph.add_edge("node_a", "node_b")
## 💁 Contributing
print(graph.compile().invoke({"text": ""}))
# {'text': 'ab'}
```
As an open-source project in a rapidly developing field, we are extremely open to contributions, whether it be in the form of a new feature, improved infrastructure, or better documentation.
Get started with the [LangGraph Quickstart](https://docs.langchain.com/oss/python/langgraph/quickstart).
To quickly build agents with LangChain's `create_agent` (built on LangGraph), see the [LangChain Agents documentation](https://docs.langchain.com/oss/python/langchain/agents).
## Core benefits
LangGraph provides low-level supporting infrastructure for *any* long-running, stateful workflow or agent. LangGraph does not abstract prompts or architecture, and provides the following central benefits:
- [Durable execution](https://docs.langchain.com/oss/python/langgraph/durable-execution): Build agents that persist through failures and can run for extended periods, automatically resuming from exactly where they left off.
- [Human-in-the-loop](https://docs.langchain.com/oss/python/langgraph/interrupts): Seamlessly incorporate human oversight by inspecting and modifying agent state at any point during execution.
- [Comprehensive memory](https://docs.langchain.com/oss/python/langgraph/memory): Create truly stateful agents with both short-term working memory for ongoing reasoning and long-term persistent memory across sessions.
- [Debugging with LangSmith](http://www.langchain.com/langsmith): Gain deep visibility into complex agent behavior with visualization tools that trace execution paths, capture state transitions, and provide detailed runtime metrics.
- [Production-ready deployment](https://docs.langchain.com/langsmith/app-development): Deploy sophisticated agent systems confidently with scalable infrastructure designed to handle the unique challenges of stateful, long-running workflows.
## LangGraphs ecosystem
While LangGraph can be used standalone, it also integrates seamlessly with any LangChain product, giving developers a full suite of tools for building agents. To improve your LLM application development, pair LangGraph with:
- [LangSmith](http://www.langchain.com/langsmith) — Helpful for agent evals and observability. Debug poor-performing LLM app runs, evaluate agent trajectories, gain visibility in production, and improve performance over time.
- [LangSmith Deployment](https://docs.langchain.com/langsmith/deployments) — Deploy and scale agents effortlessly with a purpose-built deployment platform for long running, stateful workflows. Discover, reuse, configure, and share agents across teams — and iterate quickly with visual prototyping in [LangGraph Studio](https://docs.langchain.com/oss/python/langgraph/studio).
- [LangChain](https://docs.langchain.com/oss/python/langchain/overview) Provides integrations and composable components to streamline LLM application development.
> [!NOTE]
> Looking for the JS version of LangGraph? See the [JS repo](https://github.com/langchain-ai/langgraphjs) and the [JS docs](https://docs.langchain.com/oss/javascript/langgraph/overview).
## Additional resources
- [Guides](https://docs.langchain.com/oss/python/langgraph/guides): Quick, actionable code snippets for topics such as streaming, adding memory & persistence, and design patterns (e.g. branching, subgraphs, etc.).
- [Reference](https://reference.langchain.com/python/langgraph/): Detailed reference on core classes, methods, how to use the graph and checkpointing APIs, and higher-level prebuilt components.
- [Examples](https://docs.langchain.com/oss/python/langgraph/agentic-rag): Guided examples on getting started with LangGraph.
- [LangChain Forum](https://forum.langchain.com/): Connect with the community and share all of your technical questions, ideas, and feedback.
- [LangChain Academy](https://academy.langchain.com/courses/intro-to-langgraph): Learn the basics of LangGraph in our free, structured course.
- [Case studies](https://www.langchain.com/built-with-langgraph): Hear how industry leaders use LangGraph to ship AI applications at scale.
For detailed information on how to contribute, see the [Contributing Guide](https://docs.langchain.com/oss/python/contributing/overview).
## Acknowledgements
@@ -20,6 +20,7 @@ from langchain_core.runnables.config import (
from langgraph.checkpoint.base import CheckpointMetadata
from langgraph._internal._constants import (
_CHECKPOINT_COORDINATE_KEYS,
CONF,
CONFIG_KEY_CHECKPOINT_ID,
CONFIG_KEY_CHECKPOINT_MAP,
@@ -342,6 +343,28 @@ def ensure_config(*configs: RunnableConfig | None) -> RunnableConfig:
if _is_not_empty(v)
},
)
# An explicit config that supplies its own checkpoint coordinate (a
# thread_id, or any checkpoint_ns/checkpoint_id/checkpoint_map) is addressing
# its own checkpoint lineage, so drop the inherited ambient configurable
# rather than merging over it: a child graph invoked inside a parent node
# would otherwise write its checkpoints under the parent's namespace and
# never find them again. An explicit thread_id resets even when it equals the
# ambient one, since a child reusing the parent's thread id still addresses
# its own root namespace, not the parent task's. Configs that only refine
# other keys keep the ambient and shallow-merge over it below.
if empty.get(CONF):
for config in configs:
if config is None:
continue
explicit_configurable = config.get(CONF)
if not explicit_configurable:
continue
if any(
_is_not_empty(explicit_configurable.get(k))
for k in _CHECKPOINT_COORDINATE_KEYS
):
empty[CONF] = {}
break
for config in configs:
if config is None:
continue
@@ -95,6 +95,15 @@ NULL_TASK_ID = sys.intern("00000000-0000-0000-0000-000000000000")
OVERWRITE = sys.intern("__overwrite__")
# dict key for the overwrite value, used as `{'__overwrite__': value}`
# Checkpoint coordinate keys: when any of these appear in an explicit
# configurable, the caller is addressing its own checkpoint lineage.
_CHECKPOINT_COORDINATE_KEYS = (
CONFIG_KEY_THREAD_ID,
CONFIG_KEY_CHECKPOINT_NS,
CONFIG_KEY_CHECKPOINT_ID,
CONFIG_KEY_CHECKPOINT_MAP,
)
# redefined to avoid circular import with langgraph.constants
_TAG_HIDDEN = sys.intern("langsmith:hidden")
@@ -1,5 +1,6 @@
from __future__ import annotations
import uuid
from collections.abc import Callable, Mapping
from datetime import datetime, timezone
from typing import Any, cast
@@ -34,6 +35,17 @@ def empty_checkpoint() -> Checkpoint:
)
def exit_delta_task_id(step: int, task_id: str) -> str:
"""Synthetic task id for exit-mode DeltaChannel writes.
Embeds the superstep in the first UUID group so `ORDER BY task_id, idx`
preserves chronological order while remaining a valid RFC UUID (required by
Postgres `checkpoint_writes.task_id uuid` columns).
"""
parts = str(uuid.UUID(task_id)).split("-")
return f"{step:08d}-{parts[1]}-{parts[2]}-{parts[3]}-{parts[4]}"
def delta_channels_to_snapshot(
channels: Mapping[str, BaseChannel],
counters_since_delta_snapshot: Mapping[str, tuple[int, int]],
@@ -58,6 +70,42 @@ def delta_channels_to_snapshot(
return result
def advance_delta_counters(
channels: Mapping[str, BaseChannel],
prev_metadata: Mapping[str, Any] | None,
updated_channels: set[str] | None,
) -> tuple[dict[str, tuple[int, int]], set[str]]:
"""Advance per-delta-channel `(updates, supersteps)` counters one step.
Mirrors the counter bookkeeping in `PregelLoop._put_checkpoint`: every
superstep bumps `supersteps` for all delta channels and `updates` for
those written this step, then channels that hit their snapshot cadence
are reset to `(0, 0)`.
Used by `update_state` (which creates a delta checkpoint outside the
main loop) so the written checkpoint carries a correct
`counters_since_delta_snapshot` without it, the supersteps-based
`get_delta_channel_history` walk can't locate the seed. Returns
`(new_counters, channels_to_snapshot)`; callers drop `(0, 0)` entries
before writing the metadata field.
"""
prev = dict((prev_metadata or {}).get("counters_since_delta_snapshot") or {})
updated = updated_channels or set()
new_counters: dict[str, tuple[int, int]] = {}
for name, ch in channels.items():
if not isinstance(ch, DeltaChannel):
continue
u, s = prev.get(name, (0, 0))
s += 1
if name in updated:
u += 1
new_counters[name] = (u, s)
channels_to_snapshot = delta_channels_to_snapshot(channels, new_counters)
for k in channels_to_snapshot:
new_counters[k] = (0, 0)
return new_counters, channels_to_snapshot
def create_checkpoint(
checkpoint: Checkpoint,
channels: Mapping[str, BaseChannel] | None,
+2 -1
View File
@@ -102,6 +102,7 @@ from langgraph.pregel._checkpoint import (
create_checkpoint,
delta_channels_to_snapshot,
empty_checkpoint,
exit_delta_task_id,
)
from langgraph.pregel._executor import (
AsyncBackgroundExecutor,
@@ -1272,7 +1273,7 @@ class PregelLoop:
},
)
for (step, tid), entries in grouped.items():
synth_tid = f"{step:08d}-{tid}"
synth_tid = exit_delta_task_id(step, tid)
if self.checkpointer_put_writes_accepts_task_path:
fut = self.submit(
self.checkpointer_put_writes,
+63 -12
View File
@@ -130,6 +130,7 @@ from langgraph.pregel._algo import (
from langgraph.pregel._call import identifier
from langgraph.pregel._checkpoint import (
achannels_from_checkpoint,
advance_delta_counters,
channels_from_checkpoint,
copy_checkpoint,
create_checkpoint,
@@ -2032,15 +2033,40 @@ class Pregel(
checkpointer.get_next_version,
self.trigger_to_nodes,
)
checkpoint = create_checkpoint(checkpoint, channels, step + 1)
# Advance delta-channel snapshot counters for this manual super-
# step so the written checkpoint carries a correct
# `counters_since_delta_snapshot` (mirrors the main loop). Without
# it, the supersteps-based delta history walk can't find the seed.
updated_channel_names = {
c for task in run_tasks for c, _ in task.writes if c != PUSH
}
new_counters, channels_to_snapshot = advance_delta_counters(
channels,
saved.metadata if saved else None,
updated_channel_names,
)
# Keep `updated_channels` at its default (None) — matching the
# historical checkpoint shape here — so resume/trigger semantics
# (e.g. deferred nodes) are unaffected. `get_next_version` /
# `channels_to_snapshot` are no-ops unless a delta channel snapshots.
checkpoint = create_checkpoint(
checkpoint,
channels,
step + 1,
get_next_version=checkpointer.get_next_version,
channels_to_snapshot=channels_to_snapshot,
)
update_metadata: dict[str, Any] = {
"source": "update",
"step": step + 1,
"parents": saved.metadata.get("parents", {}) if saved else {},
}
if non_zero := {k: v for k, v in new_counters.items() if v != (0, 0)}:
update_metadata["counters_since_delta_snapshot"] = non_zero
next_config = checkpointer.put(
checkpoint_config,
checkpoint,
{
"source": "update",
"step": step + 1,
"parents": saved.metadata.get("parents", {}) if saved else {},
},
update_metadata,
get_new_channel_versions(
checkpoint_previous_versions, checkpoint["channel_versions"]
),
@@ -2500,16 +2526,41 @@ class Pregel(
checkpointer.get_next_version,
self.trigger_to_nodes,
)
checkpoint = create_checkpoint(checkpoint, channels, step + 1)
# Advance delta-channel snapshot counters for this manual super-
# step so the written checkpoint carries a correct
# `counters_since_delta_snapshot` (mirrors the main loop). Without
# it, the supersteps-based delta history walk can't find the seed.
updated_channel_names = {
c for task in run_tasks for c, _ in task.writes if c != PUSH
}
new_counters, channels_to_snapshot = advance_delta_counters(
channels,
saved.metadata if saved else None,
updated_channel_names,
)
# Keep `updated_channels` at its default (None) — matching the
# historical checkpoint shape here — so resume/trigger semantics
# (e.g. deferred nodes) are unaffected. `get_next_version` /
# `channels_to_snapshot` are no-ops unless a delta channel snapshots.
checkpoint = create_checkpoint(
checkpoint,
channels,
step + 1,
get_next_version=checkpointer.get_next_version,
channels_to_snapshot=channels_to_snapshot,
)
update_metadata: dict[str, Any] = {
"source": "update",
"step": step + 1,
"parents": saved.metadata.get("parents", {}) if saved else {},
}
if non_zero := {k: v for k, v in new_counters.items() if v != (0, 0)}:
update_metadata["counters_since_delta_snapshot"] = non_zero
# save checkpoint, after applying writes
next_config = await checkpointer.aput(
checkpoint_config,
checkpoint,
{
"source": "update",
"step": step + 1,
"parents": saved.metadata.get("parents", {}) if saved else {},
},
update_metadata,
get_new_channel_versions(
checkpoint_previous_versions, checkpoint["channel_versions"]
),
+62 -7
View File
@@ -132,13 +132,23 @@ class GraphRunStream:
def abort(self) -> None:
"""Stop the run early.
Closes the mux and marks the stream exhausted. The graph
iterator is dropped; any in-flight nodes see the closure on
their next yield point. Idempotent.
Closes the underlying graph iterator (propagating `GeneratorExit`
so in-flight nodes and subgraphs are cancelled), closes the mux,
and marks the stream exhausted. Idempotent.
"""
if self._exhausted:
return
self._exhausted = True
graph_iter = self._graph_iter
self._graph_iter = None
if (
graph_iter is not None
and (close := getattr(graph_iter, "close", None)) is not None
):
try:
close()
except Exception:
pass
try:
self._mux.close()
except Exception:
@@ -348,6 +358,8 @@ class AsyncGraphRunStream:
self._scope_list: list[str] = list(mux.scope)
self._pump_cond = asyncio.Condition()
self._pumping = False
self._anext_task: asyncio.Future[Any] | None = None
self._aborting = False
for key in mux.native_keys:
setattr(self, key, mux.extensions[key])
if wire_pump:
@@ -407,7 +419,25 @@ class AsyncGraphRunStream:
try:
try:
part = await self._graph_aiter.__anext__()
# Run the pull as a child task so `abort()` can cancel it
# mid-flight. Cancelling propagates `CancelledError` into the
# graph generator frame -> Pregel loop -> nested subgraph
# nodes, which a bare `aclose()` cannot do while the generator
# is running ("asynchronous generator is already running").
self._anext_task = asyncio.ensure_future(self._graph_aiter.__anext__())
try:
part = await self._anext_task
except asyncio.CancelledError:
if self._aborting:
# Abort-initiated cancel: stop gracefully.
self._exhausted = True
return False
# Genuine external cancel of this task: also stop the
# in-flight pull, then propagate.
self._anext_task.cancel()
raise
finally:
self._anext_task = None
event = convert_to_protocol_event(part)
self._observe_event(event)
await self._mux.apush(event)
@@ -428,15 +458,40 @@ class AsyncGraphRunStream:
async def abort(self) -> None:
"""Stop the run early.
Marks the stream exhausted, wakes any pump-waiters, and closes
the mux. Any `apush` blocked on backpressure wakes and returns
without appending. Idempotent.
Marks the stream exhausted and wakes any pump-waiters. Cancels an
in-flight pull if one is running, then closes the underlying graph
iterator, so running nodes and nested subgraphs are cancelled
whether or not a pump is mid-pull. Closes the mux; any `apush`
blocked on backpressure wakes and returns without appending.
Idempotent.
"""
async with self._pump_cond:
if self._exhausted:
return
self._exhausted = True
self._aborting = True
graph_aiter = self._graph_aiter
self._graph_aiter = None
anext_task = self._anext_task
self._pump_cond.notify_all()
# If a pump is mid-pull, cancel it so the cancellation propagates
# into running nodes and nested subgraphs. Once it settles the
# generator is no longer running, so the `aclose()` below is a safe
# final cleanup (and handles the no-in-flight-pull case directly).
if anext_task is not None and not anext_task.done():
anext_task.cancel()
try:
await anext_task
except (asyncio.CancelledError, Exception):
pass
if (
graph_aiter is not None
and (aclose := getattr(graph_aiter, "aclose", None)) is not None
):
try:
await aclose()
except Exception:
pass
try:
await self._mux.aclose()
except Exception:
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "langgraph"
version = "1.2.5"
version = "1.2.6"
description = "Building stateful, multi-actor applications with LLMs"
authors = []
requires-python = ">=3.10"
@@ -6,6 +6,7 @@ channel), lazy stub creation when no parent exists, and proper read-path
reconstruction via ancestor walks.
"""
import uuid
from typing import Annotated, Any
import pytest
@@ -17,10 +18,28 @@ from typing_extensions import TypedDict
from langgraph.channels.delta import DeltaChannel
from langgraph.graph import START, StateGraph
from langgraph.graph.message import _messages_delta_reducer
from langgraph.pregel._checkpoint import exit_delta_task_id
pytestmark = pytest.mark.anyio
def test_exit_delta_task_id_is_valid_uuid_and_ordered() -> None:
"""Exit-mode synthetic task ids must parse as UUID and sort by superstep."""
tid = "4f7226e4-0270-bf16-1ef8-fb321bef9f3d"
id1 = exit_delta_task_id(1, tid)
id7 = exit_delta_task_id(7, tid)
uuid.UUID(id1)
uuid.UUID(id7)
assert id1 < id7
assert id1.split("-")[0] == "00000001"
assert id7.split("-")[0] == "00000007"
assert id1.endswith("-0270-bf16-1ef8-fb321bef9f3d")
with pytest.raises(ValueError):
uuid.UUID(f"00000001-{tid}")
def _build_graph(
checkpointer: InMemorySaver,
*,
+29 -40
View File
@@ -2755,23 +2755,26 @@ def test_in_one_fan_out_state_graph_waiting_edge_plus_regular(
"answer": "doc1,doc2,doc3,doc4",
}
assert [*app.stream({"query": "what is weather in sf"})] in (
[
{"rewrite_query": {"query": "query: what is weather in sf"}},
{"qa": {"answer": ""}},
{"analyzer_one": {"query": "analyzed: query: what is weather in sf"}},
{"retriever_two": {"docs": ["doc3", "doc4"]}},
{"retriever_one": {"docs": ["doc1", "doc2"]}},
{"qa": {"answer": "doc1,doc2,doc3,doc4"}},
],
[
{"rewrite_query": {"query": "query: what is weather in sf"}},
{"analyzer_one": {"query": "analyzed: query: what is weather in sf"}},
{"qa": {"answer": ""}},
{"retriever_two": {"docs": ["doc3", "doc4"]}},
{"retriever_one": {"docs": ["doc1", "doc2"]}},
{"qa": {"answer": "doc1,doc2,doc3,doc4"}},
],
rewrite = {"rewrite_query": {"query": "query: what is weather in sf"}}
analyzer = {"analyzer_one": {"query": "analyzed: query: what is weather in sf"}}
empty_qa = {"qa": {"answer": ""}}
retriever_one_result = {"retriever_one": {"docs": ["doc1", "doc2"]}}
retriever_two_result = {"retriever_two": {"docs": ["doc3", "doc4"]}}
def assert_valid_stream_order(
chunks: list[dict[str, Any]], terminal: dict[str, Any]
) -> None:
assert chunks[0] == rewrite
assert chunks[-1] == terminal
middle = chunks[1:-1]
assert sorted(middle, key=repr) == sorted(
[empty_qa, analyzer, retriever_one_result, retriever_two_result], key=repr
)
assert middle.index(analyzer) < middle.index(retriever_one_result)
assert_valid_stream_order(
[*app.stream({"query": "what is weather in sf"})],
{"qa": {"answer": "doc1,doc2,doc3,doc4"}},
)
app_w_interrupt = workflow.compile(
@@ -2780,25 +2783,9 @@ def test_in_one_fan_out_state_graph_waiting_edge_plus_regular(
)
config = {"configurable": {"thread_id": "1"}}
assert [
c for c in app_w_interrupt.stream({"query": "what is weather in sf"}, config)
] in (
[
{"rewrite_query": {"query": "query: what is weather in sf"}},
{"qa": {"answer": ""}},
{"analyzer_one": {"query": "analyzed: query: what is weather in sf"}},
{"retriever_two": {"docs": ["doc3", "doc4"]}},
{"retriever_one": {"docs": ["doc1", "doc2"]}},
{"__interrupt__": ()},
],
[
{"rewrite_query": {"query": "query: what is weather in sf"}},
{"analyzer_one": {"query": "analyzed: query: what is weather in sf"}},
{"qa": {"answer": ""}},
{"retriever_two": {"docs": ["doc3", "doc4"]}},
{"retriever_one": {"docs": ["doc1", "doc2"]}},
{"__interrupt__": ()},
],
assert_valid_stream_order(
[c for c in app_w_interrupt.stream({"query": "what is weather in sf"}, config)],
{"__interrupt__": ()},
)
assert [c for c in app_w_interrupt.stream(None, config)] == [
@@ -6291,14 +6278,15 @@ def test_sync_streaming_with_functional_api() -> None:
rather than have all the results arrive at once after the graph has completed.
The time of arrival between the two updates corresponding to the two `slow` tasks
should be greater than the time delay between the two tasks.
should be roughly the task delay. If results are buffered until graph completion,
the two updates arrive back-to-back instead.
"""
time_delay = 0.05
@task()
def slow() -> dict:
time.sleep(time_delay) # Simulate a delay of 10 ms
time.sleep(time_delay)
return {"tic": time.monotonic()}
@entrypoint()
@@ -6316,8 +6304,9 @@ def test_sync_streaming_with_functional_api() -> None:
assert len(arrival_times) == 2
delta = arrival_times[1] - arrival_times[0]
# Delta cannot be less than 10 ms if it is streaming as results are generated.
assert delta > time_delay
# Allow a small amount of scheduler jitter while still verifying the chunks
# arrived separately rather than back-to-back after graph completion.
assert delta > time_delay * 0.8
def test_entrypoint_without_checkpointer() -> None:
@@ -607,6 +607,164 @@ class TestStreamV2Async:
_ = await anext(aiter(run.values))
assert run._exhausted is True
async def test_abort_cancels_running_subgraph(self) -> None:
class CountState(TypedDict):
count: int
runs: list[int] = []
async def sub_node(state: CountState) -> dict:
runs.append(state["count"] + 1)
await asyncio.sleep(0.05)
return {"count": state["count"] + 1}
sub_graph = (
StateGraph(CountState)
.add_node("sub_node", sub_node)
.set_entry_point("sub_node")
.add_conditional_edges(
"sub_node",
lambda s: END if s["count"] >= 10 else "sub_node",
)
.compile()
)
async def main_node(state: CountState) -> None:
await sub_graph.ainvoke({"count": 0})
main_graph = (
StateGraph(CountState)
.add_node("main_node", main_node)
.set_entry_point("main_node")
.compile()
)
run = await main_graph.astream_events({"count": 0}, version="v3")
async for e in run:
if (
e["method"] == "values"
and e["params"]["namespace"]
and e["params"]["data"]["count"] >= 2
):
break
await run.abort()
runs_at_abort = len(runs)
# Give the (now-cancelled) subgraph a chance to keep looping.
await asyncio.sleep(0.3)
assert len(runs) == runs_at_abort
assert len(runs) < 10
async def test_abort_cancels_deeply_nested_subgraph(self) -> None:
class CountState(TypedDict):
count: int
runs: list[int] = []
async def deep_node(state: CountState) -> dict:
runs.append(state["count"] + 1)
await asyncio.sleep(0.05)
return {"count": state["count"] + 1}
# Deepest graph loops until count >= 10.
graph = (
StateGraph(CountState)
.add_node("deep_node", deep_node)
.set_entry_point("deep_node")
.add_conditional_edges(
"deep_node",
lambda s: END if s["count"] >= 10 else "deep_node",
)
.compile()
)
# Wrap it three times: graph -> subgraph -> subgraph -> subgraph.
for _ in range(3):
async def caller(state: CountState, _child: Any = graph) -> dict:
return await _child.ainvoke({"count": 0})
graph = (
StateGraph(CountState)
.add_node("caller", caller)
.set_entry_point("caller")
.compile()
)
run = await graph.astream_events({"count": 0}, version="v3")
async for e in run:
if (
e["method"] == "values"
and e["params"]["namespace"]
and e["params"]["data"]["count"] >= 2
):
break
await run.abort()
runs_at_abort = len(runs)
# Give the (now-cancelled) nested subgraph a chance to keep looping.
await asyncio.sleep(0.3)
assert len(runs) == runs_at_abort
assert len(runs) < 10
async def test_abort_cancels_subgraph_during_inflight_pump(self) -> None:
class CountState(TypedDict):
count: int
started = asyncio.Event()
cancelled = asyncio.Event()
async def sub_node(state: CountState) -> dict:
started.set()
try:
# Long-running node: still in flight when abort fires.
await asyncio.sleep(5)
except asyncio.CancelledError:
cancelled.set()
raise
return {"count": state["count"] + 1}
sub_graph = (
StateGraph(CountState)
.add_node("sub_node", sub_node)
.set_entry_point("sub_node")
.compile()
)
async def main_node(state: CountState) -> None:
await sub_graph.ainvoke({"count": 0})
main_graph = (
StateGraph(CountState)
.add_node("main_node", main_node)
.set_entry_point("main_node")
.compile()
)
run = await main_graph.astream_events({"count": 0}, version="v3")
# A consumer task drives the pump. Once the subgraph node is
# running, no further event is produced, so the consumer parks
# inside _apump_next awaiting graph_aiter.__anext__() — the
# generator is "running" and a plain aclose() would raise.
async def consume() -> None:
async for _e in run:
pass
consumer = asyncio.create_task(consume())
try:
await asyncio.wait_for(started.wait(), timeout=2.0)
# Let the consumer drain and park in __anext__.
await asyncio.sleep(0.05)
# Abort from a different task while the consumer is in __anext__.
await run.abort()
# The in-flight subgraph node must observe cancellation.
await asyncio.wait_for(cancelled.wait(), timeout=2.0)
finally:
consumer.cancel()
try:
await consumer
except asyncio.CancelledError:
pass
async def test_extensions_has_native_keys(self) -> None:
run = await _build_simple_graph().astream_events(
{"value": "x", "items": []}, version="v3"
@@ -639,3 +639,49 @@ def test_stateful_namespace_isolation(
"broccoli round 2",
"Veggie: broccoli round 2",
]
def test_child_with_own_thread_id_keeps_namespace(
sync_checkpointer: BaseCheckpointSaver,
) -> None:
"""A child graph invoked from inside a parent node with its own thread_id
must store and read its checkpoint under its own namespace, not inherit the
parent task's checkpoint_ns.
"""
class ChildState(TypedDict):
count: int
def child_node(state: ChildState) -> dict:
return {"count": (state.get("count") or 0) + 1}
child = (
StateGraph(ChildState)
.add_node("n", child_node)
.add_edge(START, "n")
.compile(checkpointer=sync_checkpointer)
)
child_thread = str(uuid4())
child_config = {"configurable": {"thread_id": child_thread}}
def parent_node(state: ParentState) -> dict:
child.invoke({}, config=child_config)
return {"result": "ok"}
parent = (
StateGraph(ParentState)
.add_node("p", parent_node)
.add_edge(START, "p")
.compile(checkpointer=sync_checkpointer)
)
parent_config = {"configurable": {"thread_id": str(uuid4())}}
parent.invoke({"result": ""}, config=parent_config)
state1 = child.get_state(child_config)
assert state1.values.get("count") == 1
assert state1.config["configurable"]["checkpoint_ns"] == ""
parent.invoke({"result": ""}, config=parent_config)
state2 = child.get_state(child_config)
assert state2.values.get("count") == 2
@@ -660,3 +660,50 @@ async def test_stateful_namespace_isolation_async(
"broccoli round 2",
"Veggie: broccoli round 2",
]
@NEEDS_CONTEXTVARS
async def test_child_with_own_thread_id_keeps_namespace_async(
async_checkpointer: BaseCheckpointSaver,
) -> None:
"""A child graph invoked from inside a parent node with its own thread_id
must store and read its checkpoint under its own namespace, not inherit the
parent task's checkpoint_ns.
"""
class ChildState(TypedDict):
count: int
def child_node(state: ChildState) -> dict:
return {"count": (state.get("count") or 0) + 1}
child = (
StateGraph(ChildState)
.add_node("n", child_node)
.add_edge(START, "n")
.compile(checkpointer=async_checkpointer)
)
child_thread = str(uuid4())
child_config = {"configurable": {"thread_id": child_thread}}
async def parent_node(state: ParentState) -> dict:
await child.ainvoke({}, config=child_config)
return {"result": "ok"}
parent = (
StateGraph(ParentState)
.add_node("p", parent_node)
.add_edge(START, "p")
.compile(checkpointer=async_checkpointer)
)
parent_config = {"configurable": {"thread_id": str(uuid4())}}
await parent.ainvoke({"result": ""}, config=parent_config)
state1 = await child.aget_state(child_config)
assert state1.values.get("count") == 1
assert state1.config["configurable"]["checkpoint_ns"] == ""
await parent.ainvoke({"result": ""}, config=parent_config)
state2 = await child.aget_state(child_config)
assert state2.values.get("count") == 2
+89
View File
@@ -506,6 +506,95 @@ def test_ensure_config_configurable_later_wins_per_key() -> None:
assert merged["configurable"]["only_b"] == "B"
def test_ensure_config_explicit_configurable_replaces_ambient() -> None:
# An explicit checkpoint coordinate (here a new thread_id) starts a fresh
# lineage and drops the ambient run context (e.g. a parent task's
# checkpoint_ns), so a child graph does not inherit it.
from langchain_core.runnables.config import var_child_runnable_config
token = var_child_runnable_config.set(
{"configurable": {"checkpoint_ns": "p:parent-task", "checkpoint_id": "cid"}}
)
try:
merged = ensure_config({"configurable": {"thread_id": "child"}})
finally:
var_child_runnable_config.reset(token)
assert merged["configurable"]["thread_id"] == "child"
assert "checkpoint_ns" not in merged["configurable"]
assert "checkpoint_id" not in merged["configurable"]
def test_ensure_config_ambient_inherited_when_no_explicit_configurable() -> None:
# With no explicit configurable, the ambient run context is inherited
# unchanged (stateless subgraph / interrupt-resume pattern).
from langchain_core.runnables.config import var_child_runnable_config
token = var_child_runnable_config.set(
{"configurable": {"checkpoint_ns": "p:parent-task"}}
)
try:
merged = ensure_config({"tags": ["t"]})
finally:
var_child_runnable_config.reset(token)
assert merged["configurable"]["checkpoint_ns"] == "p:parent-task"
def test_ensure_config_explicit_configurables_still_merge_over_ambient() -> None:
# A new thread_id drops the ambient, but explicit configs still shallow-merge
# among themselves, so a with_config(...) value (ls_agent_type) survives
# alongside an invoke-time thread_id.
from langchain_core.runnables.config import var_child_runnable_config
token = var_child_runnable_config.set(
{"configurable": {"checkpoint_ns": "p:parent-task"}}
)
try:
merged = ensure_config(
{"configurable": {"ls_agent_type": "root"}},
{"configurable": {"thread_id": "child"}},
)
finally:
var_child_runnable_config.reset(token)
assert merged["configurable"]["ls_agent_type"] == "root"
assert merged["configurable"]["thread_id"] == "child"
assert "checkpoint_ns" not in merged["configurable"]
def test_ensure_config_non_coordinate_config_keeps_ambient_checkpoint_ns() -> None:
# A nested subagent is invoked with a non-coordinate configurable key
# (ls_agent_type) and no thread_id; it must keep the inherited checkpoint_ns
# so it stays a discoverable child of the parent run (deepagents `task` tool).
from langchain_core.runnables.config import var_child_runnable_config
token = var_child_runnable_config.set(
{"configurable": {"thread_id": "parent", "checkpoint_ns": "p:parent-task"}}
)
try:
merged = ensure_config({"configurable": {"ls_agent_type": "subagent"}})
finally:
var_child_runnable_config.reset(token)
assert merged["configurable"]["ls_agent_type"] == "subagent"
assert merged["configurable"]["checkpoint_ns"] == "p:parent-task"
assert merged["configurable"]["thread_id"] == "parent"
def test_ensure_config_same_thread_id_still_clears_ambient() -> None:
# A child that reuses the parent's thread_id is still addressing its own root
# namespace on that thread, so the parent task's checkpoint_ns must not leak
# in; otherwise the child writes state that get_state cannot read back.
from langchain_core.runnables.config import var_child_runnable_config
token = var_child_runnable_config.set(
{"configurable": {"thread_id": "shared", "checkpoint_ns": "p:parent-task"}}
)
try:
merged = ensure_config({"configurable": {"thread_id": "shared"}})
finally:
var_child_runnable_config.reset(token)
assert merged["configurable"]["thread_id"] == "shared"
assert "checkpoint_ns" not in merged["configurable"]
def test_ensure_config_merges_metadata_across_configs() -> None:
a = {"metadata": {"user_id": "U1"}}
b = {"metadata": {"correlation_id": "C1"}}
+260 -197
View File
@@ -173,14 +173,14 @@ wheels = [
[[package]]
name = "bleach"
version = "6.3.0"
version = "6.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "webencodings" },
]
sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533, upload-time = "2025-10-27T17:57:39.211Z" }
sdist = { url = "https://files.pythonhosted.org/packages/48/3c/e12ac860709702bd5ebeb9b56a4fe334f1001246ee1b8f2b7ee28912df7d/bleach-6.4.0.tar.gz", hash = "sha256:4202482733d85cedd04e59fcb2f89f4e4c7c385a78d3c3c23c30446843a37452", size = 204857, upload-time = "2026-06-05T13:01:13.734Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437, upload-time = "2025-10-27T17:57:37.538Z" },
{ url = "https://files.pythonhosted.org/packages/58/9d/40b6267367182187139a4000b82a3b287d84d745bccd808e75d916920e9d/bleach-6.4.0-py3-none-any.whl", hash = "sha256:4b6b6a54fff2e69a3dde9d21cc6301220bee3c3cb792187d11403fd795031081", size = 165109, upload-time = "2026-06-05T13:01:12.504Z" },
]
[package.optional-dependencies]
@@ -523,63 +523,75 @@ toml = [
{ name = "tomli", marker = "python_full_version <= '3.11'" },
]
[[package]]
name = "croniter"
version = "6.2.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "python-dateutil", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/df/de/5832661ed55107b8a09af3f0a2e71e0957226a59eb1dcf0a445cce6daf20/croniter-6.2.2.tar.gz", hash = "sha256:ba60832a5ec8e12e51b8691c3309a113d1cf6526bdf1a48150ce8ec7a532d0ab", size = 113762, upload-time = "2026-03-15T08:43:48.112Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d0/39/783980e78cb92c2d7bdb1fc7dbc86e94ccc6d58224d76a7f1f51b6c51e30/croniter-6.2.2-py3-none-any.whl", hash = "sha256:a5d17b1060974d36251ea4faf388233eca8acf0d09cbd92d35f4c4ac8f279960", size = 45422, upload-time = "2026-03-15T08:43:46.626Z" },
]
[[package]]
name = "cryptography"
version = "46.0.7"
version = "48.0.1"
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/47/93/ac8f3d5ff04d54bc814e961a43ae5b0b146154c89c61b47bb07557679b18/cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5", size = 750652, upload-time = "2026-04-08T01:57:54.692Z" }
sdist = { url = "https://files.pythonhosted.org/packages/12/45/870e7f4bef50e5f53b9f51d4428aee5290eedf58ba443f16b1ebb7ab8e66/cryptography-48.0.1.tar.gz", hash = "sha256:266f4ee051abb2f725b74ef8072b521ce1feacf685a3364fa6a6b45548db791a", size = 832989, upload-time = "2026-06-09T22:32:31.8Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0b/5d/4a8f770695d73be252331e60e526291e3df0c9b27556a90a6b47bccca4c2/cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4", size = 7179869, upload-time = "2026-04-08T01:56:17.157Z" },
{ url = "https://files.pythonhosted.org/packages/5f/45/6d80dc379b0bbc1f9d1e429f42e4cb9e1d319c7a8201beffd967c516ea01/cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325", size = 4275492, upload-time = "2026-04-08T01:56:19.36Z" },
{ url = "https://files.pythonhosted.org/packages/4a/9a/1765afe9f572e239c3469f2cb429f3ba7b31878c893b246b4b2994ffe2fe/cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308", size = 4426670, upload-time = "2026-04-08T01:56:21.415Z" },
{ url = "https://files.pythonhosted.org/packages/8f/3e/af9246aaf23cd4ee060699adab1e47ced3f5f7e7a8ffdd339f817b446462/cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77", size = 4280275, upload-time = "2026-04-08T01:56:23.539Z" },
{ url = "https://files.pythonhosted.org/packages/0f/54/6bbbfc5efe86f9d71041827b793c24811a017c6ac0fd12883e4caa86b8ed/cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1", size = 4928402, upload-time = "2026-04-08T01:56:25.624Z" },
{ url = "https://files.pythonhosted.org/packages/2d/cf/054b9d8220f81509939599c8bdbc0c408dbd2bdd41688616a20731371fe0/cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef", size = 4459985, upload-time = "2026-04-08T01:56:27.309Z" },
{ url = "https://files.pythonhosted.org/packages/f9/46/4e4e9c6040fb01c7467d47217d2f882daddeb8828f7df800cb806d8a2288/cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de", size = 3990652, upload-time = "2026-04-08T01:56:29.095Z" },
{ url = "https://files.pythonhosted.org/packages/36/5f/313586c3be5a2fbe87e4c9a254207b860155a8e1f3cca99f9910008e7d08/cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83", size = 4279805, upload-time = "2026-04-08T01:56:30.928Z" },
{ url = "https://files.pythonhosted.org/packages/69/33/60dfc4595f334a2082749673386a4d05e4f0cf4df8248e63b2c3437585f2/cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb", size = 4892883, upload-time = "2026-04-08T01:56:32.614Z" },
{ url = "https://files.pythonhosted.org/packages/c7/0b/333ddab4270c4f5b972f980adef4faa66951a4aaf646ca067af597f15563/cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b", size = 4459756, upload-time = "2026-04-08T01:56:34.306Z" },
{ url = "https://files.pythonhosted.org/packages/d2/14/633913398b43b75f1234834170947957c6b623d1701ffc7a9600da907e89/cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85", size = 4410244, upload-time = "2026-04-08T01:56:35.977Z" },
{ url = "https://files.pythonhosted.org/packages/10/f2/19ceb3b3dc14009373432af0c13f46aa08e3ce334ec6eff13492e1812ccd/cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e", size = 4674868, upload-time = "2026-04-08T01:56:38.034Z" },
{ url = "https://files.pythonhosted.org/packages/1a/bb/a5c213c19ee94b15dfccc48f363738633a493812687f5567addbcbba9f6f/cryptography-46.0.7-cp311-abi3-win32.whl", hash = "sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457", size = 3026504, upload-time = "2026-04-08T01:56:39.666Z" },
{ url = "https://files.pythonhosted.org/packages/2b/02/7788f9fefa1d060ca68717c3901ae7fffa21ee087a90b7f23c7a603c32ae/cryptography-46.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b", size = 3488363, upload-time = "2026-04-08T01:56:41.893Z" },
{ url = "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:d151173275e1728cf7839aaa80c34fe550c04ddb27b34f48c232193df8db5842", size = 7119671, upload-time = "2026-04-08T01:56:44Z" },
{ url = "https://files.pythonhosted.org/packages/74/66/e3ce040721b0b5599e175ba91ab08884c75928fbeb74597dd10ef13505d2/cryptography-46.0.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:db0f493b9181c7820c8134437eb8b0b4792085d37dbb24da050476ccb664e59c", size = 4268551, upload-time = "2026-04-08T01:56:46.071Z" },
{ url = "https://files.pythonhosted.org/packages/03/11/5e395f961d6868269835dee1bafec6a1ac176505a167f68b7d8818431068/cryptography-46.0.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ebd6daf519b9f189f85c479427bbd6e9c9037862cf8fe89ee35503bd209ed902", size = 4408887, upload-time = "2026-04-08T01:56:47.718Z" },
{ url = "https://files.pythonhosted.org/packages/40/53/8ed1cf4c3b9c8e611e7122fb56f1c32d09e1fff0f1d77e78d9ff7c82653e/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:b7b412817be92117ec5ed95f880defe9cf18a832e8cafacf0a22337dc1981b4d", size = 4271354, upload-time = "2026-04-08T01:56:49.312Z" },
{ url = "https://files.pythonhosted.org/packages/50/46/cf71e26025c2e767c5609162c866a78e8a2915bbcfa408b7ca495c6140c4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:fbfd0e5f273877695cb93baf14b185f4878128b250cc9f8e617ea0c025dfb022", size = 4905845, upload-time = "2026-04-08T01:56:50.916Z" },
{ url = "https://files.pythonhosted.org/packages/c0/ea/01276740375bac6249d0a971ebdf6b4dc9ead0ee0a34ef3b5a88c1a9b0d4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:ffca7aa1d00cf7d6469b988c581598f2259e46215e0140af408966a24cf086ce", size = 4444641, upload-time = "2026-04-08T01:56:52.882Z" },
{ url = "https://files.pythonhosted.org/packages/3d/4c/7d258f169ae71230f25d9f3d06caabcff8c3baf0978e2b7d65e0acac3827/cryptography-46.0.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:60627cf07e0d9274338521205899337c5d18249db56865f943cbe753aa96f40f", size = 3967749, upload-time = "2026-04-08T01:56:54.597Z" },
{ url = "https://files.pythonhosted.org/packages/b5/2a/2ea0767cad19e71b3530e4cad9605d0b5e338b6a1e72c37c9c1ceb86c333/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:80406c3065e2c55d7f49a9550fe0c49b3f12e5bfff5dedb727e319e1afb9bf99", size = 4270942, upload-time = "2026-04-08T01:56:56.416Z" },
{ url = "https://files.pythonhosted.org/packages/41/3d/fe14df95a83319af25717677e956567a105bb6ab25641acaa093db79975d/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:c5b1ccd1239f48b7151a65bc6dd54bcfcc15e028c8ac126d3fada09db0e07ef1", size = 4871079, upload-time = "2026-04-08T01:56:58.31Z" },
{ url = "https://files.pythonhosted.org/packages/9c/59/4a479e0f36f8f378d397f4eab4c850b4ffb79a2f0d58704b8fa0703ddc11/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:d5f7520159cd9c2154eb61eb67548ca05c5774d39e9c2c4339fd793fe7d097b2", size = 4443999, upload-time = "2026-04-08T01:57:00.508Z" },
{ url = "https://files.pythonhosted.org/packages/28/17/b59a741645822ec6d04732b43c5d35e4ef58be7bfa84a81e5ae6f05a1d33/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fcd8eac50d9138c1d7fc53a653ba60a2bee81a505f9f8850b6b2888555a45d0e", size = 4399191, upload-time = "2026-04-08T01:57:02.654Z" },
{ url = "https://files.pythonhosted.org/packages/59/6a/bb2e166d6d0e0955f1e9ff70f10ec4b2824c9cfcdb4da772c7dd69cc7d80/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:65814c60f8cc400c63131584e3e1fad01235edba2614b61fbfbfa954082db0ee", size = 4655782, upload-time = "2026-04-08T01:57:04.592Z" },
{ url = "https://files.pythonhosted.org/packages/95/b6/3da51d48415bcb63b00dc17c2eff3a651b7c4fed484308d0f19b30e8cb2c/cryptography-46.0.7-cp314-cp314t-win32.whl", hash = "sha256:fdd1736fed309b4300346f88f74cd120c27c56852c3838cab416e7a166f67298", size = 3002227, upload-time = "2026-04-08T01:57:06.91Z" },
{ url = "https://files.pythonhosted.org/packages/32/a8/9f0e4ed57ec9cebe506e58db11ae472972ecb0c659e4d52bbaee80ca340a/cryptography-46.0.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e06acf3c99be55aa3b516397fe42f5855597f430add9c17fa46bf2e0fb34c9bb", size = 3475332, upload-time = "2026-04-08T01:57:08.807Z" },
{ url = "https://files.pythonhosted.org/packages/a7/7f/cd42fc3614386bc0c12f0cb3c4ae1fc2bbca5c9662dfed031514911d513d/cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4", size = 7165618, upload-time = "2026-04-08T01:57:10.645Z" },
{ url = "https://files.pythonhosted.org/packages/a5/d0/36a49f0262d2319139d2829f773f1b97ef8aef7f97e6e5bd21455e5a8fb5/cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7", size = 4270628, upload-time = "2026-04-08T01:57:12.885Z" },
{ url = "https://files.pythonhosted.org/packages/8a/6c/1a42450f464dda6ffbe578a911f773e54dd48c10f9895a23a7e88b3e7db5/cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832", size = 4415405, upload-time = "2026-04-08T01:57:14.923Z" },
{ url = "https://files.pythonhosted.org/packages/9a/92/4ed714dbe93a066dc1f4b4581a464d2d7dbec9046f7c8b7016f5286329e2/cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163", size = 4272715, upload-time = "2026-04-08T01:57:16.638Z" },
{ url = "https://files.pythonhosted.org/packages/b7/e6/a26b84096eddd51494bba19111f8fffe976f6a09f132706f8f1bf03f51f7/cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2", size = 4918400, upload-time = "2026-04-08T01:57:19.021Z" },
{ url = "https://files.pythonhosted.org/packages/c7/08/ffd537b605568a148543ac3c2b239708ae0bd635064bab41359252ef88ed/cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067", size = 4450634, upload-time = "2026-04-08T01:57:21.185Z" },
{ url = "https://files.pythonhosted.org/packages/16/01/0cd51dd86ab5b9befe0d031e276510491976c3a80e9f6e31810cce46c4ad/cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0", size = 3985233, upload-time = "2026-04-08T01:57:22.862Z" },
{ url = "https://files.pythonhosted.org/packages/92/49/819d6ed3a7d9349c2939f81b500a738cb733ab62fbecdbc1e38e83d45e12/cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba", size = 4271955, upload-time = "2026-04-08T01:57:24.814Z" },
{ url = "https://files.pythonhosted.org/packages/80/07/ad9b3c56ebb95ed2473d46df0847357e01583f4c52a85754d1a55e29e4d0/cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006", size = 4879888, upload-time = "2026-04-08T01:57:26.88Z" },
{ url = "https://files.pythonhosted.org/packages/b8/c7/201d3d58f30c4c2bdbe9b03844c291feb77c20511cc3586daf7edc12a47b/cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0", size = 4449961, upload-time = "2026-04-08T01:57:29.068Z" },
{ url = "https://files.pythonhosted.org/packages/a5/ef/649750cbf96f3033c3c976e112265c33906f8e462291a33d77f90356548c/cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85", size = 4401696, upload-time = "2026-04-08T01:57:31.029Z" },
{ url = "https://files.pythonhosted.org/packages/41/52/a8908dcb1a389a459a29008c29966c1d552588d4ae6d43f3a1a4512e0ebe/cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e", size = 4664256, upload-time = "2026-04-08T01:57:33.144Z" },
{ url = "https://files.pythonhosted.org/packages/4b/fa/f0ab06238e899cc3fb332623f337a7364f36f4bb3f2534c2bb95a35b132c/cryptography-46.0.7-cp38-abi3-win32.whl", hash = "sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246", size = 3013001, upload-time = "2026-04-08T01:57:34.933Z" },
{ url = "https://files.pythonhosted.org/packages/d2/f1/00ce3bde3ca542d1acd8f8cfa38e446840945aa6363f9b74746394b14127/cryptography-46.0.7-cp38-abi3-win_amd64.whl", hash = "sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3", size = 3472985, upload-time = "2026-04-08T01:57:36.714Z" },
{ url = "https://files.pythonhosted.org/packages/63/0c/dca8abb64e7ca4f6b2978769f6fea5ad06686a190cec381f0a796fdcaaba/cryptography-46.0.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:fc9ab8856ae6cf7c9358430e49b368f3108f050031442eaeb6b9d87e4dcf4e4f", size = 3476879, upload-time = "2026-04-08T01:57:38.664Z" },
{ url = "https://files.pythonhosted.org/packages/3a/ea/075aac6a84b7c271578d81a2f9968acb6e273002408729f2ddff517fed4a/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d3b99c535a9de0adced13d159c5a9cf65c325601aa30f4be08afd680643e9c15", size = 4219700, upload-time = "2026-04-08T01:57:40.625Z" },
{ url = "https://files.pythonhosted.org/packages/6c/7b/1c55db7242b5e5612b29fc7a630e91ee7a6e3c8e7bf5406d22e206875fbd/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d02c738dacda7dc2a74d1b2b3177042009d5cab7c7079db74afc19e56ca1b455", size = 4385982, upload-time = "2026-04-08T01:57:42.725Z" },
{ url = "https://files.pythonhosted.org/packages/cb/da/9870eec4b69c63ef5925bf7d8342b7e13bc2ee3d47791461c4e49ca212f4/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:04959522f938493042d595a736e7dbdff6eb6cc2339c11465b3ff89343b65f65", size = 4219115, upload-time = "2026-04-08T01:57:44.939Z" },
{ url = "https://files.pythonhosted.org/packages/f4/72/05aa5832b82dd341969e9a734d1812a6aadb088d9eb6f0430fc337cc5a8f/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:3986ac1dee6def53797289999eabe84798ad7817f3e97779b5061a95b0ee4968", size = 4385479, upload-time = "2026-04-08T01:57:46.86Z" },
{ url = "https://files.pythonhosted.org/packages/20/2a/1b016902351a523aa2bd446b50a5bc1175d7a7d1cf90fe2ef904f9b84ebc/cryptography-46.0.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:258514877e15963bd43b558917bc9f54cf7cf866c38aa576ebf47a77ddbc43a4", size = 3412829, upload-time = "2026-04-08T01:57:48.874Z" },
{ url = "https://files.pythonhosted.org/packages/1b/bc/ee4137cbbe105652c0ee4252792b78fc8e7afa4b8e61d9d5dc05a7f45731/cryptography-48.0.1-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:3e4a1a3232eef2e6c732827d5722db29a0cc8b27af2a4d865b094cf954be9ca1", size = 8008324, upload-time = "2026-06-09T22:31:00.702Z" },
{ url = "https://files.pythonhosted.org/packages/d5/85/6379d42181bfc713094f081360fc5784d6c816b599d45e7f082502d173ce/cryptography-48.0.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:32143b24adb918f078134e1e230f1eb8cc04886b92c28b5f0041aaf3e5699225", size = 4696243, upload-time = "2026-06-09T22:32:33.446Z" },
{ url = "https://files.pythonhosted.org/packages/9c/87/c85d147b53323c7eb4d850920c8901377323c2a0ff8d79c262d4fee89aa2/cryptography-48.0.1-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0d27a5696721ef7a672b8c810f6aded391058e0b9486e63e6d93baf765da691", size = 4713235, upload-time = "2026-06-09T22:31:40.141Z" },
{ url = "https://files.pythonhosted.org/packages/79/58/67cbf8cf1ee7c54b439ca07bbecf8362c07afc11a3724fea70f745784add/cryptography-48.0.1-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:eb86ce1af36fe65041b6db9a8bb064ee621a7e5fded0f80d475ec243477cd242", size = 4702323, upload-time = "2026-06-09T22:31:42.191Z" },
{ url = "https://files.pythonhosted.org/packages/89/c6/24266ac10c47f6cd2a865f4446062b466da1d1f10b27189eac00e61bf0c9/cryptography-48.0.1-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:b024e784ad6c077ee0147b35ea9cbfc1e34e1fd4c1dcca214c2794d73a12df08", size = 5300085, upload-time = "2026-06-09T22:31:58.703Z" },
{ url = "https://files.pythonhosted.org/packages/d2/bb/cc4b78784f97efc8c5874c2a9743708d172be6663024b34a0467885ae0c8/cryptography-48.0.1-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3752f2dbc8f07a30aad2932c986cea495b03bb554887828225da104f732852b6", size = 4746137, upload-time = "2026-06-09T22:31:31.01Z" },
{ url = "https://files.pythonhosted.org/packages/1f/52/0c44de3f5267f8fbe8e835138017522a333436166e406f0db9b9e6e3033f/cryptography-48.0.1-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:bd81490cd5801d755cf97bb68ac191f14b708470b1c7cf4580f669b9c9264cd8", size = 4333867, upload-time = "2026-06-09T22:32:28.096Z" },
{ url = "https://files.pythonhosted.org/packages/9a/2e/772d7adbfa931537bc401640b7cac9976bff689bda187833e5d63b428e49/cryptography-48.0.1-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:66fd0771e7b9c6dcd44cf1120690d2338d16d72795cf40cae2786a39eba65429", size = 4701805, upload-time = "2026-06-09T22:31:38.284Z" },
{ url = "https://files.pythonhosted.org/packages/f8/a3/b06844f303873493c963caf581c04df31c7035e0c1b0f02c4814d319ec80/cryptography-48.0.1-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:3fd2ca57062b241c856670b073487d2e86c4637937ca5601e48f97bf8e11fc8f", size = 5258461, upload-time = "2026-06-09T22:31:04.187Z" },
{ url = "https://files.pythonhosted.org/packages/9f/13/8b765e2e12b07c74941caadb9d1c8fdc006c4dfbf2b8f2d610519758954d/cryptography-48.0.1-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:0ee6ea481db1ab889cba043ec1eda17bb9c1ea79db6722f779c3667f9f70322f", size = 4745488, upload-time = "2026-06-09T22:32:30.07Z" },
{ url = "https://files.pythonhosted.org/packages/2e/aa/48972bce55049b32a94f4907eda4d75fa385aad8a39506cc2fc72196ecf0/cryptography-48.0.1-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f2ceef93cb096aa3c4cc4b5c94ca6131f9196d28c64d6111533402a9b2054d41", size = 4830256, upload-time = "2026-06-09T22:31:43.868Z" },
{ url = "https://files.pythonhosted.org/packages/47/a2/e5079a032fb85cf6005046ca92bbd78b0c82dad2b5751ab8c311659da06f/cryptography-48.0.1-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9bd3f92d76217892b15df84ca256c2c113d386fdda7a7d8691aeeced976507c6", size = 4979117, upload-time = "2026-06-09T22:31:05.845Z" },
{ url = "https://files.pythonhosted.org/packages/b7/a0/8f50cae9c74e718ed769d63ed5c74bd0ea830c9550a74629cebd1b9c7bc7/cryptography-48.0.1-cp311-abi3-win32.whl", hash = "sha256:b9a32b876490d66c8bcc9963ef220199569748434ab01a9d6aaeabf88e7f5158", size = 3304154, upload-time = "2026-06-09T22:32:16.845Z" },
{ url = "https://files.pythonhosted.org/packages/c5/69/0572c77dbace6fef72f33755bd52ea399c71367250d366237f8691826b9e/cryptography-48.0.1-cp311-abi3-win_amd64.whl", hash = "sha256:39489bfca54c7a1f6b297efcd8bc608ab92d16c4ca631b0cad4da46724588b24", size = 3817138, upload-time = "2026-06-09T22:32:00.388Z" },
{ url = "https://files.pythonhosted.org/packages/42/06/3e768b4c3bc78201583fa35a0e18f640dd782ff41afba88f8545481a8874/cryptography-48.0.1-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:f817adc181390bd54f2f700107a7419040fb7c1bdf2fc26f36551a06a68c3345", size = 7989830, upload-time = "2026-06-09T22:31:07.8Z" },
{ url = "https://files.pythonhosted.org/packages/8a/13/6476736484b94041110c8340a3eb63962fea4975baea8cb4a512adb44d4d/cryptography-48.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d5d30989c6917b478b5817902e85fddaea2261efa8648383d965381ccb9e1ac4", size = 4689201, upload-time = "2026-06-09T22:31:09.745Z" },
{ url = "https://files.pythonhosted.org/packages/79/62/65a87f34d2a431546e2509b85d55e8c90df86d668f6731da64d538512ac2/cryptography-48.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:df637c05205ea7c1d7fbcbe54bbfea648a52951155f997af13d895d0ecc96991", size = 4702822, upload-time = "2026-06-09T22:32:24.409Z" },
{ url = "https://files.pythonhosted.org/packages/7f/59/810b5204b0a9b10f4b6bc06bd551a8b609803cd931806bc3b71884b225e5/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:869c3b8a53bfe27147832df48b32adadf558249d50e76cb3769d40e986b13265", size = 4694875, upload-time = "2026-06-09T22:32:08.737Z" },
{ url = "https://files.pythonhosted.org/packages/24/dc/d8ca05ffea724eec6d232ea6f18e74c269eb6bdfdcc9bfba689790d1325f/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:e361afba8918070d376df76f408a4f67fec0ee9cff81a99e48fe9a233ef59e17", size = 5290385, upload-time = "2026-06-09T22:31:15.212Z" },
{ url = "https://files.pythonhosted.org/packages/03/8c/3be6cb4da181f5bb6c19cf560c2359d60644a6b5fc5b57854e528f47b296/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:d069066deead00ac7f090be101be875a06855908f7ec004c27b8fefb4acfb411", size = 4737082, upload-time = "2026-06-09T22:32:22.66Z" },
{ url = "https://files.pythonhosted.org/packages/aa/f6/d5f60a5a1434dbfd949e227fd0065d194c7e6b6ac526b17f5c06152b8231/cryptography-48.0.1-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:09f73a725d582cef64b91281a322cd798d14a33b2b6f2b7ad9531dc336d84c02", size = 4325328, upload-time = "2026-06-09T22:32:10.777Z" },
{ url = "https://files.pythonhosted.org/packages/17/b7/ba75dd947a14b6ad907b01ae8f6b5b348cdd1b48142f0063dee9e20c1d9d/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:15254441469dd6bf027039453288e2072124f8b6603563f5d759e1c9b69273fa", size = 4694530, upload-time = "2026-06-09T22:31:53.105Z" },
{ url = "https://files.pythonhosted.org/packages/62/29/50d6b9e8aff12d8b67afaeb3569335e32dc83a5723e3bbded24fdac9f809/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:8ace4507d1e6533c125f4fac754f8bb8b6a74c08e92179dabd7e16571a3efbf3", size = 5245046, upload-time = "2026-06-09T22:31:25.774Z" },
{ url = "https://files.pythonhosted.org/packages/9f/04/618f4115cfc0add0838c82507aa18a346089428da8653ad38b3ff36f5cb3/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:b4e391975f038e66432328639620a4aff2d307513b004f1ca06d6225bced815c", size = 4736660, upload-time = "2026-06-09T22:32:12.676Z" },
{ url = "https://files.pythonhosted.org/packages/24/9c/06e062462a0de28a3b3911322eded4c16deb9f441b1b7575d3dc59488ab5/cryptography-48.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42fcd8e26fe555d9b3577a135f5091fefa0aa4e99129c23fb56787a1bd4ada72", size = 4822229, upload-time = "2026-06-09T22:31:17.062Z" },
{ url = "https://files.pythonhosted.org/packages/f4/be/0561971eaaee4b8a0e7d5113c536921063ab91aaf23278ac374eaf881e11/cryptography-48.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c1400da5e32a43253392277eac7490a60e497d810a63dd5608d71bbd7af507c9", size = 4966364, upload-time = "2026-06-09T22:31:32.842Z" },
{ url = "https://files.pythonhosted.org/packages/a4/27/728c77876f12b000820b69ae490f3c4083775e79e07827e9e60be07ad209/cryptography-48.0.1-cp314-cp314t-win32.whl", hash = "sha256:0df56b056bc17c1b7d6821dfa65216e62bd232d8ab05eb3db44e71d235651471", size = 3278498, upload-time = "2026-06-09T22:31:29.154Z" },
{ url = "https://files.pythonhosted.org/packages/06/e3/79a612c6d7b1e6ee0edd43633d53035bec2cfb78c82b76f7864f39e36f34/cryptography-48.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:9de21387aa95e2a895823d0745b430bed4f33503ba9ab5e0b5311f33e37d66d2", size = 3798790, upload-time = "2026-06-09T22:31:56.697Z" },
{ url = "https://files.pythonhosted.org/packages/ca/6c/00fa2a95997164c8b2072ce327c23d4ab20809ccc323ea5fab91e53a4bba/cryptography-48.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:4fdc69f8e4316bcf0c8c8ec1f26f285d12e8142d88d96c876a59a03be3f6ae67", size = 7987408, upload-time = "2026-06-09T22:32:20.777Z" },
{ url = "https://files.pythonhosted.org/packages/b0/d9/45f309a7e4e5f3f8f121d6d3be9e94024a7726ec598d6e08ae04edb2f04d/cryptography-48.0.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48fe40804d4caa2288f24e70ca8c64c42dd826da0ad7e4f1b41b2128d679e6c8", size = 4690196, upload-time = "2026-06-09T22:31:54.74Z" },
{ url = "https://files.pythonhosted.org/packages/5f/9f/a1bc8bcc798811b8527eb374bbccf30a3f3e806829d967118222bf1125eb/cryptography-48.0.1-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:86be3b1b0b6bf09482fb50a979c508d2950ed95f5621ec77f4e385962006b83a", size = 4696782, upload-time = "2026-06-09T22:31:45.615Z" },
{ url = "https://files.pythonhosted.org/packages/66/c2/81a4fb4e4373c500bb526bc337ac5719dd31dd15b970b84a238168c6aa08/cryptography-48.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:4ab0a343c807bbcd90c971cd1ecf072937cd01847a9e002bef88fb47ac6be577", size = 4696618, upload-time = "2026-06-09T22:31:11.564Z" },
{ url = "https://files.pythonhosted.org/packages/e5/0b/aa68b221dde92d09cb29a024ede17550ee21e77a404e59fc093c82bb51e1/cryptography-48.0.1-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9621de99d2da096006b629979efd8ae7eb2d8b822488d0c89ee4000c306c59b1", size = 5289970, upload-time = "2026-06-09T22:31:20.368Z" },
{ url = "https://files.pythonhosted.org/packages/78/13/fba657f958d2af66ea959a4ba01212632089249d34af1ae48054136344d7/cryptography-48.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:88c852a0ae366e262e5a1744b685e6a433dc8788dd2a277e418bf4904203609d", size = 4731873, upload-time = "2026-06-09T22:31:22.253Z" },
{ url = "https://files.pythonhosted.org/packages/4c/4c/9a964756d24a26b3e34dfcb16f961b89838786e6700b635b0d1e3adff4b6/cryptography-48.0.1-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:43c5835e2cb98c8733d86f57d6fc879b613f5c3478607281c3e36daffc6dd8a6", size = 4330804, upload-time = "2026-06-09T22:31:36.56Z" },
{ url = "https://files.pythonhosted.org/packages/4b/0f/a10f3a6eb12950a10e3a874070283aa2dd5875b2bfd15fad8a3e17b3f13e/cryptography-48.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:fe0180af5bf9236518a087e35bf2d9a347d5f5f51e63c579d683ddff424e3d46", size = 4696217, upload-time = "2026-06-09T22:31:13.351Z" },
{ url = "https://files.pythonhosted.org/packages/f3/6f/5cd12f951165ea73ef85266775d97e4c763b2474ccfd816dd69d3a18d6f8/cryptography-48.0.1-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:b7a2d1a937a738a881737cec135a38bb61470589b17515b9f73f571d0ae10401", size = 5245252, upload-time = "2026-06-09T22:32:02.193Z" },
{ url = "https://files.pythonhosted.org/packages/68/ab/8aaa12e4516ec4464033ab79b6f3b592bd5a92102467c4ace8a0d970203f/cryptography-48.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b74ca3b8e5ecdd833bf6a002ca41b4793bb27fb8f1c06ffaf2643c9e9140e31b", size = 4731388, upload-time = "2026-06-09T22:32:04.019Z" },
{ url = "https://files.pythonhosted.org/packages/1b/24/50027ea4dca85ec1f40688f3c24fb32ccacd520583c9592c3cc95628e6fb/cryptography-48.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2c37f2461406063b417837f5f3daab668652acd82423efcd7f0a9f04be972de1", size = 4824186, upload-time = "2026-06-09T22:32:18.707Z" },
{ url = "https://files.pythonhosted.org/packages/52/41/04cb5eb17085ade6f50cc611fb657df6a0f5885350de8764ece89c050197/cryptography-48.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:86fe77abb1bd87afb251d4d02ada7ecf53a32cee9b67d976abb2e45a13297475", size = 4964539, upload-time = "2026-06-09T22:31:18.793Z" },
{ url = "https://files.pythonhosted.org/packages/36/bf/ed70785c496e89d7e73b7cda2d21f2447fd6d4e821714b8d04ff217fed92/cryptography-48.0.1-cp39-abi3-win32.whl", hash = "sha256:6b2c0c3e6ccf3ade7750f836ef3ee36eea250cc467d45c256895573ac08cc6f1", size = 3282307, upload-time = "2026-06-09T22:30:53.162Z" },
{ url = "https://files.pythonhosted.org/packages/b3/ff/371ea7d252656ee1eb6d83eeeef3d1d0c6baf1d6497687d081ea03814670/cryptography-48.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:9a49ca6c81417f6a5edb50375a60cccdd70fa0a91a5211829dbea74eba94d2ac", size = 3793408, upload-time = "2026-06-09T22:32:15.191Z" },
{ url = "https://files.pythonhosted.org/packages/a9/d3/eb4e394e587341fdad09a09101fa76478ead3a78b0ad63e55c22f0d75c02/cryptography-48.0.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:08a597acce1ff37f347400087776599e2348a3a8bc53b44120e463cd274efe4a", size = 3951747, upload-time = "2026-06-09T22:31:23.871Z" },
{ url = "https://files.pythonhosted.org/packages/e0/4a/3f43451b4f858bfceaaaffc649e6e787e8d4fb332a1d443af39ab02cc8f1/cryptography-48.0.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:735824ec41b7f74a7c45fb1591349333e4c696cb6c044e5f46356e560143e4cd", size = 4641226, upload-time = "2026-06-09T22:31:02.532Z" },
{ url = "https://files.pythonhosted.org/packages/73/4e/855584c2c23b09e4ce2d3b9c30e983e679cd60b068c513c6bbdb91e11782/cryptography-48.0.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:92a46e1d638daa264ba2971c0b0489c9409787943efae4d60ffda3d091ef832c", size = 4668958, upload-time = "2026-06-09T22:32:06.213Z" },
{ url = "https://files.pythonhosted.org/packages/42/3b/d35750e41d803d1e516fd6d6011f065424924da7af1748cef4cc9cb3ede1/cryptography-48.0.1-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:7e234ac052af99f2700826a5c29ea99d9c1b1f80341cde62d11c8154dc8e0bd9", size = 4640793, upload-time = "2026-06-09T22:32:26.331Z" },
{ url = "https://files.pythonhosted.org/packages/ca/aa/cdb7181fe865285e87e96825aaab239400f1de0c3bfba9bd9769b79f1a92/cryptography-48.0.1-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:33842cf0888951cef5bc7ac724ab844a42044c1727b967b7f8997289a0464f92", size = 4668505, upload-time = "2026-06-09T22:31:27.534Z" },
{ url = "https://files.pythonhosted.org/packages/5d/8c/ce3823c06c2804f194f9e64f0d67fa3f4094a39f2bb1a990cd03603af8fc/cryptography-48.0.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6184ca7b174f28d7c703f1290d4b297217c45355f77a98f67e9b7f14549ac54a", size = 3742204, upload-time = "2026-06-09T22:31:34.773Z" },
]
[[package]]
@@ -697,139 +709,139 @@ wheels = [
[[package]]
name = "grpcio"
version = "1.76.0"
version = "1.80.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b6/e0/318c1ce3ae5a17894d5791e87aea147587c9e702f24122cc7a5c8bbaeeb1/grpcio-1.76.0.tar.gz", hash = "sha256:7be78388d6da1a25c0d5ec506523db58b18be22d9c37d8d3a32c08be4987bd73", size = 12785182, upload-time = "2025-10-21T16:23:12.106Z" }
sdist = { url = "https://files.pythonhosted.org/packages/b7/48/af6173dbca4454f4637a4678b67f52ca7e0c1ed7d5894d89d434fecede05/grpcio-1.80.0.tar.gz", hash = "sha256:29aca15edd0688c22ba01d7cc01cb000d72b2033f4a3c72a81a19b56fd143257", size = 12978905, upload-time = "2026-03-30T08:49:10.502Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/88/17/ff4795dc9a34b6aee6ec379f1b66438a3789cd1315aac0cbab60d92f74b3/grpcio-1.76.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:65a20de41e85648e00305c1bb09a3598f840422e522277641145a32d42dcefcc", size = 5840037, upload-time = "2025-10-21T16:20:25.069Z" },
{ url = "https://files.pythonhosted.org/packages/4e/ff/35f9b96e3fa2f12e1dcd58a4513a2e2294a001d64dec81677361b7040c9a/grpcio-1.76.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:40ad3afe81676fd9ec6d9d406eda00933f218038433980aa19d401490e46ecde", size = 11836482, upload-time = "2025-10-21T16:20:30.113Z" },
{ url = "https://files.pythonhosted.org/packages/3e/1c/8374990f9545e99462caacea5413ed783014b3b66ace49e35c533f07507b/grpcio-1.76.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:035d90bc79eaa4bed83f524331d55e35820725c9fbb00ffa1904d5550ed7ede3", size = 6407178, upload-time = "2025-10-21T16:20:32.733Z" },
{ url = "https://files.pythonhosted.org/packages/1e/77/36fd7d7c75a6c12542c90a6d647a27935a1ecaad03e0ffdb7c42db6b04d2/grpcio-1.76.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4215d3a102bd95e2e11b5395c78562967959824156af11fa93d18fdd18050990", size = 7075684, upload-time = "2025-10-21T16:20:35.435Z" },
{ url = "https://files.pythonhosted.org/packages/38/f7/e3cdb252492278e004722306c5a8935eae91e64ea11f0af3437a7de2e2b7/grpcio-1.76.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:49ce47231818806067aea3324d4bf13825b658ad662d3b25fada0bdad9b8a6af", size = 6611133, upload-time = "2025-10-21T16:20:37.541Z" },
{ url = "https://files.pythonhosted.org/packages/7e/20/340db7af162ccd20a0893b5f3c4a5d676af7b71105517e62279b5b61d95a/grpcio-1.76.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8cc3309d8e08fd79089e13ed4819d0af72aa935dd8f435a195fd152796752ff2", size = 7195507, upload-time = "2025-10-21T16:20:39.643Z" },
{ url = "https://files.pythonhosted.org/packages/10/f0/b2160addc1487bd8fa4810857a27132fb4ce35c1b330c2f3ac45d697b106/grpcio-1.76.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:971fd5a1d6e62e00d945423a567e42eb1fa678ba89072832185ca836a94daaa6", size = 8160651, upload-time = "2025-10-21T16:20:42.492Z" },
{ url = "https://files.pythonhosted.org/packages/2c/2c/ac6f98aa113c6ef111b3f347854e99ebb7fb9d8f7bb3af1491d438f62af4/grpcio-1.76.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d9adda641db7207e800a7f089068f6f645959f2df27e870ee81d44701dd9db3", size = 7620568, upload-time = "2025-10-21T16:20:45.995Z" },
{ url = "https://files.pythonhosted.org/packages/90/84/7852f7e087285e3ac17a2703bc4129fafee52d77c6c82af97d905566857e/grpcio-1.76.0-cp310-cp310-win32.whl", hash = "sha256:063065249d9e7e0782d03d2bca50787f53bd0fb89a67de9a7b521c4a01f1989b", size = 3998879, upload-time = "2025-10-21T16:20:48.592Z" },
{ url = "https://files.pythonhosted.org/packages/10/30/d3d2adcbb6dd3ff59d6ac3df6ef830e02b437fb5c90990429fd180e52f30/grpcio-1.76.0-cp310-cp310-win_amd64.whl", hash = "sha256:a6ae758eb08088d36812dd5d9af7a9859c05b1e0f714470ea243694b49278e7b", size = 4706892, upload-time = "2025-10-21T16:20:50.697Z" },
{ url = "https://files.pythonhosted.org/packages/a0/00/8163a1beeb6971f66b4bbe6ac9457b97948beba8dd2fc8e1281dce7f79ec/grpcio-1.76.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:2e1743fbd7f5fa713a1b0a8ac8ebabf0ec980b5d8809ec358d488e273b9cf02a", size = 5843567, upload-time = "2025-10-21T16:20:52.829Z" },
{ url = "https://files.pythonhosted.org/packages/10/c1/934202f5cf335e6d852530ce14ddb0fef21be612ba9ecbbcbd4d748ca32d/grpcio-1.76.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:a8c2cf1209497cf659a667d7dea88985e834c24b7c3b605e6254cbb5076d985c", size = 11848017, upload-time = "2025-10-21T16:20:56.705Z" },
{ url = "https://files.pythonhosted.org/packages/11/0b/8dec16b1863d74af6eb3543928600ec2195af49ca58b16334972f6775663/grpcio-1.76.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:08caea849a9d3c71a542827d6df9d5a69067b0a1efbea8a855633ff5d9571465", size = 6412027, upload-time = "2025-10-21T16:20:59.3Z" },
{ url = "https://files.pythonhosted.org/packages/d7/64/7b9e6e7ab910bea9d46f2c090380bab274a0b91fb0a2fe9b0cd399fffa12/grpcio-1.76.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f0e34c2079d47ae9f6188211db9e777c619a21d4faba6977774e8fa43b085e48", size = 7075913, upload-time = "2025-10-21T16:21:01.645Z" },
{ url = "https://files.pythonhosted.org/packages/68/86/093c46e9546073cefa789bd76d44c5cb2abc824ca62af0c18be590ff13ba/grpcio-1.76.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8843114c0cfce61b40ad48df65abcfc00d4dba82eae8718fab5352390848c5da", size = 6615417, upload-time = "2025-10-21T16:21:03.844Z" },
{ url = "https://files.pythonhosted.org/packages/f7/b6/5709a3a68500a9c03da6fb71740dcdd5ef245e39266461a03f31a57036d8/grpcio-1.76.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8eddfb4d203a237da6f3cc8a540dad0517d274b5a1e9e636fd8d2c79b5c1d397", size = 7199683, upload-time = "2025-10-21T16:21:06.195Z" },
{ url = "https://files.pythonhosted.org/packages/91/d3/4b1f2bf16ed52ce0b508161df3a2d186e4935379a159a834cb4a7d687429/grpcio-1.76.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:32483fe2aab2c3794101c2a159070584e5db11d0aa091b2c0ea9c4fc43d0d749", size = 8163109, upload-time = "2025-10-21T16:21:08.498Z" },
{ url = "https://files.pythonhosted.org/packages/5c/61/d9043f95f5f4cf085ac5dd6137b469d41befb04bd80280952ffa2a4c3f12/grpcio-1.76.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dcfe41187da8992c5f40aa8c5ec086fa3672834d2be57a32384c08d5a05b4c00", size = 7626676, upload-time = "2025-10-21T16:21:10.693Z" },
{ url = "https://files.pythonhosted.org/packages/36/95/fd9a5152ca02d8881e4dd419cdd790e11805979f499a2e5b96488b85cf27/grpcio-1.76.0-cp311-cp311-win32.whl", hash = "sha256:2107b0c024d1b35f4083f11245c0e23846ae64d02f40b2b226684840260ed054", size = 3997688, upload-time = "2025-10-21T16:21:12.746Z" },
{ url = "https://files.pythonhosted.org/packages/60/9c/5c359c8d4c9176cfa3c61ecd4efe5affe1f38d9bae81e81ac7186b4c9cc8/grpcio-1.76.0-cp311-cp311-win_amd64.whl", hash = "sha256:522175aba7af9113c48ec10cc471b9b9bd4f6ceb36aeb4544a8e2c80ed9d252d", size = 4709315, upload-time = "2025-10-21T16:21:15.26Z" },
{ url = "https://files.pythonhosted.org/packages/bf/05/8e29121994b8d959ffa0afd28996d452f291b48cfc0875619de0bde2c50c/grpcio-1.76.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:81fd9652b37b36f16138611c7e884eb82e0cec137c40d3ef7c3f9b3ed00f6ed8", size = 5799718, upload-time = "2025-10-21T16:21:17.939Z" },
{ url = "https://files.pythonhosted.org/packages/d9/75/11d0e66b3cdf998c996489581bdad8900db79ebd83513e45c19548f1cba4/grpcio-1.76.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:04bbe1bfe3a68bbfd4e52402ab7d4eb59d72d02647ae2042204326cf4bbad280", size = 11825627, upload-time = "2025-10-21T16:21:20.466Z" },
{ url = "https://files.pythonhosted.org/packages/28/50/2f0aa0498bc188048f5d9504dcc5c2c24f2eb1a9337cd0fa09a61a2e75f0/grpcio-1.76.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d388087771c837cdb6515539f43b9d4bf0b0f23593a24054ac16f7a960be16f4", size = 6359167, upload-time = "2025-10-21T16:21:23.122Z" },
{ url = "https://files.pythonhosted.org/packages/66/e5/bbf0bb97d29ede1d59d6588af40018cfc345b17ce979b7b45424628dc8bb/grpcio-1.76.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:9f8f757bebaaea112c00dba718fc0d3260052ce714e25804a03f93f5d1c6cc11", size = 7044267, upload-time = "2025-10-21T16:21:25.995Z" },
{ url = "https://files.pythonhosted.org/packages/f5/86/f6ec2164f743d9609691115ae8ece098c76b894ebe4f7c94a655c6b03e98/grpcio-1.76.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:980a846182ce88c4f2f7e2c22c56aefd515daeb36149d1c897f83cf57999e0b6", size = 6573963, upload-time = "2025-10-21T16:21:28.631Z" },
{ url = "https://files.pythonhosted.org/packages/60/bc/8d9d0d8505feccfdf38a766d262c71e73639c165b311c9457208b56d92ae/grpcio-1.76.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f92f88e6c033db65a5ae3d97905c8fea9c725b63e28d5a75cb73b49bda5024d8", size = 7164484, upload-time = "2025-10-21T16:21:30.837Z" },
{ url = "https://files.pythonhosted.org/packages/67/e6/5d6c2fc10b95edf6df9b8f19cf10a34263b7fd48493936fffd5085521292/grpcio-1.76.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4baf3cbe2f0be3289eb68ac8ae771156971848bb8aaff60bad42005539431980", size = 8127777, upload-time = "2025-10-21T16:21:33.577Z" },
{ url = "https://files.pythonhosted.org/packages/3f/c8/dce8ff21c86abe025efe304d9e31fdb0deaaa3b502b6a78141080f206da0/grpcio-1.76.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:615ba64c208aaceb5ec83bfdce7728b80bfeb8be97562944836a7a0a9647d882", size = 7594014, upload-time = "2025-10-21T16:21:41.882Z" },
{ url = "https://files.pythonhosted.org/packages/e0/42/ad28191ebf983a5d0ecef90bab66baa5a6b18f2bfdef9d0a63b1973d9f75/grpcio-1.76.0-cp312-cp312-win32.whl", hash = "sha256:45d59a649a82df5718fd9527ce775fd66d1af35e6d31abdcdc906a49c6822958", size = 3984750, upload-time = "2025-10-21T16:21:44.006Z" },
{ url = "https://files.pythonhosted.org/packages/9e/00/7bd478cbb851c04a48baccaa49b75abaa8e4122f7d86da797500cccdd771/grpcio-1.76.0-cp312-cp312-win_amd64.whl", hash = "sha256:c088e7a90b6017307f423efbb9d1ba97a22aa2170876223f9709e9d1de0b5347", size = 4704003, upload-time = "2025-10-21T16:21:46.244Z" },
{ url = "https://files.pythonhosted.org/packages/fc/ed/71467ab770effc9e8cef5f2e7388beb2be26ed642d567697bb103a790c72/grpcio-1.76.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:26ef06c73eb53267c2b319f43e6634c7556ea37672029241a056629af27c10e2", size = 5807716, upload-time = "2025-10-21T16:21:48.475Z" },
{ url = "https://files.pythonhosted.org/packages/2c/85/c6ed56f9817fab03fa8a111ca91469941fb514e3e3ce6d793cb8f1e1347b/grpcio-1.76.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:45e0111e73f43f735d70786557dc38141185072d7ff8dc1829d6a77ac1471468", size = 11821522, upload-time = "2025-10-21T16:21:51.142Z" },
{ url = "https://files.pythonhosted.org/packages/ac/31/2b8a235ab40c39cbc141ef647f8a6eb7b0028f023015a4842933bc0d6831/grpcio-1.76.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:83d57312a58dcfe2a3a0f9d1389b299438909a02db60e2f2ea2ae2d8034909d3", size = 6362558, upload-time = "2025-10-21T16:21:54.213Z" },
{ url = "https://files.pythonhosted.org/packages/bd/64/9784eab483358e08847498ee56faf8ff6ea8e0a4592568d9f68edc97e9e9/grpcio-1.76.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3e2a27c89eb9ac3d81ec8835e12414d73536c6e620355d65102503064a4ed6eb", size = 7049990, upload-time = "2025-10-21T16:21:56.476Z" },
{ url = "https://files.pythonhosted.org/packages/2b/94/8c12319a6369434e7a184b987e8e9f3b49a114c489b8315f029e24de4837/grpcio-1.76.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61f69297cba3950a524f61c7c8ee12e55c486cb5f7db47ff9dcee33da6f0d3ae", size = 6575387, upload-time = "2025-10-21T16:21:59.051Z" },
{ url = "https://files.pythonhosted.org/packages/15/0f/f12c32b03f731f4a6242f771f63039df182c8b8e2cf8075b245b409259d4/grpcio-1.76.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6a15c17af8839b6801d554263c546c69c4d7718ad4321e3166175b37eaacca77", size = 7166668, upload-time = "2025-10-21T16:22:02.049Z" },
{ url = "https://files.pythonhosted.org/packages/ff/2d/3ec9ce0c2b1d92dd59d1c3264aaec9f0f7c817d6e8ac683b97198a36ed5a/grpcio-1.76.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:25a18e9810fbc7e7f03ec2516addc116a957f8cbb8cbc95ccc80faa072743d03", size = 8124928, upload-time = "2025-10-21T16:22:04.984Z" },
{ url = "https://files.pythonhosted.org/packages/1a/74/fd3317be5672f4856bcdd1a9e7b5e17554692d3db9a3b273879dc02d657d/grpcio-1.76.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:931091142fd8cc14edccc0845a79248bc155425eee9a98b2db2ea4f00a235a42", size = 7589983, upload-time = "2025-10-21T16:22:07.881Z" },
{ url = "https://files.pythonhosted.org/packages/45/bb/ca038cf420f405971f19821c8c15bcbc875505f6ffadafe9ffd77871dc4c/grpcio-1.76.0-cp313-cp313-win32.whl", hash = "sha256:5e8571632780e08526f118f74170ad8d50fb0a48c23a746bef2a6ebade3abd6f", size = 3984727, upload-time = "2025-10-21T16:22:10.032Z" },
{ url = "https://files.pythonhosted.org/packages/41/80/84087dc56437ced7cdd4b13d7875e7439a52a261e3ab4e06488ba6173b0a/grpcio-1.76.0-cp313-cp313-win_amd64.whl", hash = "sha256:f9f7bd5faab55f47231ad8dba7787866b69f5e93bc306e3915606779bbfb4ba8", size = 4702799, upload-time = "2025-10-21T16:22:12.709Z" },
{ url = "https://files.pythonhosted.org/packages/b4/46/39adac80de49d678e6e073b70204091e76631e03e94928b9ea4ecf0f6e0e/grpcio-1.76.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:ff8a59ea85a1f2191a0ffcc61298c571bc566332f82e5f5be1b83c9d8e668a62", size = 5808417, upload-time = "2025-10-21T16:22:15.02Z" },
{ url = "https://files.pythonhosted.org/packages/9c/f5/a4531f7fb8b4e2a60b94e39d5d924469b7a6988176b3422487be61fe2998/grpcio-1.76.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:06c3d6b076e7b593905d04fdba6a0525711b3466f43b3400266f04ff735de0cd", size = 11828219, upload-time = "2025-10-21T16:22:17.954Z" },
{ url = "https://files.pythonhosted.org/packages/4b/1c/de55d868ed7a8bd6acc6b1d6ddc4aa36d07a9f31d33c912c804adb1b971b/grpcio-1.76.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fd5ef5932f6475c436c4a55e4336ebbe47bd3272be04964a03d316bbf4afbcbc", size = 6367826, upload-time = "2025-10-21T16:22:20.721Z" },
{ url = "https://files.pythonhosted.org/packages/59/64/99e44c02b5adb0ad13ab3adc89cb33cb54bfa90c74770f2607eea629b86f/grpcio-1.76.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b331680e46239e090f5b3cead313cc772f6caa7d0fc8de349337563125361a4a", size = 7049550, upload-time = "2025-10-21T16:22:23.637Z" },
{ url = "https://files.pythonhosted.org/packages/43/28/40a5be3f9a86949b83e7d6a2ad6011d993cbe9b6bd27bea881f61c7788b6/grpcio-1.76.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2229ae655ec4e8999599469559e97630185fdd53ae1e8997d147b7c9b2b72cba", size = 6575564, upload-time = "2025-10-21T16:22:26.016Z" },
{ url = "https://files.pythonhosted.org/packages/4b/a9/1be18e6055b64467440208a8559afac243c66a8b904213af6f392dc2212f/grpcio-1.76.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:490fa6d203992c47c7b9e4a9d39003a0c2bcc1c9aa3c058730884bbbb0ee9f09", size = 7176236, upload-time = "2025-10-21T16:22:28.362Z" },
{ url = "https://files.pythonhosted.org/packages/0f/55/dba05d3fcc151ce6e81327541d2cc8394f442f6b350fead67401661bf041/grpcio-1.76.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:479496325ce554792dba6548fae3df31a72cef7bad71ca2e12b0e58f9b336bfc", size = 8125795, upload-time = "2025-10-21T16:22:31.075Z" },
{ url = "https://files.pythonhosted.org/packages/4a/45/122df922d05655f63930cf42c9e3f72ba20aadb26c100ee105cad4ce4257/grpcio-1.76.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1c9b93f79f48b03ada57ea24725d83a30284a012ec27eab2cf7e50a550cbbbcc", size = 7592214, upload-time = "2025-10-21T16:22:33.831Z" },
{ url = "https://files.pythonhosted.org/packages/4a/6e/0b899b7f6b66e5af39e377055fb4a6675c9ee28431df5708139df2e93233/grpcio-1.76.0-cp314-cp314-win32.whl", hash = "sha256:747fa73efa9b8b1488a95d0ba1039c8e2dca0f741612d80415b1e1c560febf4e", size = 4062961, upload-time = "2025-10-21T16:22:36.468Z" },
{ url = "https://files.pythonhosted.org/packages/19/41/0b430b01a2eb38ee887f88c1f07644a1df8e289353b78e82b37ef988fb64/grpcio-1.76.0-cp314-cp314-win_amd64.whl", hash = "sha256:922fa70ba549fce362d2e2871ab542082d66e2aaf0c19480ea453905b01f384e", size = 4834462, upload-time = "2025-10-21T16:22:39.772Z" },
{ url = "https://files.pythonhosted.org/packages/9d/cd/bb7b7e54084a344c03d68144450da7ddd5564e51a298ae1662de65f48e2d/grpcio-1.80.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:886457a7768e408cdce226ad1ca67d2958917d306523a0e21e1a2fdaa75c9c9c", size = 6050363, upload-time = "2026-03-30T08:46:20.894Z" },
{ url = "https://files.pythonhosted.org/packages/16/02/1417f5c3460dea65f7a2e3c14e8b31e77f7ffb730e9bfadd89eda7a9f477/grpcio-1.80.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:7b641fc3f1dc647bfd80bd713addc68f6d145956f64677e56d9ebafc0bd72388", size = 12026037, upload-time = "2026-03-30T08:46:25.144Z" },
{ url = "https://files.pythonhosted.org/packages/43/98/c910254eedf2cae368d78336a2de0678e66a7317d27c02522392f949b5c6/grpcio-1.80.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:33eb763f18f006dc7fee1e69831d38d23f5eccd15b2e0f92a13ee1d9242e5e02", size = 6602306, upload-time = "2026-03-30T08:46:27.593Z" },
{ url = "https://files.pythonhosted.org/packages/7c/f8/88ca4e78c077b2b2113d95da1e1ab43efd43d723c9a0397d26529c2c1a56/grpcio-1.80.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:52d143637e3872633fc7dd7c3c6a1c84e396b359f3a72e215f8bf69fd82084fc", size = 7301535, upload-time = "2026-03-30T08:46:29.556Z" },
{ url = "https://files.pythonhosted.org/packages/f9/96/f28660fe2fe0f153288bf4a04e4910b7309d442395135c88ed4f5b3b8b40/grpcio-1.80.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c51bf8ac4575af2e0678bccfb07e47321fc7acb5049b4482832c5c195e04e13a", size = 6808669, upload-time = "2026-03-30T08:46:31.984Z" },
{ url = "https://files.pythonhosted.org/packages/47/eb/3f68a5e955779c00aeef23850e019c1c1d0e032d90633ba49c01ad5a96e0/grpcio-1.80.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:50a9871536d71c4fba24ee856abc03a87764570f0c457dd8db0b4018f379fed9", size = 7409489, upload-time = "2026-03-30T08:46:34.684Z" },
{ url = "https://files.pythonhosted.org/packages/5b/a7/d2f681a4bfb881be40659a309771f3bdfbfdb1190619442816c3f0ffc079/grpcio-1.80.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a72d84ad0514db063e21887fbacd1fd7acb4d494a564cae22227cd45c7fbf199", size = 8423167, upload-time = "2026-03-30T08:46:36.833Z" },
{ url = "https://files.pythonhosted.org/packages/97/8a/29b4589c204959aa35ce5708400a05bba72181807c45c47b3ec000c39333/grpcio-1.80.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f7691a6788ad9196872f95716df5bc643ebba13c97140b7a5ee5c8e75d1dea81", size = 7846761, upload-time = "2026-03-30T08:46:40.091Z" },
{ url = "https://files.pythonhosted.org/packages/6b/d2/ed143e097230ee121ac5848f6ff14372dba91289b10b536d54fb1b7cbae7/grpcio-1.80.0-cp310-cp310-win32.whl", hash = "sha256:46c2390b59d67f84e882694d489f5b45707c657832d7934859ceb8c33f467069", size = 4156534, upload-time = "2026-03-30T08:46:42.026Z" },
{ url = "https://files.pythonhosted.org/packages/d5/c9/df8279bb49b29409995e95efa85b72973d62f8aeff89abee58c91f393710/grpcio-1.80.0-cp310-cp310-win_amd64.whl", hash = "sha256:dc053420fc75749c961e2a4c906398d7c15725d36ccc04ae6d16093167223b58", size = 4889869, upload-time = "2026-03-30T08:46:44.219Z" },
{ url = "https://files.pythonhosted.org/packages/5d/db/1d56e5f5823257b291962d6c0ce106146c6447f405b60b234c4f222a7cde/grpcio-1.80.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:dfab85db094068ff42e2a3563f60ab3dddcc9d6488a35abf0132daec13209c8a", size = 6055009, upload-time = "2026-03-30T08:46:46.265Z" },
{ url = "https://files.pythonhosted.org/packages/6e/18/c83f3cad64c5ca63bca7e91e5e46b0d026afc5af9d0a9972472ceba294b3/grpcio-1.80.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:5c07e82e822e1161354e32da2662f741a4944ea955f9f580ec8fb409dd6f6060", size = 12035295, upload-time = "2026-03-30T08:46:49.099Z" },
{ url = "https://files.pythonhosted.org/packages/0f/8e/e14966b435be2dda99fbe89db9525ea436edc79780431a1c2875a3582644/grpcio-1.80.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba0915d51fd4ced2db5ff719f84e270afe0e2d4c45a7bdb1e8d036e4502928c2", size = 6610297, upload-time = "2026-03-30T08:46:52.123Z" },
{ url = "https://files.pythonhosted.org/packages/cc/26/d5eb38f42ce0e3fdc8174ea4d52036ef8d58cc4426cb800f2610f625dd75/grpcio-1.80.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3cb8130ba457d2aa09fa6b7c3ed6b6e4e6a2685fce63cb803d479576c4d80e21", size = 7300208, upload-time = "2026-03-30T08:46:54.859Z" },
{ url = "https://files.pythonhosted.org/packages/25/51/bd267c989f85a17a5b3eea65a6feb4ff672af41ca614e5a0279cc0ea381c/grpcio-1.80.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:09e5e478b3d14afd23f12e49e8b44c8684ac3c5f08561c43a5b9691c54d136ab", size = 6813442, upload-time = "2026-03-30T08:46:57.056Z" },
{ url = "https://files.pythonhosted.org/packages/9e/d9/d80eef735b19e9169e30164bbf889b46f9df9127598a83d174eb13a48b26/grpcio-1.80.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:00168469238b022500e486c1c33916acf2f2a9b2c022202cf8a1885d2e3073c1", size = 7414743, upload-time = "2026-03-30T08:46:59.682Z" },
{ url = "https://files.pythonhosted.org/packages/de/f2/567f5bd5054398ed6b0509b9a30900376dcf2786bd936812098808b49d8d/grpcio-1.80.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8502122a3cc1714038e39a0b071acb1207ca7844208d5ea0d091317555ee7106", size = 8426046, upload-time = "2026-03-30T08:47:02.474Z" },
{ url = "https://files.pythonhosted.org/packages/62/29/73ef0141b4732ff5eacd68430ff2512a65c004696997f70476a83e548e7e/grpcio-1.80.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ce1794f4ea6cc3ca29463f42d665c32ba1b964b48958a66497917fe9069f26e6", size = 7851641, upload-time = "2026-03-30T08:47:05.462Z" },
{ url = "https://files.pythonhosted.org/packages/46/69/abbfa360eb229a8623bab5f5a4f8105e445bd38ce81a89514ba55d281ad0/grpcio-1.80.0-cp311-cp311-win32.whl", hash = "sha256:51b4a7189b0bef2aa30adce3c78f09c83526cf3dddb24c6a96555e3b97340440", size = 4154368, upload-time = "2026-03-30T08:47:08.027Z" },
{ url = "https://files.pythonhosted.org/packages/6f/d4/ae92206d01183b08613e846076115f5ac5991bae358d2a749fa864da5699/grpcio-1.80.0-cp311-cp311-win_amd64.whl", hash = "sha256:02e64bb0bb2da14d947a49e6f120a75e947250aebe65f9629b62bb1f5c14e6e9", size = 4894235, upload-time = "2026-03-30T08:47:10.839Z" },
{ url = "https://files.pythonhosted.org/packages/5c/e8/a2b749265eb3415abc94f2e619bbd9e9707bebdda787e61c593004ec927a/grpcio-1.80.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:c624cc9f1008361014378c9d776de7182b11fe8b2e5a81bc69f23a295f2a1ad0", size = 6015616, upload-time = "2026-03-30T08:47:13.428Z" },
{ url = "https://files.pythonhosted.org/packages/3e/97/b1282161a15d699d1e90c360df18d19165a045ce1c343c7f313f5e8a0b77/grpcio-1.80.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:f49eddcac43c3bf350c0385366a58f36bed8cc2c0ec35ef7b74b49e56552c0c2", size = 12014204, upload-time = "2026-03-30T08:47:15.873Z" },
{ url = "https://files.pythonhosted.org/packages/6e/5e/d319c6e997b50c155ac5a8cb12f5173d5b42677510e886d250d50264949d/grpcio-1.80.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d334591df610ab94714048e0d5b4f3dd5ad1bee74dfec11eee344220077a79de", size = 6563866, upload-time = "2026-03-30T08:47:18.588Z" },
{ url = "https://files.pythonhosted.org/packages/ae/f6/fdd975a2cb4d78eb67769a7b3b3830970bfa2e919f1decf724ae4445f42c/grpcio-1.80.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0cb517eb1d0d0aaf1d87af7cc5b801d686557c1d88b2619f5e31fab3c2315921", size = 7273060, upload-time = "2026-03-30T08:47:21.113Z" },
{ url = "https://files.pythonhosted.org/packages/db/f0/a3deb5feba60d9538a962913e37bd2e69a195f1c3376a3dd44fe0427e996/grpcio-1.80.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4e78c4ac0d97dc2e569b2f4bcbbb447491167cb358d1a389fc4af71ab6f70411", size = 6782121, upload-time = "2026-03-30T08:47:23.827Z" },
{ url = "https://files.pythonhosted.org/packages/ca/84/36c6dcfddc093e108141f757c407902a05085e0c328007cb090d56646cdf/grpcio-1.80.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2ed770b4c06984f3b47eb0517b1c69ad0b84ef3f40128f51448433be904634cd", size = 7383811, upload-time = "2026-03-30T08:47:26.517Z" },
{ url = "https://files.pythonhosted.org/packages/7c/ef/f3a77e3dc5b471a0ec86c564c98d6adfa3510d38f8ee99010410858d591e/grpcio-1.80.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:256507e2f524092f1473071a05e65a5b10d84b82e3ff24c5b571513cfaa61e2f", size = 8393860, upload-time = "2026-03-30T08:47:29.439Z" },
{ url = "https://files.pythonhosted.org/packages/9b/8d/9d4d27ed7f33d109c50d6b5ce578a9914aa68edab75d65869a17e630a8d1/grpcio-1.80.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a6284a5d907c37db53350645567c522be314bac859a64a7a5ca63b77bb7958f", size = 7830132, upload-time = "2026-03-30T08:47:33.254Z" },
{ url = "https://files.pythonhosted.org/packages/14/e4/9990b41c6d7a44e1e9dee8ac11d7a9802ba1378b40d77468a7761d1ad288/grpcio-1.80.0-cp312-cp312-win32.whl", hash = "sha256:c71309cfce2f22be26aa4a847357c502db6c621f1a49825ae98aa0907595b193", size = 4140904, upload-time = "2026-03-30T08:47:35.319Z" },
{ url = "https://files.pythonhosted.org/packages/2f/2c/296f6138caca1f4b92a31ace4ae1b87dab692fc16a7a3417af3bb3c805bf/grpcio-1.80.0-cp312-cp312-win_amd64.whl", hash = "sha256:9fe648599c0e37594c4809d81a9e77bd138cc82eb8baa71b6a86af65426723ff", size = 4880944, upload-time = "2026-03-30T08:47:37.831Z" },
{ url = "https://files.pythonhosted.org/packages/2f/3a/7c3c25789e3f069e581dc342e03613c5b1cb012c4e8c7d9d5cf960a75856/grpcio-1.80.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:e9e408fc016dffd20661f0126c53d8a31c2821b5c13c5d67a0f5ed5de93319ad", size = 6017243, upload-time = "2026-03-30T08:47:40.075Z" },
{ url = "https://files.pythonhosted.org/packages/04/19/21a9806eb8240e174fd1ab0cd5b9aa948bb0e05c2f2f55f9d5d7405e6d08/grpcio-1.80.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:92d787312e613754d4d8b9ca6d3297e69994a7912a32fa38c4c4e01c272974b0", size = 12010840, upload-time = "2026-03-30T08:47:43.11Z" },
{ url = "https://files.pythonhosted.org/packages/18/3a/23347d35f76f639e807fb7a36fad3068aed100996849a33809591f26eca6/grpcio-1.80.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac393b58aa16991a2f1144ec578084d544038c12242da3a215966b512904d0f", size = 6567644, upload-time = "2026-03-30T08:47:46.806Z" },
{ url = "https://files.pythonhosted.org/packages/ff/40/96e07ecb604a6a67ae6ab151e3e35b132875d98bc68ec65f3e5ab3e781d7/grpcio-1.80.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:68e5851ac4b9afe07e7f84483803ad167852570d65326b34d54ca560bfa53fb6", size = 7277830, upload-time = "2026-03-30T08:47:49.643Z" },
{ url = "https://files.pythonhosted.org/packages/9b/e2/da1506ecea1f34a5e365964644b35edef53803052b763ca214ba3870c856/grpcio-1.80.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:873ff5d17d68992ef6605330127425d2fc4e77e612fa3c3e0ed4e668685e3140", size = 6783216, upload-time = "2026-03-30T08:47:52.817Z" },
{ url = "https://files.pythonhosted.org/packages/44/83/3b20ff58d0c3b7f6caaa3af9a4174d4023701df40a3f39f7f1c8e7c48f9d/grpcio-1.80.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2bea16af2750fd0a899bf1abd9022244418b55d1f37da2202249ba4ba673838d", size = 7385866, upload-time = "2026-03-30T08:47:55.687Z" },
{ url = "https://files.pythonhosted.org/packages/47/45/55c507599c5520416de5eefecc927d6a0d7af55e91cfffb2e410607e5744/grpcio-1.80.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba0db34f7e1d803a878284cd70e4c63cb6ae2510ba51937bf8f45ba997cefcf7", size = 8391602, upload-time = "2026-03-30T08:47:58.303Z" },
{ url = "https://files.pythonhosted.org/packages/10/bb/dd06f4c24c01db9cf11341b547d0a016b2c90ed7dbbb086a5710df7dd1d7/grpcio-1.80.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8eb613f02d34721f1acf3626dfdb3545bd3c8505b0e52bf8b5710a28d02e8aa7", size = 7826752, upload-time = "2026-03-30T08:48:01.311Z" },
{ url = "https://files.pythonhosted.org/packages/f9/1e/9d67992ba23371fd63d4527096eb8c6b76d74d52b500df992a3343fd7251/grpcio-1.80.0-cp313-cp313-win32.whl", hash = "sha256:93b6f823810720912fd131f561f91f5fed0fda372b6b7028a2681b8194d5d294", size = 4142310, upload-time = "2026-03-30T08:48:04.594Z" },
{ url = "https://files.pythonhosted.org/packages/cf/e6/283326a27da9e2c3038bc93eeea36fb118ce0b2d03922a9cda6688f53c5b/grpcio-1.80.0-cp313-cp313-win_amd64.whl", hash = "sha256:e172cf795a3ba5246d3529e4d34c53db70e888fa582a8ffebd2e6e48bc0cba50", size = 4882833, upload-time = "2026-03-30T08:48:07.363Z" },
{ url = "https://files.pythonhosted.org/packages/c5/6d/e65307ce20f5a09244ba9e9d8476e99fb039de7154f37fb85f26978b59c3/grpcio-1.80.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:3d4147a97c8344d065d01bbf8b6acec2cf86fb0400d40696c8bdad34a64ffc0e", size = 6017376, upload-time = "2026-03-30T08:48:10.005Z" },
{ url = "https://files.pythonhosted.org/packages/69/10/9cef5d9650c72625a699c549940f0abb3c4bfdb5ed45a5ce431f92f31806/grpcio-1.80.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:d8e11f167935b3eb089ac9038e1a063e6d7dbe995c0bb4a661e614583352e76f", size = 12018133, upload-time = "2026-03-30T08:48:12.927Z" },
{ url = "https://files.pythonhosted.org/packages/04/82/983aabaad82ba26113caceeb9091706a0696b25da004fe3defb5b346e15b/grpcio-1.80.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f14b618fc30de822681ee986cfdcc2d9327229dc4c98aed16896761cacd468b9", size = 6574748, upload-time = "2026-03-30T08:48:16.386Z" },
{ url = "https://files.pythonhosted.org/packages/07/d7/031666ef155aa0bf399ed7e19439656c38bbd143779ae0861b038ce82abd/grpcio-1.80.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4ed39fbdcf9b87370f6e8df4e39ca7b38b3e5e9d1b0013c7b6be9639d6578d14", size = 7277711, upload-time = "2026-03-30T08:48:19.627Z" },
{ url = "https://files.pythonhosted.org/packages/e8/43/f437a78f7f4f1d311804189e8f11fb311a01049b2e08557c1068d470cb2e/grpcio-1.80.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2dcc70e9f0ba987526e8e8603a610fb4f460e42899e74e7a518bf3c68fe1bf05", size = 6785372, upload-time = "2026-03-30T08:48:22.373Z" },
{ url = "https://files.pythonhosted.org/packages/93/3d/f6558e9c6296cb4227faa5c43c54a34c68d32654b829f53288313d16a86e/grpcio-1.80.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:448c884b668b868562b1bda833c5fce6272d26e1926ec46747cda05741d302c1", size = 7395268, upload-time = "2026-03-30T08:48:25.638Z" },
{ url = "https://files.pythonhosted.org/packages/06/21/0fdd77e84720b08843c371a2efa6f2e19dbebf56adc72df73d891f5506f0/grpcio-1.80.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a1dc80fe55685b4a543555e6eef975303b36c8db1023b1599b094b92aa77965f", size = 8392000, upload-time = "2026-03-30T08:48:28.974Z" },
{ url = "https://files.pythonhosted.org/packages/f5/68/67f4947ed55d2e69f2cc199ab9fd85e0a0034d813bbeef84df6d2ba4d4b7/grpcio-1.80.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:31b9ac4ad1aa28ffee5503821fafd09e4da0a261ce1c1281c6c8da0423c83b6e", size = 7828477, upload-time = "2026-03-30T08:48:32.054Z" },
{ url = "https://files.pythonhosted.org/packages/44/b6/8d4096691b2e385e8271911a0de4f35f0a6c7d05aff7098e296c3de86939/grpcio-1.80.0-cp314-cp314-win32.whl", hash = "sha256:367ce30ba67d05e0592470428f0ec1c31714cab9ef19b8f2e37be1f4c7d32fae", size = 4218563, upload-time = "2026-03-30T08:48:34.538Z" },
{ url = "https://files.pythonhosted.org/packages/e5/8c/bbe6baf2557262834f2070cf668515fa308b2d38a4bbf771f8f7872a7036/grpcio-1.80.0-cp314-cp314-win_amd64.whl", hash = "sha256:3b01e1f5464c583d2f567b2e46ff0d516ef979978f72091fd81f5ab7fa6e2e7f", size = 5019457, upload-time = "2026-03-30T08:48:37.308Z" },
]
[[package]]
name = "grpcio-health-checking"
version = "1.76.0"
version = "1.80.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "grpcio", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "protobuf", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3e/96/5a52dcf21078b47ffa0c2ed613c3153a06f138edb6133792bace5f1ccc1d/grpcio_health_checking-1.76.0.tar.gz", hash = "sha256:b7a99d74096b3ab3a59987fc02374068e1c180a352e8d1f79f10e5a23727098d", size = 16784, upload-time = "2025-10-21T16:28:55.204Z" }
sdist = { url = "https://files.pythonhosted.org/packages/d1/a2/aa3cc47f19c03f8e5287b987317059753141a3af8f66b96d5a64b3be10b8/grpcio_health_checking-1.80.0.tar.gz", hash = "sha256:2cc5f08bc8b816b8655ab6f59c71450063ba20766d31e21a493e912e3560c8b1", size = 17117, upload-time = "2026-03-30T08:54:41.899Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/65/e6/746dffa51399827e38bb3f3f1ad656a3d8c1255039b256a6f76593368768/grpcio_health_checking-1.76.0-py3-none-any.whl", hash = "sha256:9743f345a855ba030cc7c381361606870b79d33bb71d7756efa47b6faa970f81", size = 18910, upload-time = "2025-10-21T16:27:26.332Z" },
{ url = "https://files.pythonhosted.org/packages/5e/d1/d97eb30386feff6ac2a662620e2ed68be352e9a182d62e06213db694906a/grpcio_health_checking-1.80.0-py3-none-any.whl", hash = "sha256:d804d4549cbb71e90ca2c7bf0c501060135dfd220aca8e2c54f96d3e79e210e5", size = 19125, upload-time = "2026-03-30T08:53:44.835Z" },
]
[[package]]
name = "grpcio-tools"
version = "1.75.1"
version = "1.80.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "grpcio", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "protobuf", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "setuptools", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7d/76/0cd2a2bb379275c319544a3ab613dc3cea7a167503908c1b4de55f82bd9e/grpcio_tools-1.75.1.tar.gz", hash = "sha256:bb78960cf3d58941e1fec70cbdaccf255918beed13c34112a6915a6d8facebd1", size = 5390470, upload-time = "2025-09-26T09:10:11.948Z" }
sdist = { url = "https://files.pythonhosted.org/packages/94/c8/1223f29c84a143ae9a56c084fc96894de0ba84b6e8d60a26241abd81d278/grpcio_tools-1.80.0.tar.gz", hash = "sha256:26052b19c6ce0dcf52d1024496aea3e2bdfa864159f06dc7b97b22d041a94b26", size = 6133212, upload-time = "2026-03-30T08:52:39.077Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/26/b7/7d1b0b7669f993a6a393083a876937f478ca034c283eb23baf6720d8c85a/grpcio_tools-1.75.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:ae0f04d5ec8b8e13476bf516a08fc1de4e58c6bf79f99123a6b964ca7d02c790", size = 2545419, upload-time = "2025-09-26T09:07:44.432Z" },
{ url = "https://files.pythonhosted.org/packages/3e/c0/db5d052d1ba5e859c833d1366960d784c0b44c8330012717aeaa123b6b9f/grpcio_tools-1.75.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:24a881ad7292e904fc256892b647da17d9137ef2e72faf8b7c8e515314ad1377", size = 5841650, upload-time = "2025-09-26T09:07:50.987Z" },
{ url = "https://files.pythonhosted.org/packages/af/13/ab49230ef106f2b9de156a813bc14049e6fd4fe9c26fa0cde496f0e86a09/grpcio_tools-1.75.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1b5810ace274dba12ecfac69ac32c8047c6ee0200a23274cb4885ed4187271f8", size = 2591560, upload-time = "2025-09-26T09:07:52.777Z" },
{ url = "https://files.pythonhosted.org/packages/29/fd/1fd3069fb0559c2f90d85b0fd3a73adc3f63966c6300fee01e4e52740229/grpcio_tools-1.75.1-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:ab33993288b97b1180e092fa447a8ce00fbc8c59d67b23553245b88d14fe36bb", size = 2904895, upload-time = "2025-09-26T09:07:55.002Z" },
{ url = "https://files.pythonhosted.org/packages/d6/51/e58fae40132a4589819c388333545a33a89f91b8affcac45623ace9ca659/grpcio_tools-1.75.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4cac693621043ef11d3ab2318e811d919779f8cd5011ba8e37f44c178c831d94", size = 2656151, upload-time = "2025-09-26T09:07:56.762Z" },
{ url = "https://files.pythonhosted.org/packages/39/c9/a33736c2a8ceee39991f2c9f67a426ab799c6caf09145120bae6080428d5/grpcio_tools-1.75.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a09cd5d267b296af67116fe098633ad770bc8c19831a5f3c896f65fad90c1064", size = 3105152, upload-time = "2025-09-26T09:07:58.702Z" },
{ url = "https://files.pythonhosted.org/packages/ac/71/2f09cbe321f057a47a8ae4dacf004bbe8a171fd712b8f7f689ec7b2f1c49/grpcio_tools-1.75.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dff4bcb4d16cf9ef745c1984394ed15187e6c23d73d71377377deaf443d11358", size = 3654551, upload-time = "2025-09-26T09:08:00.87Z" },
{ url = "https://files.pythonhosted.org/packages/05/54/91481a5b96cab2a81326ab1041fd7cfc6b6ce0cd82bab14ebcdb6ed78d4e/grpcio_tools-1.75.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:16d5986b37e2a9203f85e456c7ff8705b932718021d408adfe4a79e0f4d95949", size = 3322220, upload-time = "2025-09-26T09:08:02.724Z" },
{ url = "https://files.pythonhosted.org/packages/a2/07/272955f15a35ef0069ebe17a5fc14282c6dc6690edeb4dbe6a81dd2d1efb/grpcio_tools-1.75.1-cp310-cp310-win32.whl", hash = "sha256:3fbac14998bfadc6b9140b6339dbc5f673700ebb4d45ba0c4d4fbe0ffb8559a9", size = 992986, upload-time = "2025-09-26T09:08:04.6Z" },
{ url = "https://files.pythonhosted.org/packages/16/9a/482b05c1277b3385be7e426f000efb921ce3ae76bcb8aa4f9b9f724c58d3/grpcio_tools-1.75.1-cp310-cp310-win_amd64.whl", hash = "sha256:b56e495844eb899de721eb77d9e077192bdeb40842f598481d32a8f6de3db124", size = 1157427, upload-time = "2025-09-26T09:08:06.246Z" },
{ url = "https://files.pythonhosted.org/packages/45/28/71ab934662d41ded4e451d9af0ec6f9aade3525e470fdfd10bd20e588e44/grpcio_tools-1.75.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:f0635231feb70a9d551452829943a1a5fa651283e7a300aadc22df5ea5da696f", size = 2545461, upload-time = "2025-09-26T09:08:08.514Z" },
{ url = "https://files.pythonhosted.org/packages/69/40/d90f6fdb51f51b2a518401207b3920fcfdfa996ed7bca844096f111ed839/grpcio_tools-1.75.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:626293296ef7e2d87ab1a80b81a55eef91883c65b59a97576099a28b9535100b", size = 5842958, upload-time = "2025-09-26T09:08:11.468Z" },
{ url = "https://files.pythonhosted.org/packages/b4/b7/52e6f32fd0101e3ac9c654a6441b254ba5874f146b543b20afbcb8246947/grpcio_tools-1.75.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:071339d90f1faab332ce4919c815a10b9c3ed2c09473f550f686bf9cc148579f", size = 2591669, upload-time = "2025-09-26T09:08:13.481Z" },
{ url = "https://files.pythonhosted.org/packages/0a/3c/115c59a5c0c8e9d7d99a40bac8d5e91c05b6735b3bb185265d40e9fc4346/grpcio_tools-1.75.1-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:44195f58c052fa935b78c7438c85cbcd4b273dd685028e4f6d4d7b30d47daad1", size = 2904952, upload-time = "2025-09-26T09:08:15.299Z" },
{ url = "https://files.pythonhosted.org/packages/a9/cd/d2a3583a5b1d71da88f7998f20fb5a0b6fe5bb96bb916a610c29269063b6/grpcio_tools-1.75.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:860fafdb85726029d646c99859ff7bdca5aae61b5ff038c3bd355fc1ec6b2764", size = 2656311, upload-time = "2025-09-26T09:08:17.094Z" },
{ url = "https://files.pythonhosted.org/packages/aa/09/67b9215d39add550e430c9677bd43c9a315da07ab62fa3a5f44f1cf5bb75/grpcio_tools-1.75.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4559547a0cb3d3db1b982eea87d4656036339b400f48127fef932210672fb59e", size = 3105583, upload-time = "2025-09-26T09:08:19.179Z" },
{ url = "https://files.pythonhosted.org/packages/98/d7/d400b90812470f3dc2466964e62fc03592de46b5c824c82ef5303be60167/grpcio_tools-1.75.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9af65a310807d7f36a8f7cddea142fe97d6dffba74444f38870272f2e5a3a06b", size = 3654677, upload-time = "2025-09-26T09:08:21.227Z" },
{ url = "https://files.pythonhosted.org/packages/9c/93/edf6de71b4f936b3f09461a3286db1f902c6366c5de06ef19a8c2523034a/grpcio_tools-1.75.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c1de31aefc0585d2f915a7cd0994d153547495b8d79c44c58048a3ede0b65be", size = 3322147, upload-time = "2025-09-26T09:08:23.08Z" },
{ url = "https://files.pythonhosted.org/packages/80/00/0f8c6204e34070e7d4f344b27e4b1b0320dfdd94574f79738a43504d182e/grpcio_tools-1.75.1-cp311-cp311-win32.whl", hash = "sha256:efaf95fcaa5d3ac1bcfe44ceed9e2512eb95b5c8c476569bdbbe2bee4b59c8a9", size = 993388, upload-time = "2025-09-26T09:08:24.708Z" },
{ url = "https://files.pythonhosted.org/packages/b0/ae/6f738154980f606293988a64ef4bb0ea2bb12029a4529464aac56fe2ab99/grpcio_tools-1.75.1-cp311-cp311-win_amd64.whl", hash = "sha256:7cefe76fc35c825f0148d60d2294a527053d0f5dd6a60352419214a8c53223c9", size = 1157907, upload-time = "2025-09-26T09:08:26.537Z" },
{ url = "https://files.pythonhosted.org/packages/ef/a7/581bb204d19a347303ed5e25b19f7d8c6365a28c242fca013d1d6d78ad7e/grpcio_tools-1.75.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:49b68936cf212052eeafa50b824e17731b78d15016b235d36e0d32199000b14c", size = 2546099, upload-time = "2025-09-26T09:08:28.794Z" },
{ url = "https://files.pythonhosted.org/packages/9f/59/ab65998eba14ff9d292c880f6a276fe7d0571bba3bb4ddf66aca1f8438b5/grpcio_tools-1.75.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:08cb6e568e58b76a2178ad3b453845ff057131fff00f634d7e15dcd015cd455b", size = 5839838, upload-time = "2025-09-26T09:08:31.038Z" },
{ url = "https://files.pythonhosted.org/packages/7e/65/7027f71069b4c1e8c7b46de8c46c297c9d28ef6ed4ea0161e8c82c75d1d0/grpcio_tools-1.75.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:168402ad29a249092673079cf46266936ec2fb18d4f854d96e9c5fa5708efa39", size = 2592916, upload-time = "2025-09-26T09:08:33.216Z" },
{ url = "https://files.pythonhosted.org/packages/0f/84/1abfb3c679b78c7fca7524031cf9de4c4c509c441b48fd26291ac16dd1af/grpcio_tools-1.75.1-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:bbae11c29fcf450730f021bfc14b12279f2f985e2e493ccc2f133108728261db", size = 2905276, upload-time = "2025-09-26T09:08:35.691Z" },
{ url = "https://files.pythonhosted.org/packages/99/cd/7f9e05f1eddccb61bc0ead1e49eb2222441957b02ed11acfcd2f795b03a8/grpcio_tools-1.75.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:38c6c7d5d4800f636ee691cd073db1606d1a6a76424ca75c9b709436c9c20439", size = 2656424, upload-time = "2025-09-26T09:08:38.255Z" },
{ url = "https://files.pythonhosted.org/packages/29/1d/8b7852771c2467728341f7b9c3ca4ebc76e4e23485c6a3e6d97a8323ad2a/grpcio_tools-1.75.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:626f6a61a8f141dde9a657775854d1c0d99509f9a2762b82aa401a635f6ec73d", size = 3108985, upload-time = "2025-09-26T09:08:40.291Z" },
{ url = "https://files.pythonhosted.org/packages/c2/6a/069da89cdf2e97e4558bfceef5b60bf0ef200c443b465e7691869006dd32/grpcio_tools-1.75.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f61a8334ae38d4f98c744a732b89527e5af339d17180e25fff0676060f8709b7", size = 3657940, upload-time = "2025-09-26T09:08:42.437Z" },
{ url = "https://files.pythonhosted.org/packages/c3/e4/ca8dae800c084beb89e2720346f70012d36dfb9df02d8eacd518c06cf4a0/grpcio_tools-1.75.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bd0c3fb40d89a1e24a41974e77c7331e80396ab7cde39bc396a13d6b5e2a750b", size = 3324878, upload-time = "2025-09-26T09:08:45.083Z" },
{ url = "https://files.pythonhosted.org/packages/58/06/cbe923679309bf970923f4a11351ea9e485291b504d7243130fdcfdcb03f/grpcio_tools-1.75.1-cp312-cp312-win32.whl", hash = "sha256:004bc5327593eea48abd03be3188e757c3ca0039079587a6aac24275127cac20", size = 993071, upload-time = "2025-09-26T09:08:46.785Z" },
{ url = "https://files.pythonhosted.org/packages/7c/0c/84d6be007262c5d88a590082f3a1fe62d4b0eeefa10c6cdb3548f3663e80/grpcio_tools-1.75.1-cp312-cp312-win_amd64.whl", hash = "sha256:23952692160b5fe7900653dfdc9858dc78c2c42e15c27e19ee780c8917ba6028", size = 1157506, upload-time = "2025-09-26T09:08:48.844Z" },
{ url = "https://files.pythonhosted.org/packages/47/fa/624bbe1b2ccf4f6044bf3cd314fe2c35f78f702fcc2191dc65519baddca4/grpcio_tools-1.75.1-cp313-cp313-linux_armv7l.whl", hash = "sha256:ca9e116aab0ecf4365fc2980f2e8ae1b22273c3847328b9a8e05cbd14345b397", size = 2545752, upload-time = "2025-09-26T09:08:51.433Z" },
{ url = "https://files.pythonhosted.org/packages/b9/4c/6d884e2337feff0a656e395338019adecc3aa1daeae9d7e8eb54340d4207/grpcio_tools-1.75.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:9fe87a926b65eb7f41f8738b6d03677cc43185ff77a9d9b201bdb2f673f3fa1e", size = 5838163, upload-time = "2025-09-26T09:08:53.858Z" },
{ url = "https://files.pythonhosted.org/packages/d1/2a/2ba7b6911a754719643ed92ae816a7f989af2be2882b9a9e1f90f4b0e882/grpcio_tools-1.75.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:45503a6094f91b3fd31c3d9adef26ac514f102086e2a37de797e220a6791ee87", size = 2592148, upload-time = "2025-09-26T09:08:55.86Z" },
{ url = "https://files.pythonhosted.org/packages/88/db/fa613a45c3c7b00f905bd5ad3a93c73194724d0a2dd72adae3be32983343/grpcio_tools-1.75.1-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b01b60b3de67be531a39fd869d7613fa8f178aff38c05e4d8bc2fc530fa58cb5", size = 2905215, upload-time = "2025-09-26T09:08:58.27Z" },
{ url = "https://files.pythonhosted.org/packages/d7/0c/ee4786972bb82f60e4f313bb2227c79c2cd20eb13c94c0263067923cfd12/grpcio_tools-1.75.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:09e2b9b9488735514777d44c1e4eda813122d2c87aad219f98d5d49b359a8eab", size = 2656251, upload-time = "2025-09-26T09:09:00.249Z" },
{ url = "https://files.pythonhosted.org/packages/77/f1/cc5a50658d705d0b71ff8a4fbbfcc6279d3c95731a2ef7285e13dc40e2fe/grpcio_tools-1.75.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:55e60300e62b220fabe6f062fe69f143abaeff3335f79b22b56d86254f3c3c80", size = 3108911, upload-time = "2025-09-26T09:09:02.515Z" },
{ url = "https://files.pythonhosted.org/packages/09/d8/43545f77c4918e778e90bc2c02b3462ac71cee14f29d85cdb69b089538eb/grpcio_tools-1.75.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:49ce00fcc6facbbf52bf376e55b8e08810cecd03dab0b3a2986d73117c6f6ee4", size = 3657021, upload-time = "2025-09-26T09:09:05.331Z" },
{ url = "https://files.pythonhosted.org/packages/fc/0b/2ae5925374b66bc8df5b828eff1a5f9459349c83dae1773f0aa9858707e6/grpcio_tools-1.75.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:71e95479aea868f8c8014d9dc4267f26ee75388a0d8a552e1648cfa0b53d24b4", size = 3324450, upload-time = "2025-09-26T09:09:07.867Z" },
{ url = "https://files.pythonhosted.org/packages/6e/53/9f887bacbecf892ac5b0b282477ca8cfa5b73911b04259f0d88b52e9a055/grpcio_tools-1.75.1-cp313-cp313-win32.whl", hash = "sha256:fff9d2297416eae8861e53154ccf70a19994e5935e6c8f58ebf431f81cbd8d12", size = 992434, upload-time = "2025-09-26T09:09:09.966Z" },
{ url = "https://files.pythonhosted.org/packages/a5/f0/9979d97002edffdc2a88e5f2e0dccea396dd4a6eab34fa2f705fe43eae2f/grpcio_tools-1.75.1-cp313-cp313-win_amd64.whl", hash = "sha256:1849ddd508143eb48791e81d42ddc924c554d1b4900e06775a927573a8d4267f", size = 1157069, upload-time = "2025-09-26T09:09:12.287Z" },
{ url = "https://files.pythonhosted.org/packages/a6/0b/4ff4ead293f2b016668628a240937828444094778c8037d2bbef700e9097/grpcio_tools-1.75.1-cp314-cp314-linux_armv7l.whl", hash = "sha256:f281b594489184b1f9a337cdfed1fc1ddb8428f41c4b4023de81527e90b38e1e", size = 2545868, upload-time = "2025-09-26T09:09:14.716Z" },
{ url = "https://files.pythonhosted.org/packages/0e/78/aa6bf73a18de5357c01ef87eea92150931586b25196fa4df197a37bae11d/grpcio_tools-1.75.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:becf8332f391abc62bf4eea488b63be063d76a7cf2ef00b2e36c617d9ee9216b", size = 5838010, upload-time = "2025-09-26T09:09:20.415Z" },
{ url = "https://files.pythonhosted.org/packages/99/65/7eaad673bc971af45e079d3b13c20d9ba9842b8788d31953e3234c2e2cee/grpcio_tools-1.75.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a08330f24e5cd7b39541882a95a8ba04ffb4df79e2984aa0cd01ed26dcdccf49", size = 2593170, upload-time = "2025-09-26T09:09:22.889Z" },
{ url = "https://files.pythonhosted.org/packages/e4/db/57e1e29e9186c7ed223ce8a9b609d3f861c4db015efb643dfe60b403c137/grpcio_tools-1.75.1-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:6bf3742bd8f102630072ed317d1496f31c454cd85ad19d37a68bd85bf9d5f8b9", size = 2905167, upload-time = "2025-09-26T09:09:25.96Z" },
{ url = "https://files.pythonhosted.org/packages/cd/7b/894f891f3cf19812192f8bbf1e0e1c958055676ecf0a5466a350730a006d/grpcio_tools-1.75.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f26028949474feb380460ce52d9d090d00023940c65236294a66c42ac5850e8b", size = 2656210, upload-time = "2025-09-26T09:09:28.786Z" },
{ url = "https://files.pythonhosted.org/packages/99/76/8e48427da93ef243c09629969c7b5a2c59dceb674b6b623c1f5fbaa5c8c5/grpcio_tools-1.75.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1bd68fb98bf08f11b6c3210834a14eefe585bad959bdba38e78b4ae3b04ba5bd", size = 3109226, upload-time = "2025-09-26T09:09:31.307Z" },
{ url = "https://files.pythonhosted.org/packages/b3/7e/ecf71c316c2a88c2478b7c6372d0f82d05f07edbf0f31b6da613df99ec7c/grpcio_tools-1.75.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f1496e21586193da62c3a73cd16f9c63c5b3efd68ff06dab96dbdfefa90d40bf", size = 3657139, upload-time = "2025-09-26T09:09:35.043Z" },
{ url = "https://files.pythonhosted.org/packages/6f/f3/b2613e81da2085f40a989c0601ec9efc11e8b32fcb71b1234b64a18af830/grpcio_tools-1.75.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:14a78b1e36310cdb3516cdf9ee2726107875e0b247e2439d62fc8dc38cf793c1", size = 3324513, upload-time = "2025-09-26T09:09:37.44Z" },
{ url = "https://files.pythonhosted.org/packages/9a/1f/2df4fa8634542524bc22442ffe045d41905dae62cc5dd14408b80c5ac1b8/grpcio_tools-1.75.1-cp314-cp314-win32.whl", hash = "sha256:0e6f916daf222002fb98f9a6f22de0751959e7e76a24941985cc8e43cea77b50", size = 1015283, upload-time = "2025-09-26T09:09:39.461Z" },
{ url = "https://files.pythonhosted.org/packages/23/4f/f27c973ff50486a70be53a3978b6b0244398ca170a4e19d91988b5295d92/grpcio_tools-1.75.1-cp314-cp314-win_amd64.whl", hash = "sha256:878c3b362264588c45eba57ce088755f8b2b54893d41cc4a68cdeea62996da5c", size = 1189364, upload-time = "2025-09-26T09:09:42.036Z" },
{ url = "https://files.pythonhosted.org/packages/7a/54/1de67f5080da305a258758a8deb33f85666fa759f56785042a80b114a53f/grpcio_tools-1.80.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:727477b9afa4b53f5ec70cafb41c3965d893835e0d4ea9b542fe3d0d005602bf", size = 2549601, upload-time = "2026-03-30T08:50:09.498Z" },
{ url = "https://files.pythonhosted.org/packages/9a/b4/6d57ea199c5b880d182a2234aafa9a686f9c54c708ea7be75bd19d5aa825/grpcio_tools-1.80.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:85fe8d15f146c62cb76f38d963e256392d287442b9232717d30ae9e3bbda9bc3", size = 5712717, upload-time = "2026-03-30T08:50:15.028Z" },
{ url = "https://files.pythonhosted.org/packages/6a/1a/5505ee2277d368b409c796c78f22ea34a2a517b7d16755247efd663dc7af/grpcio_tools-1.80.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:95f0fffb5ca00519f3b602f938169b4dfa04b165e03258323965a9dfe8cc4d80", size = 2595941, upload-time = "2026-03-30T08:50:17.299Z" },
{ url = "https://files.pythonhosted.org/packages/4e/39/7fc1d16d8b767805079d76365d73e82c88dfaf179034473dbc9fbccedb77/grpcio_tools-1.80.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:7a0106af212748823a6ebd8ffbd9043414216f47cae3835f3187de0a62c415d3", size = 2909304, upload-time = "2026-03-30T08:50:19.485Z" },
{ url = "https://files.pythonhosted.org/packages/97/d8/276ee759755d8f34f2ca5e9d2debd1a59f29f66059fb790bc369f2236c26/grpcio_tools-1.80.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:31fd01a4038b5dfc4ec79504a17061344f670f851833411717fef66920f13cd7", size = 2660269, upload-time = "2026-03-30T08:50:21.266Z" },
{ url = "https://files.pythonhosted.org/packages/51/04/a6bb47942ad52901d777a649324d3203cf19d487f1d446263637f7a5bf12/grpcio_tools-1.80.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:57da9e19607fac4a01c48ead333c0dd15d91ed38794dce1194eda308f73e2038", size = 3109798, upload-time = "2026-03-30T08:50:23.267Z" },
{ url = "https://files.pythonhosted.org/packages/be/50/7ee69b2919916739787d725f205b878e8d1619dd30422b8278e324664669/grpcio_tools-1.80.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:90968f751851abb8b145593609800fa70c837e1c93ba0792c480b1c8d8bc29ef", size = 3658930, upload-time = "2026-03-30T08:50:25.458Z" },
{ url = "https://files.pythonhosted.org/packages/92/61/6d50783092b0e8bbcb04152d5388bf50ecf3ea2f783d95288ff6c3bb00fa/grpcio_tools-1.80.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b69dc5d6376ab43406304d1e2fc61ccf960b287d4325d77c3d45448c37a9d2da", size = 3326562, upload-time = "2026-03-30T08:50:27.809Z" },
{ url = "https://files.pythonhosted.org/packages/ea/58/d272ba549f6b1f0d8504f5fc4cd0a296f2c495a64d6e987fe871c4151557/grpcio_tools-1.80.0-cp310-cp310-win32.whl", hash = "sha256:3e8dcfebe34cb54df095de3d5871a4562a85a29f26d0f8bb41ee2c3dcfb11c3c", size = 997620, upload-time = "2026-03-30T08:50:29.959Z" },
{ url = "https://files.pythonhosted.org/packages/70/5f/9f45a9946a0298711c72ca48b2c1f46a7d0c207a44cd3e4bb59d04556ba3/grpcio_tools-1.80.0-cp310-cp310-win_amd64.whl", hash = "sha256:fc622ed4ca400695f41c9eae3266276c6ba007e4c28164ce53b44e7ccc5e492b", size = 1162466, upload-time = "2026-03-30T08:50:32.242Z" },
{ url = "https://files.pythonhosted.org/packages/8a/d7/225dc91e6cb4f8d4830f16a478a468e9c6f342dcdf8cacc3772cc1d1f607/grpcio_tools-1.80.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:1c43e5c768578fe0c6de3dbfaabe64af642951e1aa05c487cacedda63fa6c6c4", size = 2549937, upload-time = "2026-03-30T08:50:34.651Z" },
{ url = "https://files.pythonhosted.org/packages/97/3d/a3684cb7677f3bea8db434eae02a9ce30135d7a268cd473b1bc8041c4722/grpcio_tools-1.80.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:a225348456575f3ac7851d8e23163195e76d2a905ee340cf73f33da62fba08aa", size = 5713099, upload-time = "2026-03-30T08:50:37.158Z" },
{ url = "https://files.pythonhosted.org/packages/b1/81/5665c697173ec346076358bfbfed0f7386825852494593ca14386478dfee/grpcio_tools-1.80.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a9396f02820d3f51c368c2c9dee15c55c77636c91be48a4d5c702e98d6fe0fdc", size = 2595776, upload-time = "2026-03-30T08:50:39.087Z" },
{ url = "https://files.pythonhosted.org/packages/03/4f/fb81384f08a8226fa079972ba88272ac6277581fc72e8ab234d74c7e065b/grpcio_tools-1.80.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:797c08460cae16b402326eac329aec720dccf45c9f9279b95a352792eb53cf0f", size = 2909144, upload-time = "2026-03-30T08:50:40.922Z" },
{ url = "https://files.pythonhosted.org/packages/4d/9c/c957618f1c2a3195ecf5e83b03edcb364c2c1391f74183cb76e5763fa536/grpcio_tools-1.80.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1872a867eb6217de19edb70a4ce4a374ced9d94293533dfd42fa649713f55bf4", size = 2660477, upload-time = "2026-03-30T08:50:42.766Z" },
{ url = "https://files.pythonhosted.org/packages/42/c7/23913da184febfd4eaf04de256a26bc5ff0411a5feb753e2adcff10fa86a/grpcio_tools-1.80.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:db122ba5ee357e3bb14e8944d69bbebcbdae91d5eace29ed4df3edc53cbc6528", size = 3110164, upload-time = "2026-03-30T08:50:44.761Z" },
{ url = "https://files.pythonhosted.org/packages/af/fa/b25ed85ebdb0396910eaa250b1346d75527d22fca586265416bd4330dcd5/grpcio_tools-1.80.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ddefd48c227e6f4d640fe576fac5fb2c4a8898196f513604c8ec7671b3b3d421", size = 3658988, upload-time = "2026-03-30T08:50:47.546Z" },
{ url = "https://files.pythonhosted.org/packages/60/85/2a55147cc9645e2ed777d1afcd2dc68cb34ba6f6c726bd4378ddb001a5ea/grpcio_tools-1.80.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:970ec058fa469dd6dae6ebc687501c5da670d95dead75f62f5b0933dce2c9794", size = 3326662, upload-time = "2026-03-30T08:50:49.59Z" },
{ url = "https://files.pythonhosted.org/packages/68/ed/b05bee2a992e6f9bda81909692ea920d0896cfa05c5c9dd77ba03f2d22fb/grpcio_tools-1.80.0-cp311-cp311-win32.whl", hash = "sha256:526b4402d47a0e9b31cd6087e42b7674784617916cc73c764e0bc35ed41b4ee5", size = 997969, upload-time = "2026-03-30T08:50:51.539Z" },
{ url = "https://files.pythonhosted.org/packages/b6/9a/cb50c8270e2f6285ff2761130ae257ac4e51789ded4b9d9710ce0381814d/grpcio_tools-1.80.0-cp311-cp311-win_amd64.whl", hash = "sha256:ee101ecda7231770f6a5da1024a9a6ed587a7785f8fe23ab8283f4a1acb3ffe6", size = 1162742, upload-time = "2026-03-30T08:50:54.232Z" },
{ url = "https://files.pythonhosted.org/packages/0c/b9/65929df8c9614792db900a8e45d4997fadbd1734c827da3f0eb1f2fe4866/grpcio_tools-1.80.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:d19d5a8244311947b96f749c417b32d144641c6953f1164824579e1f0a51d040", size = 2550856, upload-time = "2026-03-30T08:50:57.3Z" },
{ url = "https://files.pythonhosted.org/packages/28/17/af1557544d68d1aeca9d9ea53ed16524022d521fec6ba334ab3530e9c1a6/grpcio_tools-1.80.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:fb599a3dc89ed1bb24489a2724b2f6dd4cddbbf0f7bdd69c073477bab0dc7554", size = 5710883, upload-time = "2026-03-30T08:51:00.077Z" },
{ url = "https://files.pythonhosted.org/packages/cc/48/aa9b4f7519ca972bc40d315d5c28f05ca28fa08de13d4e8b69f551b798ab/grpcio_tools-1.80.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:623ee31fc2ff7df9a987b4f3d139c30af17ce46a861ae0e25fb8c112daa32dd8", size = 2598004, upload-time = "2026-03-30T08:51:02.102Z" },
{ url = "https://files.pythonhosted.org/packages/b4/b8/b01371c119924b3beca1fe3f047b1bc2cdc66b3d37f0f3acc9d10c567a43/grpcio_tools-1.80.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b46570a68378539ee2b75a5a43202561f8d753c832798b1047099e3c551cf5d6", size = 2909568, upload-time = "2026-03-30T08:51:04.159Z" },
{ url = "https://files.pythonhosted.org/packages/4f/7c/1108f7bdb58475a7e701ec89b55eb494538b6e76acd211ba0d4cc5fd28e8/grpcio_tools-1.80.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:51caf99c28999e7e0f97e9cea190c1405b7681a57bb2e0631205accd92b43fa4", size = 2660938, upload-time = "2026-03-30T08:51:06.126Z" },
{ url = "https://files.pythonhosted.org/packages/67/59/d1c0063d4cd3b85363c7044ff3e5159d6d5df96e2692a9a5312d9c8cb290/grpcio_tools-1.80.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cdaa1c9aa8d3a87891a96700cadd29beec214711d6522818d207277f6452567c", size = 3113814, upload-time = "2026-03-30T08:51:08.834Z" },
{ url = "https://files.pythonhosted.org/packages/76/21/18d34a4efe524c903cf66b0cfa5260d81f277b6ae668b647edf795df9ce5/grpcio_tools-1.80.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3399b5fd7b59bcffd59c6b9975a969d9f37a3c87f3e3d63c3a09c147907acb0d", size = 3662793, upload-time = "2026-03-30T08:51:11.094Z" },
{ url = "https://files.pythonhosted.org/packages/f3/40/cf2d9295a6bd593244ea703858f8fc2efd315046ca3ef7c6f9ebc5b810fa/grpcio_tools-1.80.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9c6abc08d3485b2aac99bb58afcd31dc6cd4316ce36cf263ff09cb6df15f287f", size = 3329149, upload-time = "2026-03-30T08:51:13.066Z" },
{ url = "https://files.pythonhosted.org/packages/0d/1d/fc34b32167966df20d69429b71dfca83c48434b047a5ac4fd6cd91ca4eed/grpcio_tools-1.80.0-cp312-cp312-win32.whl", hash = "sha256:18c51e07652ac7386fcdbd11866f8d55a795de073337c12447b5805575339f74", size = 997519, upload-time = "2026-03-30T08:51:14.87Z" },
{ url = "https://files.pythonhosted.org/packages/91/98/6d6563cdf51085b75f8ec24605c6f2ce84197571878ca8ab4af949c6be2d/grpcio_tools-1.80.0-cp312-cp312-win_amd64.whl", hash = "sha256:ac6fdd42d5bb18f0d903a067e2825be172deff70cf197164b6f65676cb506c9b", size = 1162407, upload-time = "2026-03-30T08:51:16.793Z" },
{ url = "https://files.pythonhosted.org/packages/44/d9/f7887a4805939e9a85d03744b66fc02575dc1df3c3e8b4d9ec000ee7a33d/grpcio_tools-1.80.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:e7046837859bbfd10b01786056145480155c16b222c9e209215b68d3be13060e", size = 2550319, upload-time = "2026-03-30T08:51:19.117Z" },
{ url = "https://files.pythonhosted.org/packages/57/5a/c8a05b32bd7203f1b9f4c0151090a2d6179d6c97692d32f2066dc29c67a6/grpcio_tools-1.80.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:a447f28958a8fe84ff0d9d3d9473868feb27ee4a9c9c805e66f5b670121cec59", size = 5709681, upload-time = "2026-03-30T08:51:21.991Z" },
{ url = "https://files.pythonhosted.org/packages/82/6b/794350ed645c12c310008f97068f6a6fd927150b0d0d08aad1d909e880b1/grpcio_tools-1.80.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:75f00450e08fe648ad8a1eeb25bc52219679d54cdd02f04dfdddc747309d83f6", size = 2596820, upload-time = "2026-03-30T08:51:24.323Z" },
{ url = "https://files.pythonhosted.org/packages/f9/b2/b39e7b79f7c878135e0784a53cd7260ee77260c8c7f2c9e46bca8e05d017/grpcio_tools-1.80.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3db830eaff1f2c2797328f2fa86c9dcdbd7d81af573a68db81e27afa2182a611", size = 2909193, upload-time = "2026-03-30T08:51:27.025Z" },
{ url = "https://files.pythonhosted.org/packages/10/f3/abe089b058f87f9910c9a458409505cbeb0b3e1c2d993a79721d02ee6a32/grpcio_tools-1.80.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7982b5fe42f012686b667dda12916884de95c4b1c65ff64371fb7232a1474b23", size = 2660197, upload-time = "2026-03-30T08:51:29.392Z" },
{ url = "https://files.pythonhosted.org/packages/09/c3/3f7806ad8b731d8a89fe3c6ed496473abd1ef4c9c42c9e9a8836ce96e377/grpcio_tools-1.80.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6451b3f4eb52d12c7f32d04bf8e0185f80521f3f088ad04b8d222b3a4819c71e", size = 3113144, upload-time = "2026-03-30T08:51:31.671Z" },
{ url = "https://files.pythonhosted.org/packages/fe/f5/415ef205e0b7e75d2a2005df6120145c4f02fda28d7b3715b55d924fe1a4/grpcio_tools-1.80.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:258bc30654a9a2236be4ca8e2ad443e2ac6db7c8cc20454d34cce60265922726", size = 3661897, upload-time = "2026-03-30T08:51:34.849Z" },
{ url = "https://files.pythonhosted.org/packages/e3/d3/2ad54764c2a9547080dd8518f4a4dc7899c7e6e747a1b1de542ce6a12066/grpcio_tools-1.80.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:865a2b8e6334c838976ab02a322cbd55c863d2eaf3c1e1a0255883c63996772a", size = 3328786, upload-time = "2026-03-30T08:51:37.265Z" },
{ url = "https://files.pythonhosted.org/packages/eb/63/23ab7db01f9630ab4f3742a2fc9fbff38b0cfc30c976114f913950664a75/grpcio_tools-1.80.0-cp313-cp313-win32.whl", hash = "sha256:f760ac1722f33e774814c37b6aa0444143f612e85088ead7447a0e9cd306a1f1", size = 997087, upload-time = "2026-03-30T08:51:39.137Z" },
{ url = "https://files.pythonhosted.org/packages/9b/af/b1c1c4423fb49cb7c8e9d2c02196b038c44160b7028b425466743c6c81fa/grpcio_tools-1.80.0-cp313-cp313-win_amd64.whl", hash = "sha256:7843b9ac6ff8ca508424d0dd968bd9a1a4559967e4a290f26be5bd6f04af2234", size = 1162167, upload-time = "2026-03-30T08:51:41.498Z" },
{ url = "https://files.pythonhosted.org/packages/0e/44/7beeee2348f9f412804f5bf80b7d13b81d522bf926a338ae3da46b2213b7/grpcio_tools-1.80.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:12f950470449dbeec78317dbc090add7a00eb6ca812af7b0538ab7441e0a42c3", size = 2550303, upload-time = "2026-03-30T08:51:44.373Z" },
{ url = "https://files.pythonhosted.org/packages/2d/aa/f77dd85409a1855f8c6319ffc69d81e8c3ffe122ee3a7136653e1991d8b6/grpcio_tools-1.80.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:d3f9a376a29c9adf62bb56f7ff5bc81eb4abeaf53d1e7dde5015564832901a51", size = 5709778, upload-time = "2026-03-30T08:51:47.112Z" },
{ url = "https://files.pythonhosted.org/packages/9c/7c/ab7af4883ebdfdc228b853de89fed409703955e8d47285b321a5794856bd/grpcio_tools-1.80.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ba1ffbf2cff71533615e2c5a138ed5569611eec9ae7f9c67b8898e127b54ac0", size = 2597928, upload-time = "2026-03-30T08:51:49.494Z" },
{ url = "https://files.pythonhosted.org/packages/22/e8/4381a963d472e3ab6690ba067ed2b1f1abf8518b10f402678bd2dcb79a54/grpcio_tools-1.80.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:13f60f8d9397c514c6745a967d22b5c8c698347e88deebca1ff2e1b94555e450", size = 2909333, upload-time = "2026-03-30T08:51:52.124Z" },
{ url = "https://files.pythonhosted.org/packages/94/cb/356b5fdf79dd99455b425fb16302fe60995554ceb721afbf3cf770a19208/grpcio_tools-1.80.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:88d77bad5dd3cd5e6f952c4ecdd0ee33e0c02ecfc2e4b0cbee3391ac19e0a431", size = 2660217, upload-time = "2026-03-30T08:51:55.066Z" },
{ url = "https://files.pythonhosted.org/packages/2b/d7/1752018cc2c36b2c5612051379e2e5f59f2dbe612de23e817d2f066a9487/grpcio_tools-1.80.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:017945c3e98a4ed1c4e21399781b4137fc08dfc1f802c8ace2e64ef52d32b142", size = 3113896, upload-time = "2026-03-30T08:51:57.3Z" },
{ url = "https://files.pythonhosted.org/packages/cc/17/695bbe454f70df35c03e22b48c5314683b913d3e6ed35ec90d065418c1ab/grpcio_tools-1.80.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a33e265d4db803495007a6c623eafb0f6b9bb123ff4a0af89e44567dad809b88", size = 3661950, upload-time = "2026-03-30T08:51:59.867Z" },
{ url = "https://files.pythonhosted.org/packages/9c/d0/533d87629ec823c02c9169ee20228f734c264b209dcdf55268b5a14cde0a/grpcio_tools-1.80.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6c129da370c5f85f569be2e545317dda786a60dd51d7deea29b03b0c05f6aac3", size = 3328755, upload-time = "2026-03-30T08:52:02.942Z" },
{ url = "https://files.pythonhosted.org/packages/08/a1/504d7838770c73a9761e8a8ff4869dba1146b44f297ff0ac6641481942d3/grpcio_tools-1.80.0-cp314-cp314-win32.whl", hash = "sha256:25742de5958ae4325249a37e724e7c0e5120f8e302a24a977ebd1737b48a5e97", size = 1019620, upload-time = "2026-03-30T08:52:05.342Z" },
{ url = "https://files.pythonhosted.org/packages/f3/75/8b7cd281c5cdfb4ca2c308f7e9b2799bab2be6e7a9e9212ea5a82e2aecd4/grpcio_tools-1.80.0-cp314-cp314-win_amd64.whl", hash = "sha256:bbf8eeef78fda1966f732f79c1c802fadd5cfd203d845d2af4d314d18569069c", size = 1194210, upload-time = "2026-03-30T08:52:08.105Z" },
]
[[package]]
@@ -854,6 +866,50 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
]
[[package]]
name = "httptools"
version = "0.8.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/43/e5/d471fcb0e14523fe1c3f4ba58ca52480e7bd70ad7109a3846bc75892f7fb/httptools-0.8.0.tar.gz", hash = "sha256:6b2a32f18d97e16e90827d7a819ffa8dbd8cc245fc4e1fa9d1095b54ef4bd999", size = 271342, upload-time = "2026-05-25T22:17:48.841Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/40/b9/be66eb0decd730d89b9c94f930e4b8d87787b05724bb84af98bfd825f72c/httptools-0.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bf3b6f807c8541503cecfbb8a8dffb385640d0d96102f3d112aa8740f9b7c826", size = 208805, upload-time = "2026-05-25T22:16:50.434Z" },
{ url = "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:da684f2e1aa2ee9bdcb083f3f3a68c5956750b375bc5df864d3a5f0c42a40b77", size = 113527, upload-time = "2026-05-25T22:16:51.672Z" },
{ url = "https://files.pythonhosted.org/packages/e6/e4/77487e14fc7be47180fd0eb4267c7486d0cc59b74031839a3daf8650136b/httptools-0.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6f21e2a3b0067bbe7f67e34cfd16276af556e5e52f4c7503be0cb5f90e905e4", size = 450035, upload-time = "2026-05-25T22:16:53.313Z" },
{ url = "https://files.pythonhosted.org/packages/da/72/5a8f787e323f56fbd86c32a4be92a86776e4cfe8b4317db999f452028362/httptools-0.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea897f0c729581ebf72131a438a7932d9b14efef72d75ada966700cac3caaeb", size = 451101, upload-time = "2026-05-25T22:16:54.696Z" },
{ url = "https://files.pythonhosted.org/packages/ed/41/b44a25560955197674b6744cb903664300e239235a5eaa69df0890d87054/httptools-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c0d726cc107fceb7d45f978483b4b70dd8caa836f5914d3434bb18628eb73813", size = 436140, upload-time = "2026-05-25T22:16:56.239Z" },
{ url = "https://files.pythonhosted.org/packages/74/b0/054aac84c03d7e097bf4c605fb7e74eec3d65c0276adf64ee97f3a103ff5/httptools-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9878eb2785ba5eb70631ad269b37976f73d647955e26c91d490eb8a4edfda4ba", size = 437041, upload-time = "2026-05-25T22:16:57.716Z" },
{ url = "https://files.pythonhosted.org/packages/f8/d2/c3eedaef57de65c3cc5f8dc244cf12d09c84ad258a479055aad6db23206c/httptools-0.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ed377e64805bdba4943c82717333f8f8603a13b09aff9cead2717c6c817fb168", size = 208428, upload-time = "2026-05-25T22:16:59.717Z" },
{ url = "https://files.pythonhosted.org/packages/f1/94/dfe435d90d0ef61ec0f2cc3d480eef78c59727c6c2ce039f433882f6131a/httptools-0.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9518c406d7b310f05adb1a37f80acabac40504a575d7c0da6d3e365c695ac20d", size = 113366, upload-time = "2026-05-25T22:17:00.795Z" },
{ url = "https://files.pythonhosted.org/packages/cc/d4/13025f1a56e615dcb331e0bbe2d9a1143212b58c263385fc5d2e558f5bac/httptools-0.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:57278e6fa0424c42a8a3e454828ab4f0aff27b40cddf9679579b98c6dce6a376", size = 464676, upload-time = "2026-05-25T22:17:02.014Z" },
{ url = "https://files.pythonhosted.org/packages/bf/95/4c1c26c0b985f8a3331682d802598f14e32dc41bf7509266eb2c04ad4801/httptools-0.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bbb8caadb2b742d293169d2b458b5c001ef70e3158704aa3d3ef9597624c5d1d", size = 464235, upload-time = "2026-05-25T22:17:03.109Z" },
{ url = "https://files.pythonhosted.org/packages/a2/82/6735be2b0ca527718c431cdb8e5f70c3862c0844a687df0f572c51e11497/httptools-0.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:52dd695b865fe96d9d2b16b64a895f3f57bf3cb064e8383cd3b5713a069e8085", size = 449809, upload-time = "2026-05-25T22:17:04.443Z" },
{ url = "https://files.pythonhosted.org/packages/b5/f9/5811c74f37a758c8a4aa3dc430375119d335947e883efc4664d8f3559a41/httptools-0.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:20b4aac66ff65f7db06a375808b78f42a94970aa22e826b3cb2b43eb09174124", size = 452174, upload-time = "2026-05-25T22:17:05.476Z" },
{ url = "https://files.pythonhosted.org/packages/14/88/1d21a36da8f5cb0fa49eafd4b169eba5608d57e75bbcf61845cbc6243216/httptools-0.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:880490234c10f70a9830743097e8958d6e4b9f5a0ffc24515023afeef984054d", size = 208247, upload-time = "2026-05-25T22:17:07.843Z" },
{ url = "https://files.pythonhosted.org/packages/a5/42/cc4feea2945cb3051038f090c9b36bd5b8a9d7f5a894a506a8983e33fd1c/httptools-0.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5931891fb7b441b8a3853cf1b85c82c903defce084dd5f6771ca46e31bf862c5", size = 113064, upload-time = "2026-05-25T22:17:09.136Z" },
{ url = "https://files.pythonhosted.org/packages/e3/a6/febbb8b8db0f58b38e44ad6cb946e6a255ae49b55f2e8543408fb7501ccd/httptools-0.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b15fc622b0f869d19207c4089a501d9bcc63ca5e071ffdd2f03f922df882dcb2", size = 523851, upload-time = "2026-05-25T22:17:10.106Z" },
{ url = "https://files.pythonhosted.org/packages/b7/e4/f90a0df0b83beff265b7e3b65f2a4cefd95792d4be0ac3e16049f2acd3c2/httptools-0.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:425f83884fd6343828d8c565f046cb72b6d19063f6924093e11bcd8e1548cd09", size = 518842, upload-time = "2026-05-25T22:17:11.218Z" },
{ url = "https://files.pythonhosted.org/packages/9e/2d/0c9ac76dd2c893841fbf6498d6acec4f2442e1b7067f6e3e316a80e494e8/httptools-0.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ef7c3c97f4311c7be57e2986629df89d49cb434dbff78eafcd48c2bff986b15a", size = 501238, upload-time = "2026-05-25T22:17:12.728Z" },
{ url = "https://files.pythonhosted.org/packages/ca/42/906adc91ae3a5fa9c59c0a2f21c139725bd7e5b41ae6acd485cd14123ebf/httptools-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a1afd7c9fbff0d9f5d489c4ce2768bd09c84a46ddefc7161e6aa82ae35c85745", size = 509567, upload-time = "2026-05-25T22:17:13.842Z" },
{ url = "https://files.pythonhosted.org/packages/5e/e5/8cfcabc5546e8022f168be28bcdaa128a240a0befdd03b59d558b4f18bd6/httptools-0.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:614ceea8ea606848bece2338ac03b3ce5324bcb4be8dc7d377ed708012fa4db8", size = 205148, upload-time = "2026-05-25T22:17:16.333Z" },
{ url = "https://files.pythonhosted.org/packages/2a/0e/0fb14848c19a686c8062ff9067c1a48793e3224b47bc5b201535b6036fce/httptools-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2d689918c15a013c65ef52d9fd495d766893ab831a2c8d89f2ac5940a5df847c", size = 111368, upload-time = "2026-05-25T22:17:17.586Z" },
{ url = "https://files.pythonhosted.org/packages/2e/1b/46f1cecf06b9bbde8e4b8c88034ac7908989e5ff7a3a388ef38392949c1f/httptools-0.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eb3028cca2fc0a6d720e52ef61d8ebb62fcbfeb1de56874546d858d3f25a26b7", size = 486447, upload-time = "2026-05-25T22:17:18.564Z" },
{ url = "https://files.pythonhosted.org/packages/77/00/258bfc0837221f81d9725c45f9b948a6a6b2994a147a4fb66e85100c668f/httptools-0.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:88bdd940f2b5d487b4d032c6afa5489a7dc4694410d43de3c38c4fb3af0dc45d", size = 482448, upload-time = "2026-05-25T22:17:19.912Z" },
{ url = "https://files.pythonhosted.org/packages/04/ab/d1cef3b5523f4d272a70f42a776c3169a2dddfe3a54de4b2ce4a36341528/httptools-0.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6a43c9dd399758ccc0531acb0a3c4a6c299ee893ee9400e9c893b7bdcfae0681", size = 464460, upload-time = "2026-05-25T22:17:20.882Z" },
{ url = "https://files.pythonhosted.org/packages/ce/48/5d1d072442277bb2b3434e0e60690b8e8c23840ef7de8b6ea54040a536d3/httptools-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0770728beb05094c809b98e814edff5fef69d26ad7d21185f2f6d5884a0ba683", size = 471312, upload-time = "2026-05-25T22:17:22.085Z" },
{ url = "https://files.pythonhosted.org/packages/1a/12/fa3fbf5f9517b273edea2dc982aa82a8c634091e67c590792b729017bc6f/httptools-0.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:de242a49b5d18e0a8776e654e9f6bf6d89f3875a5c35b425a0e7ce940feb3fd6", size = 206183, upload-time = "2026-05-25T22:17:24.004Z" },
{ url = "https://files.pythonhosted.org/packages/30/fc/5e7c4cb443370f2090a3aba0453a07384d29ff66b7435bb90e77e1037599/httptools-0.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:159e9ab5f701ccd42e555a12f1ad8ff69702910fc1c996cf2bb66e5fcb7a231b", size = 112079, upload-time = "2026-05-25T22:17:25.216Z" },
{ url = "https://files.pythonhosted.org/packages/ba/53/771bd891eb0f236f32145d6a1775777ec85745f3cc983a1f23d1a3b8ddfe/httptools-0.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c4a9f1707e4823d54dfec6c33fa3697d302aed536ed352a7ebb5a061ddb869d0", size = 481596, upload-time = "2026-05-25T22:17:26.186Z" },
{ url = "https://files.pythonhosted.org/packages/62/42/94e15bc68ce3d423243c45d7f1b0c7561f13844f97dc52ae23182fb65628/httptools-0.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d76ad7b951387e3632c8716a9bb03ac5b45c5f16119aa409db0459520887944e", size = 480865, upload-time = "2026-05-25T22:17:27.542Z" },
{ url = "https://files.pythonhosted.org/packages/1c/7c/fe2980fc03723272e30f135b62360b075f513dfe7cc73aef36c7f04012bd/httptools-0.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a3b7387147361c3fd47a0bde763c5c91b5b4cd4dc9989b8ece84ff436c99843b", size = 463189, upload-time = "2026-05-25T22:17:28.546Z" },
{ url = "https://files.pythonhosted.org/packages/15/1b/47fc5fff68acd1bfa20b4734059c9a06cadb88119dcd5258b5b0d21d91c8/httptools-0.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f256d6ce930c52ca1cb2a960b7da03548c454e7d28b06059ad41bfe789036ce0", size = 466610, upload-time = "2026-05-25T22:17:29.816Z" },
{ url = "https://files.pythonhosted.org/packages/fd/c4/121648f68ce066d7bd762d6b6d97e620847642d38d54f3d90ff11d947629/httptools-0.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:de1ed58a974e75d56560acc7e7fed01a454994429456f65209789992e41f2568", size = 215023, upload-time = "2026-05-25T22:17:32.401Z" },
{ url = "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e93c227b595c6926c1acee96891dd9da4be338cfbe82e5cd3bb9d8dd7dc4ac0b", size = 117405, upload-time = "2026-05-25T22:17:33.742Z" },
{ url = "https://files.pythonhosted.org/packages/fc/37/fccd705f795386bb05bf413012fecff2a33e5aa8c2f069096de3e9fd8702/httptools-0.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2a021c3a8e65cc125390d72f59b968afca3bdcaff25bd67965e0a055a14946ca", size = 558497, upload-time = "2026-05-25T22:17:34.732Z" },
{ url = "https://files.pythonhosted.org/packages/bd/39/f172e8003576de35f5ba77ff417cf0e34429d35dc014deef15afa337a72c/httptools-0.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48774d39cbb70e2b1f71f88852a3087ae1d3a1eb80482bb48c13067ab080c14f", size = 571585, upload-time = "2026-05-25T22:17:35.813Z" },
{ url = "https://files.pythonhosted.org/packages/3e/b9/f5564760af99f3dbbf3f9104dc00e5da27e96cf433c6bdcf77617f70bf3f/httptools-0.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:88eead8ec8680a9f146c655bc88445a325bd7921cfd8194c7337e9467282427d", size = 543297, upload-time = "2026-05-25T22:17:37.08Z" },
{ url = "https://files.pythonhosted.org/packages/99/67/8d9f2c313618e161b82f3873188e7196126da1d6e29688df40eb3997c77a/httptools-0.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2c032fa028f46871ec7e1fc59fc15e8023eab3e6bbe6ece786a1611719a5d081", size = 539535, upload-time = "2026-05-25T22:17:38.032Z" },
]
[[package]]
name = "httpx"
version = "0.28.1"
@@ -1246,7 +1302,7 @@ wheels = [
[[package]]
name = "jupyter-server"
version = "2.18.0"
version = "2.20.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
@@ -1269,9 +1325,9 @@ dependencies = [
{ name = "traitlets" },
{ name = "websocket-client" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f1/ec/9302cec1ccacdd33c1b1312ac31681c8975cae56c626d783ab49edf9c681/jupyter_server-2.18.0.tar.gz", hash = "sha256:568b27bce4320a53c3eebf1bdcbee9acf48a8ab7f66ec83d900ca9909d4fb770", size = 751152, upload-time = "2026-05-04T13:39:29.685Z" }
sdist = { url = "https://files.pythonhosted.org/packages/6b/dc/db3a582633170186f8c8b31298d7eb26ad0eb031a1f53476c258b64eed05/jupyter_server-2.20.0.tar.gz", hash = "sha256:b5778ba337d8015a3dc2b80803ecdd5ac18d3797fddf61a50ea5fb472b4ebe14", size = 756523, upload-time = "2026-06-17T12:09:09.435Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cf/f9/050312d92072ddb9ce14c11171804c07435790c98d4350935a780d9e10c2/jupyter_server-2.18.0-py3-none-any.whl", hash = "sha256:69a5397a039d689da81a45955f9b23e95ee167f6d8a8d64372fb616f2aac650a", size = 391687, upload-time = "2026-05-04T13:39:27.549Z" },
{ url = "https://files.pythonhosted.org/packages/f3/71/8c002223e873a870f5c41dc69b0a7c922301123e4a31d5d01ecb700aef77/jupyter_server-2.20.0-py3-none-any.whl", hash = "sha256:c3b67c93c471e947c18b5026f04f21614218adb706df8f48227d3ee8e0a7cdcc", size = 393143, upload-time = "2026-06-17T12:09:07.234Z" },
]
[[package]]
@@ -1289,7 +1345,7 @@ wheels = [
[[package]]
name = "jupyterlab"
version = "4.5.7"
version = "4.5.9"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "async-lru" },
@@ -1307,9 +1363,9 @@ dependencies = [
{ name = "tornado" },
{ name = "traitlets" },
]
sdist = { url = "https://files.pythonhosted.org/packages/2b/22/8440ec827762146e7cdecf04335bd348795899d29dc6ae82238707353a2c/jupyterlab-4.5.7.tar.gz", hash = "sha256:55a9822c4754da305f41e113452c68383e214dcf96de760146af89ce5d5117b0", size = 23992763, upload-time = "2026-04-29T16:43:51.328Z" }
sdist = { url = "https://files.pythonhosted.org/packages/e8/52/a8d4895bef501ffeb6af448e8bf7079541c7772978211963aa653518c2d9/jupyterlab-4.5.9.tar.gz", hash = "sha256:dd79a073fecae7a39066ea99e4627ed6c76269ac926e95a810e1e1df6358d865", size = 23994445, upload-time = "2026-06-17T15:42:16.406Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3d/aa/537b8f7d80e799af19af35fb3ddfc970b951088a13c57dd9387dcfbb7f61/jupyterlab-4.5.7-py3-none-any.whl", hash = "sha256:fba4cb0e2c44a52859669d8c98b45de029d5e515f8407bf8534d2a8fc5f0964d", size = 12450123, upload-time = "2026-04-29T16:43:46.639Z" },
{ url = "https://files.pythonhosted.org/packages/c6/bb/2f9b425062416fba58f580c9b89c3b07277ccdf0a292501fedbca8ea00ea/jupyterlab-4.5.9-py3-none-any.whl", hash = "sha256:5ff0f908e8ac0afbed32b106fdef360f101c0a6654d1bf4a81e98a293ae1b336", size = 12449803, upload-time = "2026-06-17T15:42:12.18Z" },
]
[[package]]
@@ -1382,7 +1438,7 @@ wheels = [
[[package]]
name = "langgraph"
version = "1.2.5"
version = "1.2.6"
source = { editable = "." }
dependencies = [
{ name = "langchain-core" },
@@ -1525,7 +1581,7 @@ test = [
[[package]]
name = "langgraph-api"
version = "0.6.39"
version = "0.10.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cloudpickle", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
@@ -1533,9 +1589,11 @@ dependencies = [
{ name = "grpcio", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "grpcio-health-checking", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "grpcio-tools", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "httptools", marker = "python_full_version >= '3.11' and python_full_version < '3.14' and sys_platform != 'win32'" },
{ name = "httpx", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "jsonschema-rs", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "langchain-core", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "langchain-protocol", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "langgraph", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "langgraph-checkpoint", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "langgraph-runtime-inmem", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
@@ -1554,11 +1612,14 @@ dependencies = [
{ name = "truststore", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "uuid-utils", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "uvicorn", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "uvloop", marker = "python_full_version >= '3.11' and python_full_version < '3.14' and sys_platform != 'win32'" },
{ name = "watchfiles", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "websockets", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "zstandard", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b2/52/f7d25b475768e5e0748d4725c64909fc7e56a714e064976a32e7c68f6d9e/langgraph_api-0.6.39.tar.gz", hash = "sha256:052191ec9c49d76b0d5592a60fe6324eafde40e7a1afba65d1ce11a6a074674b", size = 447880, upload-time = "2026-01-16T19:54:07.475Z" }
sdist = { url = "https://files.pythonhosted.org/packages/7d/17/a23ecdad3de7e48209bc8d534312ba83e332126ec60da9e6487461b02597/langgraph_api-0.10.0.tar.gz", hash = "sha256:f594a160857e2cd7fb2352bba585111177a4a394625ad0cf5898814754fb7bc1", size = 713903, upload-time = "2026-06-11T14:36:50.469Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ea/a7/5ecccdc0e2a3900e08ac263b6e9cc6c5172c52ce3c4dda7750511e6fecc6/langgraph_api-0.6.39-py3-none-any.whl", hash = "sha256:50464c4983641c8b006a7f452583127ee2819806fc6d04844b08d5d3430df12e", size = 351764, upload-time = "2026-01-16T19:54:05.81Z" },
{ url = "https://files.pythonhosted.org/packages/0e/38/6b0cdcaaed9b3105102b452a5a70fb08894a9511458cf00c061c4725347c/langgraph_api-0.10.0-py3-none-any.whl", hash = "sha256:f4b545bf1936c4e90bed1cc07a6852b1be37e1667007ab4736d800cc18e9f9b3", size = 577475, upload-time = "2026-06-11T14:36:48.838Z" },
]
[[package]]
@@ -1721,7 +1782,7 @@ inmem = [
requires-dist = [
{ name = "click", specifier = ">=8.1.7" },
{ name = "httpx", specifier = ">=0.24.0" },
{ name = "langgraph-api", marker = "python_full_version >= '3.11' and extra == 'inmem'", specifier = ">=0.5.35,<0.12.0a0" },
{ name = "langgraph-api", marker = "python_full_version >= '3.11' and extra == 'inmem'", specifier = ">=0.5.35,<0.12.0" },
{ name = "langgraph-runtime-inmem", marker = "python_full_version >= '3.11' and extra == 'inmem'", specifier = ">=0.7" },
{ name = "langgraph-sdk", marker = "python_full_version >= '3.11'", specifier = ">=0.1.0" },
{ name = "pathspec", specifier = ">=0.11.0" },
@@ -1808,19 +1869,20 @@ test = [
[[package]]
name = "langgraph-runtime-inmem"
version = "0.22.1"
version = "0.30.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "blockbuster", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "croniter", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "langgraph", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "langgraph-checkpoint", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "sse-starlette", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "starlette", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "structlog", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/cb/8d/4b42a852a869c6a60aceae4e6157030c427ae9c07bf28769cc8e2fcec16b/langgraph_runtime_inmem-0.22.1.tar.gz", hash = "sha256:bbd983975dc372ad5cd5288263d3471732b0dff2bab3c6f41e5fe5b3a38ea1ee", size = 104172, upload-time = "2026-01-16T15:17:23.381Z" }
sdist = { url = "https://files.pythonhosted.org/packages/98/19/5d330e22e3ee2569742d3577b4ddfbb6b8e383f2edd9724b4a4b73735717/langgraph_runtime_inmem-0.30.0.tar.gz", hash = "sha256:31954e1de6cd43c284b425243d4faeae818f68b3daca4dbe4313e651b6f5e11d", size = 129940, upload-time = "2026-06-11T14:22:46.985Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b3/b2/336cb642ff4df29d46bb54e21b4ecbc6e2e38e606c1e3584d3ef67621c41/langgraph_runtime_inmem-0.22.1-py3-none-any.whl", hash = "sha256:2a04747db050cd7db878fb0c68fc7dbe8198ed71db35da323a27d1a7b2de3e97", size = 38291, upload-time = "2026-01-16T15:17:21.864Z" },
{ url = "https://files.pythonhosted.org/packages/fe/df/cfb15c70fa4dcab9ea48f8fda9f4ed87d1767eea6e4d2901dc704da297ba/langgraph_runtime_inmem-0.30.0-py3-none-any.whl", hash = "sha256:08a36b83b5e32fe6e30cb25062a1e671a42e2a0206e4043cc95f41198dcbbb12", size = 51762, upload-time = "2026-06-11T14:22:46.012Z" },
]
[[package]]
@@ -1871,7 +1933,7 @@ test = [
[[package]]
name = "langsmith"
version = "0.8.0"
version = "0.8.18"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
@@ -1881,12 +1943,13 @@ dependencies = [
{ name = "requests" },
{ name = "requests-toolbelt" },
{ name = "uuid-utils" },
{ name = "websockets" },
{ name = "xxhash" },
{ name = "zstandard" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a8/64/95f1f013531395f4e8ed73caeee780f65c7c58fe028cb543f8937b45611b/langsmith-0.8.0.tar.gz", hash = "sha256:59fe5b2a56bbbe14a08aa76691f84b49e8675dd21e11b57d80c6db8c08bac2e3", size = 4432996, upload-time = "2026-04-30T22:13:07.341Z" }
sdist = { url = "https://files.pythonhosted.org/packages/9a/d9/a6681aa9847bbbc5ec21abe20a5e233b94e5edcfe39624db607ac7e8ccb4/langsmith-0.8.18.tar.gz", hash = "sha256:32dde9c0e67e053e0fb738921fc8ced768af7b8fa83d7a0e3fd63597cf8776dd", size = 4526988, upload-time = "2026-06-19T13:12:17.123Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f3/e1/a4be2e696c9473bb53298df398237da5674704d781d4b748ed35aeef592a/langsmith-0.8.0-py3-none-any.whl", hash = "sha256:12cc4bc5622b835a6d841964d6034df3617bdb912dae0c1381fd0a68a9b3a3ef", size = 393268, upload-time = "2026-04-30T22:13:05.56Z" },
{ url = "https://files.pythonhosted.org/packages/03/70/0e0cc80a3b064c8d6c8d697c3125ed86e39d5a7393ec6dc8b07cb1cf13c4/langsmith-0.8.18-py3-none-any.whl", hash = "sha256:3940183349993faef48e6c7d08e4822ee9cefd906b362d0e3c2d650314d2f282", size = 508108, upload-time = "2026-06-19T13:12:15.348Z" },
]
[package.optional-dependencies]
@@ -2775,11 +2838,11 @@ wheels = [
[[package]]
name = "pyjwt"
version = "2.12.0"
version = "2.13.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a8/10/e8192be5f38f3e8e7e046716de4cae33d56fd5ae08927a823bb916be36c1/pyjwt-2.12.0.tar.gz", hash = "sha256:2f62390b667cd8257de560b850bb5a883102a388829274147f1d724453f8fb02", size = 102511, upload-time = "2026-03-12T17:15:30.831Z" }
sdist = { url = "https://files.pythonhosted.org/packages/3b/81/58d0ac84e1ef3a3843791d6954d94c0b33d526c75eeb1efbce9d0a4c4077/pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423", size = 107515, upload-time = "2026-05-21T19:54:36.618Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/15/70/70f895f404d363d291dcf62c12c85fdd47619ad9674ac0f53364d035925a/pyjwt-2.12.0-py3-none-any.whl", hash = "sha256:9bb459d1bdd0387967d287f5656bf7ec2b9a26645d1961628cda1764e087fd6e", size = 29700, upload-time = "2026-03-12T17:15:29.257Z" },
{ url = "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728", size = 31274, upload-time = "2026-05-21T19:54:35.362Z" },
]
[[package]]
@@ -3078,14 +3141,14 @@ wheels = [
[[package]]
name = "redis"
version = "7.4.0"
version = "8.0.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/7b/7f/3759b1d0d72b7c92f0d70ffd9dc962b7b7b5ee74e135f9d7d8ab06b8a318/redis-7.4.0.tar.gz", hash = "sha256:64a6ea7bf567ad43c964d2c30d82853f8df927c5c9017766c55a1d1ed95d18ad", size = 4943913, upload-time = "2026-03-24T09:14:37.53Z" }
sdist = { url = "https://files.pythonhosted.org/packages/cc/c3/928b290c2c0ca99ab96eea5b4ff8f30be8112b075301a7d3ba214a3c8c12/redis-8.0.1.tar.gz", hash = "sha256:afc5a7a2f5a084f5b1880dec548dd45be17db7e43c82a30d84f952aefb05cfb0", size = 5114170, upload-time = "2026-06-23T14:52:37.728Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/74/3a/95deec7db1eb53979973ebd156f3369a72732208d1391cd2e5d127062a32/redis-7.4.0-py3-none-any.whl", hash = "sha256:a9c74a5c893a5ef8455a5adb793a31bb70feb821c86eccb62eebef5a19c429ec", size = 409772, upload-time = "2026-03-24T09:14:35.968Z" },
{ url = "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl", hash = "sha256:47daa35a058c23468d6437f17a8c76882cb316b838ef763036af99b96cedd743", size = 502406, upload-time = "2026-06-23T14:52:36.137Z" },
]
[[package]]
@@ -3387,15 +3450,15 @@ wheels = [
[[package]]
name = "starlette"
version = "0.51.0"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio", marker = "python_full_version >= '3.11' and python_full_version < '3.14'" },
{ name = "typing-extensions", marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e7/65/5a1fadcc40c5fdc7df421a7506b79633af8f5d5e3a95c3e72acacec644b9/starlette-0.51.0.tar.gz", hash = "sha256:4c4fda9b1bc67f84037d3d14a5112e523509c369d9d47b111b2f984b0cc5ba6c", size = 2647658, upload-time = "2026-01-10T20:23:15.043Z" }
sdist = { url = "https://files.pythonhosted.org/packages/eb/e3/7c1dc7381d9f8ab7d854328ebfa884e62cb3f3d8549ddfd37c7814f42afa/starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0", size = 2703240, upload-time = "2026-06-12T09:23:11.602Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/18/c4/09985a03dba389d4fe16a9014147a7b02fa76ef3519bf5846462a485876d/starlette-0.51.0-py3-none-any.whl", hash = "sha256:fb460a3d6fd3c958d729fdd96aee297f89a51b0181f16401fe8fd4cb6129165d", size = 74133, upload-time = "2026-01-10T20:23:13.445Z" },
{ url = "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl", hash = "sha256:c7372aae11c3c3f26a42df7bd626cec2f47d03483d261d369516a615a53714c6", size = 73632, upload-time = "2026-06-12T09:23:10.017Z" },
]
[[package]]
@@ -3510,19 +3573,19 @@ wheels = [
[[package]]
name = "tornado"
version = "6.5.5"
version = "6.5.7"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f8/f1/3173dfa4a18db4a9b03e5d55325559dab51ee653763bb8745a75af491286/tornado-6.5.5.tar.gz", hash = "sha256:192b8f3ea91bd7f1f50c06955416ed76c6b72f96779b962f07f911b91e8d30e9", size = 516006, upload-time = "2026-03-10T21:31:02.067Z" }
sdist = { url = "https://files.pythonhosted.org/packages/64/24/95ec527ad67b76d59299e5465b3935d05e4294b7e0290a3924b7487df30b/tornado-6.5.7.tar.gz", hash = "sha256:66c513a76cda70d53907bc27cf1447557699c2e95aa48ba27a442ff61c3ddfc2", size = 519252, upload-time = "2026-06-08T17:34:51.232Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/59/8c/77f5097695f4dd8255ecbd08b2a1ed8ba8b953d337804dd7080f199e12bf/tornado-6.5.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:487dc9cc380e29f58c7ab88f9e27cdeef04b2140862e5076a66fb6bb68bb1bfa", size = 445983, upload-time = "2026-03-10T21:30:44.28Z" },
{ url = "https://files.pythonhosted.org/packages/ab/5e/7625b76cd10f98f1516c36ce0346de62061156352353ef2da44e5c21523c/tornado-6.5.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:65a7f1d46d4bb41df1ac99f5fcb685fb25c7e61613742d5108b010975a9a6521", size = 444246, upload-time = "2026-03-10T21:30:46.571Z" },
{ url = "https://files.pythonhosted.org/packages/b2/04/7b5705d5b3c0fab088f434f9c83edac1573830ca49ccf29fb83bf7178eec/tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e74c92e8e65086b338fd56333fb9a68b9f6f2fe7ad532645a290a464bcf46be5", size = 447229, upload-time = "2026-03-10T21:30:48.273Z" },
{ url = "https://files.pythonhosted.org/packages/34/01/74e034a30ef59afb4097ef8659515e96a39d910b712a89af76f5e4e1f93c/tornado-6.5.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:435319e9e340276428bbdb4e7fa732c2d399386d1de5686cb331ec8eee754f07", size = 448192, upload-time = "2026-03-10T21:30:51.22Z" },
{ url = "https://files.pythonhosted.org/packages/be/00/fe9e02c5a96429fce1a1d15a517f5d8444f9c412e0bb9eadfbe3b0fc55bf/tornado-6.5.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3f54aa540bdbfee7b9eb268ead60e7d199de5021facd276819c193c0fb28ea4e", size = 448039, upload-time = "2026-03-10T21:30:53.52Z" },
{ url = "https://files.pythonhosted.org/packages/82/9e/656ee4cec0398b1d18d0f1eb6372c41c6b889722641d84948351ae19556d/tornado-6.5.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36abed1754faeb80fbd6e64db2758091e1320f6bba74a4cf8c09cd18ccce8aca", size = 447445, upload-time = "2026-03-10T21:30:55.541Z" },
{ url = "https://files.pythonhosted.org/packages/5a/76/4921c00511f88af86a33de770d64141170f1cfd9c00311aea689949e274e/tornado-6.5.5-cp39-abi3-win32.whl", hash = "sha256:dd3eafaaeec1c7f2f8fdcd5f964e8907ad788fe8a5a32c4426fbbdda621223b7", size = 448582, upload-time = "2026-03-10T21:30:57.142Z" },
{ url = "https://files.pythonhosted.org/packages/2c/23/f6c6112a04d28eed765e374435fb1a9198f73e1ec4b4024184f21faeb1ad/tornado-6.5.5-cp39-abi3-win_amd64.whl", hash = "sha256:6443a794ba961a9f619b1ae926a2e900ac20c34483eea67be4ed8f1e58d3ef7b", size = 448990, upload-time = "2026-03-10T21:30:58.857Z" },
{ url = "https://files.pythonhosted.org/packages/b7/c8/876602cbc96469911f0939f703453c1157b0c826ecb05bdd32e023397d4e/tornado-6.5.5-cp39-abi3-win_arm64.whl", hash = "sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6", size = 448016, upload-time = "2026-03-10T21:31:00.43Z" },
{ url = "https://files.pythonhosted.org/packages/02/dc/c7043cab6fed8ae159fc1923ce829ada35c4dbd797d408a43858ffaf9639/tornado-6.5.7-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:148b2eb15c2c765a50796172c1e499649b35f30d2e3c3d3e15913cfa56bfb163", size = 448543, upload-time = "2026-06-08T17:34:38.052Z" },
{ url = "https://files.pythonhosted.org/packages/92/4f/090b1431e5a43df696feceffc268c5383cc079ecb5f08ce58f917109aafe/tornado-6.5.7-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9da38de27f1da3b78a966f0dae12b5a1ea9afe72ca805d84ff06508272ddf100", size = 446707, upload-time = "2026-06-08T17:34:39.594Z" },
{ url = "https://files.pythonhosted.org/packages/37/d8/ef374952fd5da67d4463122c2b8e5a96536ec10b4b339254c6dcde81d01c/tornado-6.5.7-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8d759e71906ee783f8867b93bf26a265743da4c1e2f4a018464c1ba019862972", size = 449774, upload-time = "2026-06-08T17:34:41.204Z" },
{ url = "https://files.pythonhosted.org/packages/35/37/d434c73f4c6e014b745b9b37085f34f40c022f007efff3d7fe65991899f3/tornado-6.5.7-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a46347a18f23fb92b396beebe0fb78f61dda0cc302445202c16203d8a18848b", size = 450745, upload-time = "2026-06-08T17:34:42.531Z" },
{ url = "https://files.pythonhosted.org/packages/b6/2b/56b9aff361d7f1ab728a805ec7d7ea835f8807afa9f5cc690ea0e630efb9/tornado-6.5.7-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7778b30bef919231265e91c69963ce0f49a1e9c07ac900bbe75b19ce2575ba92", size = 450578, upload-time = "2026-06-08T17:34:43.787Z" },
{ url = "https://files.pythonhosted.org/packages/02/30/a7444fb23aa76860a14198fab96ac79f1866b0a6e19e26c4381b0938e50f/tornado-6.5.7-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e726f0c75da7726eec023aa62751ff8878bd2737e34fbdd33b1ae5897d2200f5", size = 449985, upload-time = "2026-06-08T17:34:45.326Z" },
{ url = "https://files.pythonhosted.org/packages/5c/42/5f0e56c01e8d9d36f4e23f367b85ae6cae0c1ecddd5e6977d8388ad27488/tornado-6.5.7-cp39-abi3-win32.whl", hash = "sha256:f8de3bf12d3efdd0cbe7c8887868198f8a91415e3f29fcf258d9b8eb7b1d9ae4", size = 451047, upload-time = "2026-06-08T17:34:46.784Z" },
{ url = "https://files.pythonhosted.org/packages/c9/a4/b393076ffb21b469eec5b328a0534cf03a3b90bfc6b1f09507cdd075d938/tornado-6.5.7-cp39-abi3-win_amd64.whl", hash = "sha256:de942f843533a039ef9fa3d9c88c7cd8a7c94553fb5ad0154270989b3d99a2c4", size = 451485, upload-time = "2026-06-08T17:34:48.248Z" },
{ url = "https://files.pythonhosted.org/packages/71/2e/7b1c769803121b809112cf9a00681c472eae1d80e32d7ec0e0bd61d0d0e1/tornado-6.5.7-cp39-abi3-win_arm64.whl", hash = "sha256:ff934fce95643af5f11efdae618eaa73d469dc588641e5c8d19295a0c65c4796", size = 450506, upload-time = "2026-06-08T17:34:49.702Z" },
]
[[package]]
+37 -7
View File
@@ -1,16 +1,36 @@
# LangGraph Prebuilt
This library defines high-level APIs for creating and executing LangGraph agents and tools.
[![PyPI - Version](https://img.shields.io/pypi/v/langgraph-prebuilt?label=%20)](https://pypi.org/project/langgraph-prebuilt/#history)
[![PyPI - License](https://img.shields.io/pypi/l/langgraph-prebuilt)](https://opensource.org/licenses/MIT)
[![PyPI - Downloads](https://img.shields.io/pepy/dt/langgraph-prebuilt)](https://pypistats.org/packages/langgraph-prebuilt)
[![Twitter](https://img.shields.io/twitter/url/https/twitter.com/langchain_oss.svg?style=social&label=Follow%20%40LangChain)](https://x.com/langchain_oss)
To help you ship LangGraph apps to production faster, check out [LangSmith](https://www.langchain.com/langsmith).
[LangSmith](https://www.langchain.com/langsmith) is a unified developer platform for building, testing, and monitoring LLM applications.
## Quick Install
```bash
uv add langgraph
```
## 🤔 What is this?
This library defines high-level APIs for creating and executing LangGraph agents and tools. It includes prebuilt components such as `create_react_agent`, `ToolNode`, validation helpers, and Agent Inbox schemas.
## 📖 Documentation
For full documentation, see the [API reference](https://reference.langchain.com/python/langgraph.prebuilt/). For conceptual guides and tutorials, see the [LangGraph Docs](https://docs.langchain.com/oss/python/langgraph/overview).
> [!IMPORTANT]
> This library is meant to be bundled with `langgraph`, don't install it directly
> This library is bundled with `langgraph`; most users should install `langgraph` instead of installing `langgraph-prebuilt` directly.
## Agents
`langgraph-prebuilt` provides an [implementation](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent) of a tool-calling [ReAct-style](https://langchain-ai.github.io/langgraph/concepts/agentic_concepts/#react-implementation) agent - `create_react_agent`:
`langgraph-prebuilt` provides an [implementation](https://reference.langchain.com/python/langgraph.prebuilt/chat_agent_executor/create_react_agent) of a tool-calling ReAct-style agent - `create_react_agent`:
```bash
pip install langchain-anthropic
uv add langchain-anthropic
```
```python
@@ -39,7 +59,7 @@ app.invoke(
### ToolNode
`langgraph-prebuilt` provides an [implementation](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.tool_node.ToolNode) of a node that executes tool calls - `ToolNode`:
`langgraph-prebuilt` provides an [implementation](https://reference.langchain.com/python/langgraph.prebuilt/tool_node/ToolNode) of a node that executes tool calls - `ToolNode`:
```python
from langgraph.prebuilt import ToolNode
@@ -61,7 +81,7 @@ tool_node.invoke({"messages": [ai_message]})
### ValidationNode
`langgraph-prebuilt` provides an [implementation](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.tool_validator.ValidationNode) of a node that validates tool calls against a pydantic schema - `ValidationNode`:
`langgraph-prebuilt` provides an [implementation](https://reference.langchain.com/python/langgraph.prebuilt/tool_validator/ValidationNode) of a node that validates tool calls against a pydantic schema - `ValidationNode`:
```python
from pydantic import BaseModel, field_validator
@@ -114,4 +134,14 @@ def my_graph_function():
if response['type'] == "response":
# Do something with the response
...
```
```
## 📕 Releases & Versioning
See our [Releases](https://docs.langchain.com/oss/python/release-policy) and [Versioning](https://docs.langchain.com/oss/python/versioning) policies.
## 💁 Contributing
As an open-source project in a rapidly developing field, we are extremely open to contributions, whether it be in the form of a new feature, improved infrastructure, or better documentation.
For detailed information on how to contribute, see the [Contributing Guide](https://docs.langchain.com/oss/python/contributing/overview).
+5 -4
View File
@@ -285,7 +285,7 @@ wheels = [
[[package]]
name = "langgraph"
version = "1.2.5"
version = "1.2.6"
source = { editable = "../langgraph" }
dependencies = [
{ name = "langchain-core" },
@@ -640,7 +640,7 @@ test = [
[[package]]
name = "langsmith"
version = "0.8.0"
version = "0.8.18"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
@@ -650,12 +650,13 @@ dependencies = [
{ name = "requests" },
{ name = "requests-toolbelt" },
{ name = "uuid-utils" },
{ name = "websockets" },
{ name = "xxhash" },
{ name = "zstandard" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a8/64/95f1f013531395f4e8ed73caeee780f65c7c58fe028cb543f8937b45611b/langsmith-0.8.0.tar.gz", hash = "sha256:59fe5b2a56bbbe14a08aa76691f84b49e8675dd21e11b57d80c6db8c08bac2e3", size = 4432996, upload-time = "2026-04-30T22:13:07.341Z" }
sdist = { url = "https://files.pythonhosted.org/packages/9a/d9/a6681aa9847bbbc5ec21abe20a5e233b94e5edcfe39624db607ac7e8ccb4/langsmith-0.8.18.tar.gz", hash = "sha256:32dde9c0e67e053e0fb738921fc8ced768af7b8fa83d7a0e3fd63597cf8776dd", size = 4526988, upload-time = "2026-06-19T13:12:17.123Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f3/e1/a4be2e696c9473bb53298df398237da5674704d781d4b748ed35aeef592a/langsmith-0.8.0-py3-none-any.whl", hash = "sha256:12cc4bc5622b835a6d841964d6034df3617bdb912dae0c1381fd0a68a9b3a3ef", size = 393268, upload-time = "2026-04-30T22:13:05.56Z" },
{ url = "https://files.pythonhosted.org/packages/03/70/0e0cc80a3b064c8d6c8d697c3125ed86e39d5a7393ec6dc8b07cb1cf13c4/langsmith-0.8.18-py3-none-any.whl", hash = "sha256:3940183349993faef48e6c7d08e4822ee9cefd906b362d0e3c2d650314d2f282", size = 508108, upload-time = "2026-06-19T13:12:15.348Z" },
]
[[package]]
+11 -1
View File
@@ -1 +1,11 @@
This repository has been moved to [langchain-ai/langgraphjs](https://github.com/langchain-ai/langgraphjs/tree/main/libs/sdk).
# LangGraph JavaScript SDK
Looking for the JS/TS version? Check out [LangGraph.js](https://github.com/langchain-ai/langgraphjs).
## 🤔 What is this?
This package has moved to [langchain-ai/langgraphjs](https://github.com/langchain-ai/langgraphjs/tree/main/libs/sdk).
## 📖 Documentation
For JavaScript and TypeScript documentation, see the [LangGraph.js docs](https://docs.langchain.com/oss/javascript/langgraph/overview).
+30 -9
View File
@@ -1,17 +1,30 @@
# LangGraph Python SDK
This repository contains the Python SDK for interacting with the LangSmith Deployment REST API.
[![PyPI - Version](https://img.shields.io/pypi/v/langgraph-sdk?label=%20)](https://pypi.org/project/langgraph-sdk/#history)
[![PyPI - License](https://img.shields.io/pypi/l/langgraph-sdk)](https://opensource.org/licenses/MIT)
[![PyPI - Downloads](https://img.shields.io/pepy/dt/langgraph-sdk)](https://pypistats.org/packages/langgraph-sdk)
[![Twitter](https://img.shields.io/twitter/url/https/twitter.com/langchain_oss.svg?style=social&label=Follow%20%40LangChain)](https://x.com/langchain_oss)
## Quick Start
To help you ship LangGraph apps to production faster, check out [LangSmith](https://www.langchain.com/langsmith).
[LangSmith](https://www.langchain.com/langsmith) is a unified developer platform for building, testing, and monitoring LLM applications.
To get started with the Python SDK, [install the package](https://pypi.org/project/langgraph-sdk/)
## Quick Install
```bash
pip install -U langgraph-sdk
uv add langgraph-sdk
```
You will need a running LangGraph API server. If you're running a server locally using `langgraph-cli`, SDK will automatically point at `http://localhost:8123`, otherwise
you would need to specify the server URL when creating a client.
## 🤔 What is this?
This library provides the Python SDK for interacting with the LangGraph API. Use it to connect to a running LangGraph API server, manage assistants and threads, and stream runs from Python applications.
You will need a running LangGraph API server. If you're running a server locally using `langgraph-cli`, the SDK will automatically point at `http://localhost:8123`; otherwise, specify the server URL when creating a client.
## 📖 Documentation
For full documentation, see the [API reference](https://reference.langchain.com/python/langgraph-sdk/). For conceptual guides and tutorials, see the [LangGraph Docs](https://docs.langchain.com/oss/python/langgraph/overview).
## Quick Start
```python
from langgraph_sdk import get_client
@@ -43,9 +56,7 @@ async for chunk in client.runs.stream(thread['thread_id'], agent['assistant_id']
## Thread-Centric Streaming (v3)
`client.threads.stream()` returns a context manager that owns the SSE session for one
thread. Typed projections — values snapshots, message streams, tool calls, custom
events — all share the same underlying connection.
`client.threads.stream()` returns a context manager that owns the SSE session for one thread. Typed projections — values snapshots, message streams, tool calls, custom events — all share the same underlying connection.
```python
from langgraph_sdk import get_client
@@ -73,3 +84,13 @@ async with client.threads.stream(
final = await thread.output # terminal state values
```
## 📕 Releases & Versioning
See our [Releases](https://docs.langchain.com/oss/python/release-policy) and [Versioning](https://docs.langchain.com/oss/python/versioning) policies.
## 💁 Contributing
As an open-source project in a rapidly developing field, we are extremely open to contributions, whether it be in the form of a new feature, improved infrastructure, or better documentation.
For detailed information on how to contribute, see the [Contributing Guide](https://docs.langchain.com/oss/python/contributing/overview).
+8 -7
View File
@@ -298,7 +298,7 @@ wheels = [
[[package]]
name = "langgraph"
version = "1.2.5"
version = "1.2.6"
source = { editable = "../langgraph" }
dependencies = [
{ name = "langchain-core" },
@@ -553,7 +553,7 @@ test = [
[[package]]
name = "langsmith"
version = "0.8.0"
version = "0.8.18"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "httpx" },
@@ -563,12 +563,13 @@ dependencies = [
{ name = "requests" },
{ name = "requests-toolbelt" },
{ name = "uuid-utils" },
{ name = "websockets" },
{ name = "xxhash" },
{ name = "zstandard" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a8/64/95f1f013531395f4e8ed73caeee780f65c7c58fe028cb543f8937b45611b/langsmith-0.8.0.tar.gz", hash = "sha256:59fe5b2a56bbbe14a08aa76691f84b49e8675dd21e11b57d80c6db8c08bac2e3", size = 4432996, upload-time = "2026-04-30T22:13:07.341Z" }
sdist = { url = "https://files.pythonhosted.org/packages/9a/d9/a6681aa9847bbbc5ec21abe20a5e233b94e5edcfe39624db607ac7e8ccb4/langsmith-0.8.18.tar.gz", hash = "sha256:32dde9c0e67e053e0fb738921fc8ced768af7b8fa83d7a0e3fd63597cf8776dd", size = 4526988, upload-time = "2026-06-19T13:12:17.123Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f3/e1/a4be2e696c9473bb53298df398237da5674704d781d4b748ed35aeef592a/langsmith-0.8.0-py3-none-any.whl", hash = "sha256:12cc4bc5622b835a6d841964d6034df3617bdb912dae0c1381fd0a68a9b3a3ef", size = 393268, upload-time = "2026-04-30T22:13:05.56Z" },
{ url = "https://files.pythonhosted.org/packages/03/70/0e0cc80a3b064c8d6c8d697c3125ed86e39d5a7393ec6dc8b07cb1cf13c4/langsmith-0.8.18-py3-none-any.whl", hash = "sha256:3940183349993faef48e6c7d08e4822ee9cefd906b362d0e3c2d650314d2f282", size = 508108, upload-time = "2026-06-19T13:12:15.348Z" },
]
[[package]]
@@ -1040,15 +1041,15 @@ wheels = [
[[package]]
name = "starlette"
version = "1.0.1"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/08/a3/84e821cc54b4ab50ae6dbc6ac3800a651b65ec35f045cc73785380654057/starlette-1.0.1.tar.gz", hash = "sha256:512399c5f1de7fac99c88572212ded9ddeddef2fb32afa82d724000e88b38f4f", size = 2659596, upload-time = "2026-05-21T21:58:58.433Z" }
sdist = { url = "https://files.pythonhosted.org/packages/eb/e3/7c1dc7381d9f8ab7d854328ebfa884e62cb3f3d8549ddfd37c7814f42afa/starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0", size = 2703240, upload-time = "2026-06-12T09:23:11.602Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/e1/b2df4bc09a1e51ff664c1e17018a4274b42e5e9352e4a478ea540512dc88/starlette-1.0.1-py3-none-any.whl", hash = "sha256:7c0e69b2ee1c848bd54669d908500117a3ee13de603a21427e5c6fc1adf98dcd", size = 72802, upload-time = "2026-05-21T21:58:56.551Z" },
{ url = "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl", hash = "sha256:c7372aae11c3c3f26a42df7bd626cec2f47d03483d261d369516a615a53714c6", size = 73632, upload-time = "2026-06-12T09:23:10.017Z" },
]
[[package]]